From d546dfff0995589a59308b613bcba0a65a166eca Mon Sep 17 00:00:00 2001 From: Serhii Mamontov Date: Fri, 29 Mar 2024 11:28:30 +0200 Subject: [PATCH] feat(browser): replace `superagent` with web worker Separate transport provider for browser version of PubNub SDK to provide better user experience. feat(types): client interface rewritten with TypeScript Client interface rewritten with TypeScript which gives up-tp-date interface. --- .eslintrc.js => .eslintrc.cjs | 0 .mocharc.yml | 2 +- dist/web/pubnub.js | 24245 ++++++++-------- dist/web/pubnub.min.js | 19 +- lib/core/components/abort_signal.js | 27 +- lib/core/components/config.js | 209 - lib/core/components/configuration.js | 139 + lib/core/components/cryptography/index.js | 297 +- lib/core/components/endpoint.js | 282 - lib/core/components/eventEmitter.js | 338 +- lib/core/components/listener_manager.js | 212 +- lib/core/components/reconnection_manager.js | 52 +- lib/core/components/request.js | 243 + lib/core/components/subscription-manager.js | 411 + lib/core/components/subscription_manager.js | 434 - lib/core/components/telemetry_manager.js | 137 - lib/core/components/token_manager.js | 3 +- lib/core/constants/categories.js | 96 +- lib/core/constants/operations.js | 312 +- lib/core/endpoints/access_manager/audit.js | 170 +- lib/core/endpoints/access_manager/grant.js | 237 +- .../endpoints/access_manager/grant_token.js | 482 +- .../endpoints/access_manager/revoke_token.js | 132 +- .../endpoints/actions/add_message_action.js | 187 +- .../endpoints/actions/get_message_actions.js | 181 +- .../actions/remove_message_action.js | 153 +- .../endpoints/channel_groups/add_channels.js | 152 +- .../endpoints/channel_groups/delete_group.js | 139 +- .../endpoints/channel_groups/list_channels.js | 139 +- .../endpoints/channel_groups/list_groups.js | 130 +- .../channel_groups/remove_channels.js | 153 +- lib/core/endpoints/endpoint.js | 3 - lib/core/endpoints/fetch_messages.js | 392 +- lib/core/endpoints/file_upload/delete_file.js | 129 +- .../endpoints/file_upload/download_file.js | 135 +- .../file_upload/generate_upload_url.js | 144 +- .../endpoints/file_upload/get_file_url.js | 139 +- lib/core/endpoints/file_upload/list_files.js | 163 +- .../endpoints/file_upload/publish_file.js | 204 +- lib/core/endpoints/file_upload/send_file.js | 281 +- lib/core/endpoints/file_upload/types.js | 2 - lib/core/endpoints/file_upload/upload-file.js | 137 + lib/core/endpoints/history/delete_messages.js | 169 +- lib/core/endpoints/history/get_history.js | 280 +- lib/core/endpoints/history/message_counts.js | 188 +- lib/core/endpoints/objects/channel/get.js | 178 +- lib/core/endpoints/objects/channel/get_all.js | 202 +- lib/core/endpoints/objects/channel/remove.js | 123 +- lib/core/endpoints/objects/channel/set.js | 192 +- lib/core/endpoints/objects/member/get.js | 256 +- lib/core/endpoints/objects/member/set.js | 271 +- lib/core/endpoints/objects/membership/get.js | 257 +- lib/core/endpoints/objects/membership/set.js | 275 +- lib/core/endpoints/objects/uuid/get.js | 187 +- lib/core/endpoints/objects/uuid/get_all.js | 199 +- lib/core/endpoints/objects/uuid/remove.js | 131 +- lib/core/endpoints/objects/uuid/set.js | 197 +- lib/core/endpoints/presence/get_state.js | 171 +- lib/core/endpoints/presence/heartbeat.js | 157 +- lib/core/endpoints/presence/here_now.js | 267 +- lib/core/endpoints/presence/leave.js | 149 +- lib/core/endpoints/presence/set_state.js | 161 +- lib/core/endpoints/presence/where_now.js | 136 +- lib/core/endpoints/publish.js | 264 +- lib/core/endpoints/push/add_push_channels.js | 135 +- lib/core/endpoints/push/list_push_channels.js | 133 +- lib/core/endpoints/push/push.js | 154 + lib/core/endpoints/push/remove_device.js | 133 +- .../endpoints/push/remove_push_channels.js | 135 +- lib/core/endpoints/signal.js | 148 +- lib/core/endpoints/subscribe.js | 470 +- .../endpoints/subscriptionUtils/handshake.js | 100 +- .../subscriptionUtils/receiveMessages.js | 138 +- lib/core/endpoints/time.js | 118 +- lib/core/endpoints/user/create.js | 40 - lib/core/endpoints/user/fetch.js | 34 - lib/core/interfaces/configuration.js | 178 + lib/core/interfaces/crypto-module.js | 90 + lib/core/interfaces/cryptography.js | 5 + .../_endpoint.js => interfaces/request.js} | 0 .../interfaces/transport.js} | 0 lib/core/pubnub-channel-groups.js | 166 + lib/core/pubnub-common.js | 2409 +- lib/core/pubnub-objects.js | 663 + lib/core/pubnub-push.js | 136 + lib/core/types/api/access-panager.js | 4 + lib/core/types/api/app-context.js | 3 + lib/core/types/api/channel-groups.js | 2 + lib/core/types/api/file-sharing.js | 6 + lib/core/types/api/history.js | 25 + lib/core/types/api/index.js | 182 + lib/core/types/api/message-action.js | 2 + lib/core/types/api/presence.js | 3 + lib/core/types/api/push-notifications.js | 2 + lib/core/types/api/push.js | 3 + lib/core/types/api/subscription.js | 2 + lib/core/types/file.js | 5 + lib/core/types/transport-request.js | 33 + lib/core/types/transport-response.js | 2 + lib/core/utils.js | 83 +- .../modules/NodeCryptoModule/ICryptor.js | 3 + .../NodeCryptoModule/ILegacyCryptor.js | 3 + .../modules/NodeCryptoModule/aesCbcCryptor.js | 134 +- .../modules/NodeCryptoModule/legacyCryptor.js | 64 +- .../NodeCryptoModule/nodeCryptoModule.js | 420 +- .../modules/WebCryptoModule/ICryptor.js | 3 + .../modules/WebCryptoModule/ILegacyCryptor.js | 3 + .../modules/WebCryptoModule/aesCbcCryptor.js | 142 +- .../modules/WebCryptoModule/legacyCryptor.js | 82 +- .../WebCryptoModule/webCryptoModule.js | 341 +- lib/crypto/modules/node.js | 359 +- lib/crypto/modules/web.js | 297 +- lib/entities/Channel.js | 2 +- lib/entities/ChannelGroup.js | 2 +- lib/entities/SubscribeCapable.js | 8 +- lib/entities/Subscription.js | 2 +- lib/event-engine/core/reconnectionDelay.js | 27 - lib/event-engine/core/retryPolicy.js | 26 +- lib/event-engine/dispatcher.js | 314 +- lib/event-engine/effects.js | 2 + lib/event-engine/index.js | 4 +- lib/event-engine/presence/dispatcher.js | 207 +- lib/event-engine/presence/effects.js | 2 + lib/event-engine/presence/presence.js | 2 +- lib/event-engine/states/handshake_failure.js | 26 - lib/event-engine/states/receive_failure.js | 38 - lib/file/index.js | 2 - lib/file/modules/node.js | 317 +- lib/file/modules/react-native.js | 392 +- lib/file/modules/web.js | 276 +- lib/models/PubNubError.js | 52 + lib/networking/index.js | 102 - lib/networking/modules/react_native.js | 3 +- lib/networking/modules/web-node.js | 22 +- lib/networking/utils.js | 2 + lib/node/configuration.js | 40 + lib/node/index.js | 129 +- lib/react_native/configuration.js | 13 + lib/react_native/index.js | 76 +- lib/transport/middleware.js | 135 + lib/transport/node-transport.js | 324 + lib/transport/react-native-transport.js | 252 + lib/transport/web-transport.js | 133 + lib/transport/web-worker.js | 362 + lib/web/configuration.js | 42 + lib/web/index.js | 125 +- package-lock.json | 4430 +-- package.json | 53 +- rollup.config.js | 104 +- src/core/components/config.js | 386 - src/core/components/configuration.ts | 210 + src/core/components/cryptography/index.js | 173 - src/core/components/cryptography/index.ts | 309 + src/core/components/deduping_manager.js | 2 - src/core/components/endpoint.js | 280 - src/core/components/eventEmitter.js | 289 - src/core/components/eventEmitter.ts | 197 + src/core/components/listener_manager.js | 102 - src/core/components/listener_manager.ts | 279 + src/core/components/reconnection_manager.js | 34 - src/core/components/reconnection_manager.ts | 56 + src/core/components/request.ts | 176 + src/core/components/subscription-manager.ts | 521 + src/core/components/subscription_manager.js | 579 - src/core/components/telemetry_manager.js | 151 - src/core/components/token_manager.js | 5 +- src/core/constants/categories.js | 36 - src/core/constants/categories.ts | 87 + src/core/constants/operations.js | 92 - src/core/constants/operations.ts | 293 + src/core/endpoints/access_manager/audit.js | 49 - src/core/endpoints/access_manager/audit.ts | 108 + src/core/endpoints/access_manager/grant.js | 84 - src/core/endpoints/access_manager/grant.ts | 184 + .../endpoints/access_manager/grant_token.js | 299 - .../endpoints/access_manager/grant_token.ts | 259 + .../endpoints/access_manager/revoke_token.js | 37 - .../endpoints/access_manager/revoke_token.ts | 89 + .../endpoints/actions/add_message_action.js | 56 - .../endpoints/actions/add_message_action.ts | 103 + .../endpoints/actions/get_message_actions.js | 51 - .../endpoints/actions/get_message_actions.ts | 109 + .../actions/remove_message_action.js | 45 - .../actions/remove_message_action.ts | 95 + .../endpoints/channel_groups/add_channels.js | 42 - .../endpoints/channel_groups/add_channels.ts | 102 + .../endpoints/channel_groups/delete_group.js | 40 - .../endpoints/channel_groups/delete_group.ts | 91 + .../endpoints/channel_groups/list_channels.js | 39 - .../endpoints/channel_groups/list_channels.ts | 106 + .../endpoints/channel_groups/list_groups.js | 36 - .../endpoints/channel_groups/list_groups.ts | 99 + .../channel_groups/remove_channels.js | 42 - .../channel_groups/remove_channels.ts | 105 + src/core/endpoints/endpoint.js | 3 - src/core/endpoints/fetch_messages.js | 127 - src/core/endpoints/fetch_messages.ts | 351 + src/core/endpoints/file_upload/delete_file.js | 39 - src/core/endpoints/file_upload/delete_file.ts | 82 + .../endpoints/file_upload/download_file.js | 56 - .../endpoints/file_upload/download_file.ts | 101 + .../file_upload/generate_upload_url.js | 41 - .../file_upload/generate_upload_url.ts | 146 + .../endpoints/file_upload/get_file_url.js | 63 - .../endpoints/file_upload/get_file_url.ts | 70 + src/core/endpoints/file_upload/list_files.js | 45 - src/core/endpoints/file_upload/list_files.ts | 110 + .../endpoints/file_upload/publish_file.js | 79 - .../endpoints/file_upload/publish_file.ts | 134 + src/core/endpoints/file_upload/send_file.js | 131 - src/core/endpoints/file_upload/send_file.ts | 173 + src/core/endpoints/file_upload/types.js | 1 - src/core/endpoints/file_upload/upload-file.ts | 62 + src/core/endpoints/history/delete_messages.js | 50 - src/core/endpoints/history/delete_messages.ts | 96 + src/core/endpoints/history/get_history.js | 92 - src/core/endpoints/history/get_history.ts | 210 + src/core/endpoints/history/message_counts.js | 55 - src/core/endpoints/history/message_counts.ts | 122 + src/core/endpoints/objects/channel/get.js | 40 - src/core/endpoints/objects/channel/get.ts | 89 + src/core/endpoints/objects/channel/get_all.js | 66 - src/core/endpoints/objects/channel/get_all.ts | 102 + src/core/endpoints/objects/channel/remove.js | 31 - src/core/endpoints/objects/channel/remove.ts | 68 + src/core/endpoints/objects/channel/set.js | 49 - src/core/endpoints/objects/channel/set.ts | 95 + src/core/endpoints/objects/member/get.js | 93 - src/core/endpoints/objects/member/get.ts | 151 + src/core/endpoints/objects/member/set.js | 107 - src/core/endpoints/objects/member/set.ts | 152 + src/core/endpoints/objects/membership/get.js | 89 - src/core/endpoints/objects/membership/get.ts | 154 + src/core/endpoints/objects/membership/set.js | 105 - src/core/endpoints/objects/membership/set.ts | 156 + src/core/endpoints/objects/uuid/get.js | 44 - src/core/endpoints/objects/uuid/get.ts | 95 + src/core/endpoints/objects/uuid/get_all.js | 67 - src/core/endpoints/objects/uuid/get_all.ts | 99 + src/core/endpoints/objects/uuid/remove.js | 32 - src/core/endpoints/objects/uuid/remove.ts | 71 + src/core/endpoints/objects/uuid/set.js | 50 - src/core/endpoints/objects/uuid/set.ts | 98 + src/core/endpoints/presence/get_state.js | 53 - src/core/endpoints/presence/get_state.ts | 122 + src/core/endpoints/presence/heartbeat.js | 49 - src/core/endpoints/presence/heartbeat.ts | 101 + src/core/endpoints/presence/here_now.js | 133 - src/core/endpoints/presence/here_now.ts | 211 + src/core/endpoints/presence/leave.js | 44 - src/core/endpoints/presence/leave.ts | 103 + src/core/endpoints/presence/set_state.js | 50 - src/core/endpoints/presence/set_state.ts | 116 + src/core/endpoints/presence/where_now.js | 40 - src/core/endpoints/presence/where_now.ts | 93 + src/core/endpoints/publish.js | 91 - src/core/endpoints/publish.ts | 229 + src/core/endpoints/push/add_push_channels.js | 53 - src/core/endpoints/push/add_push_channels.ts | 59 + src/core/endpoints/push/list_push_channels.js | 51 - src/core/endpoints/push/list_push_channels.ts | 59 + src/core/endpoints/push/push.ts | 121 + src/core/endpoints/push/remove_device.js | 52 - src/core/endpoints/push/remove_device.ts | 59 + .../endpoints/push/remove_push_channels.js | 53 - .../endpoints/push/remove_push_channels.ts | 59 + src/core/endpoints/signal.js | 49 - src/core/endpoints/signal.ts | 103 + src/core/endpoints/subscribe.js | 89 - src/core/endpoints/subscribe.ts | 838 + .../endpoints/subscriptionUtils/handshake.js | 45 - .../endpoints/subscriptionUtils/handshake.ts | 39 + .../subscriptionUtils/receiveMessages.js | 76 - .../subscriptionUtils/receiveMessages.ts | 48 + src/core/endpoints/time.js | 32 - src/core/endpoints/time.ts | 55 + src/core/interfaces/configuration.ts | 632 +- src/core/interfaces/crypto-module.ts | 201 +- src/core/interfaces/cryptography.ts | 70 + src/core/interfaces/file.ts | 137 - src/core/interfaces/request.ts | 38 + src/core/interfaces/transport.ts | 28 +- src/core/pubnub-channel-groups.ts | 222 + src/core/pubnub-common.js | 847 - src/core/pubnub-common.ts | 3215 ++ src/core/pubnub-objects.ts | 1094 + src/core/pubnub-push.ts | 157 + src/core/types/api/access-panager.ts | 564 + src/core/types/api/app-context.ts | 1088 + src/core/types/api/channel-groups.ts | 64 + src/core/types/api/file-sharing.ts | 454 + src/core/types/api/history.ts | 475 + src/core/types/api/index.ts | 295 + src/core/types/api/message-action.ts | 175 + src/core/types/api/presence.ts | 250 + src/core/types/api/push-notifications.ts | 53 + src/core/types/api/push.ts | 121 + src/core/types/api/subscription.ts | 371 + src/core/types/file.ts | 107 + src/core/types/transport-request.ts | 64 +- src/core/types/transport-response.ts | 12 +- src/core/utils.js | 71 - src/core/utils.ts | 51 + .../modules/NodeCryptoModule/ICryptor.ts | 91 +- .../NodeCryptoModule/ILegacyCryptor.ts | 94 +- .../modules/NodeCryptoModule/aesCbcCryptor.ts | 143 +- .../modules/NodeCryptoModule/legacyCryptor.ts | 77 +- .../NodeCryptoModule/nodeCryptoModule.ts | 442 +- .../modules/WebCryptoModule/ICryptor.ts | 77 +- .../modules/WebCryptoModule/ILegacyCryptor.ts | 94 +- .../modules/WebCryptoModule/aesCbcCryptor.ts | 136 +- .../modules/WebCryptoModule/legacyCryptor.ts | 92 +- .../WebCryptoModule/webCryptoModule.ts | 283 +- src/crypto/modules/node.js | 191 - src/crypto/modules/node.ts | 293 + src/crypto/modules/web.js | 117 - src/crypto/modules/web.ts | 233 + src/entities/Channel.ts | 18 +- src/entities/ChannelGroup.ts | 18 +- src/entities/ChannelMetadata.ts | 18 +- src/entities/SubscribeCapable.ts | 26 +- src/entities/Subscription.ts | 12 +- src/entities/SubscriptionSet.ts | 12 +- src/entities/UserMetadata.ts | 18 +- src/entities/commonTypes.ts | 27 - src/event-engine/core/handler.ts | 5 +- src/event-engine/core/retryPolicy.ts | 80 +- src/event-engine/core/types.ts | 2 - src/event-engine/dispatcher.ts | 41 +- src/event-engine/effects.ts | 11 +- src/event-engine/events.ts | 39 +- src/event-engine/index.ts | 8 +- src/event-engine/presence/dispatcher.ts | 23 +- src/event-engine/presence/effects.ts | 3 + src/event-engine/presence/events.ts | 2 +- src/event-engine/presence/presence.ts | 4 +- .../presence/states/heartbeat_reconnecting.ts | 2 +- src/event-engine/states/handshake_failed.ts | 6 +- .../states/handshake_reconnecting.ts | 6 +- src/event-engine/states/handshake_stopped.ts | 4 +- src/event-engine/states/handshaking.ts | 4 +- src/event-engine/states/receive_failed.ts | 6 +- .../states/receive_reconnecting.ts | 6 +- src/event-engine/states/receive_stopped.ts | 4 +- src/event-engine/states/receiving.ts | 4 +- src/file/index.js | 1 - src/file/modules/node.ts | 327 +- src/file/modules/react-native.js | 167 - src/file/modules/react-native.ts | 261 + src/file/modules/web.ts | 264 +- src/models/PubNubError.ts | 32 + src/networking/index.js | 135 - src/networking/modules/web-node.js | 19 +- src/networking/utils.js | 3 + src/node/configuration.ts | 80 +- src/node/index.ts | 138 +- src/react_native/configuration.ts | 19 + src/react_native/index.js | 35 - src/react_native/index.ts | 57 + src/transport/middleware.ts | 132 +- src/transport/node-transport.ts | 188 +- src/transport/react-native-transport.ts | 176 + src/transport/titanium-transport.ts | 9 - src/transport/transport.ts | 44 - src/transport/web-transport.ts | 174 +- src/transport/web-worker.ts | 543 + src/web/configuration.ts | 83 +- src/web/index.ts | 120 +- test/{setup.js => setup.cjs} | 0 369 files changed, 52757 insertions(+), 29815 deletions(-) rename .eslintrc.js => .eslintrc.cjs (100%) delete mode 100644 lib/core/components/config.js create mode 100644 lib/core/components/configuration.js delete mode 100644 lib/core/components/endpoint.js create mode 100644 lib/core/components/request.js create mode 100644 lib/core/components/subscription-manager.js delete mode 100644 lib/core/components/subscription_manager.js delete mode 100644 lib/core/components/telemetry_manager.js delete mode 100644 lib/core/endpoints/endpoint.js delete mode 100644 lib/core/endpoints/file_upload/types.js create mode 100644 lib/core/endpoints/file_upload/upload-file.js create mode 100644 lib/core/endpoints/push/push.js delete mode 100644 lib/core/endpoints/user/create.js delete mode 100644 lib/core/endpoints/user/fetch.js create mode 100644 lib/core/interfaces/configuration.js create mode 100644 lib/core/interfaces/crypto-module.js create mode 100644 lib/core/interfaces/cryptography.js rename lib/core/{components/_endpoint.js => interfaces/request.js} (100%) rename lib/{entities/common.js => core/interfaces/transport.js} (100%) create mode 100644 lib/core/pubnub-channel-groups.js create mode 100644 lib/core/pubnub-objects.js create mode 100644 lib/core/pubnub-push.js create mode 100644 lib/core/types/api/access-panager.js create mode 100644 lib/core/types/api/app-context.js create mode 100644 lib/core/types/api/channel-groups.js create mode 100644 lib/core/types/api/file-sharing.js create mode 100644 lib/core/types/api/history.js create mode 100644 lib/core/types/api/index.js create mode 100644 lib/core/types/api/message-action.js create mode 100644 lib/core/types/api/presence.js create mode 100644 lib/core/types/api/push-notifications.js create mode 100644 lib/core/types/api/push.js create mode 100644 lib/core/types/api/subscription.js create mode 100644 lib/core/types/file.js create mode 100644 lib/core/types/transport-request.js create mode 100644 lib/core/types/transport-response.js delete mode 100644 lib/event-engine/core/reconnectionDelay.js delete mode 100644 lib/event-engine/states/handshake_failure.js delete mode 100644 lib/event-engine/states/receive_failure.js delete mode 100644 lib/file/index.js create mode 100644 lib/models/PubNubError.js delete mode 100644 lib/networking/index.js create mode 100644 lib/node/configuration.js create mode 100644 lib/react_native/configuration.js create mode 100644 lib/transport/middleware.js create mode 100644 lib/transport/node-transport.js create mode 100644 lib/transport/react-native-transport.js create mode 100644 lib/transport/web-transport.js create mode 100644 lib/transport/web-worker.js create mode 100644 lib/web/configuration.js delete mode 100644 src/core/components/config.js create mode 100644 src/core/components/configuration.ts delete mode 100644 src/core/components/cryptography/index.js create mode 100644 src/core/components/cryptography/index.ts delete mode 100644 src/core/components/endpoint.js delete mode 100644 src/core/components/eventEmitter.js create mode 100644 src/core/components/eventEmitter.ts delete mode 100644 src/core/components/listener_manager.js create mode 100644 src/core/components/listener_manager.ts delete mode 100644 src/core/components/reconnection_manager.js create mode 100644 src/core/components/reconnection_manager.ts create mode 100644 src/core/components/request.ts create mode 100644 src/core/components/subscription-manager.ts delete mode 100644 src/core/components/subscription_manager.js delete mode 100644 src/core/components/telemetry_manager.js delete mode 100644 src/core/constants/categories.js create mode 100644 src/core/constants/categories.ts delete mode 100644 src/core/constants/operations.js create mode 100644 src/core/constants/operations.ts delete mode 100644 src/core/endpoints/access_manager/audit.js create mode 100644 src/core/endpoints/access_manager/audit.ts delete mode 100644 src/core/endpoints/access_manager/grant.js create mode 100644 src/core/endpoints/access_manager/grant.ts delete mode 100644 src/core/endpoints/access_manager/grant_token.js create mode 100644 src/core/endpoints/access_manager/grant_token.ts delete mode 100644 src/core/endpoints/access_manager/revoke_token.js create mode 100644 src/core/endpoints/access_manager/revoke_token.ts delete mode 100644 src/core/endpoints/actions/add_message_action.js create mode 100644 src/core/endpoints/actions/add_message_action.ts delete mode 100644 src/core/endpoints/actions/get_message_actions.js create mode 100644 src/core/endpoints/actions/get_message_actions.ts delete mode 100644 src/core/endpoints/actions/remove_message_action.js create mode 100644 src/core/endpoints/actions/remove_message_action.ts delete mode 100644 src/core/endpoints/channel_groups/add_channels.js create mode 100644 src/core/endpoints/channel_groups/add_channels.ts delete mode 100644 src/core/endpoints/channel_groups/delete_group.js create mode 100644 src/core/endpoints/channel_groups/delete_group.ts delete mode 100644 src/core/endpoints/channel_groups/list_channels.js create mode 100644 src/core/endpoints/channel_groups/list_channels.ts delete mode 100644 src/core/endpoints/channel_groups/list_groups.js create mode 100644 src/core/endpoints/channel_groups/list_groups.ts delete mode 100644 src/core/endpoints/channel_groups/remove_channels.js create mode 100644 src/core/endpoints/channel_groups/remove_channels.ts delete mode 100644 src/core/endpoints/endpoint.js delete mode 100644 src/core/endpoints/fetch_messages.js create mode 100644 src/core/endpoints/fetch_messages.ts delete mode 100644 src/core/endpoints/file_upload/delete_file.js create mode 100644 src/core/endpoints/file_upload/delete_file.ts delete mode 100644 src/core/endpoints/file_upload/download_file.js create mode 100644 src/core/endpoints/file_upload/download_file.ts delete mode 100644 src/core/endpoints/file_upload/generate_upload_url.js create mode 100644 src/core/endpoints/file_upload/generate_upload_url.ts delete mode 100644 src/core/endpoints/file_upload/get_file_url.js create mode 100644 src/core/endpoints/file_upload/get_file_url.ts delete mode 100644 src/core/endpoints/file_upload/list_files.js create mode 100644 src/core/endpoints/file_upload/list_files.ts delete mode 100644 src/core/endpoints/file_upload/publish_file.js create mode 100644 src/core/endpoints/file_upload/publish_file.ts delete mode 100644 src/core/endpoints/file_upload/send_file.js create mode 100644 src/core/endpoints/file_upload/send_file.ts delete mode 100644 src/core/endpoints/file_upload/types.js create mode 100644 src/core/endpoints/file_upload/upload-file.ts delete mode 100644 src/core/endpoints/history/delete_messages.js create mode 100644 src/core/endpoints/history/delete_messages.ts delete mode 100644 src/core/endpoints/history/get_history.js create mode 100644 src/core/endpoints/history/get_history.ts delete mode 100644 src/core/endpoints/history/message_counts.js create mode 100644 src/core/endpoints/history/message_counts.ts delete mode 100644 src/core/endpoints/objects/channel/get.js create mode 100644 src/core/endpoints/objects/channel/get.ts delete mode 100644 src/core/endpoints/objects/channel/get_all.js create mode 100644 src/core/endpoints/objects/channel/get_all.ts delete mode 100644 src/core/endpoints/objects/channel/remove.js create mode 100644 src/core/endpoints/objects/channel/remove.ts delete mode 100644 src/core/endpoints/objects/channel/set.js create mode 100644 src/core/endpoints/objects/channel/set.ts delete mode 100644 src/core/endpoints/objects/member/get.js create mode 100644 src/core/endpoints/objects/member/get.ts delete mode 100644 src/core/endpoints/objects/member/set.js create mode 100644 src/core/endpoints/objects/member/set.ts delete mode 100644 src/core/endpoints/objects/membership/get.js create mode 100644 src/core/endpoints/objects/membership/get.ts delete mode 100644 src/core/endpoints/objects/membership/set.js create mode 100644 src/core/endpoints/objects/membership/set.ts delete mode 100644 src/core/endpoints/objects/uuid/get.js create mode 100644 src/core/endpoints/objects/uuid/get.ts delete mode 100644 src/core/endpoints/objects/uuid/get_all.js create mode 100644 src/core/endpoints/objects/uuid/get_all.ts delete mode 100644 src/core/endpoints/objects/uuid/remove.js create mode 100644 src/core/endpoints/objects/uuid/remove.ts delete mode 100644 src/core/endpoints/objects/uuid/set.js create mode 100644 src/core/endpoints/objects/uuid/set.ts delete mode 100644 src/core/endpoints/presence/get_state.js create mode 100644 src/core/endpoints/presence/get_state.ts delete mode 100644 src/core/endpoints/presence/heartbeat.js create mode 100644 src/core/endpoints/presence/heartbeat.ts delete mode 100644 src/core/endpoints/presence/here_now.js create mode 100644 src/core/endpoints/presence/here_now.ts delete mode 100644 src/core/endpoints/presence/leave.js create mode 100644 src/core/endpoints/presence/leave.ts delete mode 100644 src/core/endpoints/presence/set_state.js create mode 100644 src/core/endpoints/presence/set_state.ts delete mode 100644 src/core/endpoints/presence/where_now.js create mode 100644 src/core/endpoints/presence/where_now.ts delete mode 100644 src/core/endpoints/publish.js create mode 100644 src/core/endpoints/publish.ts delete mode 100644 src/core/endpoints/push/add_push_channels.js create mode 100644 src/core/endpoints/push/add_push_channels.ts delete mode 100644 src/core/endpoints/push/list_push_channels.js create mode 100644 src/core/endpoints/push/list_push_channels.ts create mode 100644 src/core/endpoints/push/push.ts delete mode 100644 src/core/endpoints/push/remove_device.js create mode 100644 src/core/endpoints/push/remove_device.ts delete mode 100644 src/core/endpoints/push/remove_push_channels.js create mode 100644 src/core/endpoints/push/remove_push_channels.ts delete mode 100644 src/core/endpoints/signal.js create mode 100644 src/core/endpoints/signal.ts delete mode 100644 src/core/endpoints/subscribe.js create mode 100644 src/core/endpoints/subscribe.ts delete mode 100644 src/core/endpoints/subscriptionUtils/handshake.js create mode 100644 src/core/endpoints/subscriptionUtils/handshake.ts delete mode 100644 src/core/endpoints/subscriptionUtils/receiveMessages.js create mode 100644 src/core/endpoints/subscriptionUtils/receiveMessages.ts delete mode 100644 src/core/endpoints/time.js create mode 100644 src/core/endpoints/time.ts create mode 100644 src/core/interfaces/cryptography.ts delete mode 100644 src/core/interfaces/file.ts create mode 100644 src/core/interfaces/request.ts create mode 100644 src/core/pubnub-channel-groups.ts delete mode 100644 src/core/pubnub-common.js create mode 100644 src/core/pubnub-common.ts create mode 100644 src/core/pubnub-objects.ts create mode 100644 src/core/pubnub-push.ts create mode 100644 src/core/types/api/access-panager.ts create mode 100644 src/core/types/api/app-context.ts create mode 100644 src/core/types/api/channel-groups.ts create mode 100644 src/core/types/api/file-sharing.ts create mode 100644 src/core/types/api/history.ts create mode 100644 src/core/types/api/index.ts create mode 100644 src/core/types/api/message-action.ts create mode 100644 src/core/types/api/presence.ts create mode 100644 src/core/types/api/push-notifications.ts create mode 100644 src/core/types/api/push.ts create mode 100644 src/core/types/api/subscription.ts create mode 100644 src/core/types/file.ts delete mode 100644 src/core/utils.js create mode 100644 src/core/utils.ts delete mode 100644 src/crypto/modules/node.js create mode 100644 src/crypto/modules/node.ts delete mode 100644 src/crypto/modules/web.js create mode 100644 src/crypto/modules/web.ts delete mode 100644 src/file/index.js delete mode 100644 src/file/modules/react-native.js create mode 100644 src/file/modules/react-native.ts create mode 100644 src/models/PubNubError.ts delete mode 100644 src/networking/index.js create mode 100644 src/react_native/configuration.ts delete mode 100644 src/react_native/index.js create mode 100644 src/react_native/index.ts create mode 100644 src/transport/react-native-transport.ts delete mode 100644 src/transport/titanium-transport.ts delete mode 100644 src/transport/transport.ts create mode 100644 src/transport/web-worker.ts rename test/{setup.js => setup.cjs} (100%) diff --git a/.eslintrc.js b/.eslintrc.cjs similarity index 100% rename from .eslintrc.js rename to .eslintrc.cjs diff --git a/.mocharc.yml b/.mocharc.yml index 425715e05..34760e229 100644 --- a/.mocharc.yml +++ b/.mocharc.yml @@ -1,5 +1,5 @@ spec: test/**/*.test.{ts,js} -require: test/setup.js +require: test/setup.cjs exclude: - test/dist/*.js - test/feature/*.js diff --git a/dist/web/pubnub.js b/dist/web/pubnub.js index 112124b0c..42b045caf 100644 --- a/dist/web/pubnub.js +++ b/dist/web/pubnub.js @@ -4,7 +4,7 @@ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.PubNub = factory()); })(this, (function () { 'use strict'; - /*! ***************************************************************************** + /****************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any @@ -18,7 +18,7 @@ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ - /* global Reflect, Promise */ + /* global Reflect, Promise, SuppressedError, Symbol */ var extendStatics = function(d, b) { extendStatics = Object.setPrototypeOf || @@ -74,7 +74,7 @@ function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); - while (_) try { + while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { @@ -108,7 +108,7 @@ throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); } - function __read$1(o, n) { + function __read(o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; @@ -125,7 +125,7 @@ return ar; } - function __spreadArray$1(to, from, pack) { + function __spreadArray(to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); @@ -133,23 +133,17 @@ } } return to.concat(ar || Array.prototype.slice.call(from)); - } + } + + typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { + var e = new Error(message); + return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; + }; var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; - function getAugmentedNamespace(n) { - if (n.__esModule) return n; - var a = Object.defineProperty({}, '__esModule', {value: true}); - Object.keys(n).forEach(function (k) { - var d = Object.getOwnPropertyDescriptor(n, k); - Object.defineProperty(a, k, d.get ? d : { - enumerable: true, - get: function () { - return n[k]; - } - }); - }); - return a; + function getDefaultExportFromCjs (x) { + return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; } var cbor = {exports: {}}; @@ -179,646 +173,631 @@ */ (function (module) { - (function(global, undefined$1) {var POW_2_24 = Math.pow(2, -24), - POW_2_32 = Math.pow(2, 32), - POW_2_53 = Math.pow(2, 53); + (function(global, undefined$1) { var POW_2_24 = Math.pow(2, -24), + POW_2_32 = Math.pow(2, 32), + POW_2_53 = Math.pow(2, 53); - function encode(value) { - var data = new ArrayBuffer(256); - var dataView = new DataView(data); - var lastLength; - var offset = 0; + function encode(value) { + var data = new ArrayBuffer(256); + var dataView = new DataView(data); + var lastLength; + var offset = 0; - function ensureSpace(length) { - var newByteLength = data.byteLength; - var requiredLength = offset + length; - while (newByteLength < requiredLength) - newByteLength *= 2; - if (newByteLength !== data.byteLength) { - var oldDataView = dataView; - data = new ArrayBuffer(newByteLength); - dataView = new DataView(data); - var uint32count = (offset + 3) >> 2; - for (var i = 0; i < uint32count; ++i) - dataView.setUint32(i * 4, oldDataView.getUint32(i * 4)); - } + function ensureSpace(length) { + var newByteLength = data.byteLength; + var requiredLength = offset + length; + while (newByteLength < requiredLength) + newByteLength *= 2; + if (newByteLength !== data.byteLength) { + var oldDataView = dataView; + data = new ArrayBuffer(newByteLength); + dataView = new DataView(data); + var uint32count = (offset + 3) >> 2; + for (var i = 0; i < uint32count; ++i) + dataView.setUint32(i * 4, oldDataView.getUint32(i * 4)); + } - lastLength = length; - return dataView; - } - function write() { - offset += lastLength; - } - function writeFloat64(value) { - write(ensureSpace(8).setFloat64(offset, value)); - } - function writeUint8(value) { - write(ensureSpace(1).setUint8(offset, value)); - } - function writeUint8Array(value) { - var dataView = ensureSpace(value.length); - for (var i = 0; i < value.length; ++i) - dataView.setUint8(offset + i, value[i]); - write(); - } - function writeUint16(value) { - write(ensureSpace(2).setUint16(offset, value)); - } - function writeUint32(value) { - write(ensureSpace(4).setUint32(offset, value)); - } - function writeUint64(value) { - var low = value % POW_2_32; - var high = (value - low) / POW_2_32; - var dataView = ensureSpace(8); - dataView.setUint32(offset, high); - dataView.setUint32(offset + 4, low); - write(); - } - function writeTypeAndLength(type, length) { - if (length < 24) { - writeUint8(type << 5 | length); - } else if (length < 0x100) { - writeUint8(type << 5 | 24); - writeUint8(length); - } else if (length < 0x10000) { - writeUint8(type << 5 | 25); - writeUint16(length); - } else if (length < 0x100000000) { - writeUint8(type << 5 | 26); - writeUint32(length); - } else { - writeUint8(type << 5 | 27); - writeUint64(length); - } - } - - function encodeItem(value) { - var i; + lastLength = length; + return dataView; + } + function write() { + offset += lastLength; + } + function writeFloat64(value) { + write(ensureSpace(8).setFloat64(offset, value)); + } + function writeUint8(value) { + write(ensureSpace(1).setUint8(offset, value)); + } + function writeUint8Array(value) { + var dataView = ensureSpace(value.length); + for (var i = 0; i < value.length; ++i) + dataView.setUint8(offset + i, value[i]); + write(); + } + function writeUint16(value) { + write(ensureSpace(2).setUint16(offset, value)); + } + function writeUint32(value) { + write(ensureSpace(4).setUint32(offset, value)); + } + function writeUint64(value) { + var low = value % POW_2_32; + var high = (value - low) / POW_2_32; + var dataView = ensureSpace(8); + dataView.setUint32(offset, high); + dataView.setUint32(offset + 4, low); + write(); + } + function writeTypeAndLength(type, length) { + if (length < 24) { + writeUint8(type << 5 | length); + } else if (length < 0x100) { + writeUint8(type << 5 | 24); + writeUint8(length); + } else if (length < 0x10000) { + writeUint8(type << 5 | 25); + writeUint16(length); + } else if (length < 0x100000000) { + writeUint8(type << 5 | 26); + writeUint32(length); + } else { + writeUint8(type << 5 | 27); + writeUint64(length); + } + } + + function encodeItem(value) { + var i; - if (value === false) - return writeUint8(0xf4); - if (value === true) - return writeUint8(0xf5); - if (value === null) - return writeUint8(0xf6); - if (value === undefined$1) - return writeUint8(0xf7); - - switch (typeof value) { - case "number": - if (Math.floor(value) === value) { - if (0 <= value && value <= POW_2_53) - return writeTypeAndLength(0, value); - if (-POW_2_53 <= value && value < 0) - return writeTypeAndLength(1, -(value + 1)); - } - writeUint8(0xfb); - return writeFloat64(value); + if (value === false) + return writeUint8(0xf4); + if (value === true) + return writeUint8(0xf5); + if (value === null) + return writeUint8(0xf6); + if (value === undefined$1) + return writeUint8(0xf7); + + switch (typeof value) { + case "number": + if (Math.floor(value) === value) { + if (0 <= value && value <= POW_2_53) + return writeTypeAndLength(0, value); + if (-POW_2_53 <= value && value < 0) + return writeTypeAndLength(1, -(value + 1)); + } + writeUint8(0xfb); + return writeFloat64(value); - case "string": - var utf8data = []; - for (i = 0; i < value.length; ++i) { - var charCode = value.charCodeAt(i); - if (charCode < 0x80) { - utf8data.push(charCode); - } else if (charCode < 0x800) { - utf8data.push(0xc0 | charCode >> 6); - utf8data.push(0x80 | charCode & 0x3f); - } else if (charCode < 0xd800) { - utf8data.push(0xe0 | charCode >> 12); - utf8data.push(0x80 | (charCode >> 6) & 0x3f); - utf8data.push(0x80 | charCode & 0x3f); - } else { - charCode = (charCode & 0x3ff) << 10; - charCode |= value.charCodeAt(++i) & 0x3ff; - charCode += 0x10000; + case "string": + var utf8data = []; + for (i = 0; i < value.length; ++i) { + var charCode = value.charCodeAt(i); + if (charCode < 0x80) { + utf8data.push(charCode); + } else if (charCode < 0x800) { + utf8data.push(0xc0 | charCode >> 6); + utf8data.push(0x80 | charCode & 0x3f); + } else if (charCode < 0xd800) { + utf8data.push(0xe0 | charCode >> 12); + utf8data.push(0x80 | (charCode >> 6) & 0x3f); + utf8data.push(0x80 | charCode & 0x3f); + } else { + charCode = (charCode & 0x3ff) << 10; + charCode |= value.charCodeAt(++i) & 0x3ff; + charCode += 0x10000; - utf8data.push(0xf0 | charCode >> 18); - utf8data.push(0x80 | (charCode >> 12) & 0x3f); - utf8data.push(0x80 | (charCode >> 6) & 0x3f); - utf8data.push(0x80 | charCode & 0x3f); - } - } + utf8data.push(0xf0 | charCode >> 18); + utf8data.push(0x80 | (charCode >> 12) & 0x3f); + utf8data.push(0x80 | (charCode >> 6) & 0x3f); + utf8data.push(0x80 | charCode & 0x3f); + } + } - writeTypeAndLength(3, utf8data.length); - return writeUint8Array(utf8data); + writeTypeAndLength(3, utf8data.length); + return writeUint8Array(utf8data); - default: - var length; - if (Array.isArray(value)) { - length = value.length; - writeTypeAndLength(4, length); - for (i = 0; i < length; ++i) - encodeItem(value[i]); - } else if (value instanceof Uint8Array) { - writeTypeAndLength(2, value.length); - writeUint8Array(value); - } else { - var keys = Object.keys(value); - length = keys.length; - writeTypeAndLength(5, length); - for (i = 0; i < length; ++i) { - var key = keys[i]; - encodeItem(key); - encodeItem(value[key]); - } - } - } - } - - encodeItem(value); + default: + var length; + if (Array.isArray(value)) { + length = value.length; + writeTypeAndLength(4, length); + for (i = 0; i < length; ++i) + encodeItem(value[i]); + } else if (value instanceof Uint8Array) { + writeTypeAndLength(2, value.length); + writeUint8Array(value); + } else { + var keys = Object.keys(value); + length = keys.length; + writeTypeAndLength(5, length); + for (i = 0; i < length; ++i) { + var key = keys[i]; + encodeItem(key); + encodeItem(value[key]); + } + } + } + } + + encodeItem(value); - if ("slice" in data) - return data.slice(0, offset); - - var ret = new ArrayBuffer(offset); - var retView = new DataView(ret); - for (var i = 0; i < offset; ++i) - retView.setUint8(i, dataView.getUint8(i)); - return ret; - } + if ("slice" in data) + return data.slice(0, offset); + + var ret = new ArrayBuffer(offset); + var retView = new DataView(ret); + for (var i = 0; i < offset; ++i) + retView.setUint8(i, dataView.getUint8(i)); + return ret; + } - function decode(data, tagger, simpleValue) { - var dataView = new DataView(data); - var offset = 0; - - if (typeof tagger !== "function") - tagger = function(value) { return value; }; - if (typeof simpleValue !== "function") - simpleValue = function() { return undefined$1; }; + function decode(data, tagger, simpleValue) { + var dataView = new DataView(data); + var offset = 0; + + if (typeof tagger !== "function") + tagger = function(value) { return value; }; + if (typeof simpleValue !== "function") + simpleValue = function() { return undefined$1; }; - function read(value, length) { - offset += length; - return value; - } - function readArrayBuffer(length) { - return read(new Uint8Array(data, offset, length), length); - } - function readFloat16() { - var tempArrayBuffer = new ArrayBuffer(4); - var tempDataView = new DataView(tempArrayBuffer); - var value = readUint16(); + function read(value, length) { + offset += length; + return value; + } + function readArrayBuffer(length) { + return read(new Uint8Array(data, offset, length), length); + } + function readFloat16() { + var tempArrayBuffer = new ArrayBuffer(4); + var tempDataView = new DataView(tempArrayBuffer); + var value = readUint16(); - var sign = value & 0x8000; - var exponent = value & 0x7c00; - var fraction = value & 0x03ff; - - if (exponent === 0x7c00) - exponent = 0xff << 10; - else if (exponent !== 0) - exponent += (127 - 15) << 10; - else if (fraction !== 0) - return fraction * POW_2_24; - - tempDataView.setUint32(0, sign << 16 | exponent << 13 | fraction << 13); - return tempDataView.getFloat32(0); - } - function readFloat32() { - return read(dataView.getFloat32(offset), 4); - } - function readFloat64() { - return read(dataView.getFloat64(offset), 8); - } - function readUint8() { - return read(dataView.getUint8(offset), 1); - } - function readUint16() { - return read(dataView.getUint16(offset), 2); - } - function readUint32() { - return read(dataView.getUint32(offset), 4); - } - function readUint64() { - return readUint32() * POW_2_32 + readUint32(); - } - function readBreak() { - if (dataView.getUint8(offset) !== 0xff) - return false; - offset += 1; - return true; - } - function readLength(additionalInformation) { - if (additionalInformation < 24) - return additionalInformation; - if (additionalInformation === 24) - return readUint8(); - if (additionalInformation === 25) - return readUint16(); - if (additionalInformation === 26) - return readUint32(); - if (additionalInformation === 27) - return readUint64(); - if (additionalInformation === 31) - return -1; - throw "Invalid length encoding"; - } - function readIndefiniteStringLength(majorType) { - var initialByte = readUint8(); - if (initialByte === 0xff) - return -1; - var length = readLength(initialByte & 0x1f); - if (length < 0 || (initialByte >> 5) !== majorType) - throw "Invalid indefinite length element"; - return length; - } + var sign = value & 0x8000; + var exponent = value & 0x7c00; + var fraction = value & 0x03ff; + + if (exponent === 0x7c00) + exponent = 0xff << 10; + else if (exponent !== 0) + exponent += (127 - 15) << 10; + else if (fraction !== 0) + return fraction * POW_2_24; + + tempDataView.setUint32(0, sign << 16 | exponent << 13 | fraction << 13); + return tempDataView.getFloat32(0); + } + function readFloat32() { + return read(dataView.getFloat32(offset), 4); + } + function readFloat64() { + return read(dataView.getFloat64(offset), 8); + } + function readUint8() { + return read(dataView.getUint8(offset), 1); + } + function readUint16() { + return read(dataView.getUint16(offset), 2); + } + function readUint32() { + return read(dataView.getUint32(offset), 4); + } + function readUint64() { + return readUint32() * POW_2_32 + readUint32(); + } + function readBreak() { + if (dataView.getUint8(offset) !== 0xff) + return false; + offset += 1; + return true; + } + function readLength(additionalInformation) { + if (additionalInformation < 24) + return additionalInformation; + if (additionalInformation === 24) + return readUint8(); + if (additionalInformation === 25) + return readUint16(); + if (additionalInformation === 26) + return readUint32(); + if (additionalInformation === 27) + return readUint64(); + if (additionalInformation === 31) + return -1; + throw "Invalid length encoding"; + } + function readIndefiniteStringLength(majorType) { + var initialByte = readUint8(); + if (initialByte === 0xff) + return -1; + var length = readLength(initialByte & 0x1f); + if (length < 0 || (initialByte >> 5) !== majorType) + throw "Invalid indefinite length element"; + return length; + } - function appendUtf16data(utf16data, length) { - for (var i = 0; i < length; ++i) { - var value = readUint8(); - if (value & 0x80) { - if (value < 0xe0) { - value = (value & 0x1f) << 6 - | (readUint8() & 0x3f); - length -= 1; - } else if (value < 0xf0) { - value = (value & 0x0f) << 12 - | (readUint8() & 0x3f) << 6 - | (readUint8() & 0x3f); - length -= 2; - } else { - value = (value & 0x0f) << 18 - | (readUint8() & 0x3f) << 12 - | (readUint8() & 0x3f) << 6 - | (readUint8() & 0x3f); - length -= 3; - } - } + function appendUtf16data(utf16data, length) { + for (var i = 0; i < length; ++i) { + var value = readUint8(); + if (value & 0x80) { + if (value < 0xe0) { + value = (value & 0x1f) << 6 + | (readUint8() & 0x3f); + length -= 1; + } else if (value < 0xf0) { + value = (value & 0x0f) << 12 + | (readUint8() & 0x3f) << 6 + | (readUint8() & 0x3f); + length -= 2; + } else { + value = (value & 0x0f) << 18 + | (readUint8() & 0x3f) << 12 + | (readUint8() & 0x3f) << 6 + | (readUint8() & 0x3f); + length -= 3; + } + } - if (value < 0x10000) { - utf16data.push(value); - } else { - value -= 0x10000; - utf16data.push(0xd800 | (value >> 10)); - utf16data.push(0xdc00 | (value & 0x3ff)); - } - } - } + if (value < 0x10000) { + utf16data.push(value); + } else { + value -= 0x10000; + utf16data.push(0xd800 | (value >> 10)); + utf16data.push(0xdc00 | (value & 0x3ff)); + } + } + } - function decodeItem() { - var initialByte = readUint8(); - var majorType = initialByte >> 5; - var additionalInformation = initialByte & 0x1f; - var i; - var length; + function decodeItem() { + var initialByte = readUint8(); + var majorType = initialByte >> 5; + var additionalInformation = initialByte & 0x1f; + var i; + var length; - if (majorType === 7) { - switch (additionalInformation) { - case 25: - return readFloat16(); - case 26: - return readFloat32(); - case 27: - return readFloat64(); - } - } + if (majorType === 7) { + switch (additionalInformation) { + case 25: + return readFloat16(); + case 26: + return readFloat32(); + case 27: + return readFloat64(); + } + } - length = readLength(additionalInformation); - if (length < 0 && (majorType < 2 || 6 < majorType)) - throw "Invalid length"; + length = readLength(additionalInformation); + if (length < 0 && (majorType < 2 || 6 < majorType)) + throw "Invalid length"; - switch (majorType) { - case 0: - return length; - case 1: - return -1 - length; - case 2: - if (length < 0) { - var elements = []; - var fullArrayLength = 0; - while ((length = readIndefiniteStringLength(majorType)) >= 0) { - fullArrayLength += length; - elements.push(readArrayBuffer(length)); - } - var fullArray = new Uint8Array(fullArrayLength); - var fullArrayOffset = 0; - for (i = 0; i < elements.length; ++i) { - fullArray.set(elements[i], fullArrayOffset); - fullArrayOffset += elements[i].length; - } - return fullArray; - } - return readArrayBuffer(length); - case 3: - var utf16data = []; - if (length < 0) { - while ((length = readIndefiniteStringLength(majorType)) >= 0) - appendUtf16data(utf16data, length); - } else - appendUtf16data(utf16data, length); - return String.fromCharCode.apply(null, utf16data); - case 4: - var retArray; - if (length < 0) { - retArray = []; - while (!readBreak()) - retArray.push(decodeItem()); - } else { - retArray = new Array(length); - for (i = 0; i < length; ++i) - retArray[i] = decodeItem(); - } - return retArray; - case 5: - var retObject = {}; - for (i = 0; i < length || length < 0 && !readBreak(); ++i) { - var key = decodeItem(); - retObject[key] = decodeItem(); - } - return retObject; - case 6: - return tagger(decodeItem(), length); - case 7: - switch (length) { - case 20: - return false; - case 21: - return true; - case 22: - return null; - case 23: - return undefined$1; - default: - return simpleValue(length); - } - } - } + switch (majorType) { + case 0: + return length; + case 1: + return -1 - length; + case 2: + if (length < 0) { + var elements = []; + var fullArrayLength = 0; + while ((length = readIndefiniteStringLength(majorType)) >= 0) { + fullArrayLength += length; + elements.push(readArrayBuffer(length)); + } + var fullArray = new Uint8Array(fullArrayLength); + var fullArrayOffset = 0; + for (i = 0; i < elements.length; ++i) { + fullArray.set(elements[i], fullArrayOffset); + fullArrayOffset += elements[i].length; + } + return fullArray; + } + return readArrayBuffer(length); + case 3: + var utf16data = []; + if (length < 0) { + while ((length = readIndefiniteStringLength(majorType)) >= 0) + appendUtf16data(utf16data, length); + } else + appendUtf16data(utf16data, length); + return String.fromCharCode.apply(null, utf16data); + case 4: + var retArray; + if (length < 0) { + retArray = []; + while (!readBreak()) + retArray.push(decodeItem()); + } else { + retArray = new Array(length); + for (i = 0; i < length; ++i) + retArray[i] = decodeItem(); + } + return retArray; + case 5: + var retObject = {}; + for (i = 0; i < length || length < 0 && !readBreak(); ++i) { + var key = decodeItem(); + retObject[key] = decodeItem(); + } + return retObject; + case 6: + return tagger(decodeItem(), length); + case 7: + switch (length) { + case 20: + return false; + case 21: + return true; + case 22: + return null; + case 23: + return undefined$1; + default: + return simpleValue(length); + } + } + } - var ret = decodeItem(); - if (offset !== data.byteLength) - throw "Remaining bytes"; - return ret; - } + var ret = decodeItem(); + if (offset !== data.byteLength) + throw "Remaining bytes"; + return ret; + } - var obj = { encode: encode, decode: decode }; + var obj = { encode: encode, decode: decode }; - if (typeof undefined$1 === "function" && undefined$1.amd) - undefined$1("cbor/cbor", obj); - else if (module.exports) - module.exports = obj; - else if (!global.CBOR) - global.CBOR = obj; + if (typeof undefined$1 === "function" && undefined$1.amd) + undefined$1("cbor/cbor", obj); + else if (module.exports) + module.exports = obj; + else if (!global.CBOR) + global.CBOR = obj; - })(commonjsGlobal); - }(cbor)); - - var CborReader = cbor.exports; - - var uuid = {exports: {}}; - - /*! lil-uuid - v0.1 - MIT License - https://github.com/lil-js/uuid */ - - (function (module, exports) { - (function (root, factory) { - { - factory(exports); - if (module !== null) { - module.exports = exports.uuid; - } - } - }(commonjsGlobal, function (exports) { - var VERSION = '0.1.0'; - var uuidRegex = { - '3': /^[0-9A-F]{8}-[0-9A-F]{4}-3[0-9A-F]{3}-[0-9A-F]{4}-[0-9A-F]{12}$/i, - '4': /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i, - '5': /^[0-9A-F]{8}-[0-9A-F]{4}-5[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i, - all: /^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i - }; - - function uuid() { - var uuid = '', i, random; - for (i = 0; i < 32; i++) { - random = Math.random() * 16 | 0; - if (i === 8 || i === 12 || i === 16 || i === 20) uuid += '-'; - uuid += (i === 12 ? 4 : (i === 16 ? (random & 3 | 8) : random)).toString(16); - } - return uuid - } - - function isUUID(str, version) { - var pattern = uuidRegex[version || 'all']; - return pattern && pattern.test(str) || false - } - - uuid.isUUID = isUUID; - uuid.VERSION = VERSION; - - exports.uuid = uuid; - exports.isUUID = isUUID; - })); - }(uuid, uuid.exports)); - - var uuidGenerator$1 = uuid.exports; + })(commonjsGlobal); + } (cbor)); - var uuidGenerator = { - createUUID: function () { - if (uuidGenerator$1.uuid) { - return uuidGenerator$1.uuid(); - } - return uuidGenerator$1(); - }, - }; + var cborExports = cbor.exports; + var CborReader = /*@__PURE__*/getDefaultExportFromCjs(cborExports); - /* */ - var PRESENCE_TIMEOUT_MINIMUM = 20; - var PRESENCE_TIMEOUT_DEFAULT = 300; - var makeDefaultOrigins = function () { return Array.from({ length: 20 }, function (_, i) { return "ps".concat(i + 1, ".pndsn.com"); }); }; - var default_1$b = /** @class */ (function () { - function default_1(_a) { - var setup = _a.setup; - var _b, _c, _d, _e; - this._PNSDKSuffix = {}; - this.instanceId = "pn-".concat(uuidGenerator.createUUID()); - this.secretKey = setup.secretKey || setup.secret_key; - this.subscribeKey = setup.subscribeKey || setup.subscribe_key; - this.publishKey = setup.publishKey || setup.publish_key; - this.sdkName = setup.sdkName; - this.sdkFamily = setup.sdkFamily; - this.partnerId = setup.partnerId; - this.setAuthKey(setup.authKey); - this.cryptoModule = setup.cryptoModule; - this.setFilterExpression(setup.filterExpression); - if (typeof setup.origin !== 'string' && !Array.isArray(setup.origin) && setup.origin !== undefined) { - throw new Error('Origin must be either undefined, a string or a list of strings.'); - } - this.origin = setup.origin || makeDefaultOrigins(); - this.secure = setup.ssl || false; - this.restore = setup.restore || false; - this.proxy = setup.proxy; - this.keepAlive = setup.keepAlive; - this.keepAliveSettings = setup.keepAliveSettings; - this.autoNetworkDetection = setup.autoNetworkDetection || false; - this.dedupeOnSubscribe = setup.dedupeOnSubscribe || false; - this.maximumCacheSize = setup.maximumCacheSize || 100; - this.customEncrypt = setup.customEncrypt; - this.customDecrypt = setup.customDecrypt; - this.fileUploadPublishRetryLimit = (_b = setup.fileUploadPublishRetryLimit) !== null && _b !== void 0 ? _b : 5; - this.useRandomIVs = (_c = setup.useRandomIVs) !== null && _c !== void 0 ? _c : true; - this.enableEventEngine = (_d = setup.enableEventEngine) !== null && _d !== void 0 ? _d : false; - this.maintainPresenceState = (_e = setup.maintainPresenceState) !== null && _e !== void 0 ? _e : true; - // if location config exist and we are in https, force secure to true. - if (typeof location !== 'undefined' && location.protocol === 'https:') { - this.secure = true; - } - this.logVerbosity = setup.logVerbosity || false; - this.suppressLeaveEvents = setup.suppressLeaveEvents || false; - this.announceFailedHeartbeats = setup.announceFailedHeartbeats || true; - this.announceSuccessfulHeartbeats = setup.announceSuccessfulHeartbeats || false; - this.useInstanceId = setup.useInstanceId || false; - this.useRequestId = setup.useRequestId || false; - this.requestMessageCountThreshold = setup.requestMessageCountThreshold; - if (setup.retryConfiguration) { - this._setRetryConfiguration(setup.retryConfiguration); - } - // set timeout to how long a transaction request will wait for the server (default 15 seconds) - this.setTransactionTimeout(setup.transactionalRequestTimeout || 15 * 1000); - // set timeout to how long a subscribe event loop will run (default 310 seconds) - this.setSubscribeTimeout(setup.subscribeRequestTimeout || 310 * 1000); - // set config on beacon (https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon) usage - this.setSendBeaconConfig(setup.useSendBeacon || true); - // how long the SDK will report the client to be alive before issuing a timeout - if (setup.presenceTimeout) { - this.setPresenceTimeout(setup.presenceTimeout); - } - else { - this._presenceTimeout = PRESENCE_TIMEOUT_DEFAULT; - } - if (setup.heartbeatInterval != null) { - this.setHeartbeatInterval(setup.heartbeatInterval); - } - if (typeof setup.userId === 'string') { - if (typeof setup.uuid === 'string') { - throw new Error('Only one of the following configuration options has to be provided: `uuid` or `userId`'); - } - this.setUserId(setup.userId); - } - else { - if (typeof setup.uuid !== 'string') { - throw new Error('One of the following configuration options has to be provided: `uuid` or `userId`'); - } - this.setUUID(setup.uuid); - } - this.setCipherKey(setup.cipherKey, setup); - } - // exposed setters - default_1.prototype.getAuthKey = function () { - return this.authKey; - }; - default_1.prototype.setAuthKey = function (val) { - this.authKey = val; - return this; - }; - default_1.prototype.setCipherKey = function (val, setup, modules) { + /** + * Crypto module. + */ + var AbstractCryptoModule = /** @class */ (function () { + // endregion + function AbstractCryptoModule(configuration) { var _a; - this.cipherKey = val; - if (this.cipherKey) { - this.cryptoModule = - (_a = setup.cryptoModule) !== null && _a !== void 0 ? _a : setup.initCryptoModule({ cipherKey: this.cipherKey, useRandomIVs: this.useRandomIVs }); - if (modules) - modules.cryptoModule = this.cryptoModule; - } - return this; - }; - default_1.prototype.getUUID = function () { - return this.UUID; - }; - default_1.prototype.setUUID = function (val) { - if (!val || typeof val !== 'string' || val.trim().length === 0) { - throw new Error('Missing uuid parameter. Provide a valid string uuid'); - } - this.UUID = val; - return this; - }; - default_1.prototype.getUserId = function () { - return this.UUID; - }; - default_1.prototype.setUserId = function (value) { - if (!value || typeof value !== 'string' || value.trim().length === 0) { - throw new Error('Missing or invalid userId parameter. Provide a valid string userId'); - } - this.UUID = value; - return this; - }; - default_1.prototype.getFilterExpression = function () { - return this.filterExpression; - }; - default_1.prototype.setFilterExpression = function (val) { - this.filterExpression = val; - return this; - }; - default_1.prototype.getPresenceTimeout = function () { - return this._presenceTimeout; - }; - default_1.prototype.setPresenceTimeout = function (val) { - if (val >= PRESENCE_TIMEOUT_MINIMUM) { - this._presenceTimeout = val; - } - else { - this._presenceTimeout = PRESENCE_TIMEOUT_MINIMUM; - // eslint-disable-next-line no-console - console.log('WARNING: Presence timeout is less than the minimum. Using minimum value: ', this._presenceTimeout); - } - this.setHeartbeatInterval(this._presenceTimeout / 2 - 1); - return this; - }; - default_1.prototype.setProxy = function (proxy) { - this.proxy = proxy; - }; - default_1.prototype.getHeartbeatInterval = function () { - return this._heartbeatInterval; - }; - default_1.prototype.setHeartbeatInterval = function (val) { - this._heartbeatInterval = val; - return this; - }; - // deprecated setters. - default_1.prototype.getSubscribeTimeout = function () { - return this._subscribeRequestTimeout; + this.defaultCryptor = configuration.default; + this.cryptors = (_a = configuration.cryptors) !== null && _a !== void 0 ? _a : []; + } + // -------------------------------------------------------- + // --------------- Convenience functions ------------------ + // -------------------------------------------------------- + // region Convenience functions + /** + * Construct crypto module with legacy cryptor for encryption and both legacy and AES-CBC + * cryptors for decryption. + * + * @param config Cryptors configuration options. + * + * @returns Crypto module which encrypts data using legacy cryptor. + * + * @throws Error if `config.cipherKey` not set. + */ + AbstractCryptoModule.legacyCryptoModule = function (config) { + throw new Error('Should be implemented by concrete crypto module implementation.'); }; - default_1.prototype.setSubscribeTimeout = function (val) { - this._subscribeRequestTimeout = val; - return this; + /** + * Construct crypto module with AES-CBC cryptor for encryption and both AES-CBC and legacy + * cryptors for decryption. + * + * @param config Cryptors configuration options. + * + * @returns Crypto module which encrypts data using AES-CBC cryptor. + * + * @throws Error if `config.cipherKey` not set. + */ + AbstractCryptoModule.aesCbcCryptoModule = function (config) { + throw new Error('Should be implemented by concrete crypto module implementation.'); + }; + // endregion + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + // region Helpers + /** + * Retrieve list of module's cryptors. + */ + AbstractCryptoModule.prototype.getAllCryptors = function () { + return __spreadArray([this.defaultCryptor], __read(this.cryptors), false); }; - default_1.prototype.getTransactionTimeout = function () { - return this._transactionalRequestTimeout; + /** + * `String` to {@link ArrayBuffer} response decoder. + */ + AbstractCryptoModule.encoder = new TextEncoder(); + /** + * {@link ArrayBuffer} to {@link string} decoder. + */ + AbstractCryptoModule.decoder = new TextDecoder(); + return AbstractCryptoModule; + }()); + + /* global File, FileReader */ + /** + * Browser {@link PubNub} File object module. + */ + // endregion + /** + * Web implementation for {@link PubNub} File object. + * + * **Important:** Class should implement constructor and class fields from {@link PubNubFileConstructor}. + */ + var PubNubFile = /** @class */ (function () { + function PubNubFile(file) { + var fileMimeType; + var fileName; + var fileData; + if (file instanceof File) { + fileData = file; + fileName = file.name; + fileMimeType = file.type; + } + else if ('data' in file) { + var contents = file.data; + fileMimeType = file.mimeType; + fileName = file.name; + fileData = new File([contents], fileName, { type: fileMimeType }); + } + if (fileData === undefined) + throw new Error("Couldn't construct a file out of supplied options."); + if (fileName === undefined) + throw new Error("Couldn't guess filename out of the options. Please provide one."); + this.mimeType = fileMimeType; + this.data = fileData; + this.name = fileName; + } + // endregion + PubNubFile.create = function (file) { + return new PubNubFile(file); }; - default_1.prototype.setTransactionTimeout = function (val) { - this._transactionalRequestTimeout = val; - return this; + /** + * Convert {@link PubNub} File object content to {@link Buffer}. + * + * @throws Error because {@link Buffer} not available in browser environment. + */ + PubNubFile.prototype.toBuffer = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + throw new Error('This feature is only supported in Node.js environments.'); + }); + }); }; - default_1.prototype.isSendBeaconEnabled = function () { - return this._useSendBeacon; + /** + * Convert {@link PubNub} File object content to {@link ArrayBuffer}. + * + * @returns Asynchronous results of conversion to the {@link ArrayBuffer}. + */ + PubNubFile.prototype.toArrayBuffer = function () { + return __awaiter(this, void 0, void 0, function () { + var _this = this; + return __generator(this, function (_a) { + return [2 /*return*/, new Promise(function (resolve, reject) { + var reader = new FileReader(); + reader.addEventListener('load', function () { + if (reader.result instanceof ArrayBuffer) + return resolve(reader.result); + }); + reader.addEventListener('error', function () { return reject(reader.error); }); + reader.readAsArrayBuffer(_this.data); + })]; + }); + }); }; - default_1.prototype.setSendBeaconConfig = function (val) { - this._useSendBeacon = val; - return this; + /** + * Convert {@link PubNub} File object content to {@link string}. + * + * @returns Asynchronous results of conversion to the {@link string}. + */ + PubNubFile.prototype.toString = function () { + return __awaiter(this, void 0, void 0, function () { + var _this = this; + return __generator(this, function (_a) { + return [2 /*return*/, new Promise(function (resolve, reject) { + var reader = new FileReader(); + reader.addEventListener('load', function () { + if (typeof reader.result === 'string') { + return resolve(reader.result); + } + }); + reader.addEventListener('error', function () { + reject(reader.error); + }); + reader.readAsBinaryString(_this.data); + })]; + }); + }); }; - default_1.prototype.getVersion = function () { - return '7.6.0'; + /** + * Convert {@link PubNub} File object content to {@link Readable} stream. + * + * @throws Error because {@link Readable} stream not available in browser environment. + */ + PubNubFile.prototype.toStream = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + throw new Error('This feature is only supported in Node.js environments.'); + }); + }); }; - default_1.prototype._setRetryConfiguration = function (configuration) { - if (configuration.minimumdelay < 2) { - throw new Error('Minimum delay can not be set less than 2 seconds for retry'); - } - if (configuration.maximumDelay > 150) { - throw new Error('Maximum delay can not be set more than 150 seconds for retry'); - } - if (configuration.maximumDelay && maximumRetry > 6) { - throw new Error('Maximum retry for exponential retry policy can not be more than 6'); - } - else if (configuration.maximumRetry > 10) { - throw new Error('Maximum retry for linear retry policy can not be more than 10'); - } - this.retryConfiguration = configuration; + /** + * Convert {@link PubNub} File object content to {@link File}. + * + * @returns Asynchronous results of conversion to the {@link File}. + */ + PubNubFile.prototype.toFile = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this.data]; + }); + }); }; - default_1.prototype._addPnsdkSuffix = function (name, suffix) { - this._PNSDKSuffix[name] = suffix; + /** + * Convert {@link PubNub} File object content to file `Uri`. + * + * @throws Error because file `Uri` not available in browser environment. + */ + PubNubFile.prototype.toFileUri = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + throw new Error('This feature is only supported in React Native environments.'); + }); + }); }; - default_1.prototype._getPnsdkSuffix = function (separator) { - var _this = this; - return Object.keys(this._PNSDKSuffix).reduce(function (result, key) { return result + separator + _this._PNSDKSuffix[key]; }, ''); + /** + * Convert {@link PubNub} File object content to {@link Blob}. + * + * @returns Asynchronous results of conversion to the {@link Blob}. + */ + PubNubFile.prototype.toBlob = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this.data]; + }); + }); }; - return default_1; + // region Class properties + /** + * Whether {@link Blob} data supported by platform or not. + */ + PubNubFile.supportsBlob = typeof Blob !== 'undefined'; + /** + * Whether {@link File} data supported by platform or not. + */ + PubNubFile.supportsFile = typeof File !== 'undefined'; + /** + * Whether {@link Buffer} data supported by platform or not. + */ + PubNubFile.supportsBuffer = false; + /** + * Whether {@link Stream} data supported by platform or not. + */ + PubNubFile.supportsStream = false; + /** + * Whether {@link String} data supported by platform or not. + */ + PubNubFile.supportsString = true; + /** + * Whether {@link ArrayBuffer} supported by platform or not. + */ + PubNubFile.supportsArrayBuffer = true; + /** + * Whether {@link PubNub} File object encryption supported or not. + */ + PubNubFile.supportsEncryptFile = true; + /** + * Whether `File Uri` data supported by platform or not. + */ + PubNubFile.supportsFileUri = false; + return PubNubFile; }()); var BASE64_CHARMAP = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; @@ -828,7 +807,7 @@ * @param paddedInput Base64 string with padding * @returns ArrayBuffer with decoded data */ - function decode$1(paddedInput) { + function decode(paddedInput) { // Remove up to last two equal signs. var input = paddedInput.replace(/==?$/, ''); var outputLength = Math.floor((input.length / 4) * 3); @@ -867,7 +846,7 @@ } return data; } - function encode$1(input) { + function encode(input) { var base64 = ''; var encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; var bytes = new Uint8Array(input); @@ -907,6 +886,28 @@ return base64; } + var PubNubError = /** @class */ (function (_super) { + __extends(PubNubError, _super); + function PubNubError(message, status) { + var _newTarget = this.constructor; + var _this = _super.call(this, message) || this; + _this.status = status; + _this.name = _this.constructor.name; + _this.message = message; + Object.setPrototypeOf(_this, _newTarget.prototype); + return _this; + } + return PubNubError; + }(Error)); + function createError(errorPayload, type) { + var _a; + (_a = errorPayload.statusCode) !== null && _a !== void 0 ? _a : (errorPayload.statusCode = 0); + return __assign(__assign({}, errorPayload), { statusCode: errorPayload.statusCode, error: true, type: type }); + } + function createValidationError(message, statusCode) { + return createError(__assign({ message: message }, (statusCode !== undefined ? { statusCode: statusCode } : {})), 'validationError'); + } + /*eslint-disable */ /* CryptoJS v3.1.2 @@ -1594,1524 +1595,1566 @@ })(); var hmacSha256 = CryptoJS; - function bufferToWordArray(b) { - var wa = []; - var i; - for (i = 0; i < b.length; i += 1) { - wa[(i / 4) | 0] |= b[i] << (24 - 8 * i); - } - return hmacSha256.lib.WordArray.create(wa, b.length); - } - var default_1$a = /** @class */ (function () { - function default_1(_a) { - var config = _a.config; - this._config = config; - this._iv = '0123456789012345'; - this._allowedKeyEncodings = ['hex', 'utf8', 'base64', 'binary']; - this._allowedKeyLengths = [128, 256]; - this._allowedModes = ['ecb', 'cbc']; - this._defaultOptions = { - encryptKey: true, - keyEncoding: 'utf8', - keyLength: 256, - mode: 'cbc', + + var CryptoJS$1 = /*@__PURE__*/getDefaultExportFromCjs(hmacSha256); + + /** + * AES-CBC cryptor module. + */ + /** + * AES-CBC cryptor. + * + * AES-CBC cryptor with enhanced cipher strength. + */ + var AesCbcCryptor = /** @class */ (function () { + function AesCbcCryptor(_a) { + var cipherKey = _a.cipherKey; + this.cipherKey = cipherKey; + this.CryptoJS = CryptoJS$1; + this.encryptedKey = this.CryptoJS.SHA256(cipherKey); + } + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + // region Encryption + AesCbcCryptor.prototype.encrypt = function (data) { + var stringData = typeof data === 'string' ? data : AesCbcCryptor.decoder.decode(data); + if (stringData.length === 0) + throw new Error('encryption error. empty content'); + var abIv = this.getIv(); + return { + metadata: abIv, + data: decode(this.CryptoJS.AES.encrypt(data, this.encryptedKey, { + iv: this.bufferToWordArray(abIv), + mode: this.CryptoJS.mode.CBC, + }).ciphertext.toString(this.CryptoJS.enc.Base64)), }; - } - default_1.prototype.HMACSHA256 = function (data) { - var hash = hmacSha256.HmacSHA256(data, this._config.secretKey); - return hash.toString(hmacSha256.enc.Base64); }; - default_1.prototype.SHA256 = function (s) { - return hmacSha256.SHA256(s).toString(hmacSha256.enc.Hex); + AesCbcCryptor.prototype.encryptFileData = function (data) { + return __awaiter(this, void 0, void 0, function () { + var key, iv; + var _a; + return __generator(this, function (_b) { + switch (_b.label) { + case 0: return [4 /*yield*/, this.getKey()]; + case 1: + key = _b.sent(); + iv = this.getIv(); + _a = {}; + return [4 /*yield*/, crypto.subtle.encrypt({ name: this.algo, iv: iv }, key, data)]; + case 2: return [2 /*return*/, (_a.data = _b.sent(), + _a.metadata = iv, + _a)]; + } + }); + }); }; - default_1.prototype._parseOptions = function (incomingOptions) { - // Defaults - var options = incomingOptions || {}; - if (!options.hasOwnProperty('encryptKey')) - options.encryptKey = this._defaultOptions.encryptKey; - if (!options.hasOwnProperty('keyEncoding')) - options.keyEncoding = this._defaultOptions.keyEncoding; - if (!options.hasOwnProperty('keyLength')) - options.keyLength = this._defaultOptions.keyLength; - if (!options.hasOwnProperty('mode')) - options.mode = this._defaultOptions.mode; - // Validation - if (this._allowedKeyEncodings.indexOf(options.keyEncoding.toLowerCase()) === -1) { - options.keyEncoding = this._defaultOptions.keyEncoding; - } - if (this._allowedKeyLengths.indexOf(parseInt(options.keyLength, 10)) === -1) { - options.keyLength = this._defaultOptions.keyLength; - } - if (this._allowedModes.indexOf(options.mode.toLowerCase()) === -1) { - options.mode = this._defaultOptions.mode; - } - return options; + // endregion + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + // region Decryption + AesCbcCryptor.prototype.decrypt = function (encryptedData) { + var iv = this.bufferToWordArray(new Uint8ClampedArray(encryptedData.metadata)); + var data = this.bufferToWordArray(new Uint8ClampedArray(encryptedData.data)); + return AesCbcCryptor.encoder.encode(this.CryptoJS.AES.decrypt({ ciphertext: data }, this.encryptedKey, { + iv: iv, + mode: this.CryptoJS.mode.CBC, + }).toString(this.CryptoJS.enc.Utf8)).buffer; }; - default_1.prototype._decodeKey = function (key, options) { - if (options.keyEncoding === 'base64') { - return hmacSha256.enc.Base64.parse(key); - } - if (options.keyEncoding === 'hex') { - return hmacSha256.enc.Hex.parse(key); - } - return key; + AesCbcCryptor.prototype.decryptFileData = function (encryptedData) { + return __awaiter(this, void 0, void 0, function () { + var key; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, this.getKey()]; + case 1: + key = _a.sent(); + return [2 /*return*/, crypto.subtle.decrypt({ name: this.algo, iv: encryptedData.metadata }, key, encryptedData.data)]; + } + }); + }); }; - default_1.prototype._getPaddedKey = function (key, options) { - key = this._decodeKey(key, options); - if (options.encryptKey) { - return hmacSha256.enc.Utf8.parse(this.SHA256(key).slice(0, 32)); - } - return key; + Object.defineProperty(AesCbcCryptor.prototype, "identifier", { + // endregion + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + // region Helpers + get: function () { + return 'ACRH'; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(AesCbcCryptor.prototype, "algo", { + /** + * Cryptor algorithm. + * + * @returns Cryptor module algorithm. + */ + get: function () { + return 'AES-CBC'; + }, + enumerable: false, + configurable: true + }); + /** + * Generate random initialization vector. + * + * @returns Random initialization vector. + */ + AesCbcCryptor.prototype.getIv = function () { + return crypto.getRandomValues(new Uint8Array(AesCbcCryptor.BLOCK_SIZE)); + }; + /** + * Convert cipher key to the {@link Buffer}. + * + * @returns SHA256 encoded cipher key {@link Buffer}. + */ + AesCbcCryptor.prototype.getKey = function () { + return __awaiter(this, void 0, void 0, function () { + var bKey, abHash; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + bKey = AesCbcCryptor.encoder.encode(this.cipherKey); + return [4 /*yield*/, crypto.subtle.digest('SHA-256', bKey.buffer)]; + case 1: + abHash = _a.sent(); + return [2 /*return*/, crypto.subtle.importKey('raw', abHash, this.algo, true, ['encrypt', 'decrypt'])]; + } + }); + }); }; - default_1.prototype._getMode = function (options) { - if (options.mode === 'ecb') { - return hmacSha256.mode.ECB; + /** + * Convert bytes array to words array. + * + * @param b - Bytes array (buffer) which should be converted. + * + * @returns Word sized array. + */ + AesCbcCryptor.prototype.bufferToWordArray = function (b) { + var wa = []; + var i; + for (i = 0; i < b.length; i += 1) { + wa[(i / 4) | 0] |= b[i] << (24 - 8 * i); } - return hmacSha256.mode.CBC; + return this.CryptoJS.lib.WordArray.create(wa, b.length); }; - default_1.prototype._getIV = function (options) { - return options.mode === 'cbc' ? hmacSha256.enc.Utf8.parse(this._iv) : null; + /** + * Cryptor block size. + */ + AesCbcCryptor.BLOCK_SIZE = 16; + /** + * {@link string|String} to {@link ArrayBuffer} response decoder. + */ + AesCbcCryptor.encoder = new TextEncoder(); + /** + * {@link ArrayBuffer} to {@link string} decoder. + */ + AesCbcCryptor.decoder = new TextDecoder(); + return AesCbcCryptor; + }()); + + /** + * Legacy cryptography module. + */ + /** + * Convert bytes array to words array. + * + * @param b - Bytes array (buffer) which should be converted. + * + * @returns Word sized array. + */ + /* eslint-disable @typescript-eslint/no-explicit-any */ + function bufferToWordArray(b) { + var wa = []; + var i; + for (i = 0; i < b.length; i += 1) { + wa[(i / 4) | 0] |= b[i] << (24 - 8 * i); + } + // @ts-expect-error Bundled library without types. + return CryptoJS$1.lib.WordArray.create(wa, b.length); + } + var default_1$3 = /** @class */ (function () { + function default_1(configuration) { + this.configuration = configuration; + /** + * Crypto initialization vector. + */ + this.iv = '0123456789012345'; + /** + * List os allowed cipher key encodings. + */ + this.allowedKeyEncodings = ['hex', 'utf8', 'base64', 'binary']; + /** + * Allowed cipher key lengths. + */ + this.allowedKeyLengths = [128, 256]; + /** + * Allowed crypto modes. + */ + this.allowedModes = ['ecb', 'cbc']; + this.defaultOptions = { + encryptKey: true, + keyEncoding: 'utf8', + keyLength: 256, + mode: 'cbc', + }; + } + /** + * Generate HMAC-SHA256 hash from input data. + * + * @param data - Data from which hash should be generated. + * + * @returns HMAC-SHA256 hash from provided `data`. + */ + default_1.prototype.HMACSHA256 = function (data) { + // @ts-expect-error Bundled library without types. + var hash = CryptoJS$1.HmacSHA256(data, this.configuration.secretKey); + // @ts-expect-error Bundled library without types. + return hash.toString(CryptoJS$1.enc.Base64); }; - default_1.prototype._getRandomIV = function () { - return hmacSha256.lib.WordArray.random(16); + /** + * Generate SHA256 hash from input data. + * + * @param data - Data from which hash should be generated. + * + * @returns SHA256 hash from provided `data`. + */ + default_1.prototype.SHA256 = function (data) { + // @ts-expect-error Bundled library without types. + return CryptoJS$1.SHA256(data).toString(CryptoJS$1.enc.Hex); }; + /** + * Encrypt provided data. + * + * @param data - Source data which should be encrypted. + * @param [customCipherKey] - Custom cipher key (different from defined on client level). + * @param [options] - Specific crypto configuration options. + * + * @returns Encrypted `data`. + */ default_1.prototype.encrypt = function (data, customCipherKey, options) { - if (this._config.customEncrypt) { - return this._config.customEncrypt(data); - } + if (this.configuration.customEncrypt) + return this.configuration.customEncrypt(data); return this.pnEncrypt(data, customCipherKey, options); }; + /** + * Decrypt provided data. + * + * @param data - Encrypted data which should be decrypted. + * @param [customCipherKey] - Custom cipher key (different from defined on client level). + * @param [options] - Specific crypto configuration options. + * + * @returns Decrypted `data`. + */ default_1.prototype.decrypt = function (data, customCipherKey, options) { - if (this._config.customDecrypt) { - return this._config.customDecrypt(data); - } + if (this.configuration.customDecrypt) + return this.configuration.customDecrypt(data); return this.pnDecrypt(data, customCipherKey, options); }; + /** + * Encrypt provided data. + * + * @param data - Source data which should be encrypted. + * @param [customCipherKey] - Custom cipher key (different from defined on client level). + * @param [options] - Specific crypto configuration options. + * + * @returns Encrypted `data` as string. + */ default_1.prototype.pnEncrypt = function (data, customCipherKey, options) { - if (!customCipherKey && !this._config.cipherKey) + var decidedCipherKey = customCipherKey !== null && customCipherKey !== void 0 ? customCipherKey : this.configuration.cipherKey; + if (!decidedCipherKey) return data; - options = this._parseOptions(options); - var mode = this._getMode(options); - var cipherKey = this._getPaddedKey(customCipherKey || this._config.cipherKey, options); - if (this._config.useRandomIVs) { - var waIv = this._getRandomIV(); - var waPayload = hmacSha256.AES.encrypt(data, cipherKey, { iv: waIv, mode: mode }).ciphertext; - return waIv.clone().concat(waPayload.clone()).toString(hmacSha256.enc.Base64); - } - var iv = this._getIV(options); - var encryptedHexArray = hmacSha256.AES.encrypt(data, cipherKey, { iv: iv, mode: mode }).ciphertext; - var base64Encrypted = encryptedHexArray.toString(hmacSha256.enc.Base64); + options = this.parseOptions(options); + var mode = this.getMode(options); + var cipherKey = this.getPaddedKey(decidedCipherKey, options); + if (this.configuration.useRandomIVs) { + var waIv = this.getRandomIV(); + // @ts-expect-error Bundled library without types. + var waPayload = CryptoJS$1.AES.encrypt(data, cipherKey, { iv: waIv, mode: mode }).ciphertext; + // @ts-expect-error Bundled library without types. + return waIv.clone().concat(waPayload.clone()).toString(CryptoJS$1.enc.Base64); + } + var iv = this.getIV(options); + // @ts-expect-error Bundled library without types. + var encryptedHexArray = CryptoJS$1.AES.encrypt(data, cipherKey, { iv: iv, mode: mode }).ciphertext; + // @ts-expect-error Bundled library without types. + var base64Encrypted = encryptedHexArray.toString(CryptoJS$1.enc.Base64); return base64Encrypted || data; }; + /** + * Decrypt provided data. + * + * @param data - Encrypted data which should be decrypted. + * @param [customCipherKey] - Custom cipher key (different from defined on client level). + * @param [options] - Specific crypto configuration options. + * + * @returns Decrypted `data`. + */ default_1.prototype.pnDecrypt = function (data, customCipherKey, options) { - if (!customCipherKey && !this._config.cipherKey) + var decidedCipherKey = customCipherKey !== null && customCipherKey !== void 0 ? customCipherKey : this.configuration.cipherKey; + if (!decidedCipherKey) return data; - options = this._parseOptions(options); - var mode = this._getMode(options); - var cipherKey = this._getPaddedKey(customCipherKey || this._config.cipherKey, options); - if (this._config.useRandomIVs) { - var ciphertext = new Uint8ClampedArray(decode$1(data)); + options = this.parseOptions(options); + var mode = this.getMode(options); + var cipherKey = this.getPaddedKey(decidedCipherKey, options); + if (this.configuration.useRandomIVs) { + var ciphertext = new Uint8ClampedArray(decode(data)); var iv = bufferToWordArray(ciphertext.slice(0, 16)); var payload = bufferToWordArray(ciphertext.slice(16)); try { - var plainJSON = hmacSha256.AES.decrypt({ ciphertext: payload }, cipherKey, { iv: iv, mode: mode }).toString(hmacSha256.enc.Utf8); - var plaintext = JSON.parse(plainJSON); - return plaintext; + // @ts-expect-error Bundled library without types. + var plainJSON = CryptoJS$1.AES.decrypt({ ciphertext: payload }, cipherKey, { iv: iv, mode: mode }).toString( + // @ts-expect-error Bundled library without types. + CryptoJS$1.enc.Utf8); + return JSON.parse(plainJSON); } catch (e) { return null; } } else { - var iv = this._getIV(options); + var iv = this.getIV(options); try { - var ciphertext = hmacSha256.enc.Base64.parse(data); - var plainJSON = hmacSha256.AES.decrypt({ ciphertext: ciphertext }, cipherKey, { iv: iv, mode: mode }).toString(hmacSha256.enc.Utf8); - var plaintext = JSON.parse(plainJSON); - return plaintext; + // @ts-expect-error Bundled library without types. + var ciphertext = CryptoJS$1.enc.Base64.parse(data); + // @ts-expect-error Bundled library without types. + var plainJSON = CryptoJS$1.AES.decrypt({ ciphertext: ciphertext }, cipherKey, { iv: iv, mode: mode }).toString(CryptoJS$1.enc.Utf8); + return JSON.parse(plainJSON); } catch (e) { return null; } } }; - return default_1; - }()); - - var default_1$9 = /** @class */ (function () { - function default_1(_a) { - var timeEndpoint = _a.timeEndpoint; - this._timeEndpoint = timeEndpoint; - } - default_1.prototype.onReconnection = function (reconnectionCallback) { - this._reconnectionCallback = reconnectionCallback; + /** + * Pre-process provided custom crypto configuration. + * + * @param incomingOptions - Configuration which should be pre-processed before use. + * + * @returns Normalized crypto configuration options. + */ + default_1.prototype.parseOptions = function (incomingOptions) { + var _a, _b, _c, _d; + if (!incomingOptions) + return this.defaultOptions; + // Defaults + var options = { + encryptKey: (_a = incomingOptions.encryptKey) !== null && _a !== void 0 ? _a : this.defaultOptions.encryptKey, + keyEncoding: (_b = incomingOptions.keyEncoding) !== null && _b !== void 0 ? _b : this.defaultOptions.keyEncoding, + keyLength: (_c = incomingOptions.keyLength) !== null && _c !== void 0 ? _c : this.defaultOptions.keyLength, + mode: (_d = incomingOptions.mode) !== null && _d !== void 0 ? _d : this.defaultOptions.mode, + }; + // Validation + if (this.allowedKeyEncodings.indexOf(options.keyEncoding.toLowerCase()) === -1) + options.keyEncoding = this.defaultOptions.keyEncoding; + if (this.allowedKeyLengths.indexOf(options.keyLength) === -1) + options.keyLength = this.defaultOptions.keyLength; + if (this.allowedModes.indexOf(options.mode.toLowerCase()) === -1) + options.mode = this.defaultOptions.mode; + return options; }; - default_1.prototype.startPolling = function () { - this._timeTimer = setInterval(this._performTimeLoop.bind(this), 3000); + /** + * Decode provided cipher key. + * + * @param key - Key in `encoding` provided by `options`. + * @param options - Crypto configuration options with cipher key details. + * + * @returns Array buffer with decoded key. + */ + default_1.prototype.decodeKey = function (key, options) { + // @ts-expect-error Bundled library without types. + if (options.keyEncoding === 'base64') + return CryptoJS$1.enc.Base64.parse(key); + // @ts-expect-error Bundled library without types. + if (options.keyEncoding === 'hex') + return CryptoJS$1.enc.Hex.parse(key); + return key; }; - default_1.prototype.stopPolling = function () { - clearInterval(this._timeTimer); + /** + * Add padding to the cipher key. + * + * @param key - Key which should be padded. + * @param options - Crypto configuration options with cipher key details. + * + * @returns Properly padded cipher key. + */ + default_1.prototype.getPaddedKey = function (key, options) { + key = this.decodeKey(key, options); + // @ts-expect-error Bundled library without types. + if (options.encryptKey) + return CryptoJS$1.enc.Utf8.parse(this.SHA256(key).slice(0, 32)); + return key; }; - default_1.prototype._performTimeLoop = function () { - var _this = this; - this._timeEndpoint(function (status) { - if (!status.error) { - clearInterval(_this._timeTimer); - _this._reconnectionCallback(); - } - }); + /** + * Cipher mode. + * + * @param options - Crypto configuration with information about cipher mode. + * + * @returns Crypto cipher mode. + */ + default_1.prototype.getMode = function (options) { + // @ts-expect-error Bundled library without types. + if (options.mode === 'ecb') + return CryptoJS$1.mode.ECB; + // @ts-expect-error Bundled library without types. + return CryptoJS$1.mode.CBC; + }; + /** + * Cipher initialization vector. + * + * @param options - Crypto configuration with information about cipher mode. + * + * @returns Initialization vector. + */ + default_1.prototype.getIV = function (options) { + // @ts-expect-error Bundled library without types. + return options.mode === 'cbc' ? CryptoJS$1.enc.Utf8.parse(this.iv) : null; + }; + /** + * Random initialization vector. + * + * @returns Generated random initialization vector. + */ + default_1.prototype.getRandomIV = function () { + // @ts-expect-error Bundled library without types. + return CryptoJS$1.lib.WordArray.random(16); }; return default_1; }()); - /* */ - var hashCode = function (payload) { - var hash = 0; - if (payload.length === 0) - return hash; - for (var i = 0; i < payload.length; i += 1) { - var character = payload.charCodeAt(i); - hash = (hash << 5) - hash + character; // eslint-disable-line - hash = hash & hash; // eslint-disable-line - } - return hash; - }; - var default_1$8 = /** @class */ (function () { - function default_1(_a) { - var config = _a.config; - this.hashHistory = []; - this._config = config; + /* global crypto */ + /** + * Legacy browser cryptography module. + */ + function concatArrayBuffer(ab1, ab2) { + var tmp = new Uint8Array(ab1.byteLength + ab2.byteLength); + tmp.set(new Uint8Array(ab1), 0); + tmp.set(new Uint8Array(ab2), ab1.byteLength); + return tmp.buffer; + } + /** + * Legacy cryptography implementation for browser-based {@link PubNub} client. + */ + var WebCryptography = /** @class */ (function () { + function WebCryptography() { } - default_1.prototype.getKey = function (message) { - var hashedPayload = hashCode(JSON.stringify(message.payload)).toString(); - var timetoken = message.publishMetaData.publishTimetoken; - return "".concat(timetoken, "-").concat(hashedPayload); + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + // region Encryption + /** + * Encrypt provided source data using specific encryption {@link key}. + * + * @param key - Data encryption key.
**Note:** Same key should be used to `decrypt` data. + * @param input - Source data for encryption. + * + * @returns Encrypted data as object or stream (depending on from source data type). + * + * @throws Error if unknown data type has been passed. + */ + WebCryptography.prototype.encrypt = function (key, input) { + return __awaiter(this, void 0, void 0, function () { + var cKey; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!(input instanceof ArrayBuffer) && typeof input !== 'string') + throw new Error('Cannot encrypt this file. In browsers file encryption supports only string or ArrayBuffer'); + return [4 /*yield*/, this.getKey(key)]; + case 1: + cKey = _a.sent(); + return [2 /*return*/, input instanceof ArrayBuffer ? this.encryptArrayBuffer(cKey, input) : this.encryptString(cKey, input)]; + } + }); + }); }; - default_1.prototype.isDuplicate = function (message) { - return this.hashHistory.includes(this.getKey(message)); + /** + * Encrypt provided source {@link Buffer} using specific encryption {@link ArrayBuffer}. + * + * @param key - Data encryption key.
**Note:** Same key should be used to `decrypt` {@link ArrayBuffer}. + * @param buffer - Source {@link ArrayBuffer} for encryption. + * + * @returns Encrypted data as {@link ArrayBuffer} object. + */ + WebCryptography.prototype.encryptArrayBuffer = function (key, buffer) { + return __awaiter(this, void 0, void 0, function () { + var abIv, _a, _b; + return __generator(this, function (_c) { + switch (_c.label) { + case 0: + abIv = crypto.getRandomValues(new Uint8Array(16)); + _a = concatArrayBuffer; + _b = [abIv.buffer]; + return [4 /*yield*/, crypto.subtle.encrypt({ name: 'AES-CBC', iv: abIv }, key, buffer)]; + case 1: return [2 /*return*/, _a.apply(void 0, _b.concat([_c.sent()]))]; + } + }); + }); }; - default_1.prototype.addEntry = function (message) { - if (this.hashHistory.length >= this._config.maximumCacheSize) { - this.hashHistory.shift(); - } - this.hashHistory.push(this.getKey(message)); - }; - default_1.prototype.clearHistory = function () { - this.hashHistory = []; - }; - return default_1; - }()); - - /* */ - var categories = { - // SDK will announce when the network appears to be connected again. - PNNetworkUpCategory: 'PNNetworkUpCategory', - // SDK will announce when the network appears to down. - PNNetworkDownCategory: 'PNNetworkDownCategory', - // call failed when network was unable to complete the call. - PNNetworkIssuesCategory: 'PNNetworkIssuesCategory', - // network call timed out - PNTimeoutCategory: 'PNTimeoutCategory', - // server responded with bad response - PNBadRequestCategory: 'PNBadRequestCategory', - // server responded with access denied - PNAccessDeniedCategory: 'PNAccessDeniedCategory', - // something strange happened; please check the logs. - PNUnknownCategory: 'PNUnknownCategory', - // on reconnection - PNReconnectedCategory: 'PNReconnectedCategory', - PNConnectedCategory: 'PNConnectedCategory', - PNRequestMessageCountExceededCategory: 'PNRequestMessageCountExceededCategory', - PNDisconnectedCategory: 'PNDisconnectedCategory', - PNConnectionErrorCategory: 'PNConnectionErrorCategory', - PNDisconnectedUnexpectedlyCategory: 'PNDisconnectedUnexpectedlyCategory', - }; - - var default_1$7 = /** @class */ (function () { - function default_1(_a) { - var subscribeEndpoint = _a.subscribeEndpoint, leaveEndpoint = _a.leaveEndpoint, heartbeatEndpoint = _a.heartbeatEndpoint, setStateEndpoint = _a.setStateEndpoint, timeEndpoint = _a.timeEndpoint, getFileUrl = _a.getFileUrl, config = _a.config, crypto = _a.crypto, listenerManager = _a.listenerManager, cryptoModule = _a.cryptoModule, eventEmitter = _a.eventEmitter; - this._listenerManager = listenerManager; - this._config = config; - this._leaveEndpoint = leaveEndpoint; - this._heartbeatEndpoint = heartbeatEndpoint; - this._setStateEndpoint = setStateEndpoint; - this._subscribeEndpoint = subscribeEndpoint; - this._getFileUrl = getFileUrl; - this._crypto = crypto; - this._cryptoModule = cryptoModule; - this._channels = {}; - this._presenceChannels = {}; - this._heartbeatChannels = {}; - this._heartbeatChannelGroups = {}; - this._channelGroups = {}; - this._presenceChannelGroups = {}; - this._pendingChannelSubscriptions = []; - this._pendingChannelGroupSubscriptions = []; - this._currentTimetoken = 0; - this._lastTimetoken = 0; - this._storedTimetoken = null; - this._subscriptionStatusAnnounced = false; - this._isOnline = true; - this._reconnectionManager = new default_1$9({ timeEndpoint: timeEndpoint }); - this._dedupingManager = new default_1$8({ config: config }); - if (this._cryptoModule) - this._decoder = new TextDecoder(); - this._eventEmitter = eventEmitter; - } - default_1.prototype.adaptStateChange = function (args, callback) { - var _this = this; - var state = args.state, _a = args.channels, channels = _a === void 0 ? [] : _a, _b = args.channelGroups, channelGroups = _b === void 0 ? [] : _b, _c = args.withHeartbeat, withHeartbeat = _c === void 0 ? false : _c; - channels.forEach(function (channel) { - if (channel in _this._channels) - _this._channels[channel].state = state; - }); - channelGroups.forEach(function (channelGroup) { - if (channelGroup in _this._channelGroups) { - _this._channelGroups[channelGroup].state = state; - } + /** + * Encrypt provided source {@link string} using specific encryption {@link key}. + * + * @param key - Data encryption key.
**Note:** Same key should be used to `decrypt` {@link string}. + * @param text - Source {@link string} for encryption. + * + * @returns Encrypted data as byte {@link string}. + */ + WebCryptography.prototype.encryptString = function (key, text) { + return __awaiter(this, void 0, void 0, function () { + var abIv, abPlaintext, abPayload, ciphertext; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + abIv = crypto.getRandomValues(new Uint8Array(16)); + abPlaintext = WebCryptography.encoder.encode(text).buffer; + return [4 /*yield*/, crypto.subtle.encrypt({ name: 'AES-CBC', iv: abIv }, key, abPlaintext)]; + case 1: + abPayload = _a.sent(); + ciphertext = concatArrayBuffer(abIv.buffer, abPayload); + return [2 /*return*/, WebCryptography.decoder.decode(ciphertext)]; + } + }); }); - if (withHeartbeat) { - var presenceState_1 = {}; - channels.forEach(function (channel) { return (presenceState_1[channel] = state); }); - channelGroups.forEach(function (group) { return (presenceState_1[group] = state); }); - return this._heartbeatEndpoint({ channels: channels, channelGroups: channelGroups, state: presenceState_1 }, callback); - } - return this._setStateEndpoint({ state: state, channels: channels, channelGroups: channelGroups }, callback); }; - default_1.prototype.adaptPresenceChange = function (args) { - var _this = this; - var connected = args.connected, _a = args.channels, channels = _a === void 0 ? [] : _a, _b = args.channelGroups, channelGroups = _b === void 0 ? [] : _b; - if (connected) { - channels.forEach(function (channel) { - _this._heartbeatChannels[channel] = { state: {} }; - }); - channelGroups.forEach(function (channelGroup) { - _this._heartbeatChannelGroups[channelGroup] = { state: {} }; - }); - } - else { - channels.forEach(function (channel) { - if (channel in _this._heartbeatChannels) { - delete _this._heartbeatChannels[channel]; + /** + * Encrypt provided {@link PubNub} File object using specific encryption {@link key}. + * + * @param key - Key for {@link PubNub} File object encryption.
**Note:** Same key should be + * used to `decrypt` data. + * @param file - Source {@link PubNub} File object for encryption. + * @param File - Class constructor for {@link PubNub} File object. + * + * @returns Encrypted data as {@link PubNub} File object. + * + * @throws Error if file is empty or contains unsupported data type. + */ + WebCryptography.prototype.encryptFile = function (key, file, File) { + return __awaiter(this, void 0, void 0, function () { + var bKey, abPlaindata, abCipherdata; + var _a, _b; + return __generator(this, function (_c) { + switch (_c.label) { + case 0: + if ((_a = file.contentLength) !== null && _a !== void 0 ? _a : 0 <= 0) + throw new Error('encryption error. empty content'); + return [4 /*yield*/, this.getKey(key)]; + case 1: + bKey = _c.sent(); + return [4 /*yield*/, file.toArrayBuffer()]; + case 2: + abPlaindata = _c.sent(); + return [4 /*yield*/, this.encryptArrayBuffer(bKey, abPlaindata)]; + case 3: + abCipherdata = _c.sent(); + return [2 /*return*/, File.create({ + name: file.name, + mimeType: (_b = file.mimeType) !== null && _b !== void 0 ? _b : 'application/octet-stream', + data: abCipherdata, + })]; } }); - channelGroups.forEach(function (channelGroup) { - if (channelGroup in _this._heartbeatChannelGroups) { - delete _this._heartbeatChannelGroups[channelGroup]; + }); + }; + // endregion + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + // region Decryption + /** + * Decrypt provided encrypted data using specific decryption {@link key}. + * + * @param key - Data decryption key.
**Note:** Should be the same as used to `encrypt` data. + * @param input - Encrypted data for decryption. + * + * @returns Decrypted data as object or stream (depending on from encrypted data type). + * + * @throws Error if unknown data type has been passed. + */ + WebCryptography.prototype.decrypt = function (key, input) { + return __awaiter(this, void 0, void 0, function () { + var cKey; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!(input instanceof ArrayBuffer) && typeof input !== 'string') + throw new Error('Cannot decrypt this file. In browsers file decryption supports only string or ArrayBuffer'); + return [4 /*yield*/, this.getKey(key)]; + case 1: + cKey = _a.sent(); + return [2 /*return*/, input instanceof ArrayBuffer ? this.decryptArrayBuffer(cKey, input) : this.decryptString(cKey, input)]; } }); - if (this._config.suppressLeaveEvents === false) { - this._leaveEndpoint({ channels: channels, channelGroups: channelGroups }, function (status) { - _this._listenerManager.announceStatus(status); - }); - } - } - this.reconnect(); - }; - default_1.prototype.adaptSubscribeChange = function (args) { - var _this = this; - var timetoken = args.timetoken, _a = args.channels, channels = _a === void 0 ? [] : _a, _b = args.channelGroups, channelGroups = _b === void 0 ? [] : _b, _c = args.withPresence, withPresence = _c === void 0 ? false : _c, _d = args.withHeartbeats, withHeartbeats = _d === void 0 ? false : _d; - if (!this._config.subscribeKey || this._config.subscribeKey === '') { - // eslint-disable-next-line - if (console && console.log) { - console.log('subscribe key missing; aborting subscribe'); //eslint-disable-line - } - return; - } - if (timetoken) { - this._lastTimetoken = this._currentTimetoken; - this._currentTimetoken = timetoken; - } - // reset the current timetoken to get a connect event. - // $FlowFixMe - if (this._currentTimetoken !== '0' && this._currentTimetoken !== 0) { - this._storedTimetoken = this._currentTimetoken; - this._currentTimetoken = 0; - } - channels.forEach(function (channel) { - _this._channels[channel] = { state: {} }; - if (withPresence) - _this._presenceChannels[channel] = {}; - if (withHeartbeats || _this._config.getHeartbeatInterval()) - _this._heartbeatChannels[channel] = {}; - _this._pendingChannelSubscriptions.push(channel); }); - channelGroups.forEach(function (channelGroup) { - _this._channelGroups[channelGroup] = { state: {} }; - if (withPresence) - _this._presenceChannelGroups[channelGroup] = {}; - if (withHeartbeats || _this._config.getHeartbeatInterval()) - _this._heartbeatChannelGroups[channelGroup] = {}; - _this._pendingChannelGroupSubscriptions.push(channelGroup); + }; + /** + * Decrypt provided encrypted {@link ArrayBuffer} using specific decryption {@link key}. + * + * @param key - Data decryption key.
**Note:** Should be the same as used to `encrypt` {@link ArrayBuffer}. + * @param buffer - Encrypted {@link ArrayBuffer} for decryption. + * + * @returns Decrypted data as {@link ArrayBuffer} object. + */ + WebCryptography.prototype.decryptArrayBuffer = function (key, buffer) { + return __awaiter(this, void 0, void 0, function () { + var abIv; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + abIv = buffer.slice(0, 16); + if (buffer.slice(WebCryptography.IV_LENGTH).byteLength <= 0) + throw new Error('decryption error: empty content'); + return [4 /*yield*/, crypto.subtle.decrypt({ name: 'AES-CBC', iv: abIv }, key, buffer.slice(WebCryptography.IV_LENGTH))]; + case 1: return [2 /*return*/, _a.sent()]; + } + }); }); - this._subscriptionStatusAnnounced = false; - this.reconnect(); }; - default_1.prototype.adaptUnsubscribeChange = function (args, isOffline) { - var _this = this; - var _a = args.channels, channels = _a === void 0 ? [] : _a, _b = args.channelGroups, channelGroups = _b === void 0 ? [] : _b; - // keep track of which channels and channel groups - // we are going to unsubscribe from. - var actualChannels = []; - var actualChannelGroups = []; - // - channels.forEach(function (channel) { - if (channel in _this._channels) { - delete _this._channels[channel]; - actualChannels.push(channel); - if (channel in _this._heartbeatChannels) { - delete _this._heartbeatChannels[channel]; + /** + * Decrypt provided encrypted {@link string} using specific decryption {@link key}. + * + * @param key - Data decryption key.
**Note:** Should be the same as used to `encrypt` {@link string}. + * @param text - Encrypted {@link string} for decryption. + * + * @returns Decrypted data as byte {@link string}. + */ + WebCryptography.prototype.decryptString = function (key, text) { + return __awaiter(this, void 0, void 0, function () { + var abCiphertext, abIv, abPayload, abPlaintext; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + abCiphertext = WebCryptography.encoder.encode(text).buffer; + abIv = abCiphertext.slice(0, 16); + abPayload = abCiphertext.slice(16); + return [4 /*yield*/, crypto.subtle.decrypt({ name: 'AES-CBC', iv: abIv }, key, abPayload)]; + case 1: + abPlaintext = _a.sent(); + return [2 /*return*/, WebCryptography.decoder.decode(abPlaintext)]; } - } - if (channel in _this._presenceChannels) { - delete _this._presenceChannels[channel]; - actualChannels.push(channel); - } + }); }); - channelGroups.forEach(function (channelGroup) { - if (channelGroup in _this._channelGroups) { - delete _this._channelGroups[channelGroup]; - actualChannelGroups.push(channelGroup); - if (channelGroup in _this._heartbeatChannelGroups) { - delete _this._heartbeatChannelGroups[channelGroup]; + }; + /** + * Decrypt provided {@link PubNub} File object using specific decryption {@link key}. + * + * @param key - Key for {@link PubNub} File object decryption.
**Note:** Should be the same + * as used to `encrypt` data. + * @param file - Encrypted {@link PubNub} File object for decryption. + * @param File - Class constructor for {@link PubNub} File object. + * + * @returns Decrypted data as {@link PubNub} File object. + * + * @throws Error if file is empty or contains unsupported data type. + */ + WebCryptography.prototype.decryptFile = function (key, file, File) { + return __awaiter(this, void 0, void 0, function () { + var bKey, abCipherdata, abPlaindata; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, this.getKey(key)]; + case 1: + bKey = _a.sent(); + return [4 /*yield*/, file.toArrayBuffer()]; + case 2: + abCipherdata = _a.sent(); + return [4 /*yield*/, this.decryptArrayBuffer(bKey, abCipherdata)]; + case 3: + abPlaindata = _a.sent(); + return [2 /*return*/, File.create({ + name: file.name, + mimeType: file.mimeType, + data: abPlaindata, + })]; } - } - if (channelGroup in _this._presenceChannelGroups) { - delete _this._presenceChannelGroups[channelGroup]; - actualChannelGroups.push(channelGroup); - } + }); }); - // no-op if there are no channels and cg's to unsubscribe from. - if (actualChannels.length === 0 && actualChannelGroups.length === 0) { - return; - } - if (this._config.suppressLeaveEvents === false && !isOffline) { - this._leaveEndpoint({ channels: actualChannels, channelGroups: actualChannelGroups }, function (status) { - status.affectedChannels = actualChannels; - status.affectedChannelGroups = actualChannelGroups; - status.currentTimetoken = _this._currentTimetoken; - status.lastTimetoken = _this._lastTimetoken; - _this._listenerManager.announceStatus(status); + }; + // endregion + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + // region Helpers + /** + * Convert cipher key to the {@link Buffer}. + * + * @param key - String cipher key. + * + * @returns SHA256 HEX encoded cipher key {@link CryptoKey}. + */ + WebCryptography.prototype.getKey = function (key) { + return __awaiter(this, void 0, void 0, function () { + var digest, hashHex, abKey; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, crypto.subtle.digest('SHA-256', WebCryptography.encoder.encode(key))]; + case 1: + digest = _a.sent(); + hashHex = Array.from(new Uint8Array(digest)) + .map(function (b) { return b.toString(16).padStart(2, '0'); }) + .join(''); + abKey = WebCryptography.encoder.encode(hashHex.slice(0, 32)).buffer; + return [2 /*return*/, crypto.subtle.importKey('raw', abKey, 'AES-CBC', true, ['encrypt', 'decrypt'])]; + } }); - } - // if we have nothing to subscribe to, reset the timetoken. - if (Object.keys(this._channels).length === 0 && - Object.keys(this._presenceChannels).length === 0 && - Object.keys(this._channelGroups).length === 0 && - Object.keys(this._presenceChannelGroups).length === 0) { - this._lastTimetoken = 0; - this._currentTimetoken = 0; - this._storedTimetoken = null; - this._region = null; - this._reconnectionManager.stopPolling(); - } - this.reconnect(); + }); }; - default_1.prototype.unsubscribeAll = function (isOffline) { - this.adaptUnsubscribeChange({ - channels: this.getSubscribedChannels(), - channelGroups: this.getSubscribedChannelGroups(), - }, isOffline); + /** + * Random initialization vector size. + */ + WebCryptography.IV_LENGTH = 16; + /** + * {@link string|String} to {@link ArrayBuffer} response decoder. + */ + WebCryptography.encoder = new TextEncoder(); + /** + * {@link ArrayBuffer} to {@link string} decoder. + */ + WebCryptography.decoder = new TextDecoder(); + return WebCryptography; + }()); + + /** + * Legacy cryptor module. + */ + /** + * Legacy cryptor. + */ + var LegacyCryptor = /** @class */ (function () { + function LegacyCryptor(config) { + this.config = config; + this.cryptor = new default_1$3(__assign({}, config)); + this.fileCryptor = new WebCryptography(); + } + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + // region Encryption + LegacyCryptor.prototype.encrypt = function (data) { + var stringData = typeof data === 'string' ? data : LegacyCryptor.decoder.decode(data); + return { + data: LegacyCryptor.encoder.encode(this.cryptor.encrypt(stringData)), + metadata: null, + }; }; - default_1.prototype.getHeartbeatChannels = function () { - return Object.keys(this._heartbeatChannels); + LegacyCryptor.prototype.encryptFile = function (file, File) { + return __awaiter(this, void 0, void 0, function () { + var _a; + return __generator(this, function (_b) { + if (!this.config.cipherKey) + throw new PubNubError('File encryption error: cipher key not set.'); + return [2 /*return*/, this.fileCryptor.encryptFile((_a = this.config) === null || _a === void 0 ? void 0 : _a.cipherKey, file, File)]; + }); + }); }; - default_1.prototype.getHeartbeatChannelGroups = function () { - return Object.keys(this._heartbeatChannelGroups); + // endregion + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + // region Decryption + LegacyCryptor.prototype.decrypt = function (encryptedData) { + var data = typeof encryptedData.data === 'string' ? encryptedData.data : encode(encryptedData.data); + return this.cryptor.decrypt(data); }; - default_1.prototype.getSubscribedChannels = function () { - return Object.keys(this._channels); + LegacyCryptor.prototype.decryptFile = function (file, File) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + if (!this.config.cipherKey) + throw new PubNubError('File encryption error: cipher key not set.'); + return [2 /*return*/, this.fileCryptor.decryptFile(this.config.cipherKey, file, File)]; + }); + }); }; - default_1.prototype.getSubscribedChannelGroups = function () { - return Object.keys(this._channelGroups); + Object.defineProperty(LegacyCryptor.prototype, "identifier", { + // endregion + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + // region Helpers + get: function () { + return ''; + }, + enumerable: false, + configurable: true + }); + /** + * `string` to {@link ArrayBuffer} response decoder. + */ + LegacyCryptor.encoder = new TextEncoder(); + /** + * {@link ArrayBuffer} to {@link string} decoder. + */ + LegacyCryptor.decoder = new TextDecoder(); + return LegacyCryptor; + }()); + + /** + * Browser crypto module. + */ + /** + * CryptoModule for browser platform. + */ + var WebCryptoModule = /** @class */ (function (_super) { + __extends(WebCryptoModule, _super); + function WebCryptoModule() { + return _super !== null && _super.apply(this, arguments) || this; + } + // -------------------------------------------------------- + // --------------- Convenience functions ------------------ + // ------------------------------------------------------- + // region Convenience functions + WebCryptoModule.legacyCryptoModule = function (config) { + var _a; + if (!config.cipherKey) + throw new PubNubError('Crypto module error: cipher key not set.'); + return new WebCryptoModule({ + default: new LegacyCryptor(__assign(__assign({}, config), { useRandomIVs: (_a = config.useRandomIVs) !== null && _a !== void 0 ? _a : true })), + cryptors: [new AesCbcCryptor({ cipherKey: config.cipherKey })], + }); }; - default_1.prototype.reconnect = function () { - this._startSubscribeLoop(); - this._registerHeartbeatTimer(); + WebCryptoModule.aesCbcCryptoModule = function (config) { + var _a; + if (!config.cipherKey) + throw new PubNubError('Crypto module error: cipher key not set.'); + return new WebCryptoModule({ + default: new AesCbcCryptor({ cipherKey: config.cipherKey }), + cryptors: [ + new LegacyCryptor(__assign(__assign({}, config), { useRandomIVs: (_a = config.useRandomIVs) !== null && _a !== void 0 ? _a : true })), + ], + }); }; - default_1.prototype.disconnect = function () { - this._stopSubscribeLoop(); - this._stopHeartbeatTimer(); - this._reconnectionManager.stopPolling(); + /** + * Construct crypto module with `cryptor` as default for data encryption and decryption. + * + * @param defaultCryptor - Default cryptor for data encryption and decryption. + * + * @returns Crypto module with pre-configured default cryptor. + */ + WebCryptoModule.withDefaultCryptor = function (defaultCryptor) { + return new this({ default: defaultCryptor }); }; - default_1.prototype._registerHeartbeatTimer = function () { - this._stopHeartbeatTimer(); - // if the interval is 0 or undefined, do not queue up heartbeating - if (this._config.getHeartbeatInterval() === 0 || this._config.getHeartbeatInterval() === undefined) { - return; - } - this._performHeartbeatLoop(); - // $FlowFixMe - this._heartbeatTimer = setInterval(this._performHeartbeatLoop.bind(this), this._config.getHeartbeatInterval() * 1000); - }; - default_1.prototype._stopHeartbeatTimer = function () { - if (this._heartbeatTimer) { - // $FlowFixMe - clearInterval(this._heartbeatTimer); - this._heartbeatTimer = null; - } + // endregion + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + // region Encryption + WebCryptoModule.prototype.encrypt = function (data) { + // Encrypt data. + var encrypted = data instanceof ArrayBuffer && this.defaultCryptor.identifier === WebCryptoModule.LEGACY_IDENTIFIER + ? this.defaultCryptor.encrypt(WebCryptoModule.decoder.decode(data)) + : this.defaultCryptor.encrypt(data); + if (!encrypted.metadata) + return encrypted.data; + var headerData = this.getHeaderData(encrypted); + return this.concatArrayBuffer(headerData, encrypted.data); }; - default_1.prototype._performHeartbeatLoop = function () { - var _this = this; - var heartbeatChannels = this.getHeartbeatChannels(); - var heartbeatChannelGroups = this.getHeartbeatChannelGroups(); - var presenceState = {}; - if (heartbeatChannels.length === 0 && heartbeatChannelGroups.length === 0) { - return; - } - this.getSubscribedChannels().forEach(function (channel) { - var channelState = _this._channels[channel].state; - if (Object.keys(channelState).length) { - presenceState[channel] = channelState; - } - }); - this.getSubscribedChannelGroups().forEach(function (channelGroup) { - var channelGroupState = _this._channelGroups[channelGroup].state; - if (Object.keys(channelGroupState).length) { - presenceState[channelGroup] = channelGroupState; - } + WebCryptoModule.prototype.encryptFile = function (file, File) { + return __awaiter(this, void 0, void 0, function () { + var fileData, encrypted; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + /** + * Files handled differently in case of Legacy cryptor. + * (as long as we support legacy need to check on instance type) + */ + if (this.defaultCryptor.identifier === CryptorHeader.LEGACY_IDENTIFIER) + return [2 /*return*/, this.defaultCryptor.encryptFile(file, File)]; + return [4 /*yield*/, this.getFileData(file)]; + case 1: + fileData = _a.sent(); + return [4 /*yield*/, this.defaultCryptor.encryptFileData(fileData)]; + case 2: + encrypted = _a.sent(); + return [2 /*return*/, File.create({ + name: file.name, + mimeType: 'application/octet-stream', + data: this.concatArrayBuffer(this.getHeaderData(encrypted), encrypted.data), + })]; + } + }); }); - var onHeartbeat = function (status) { - if (status.error && _this._config.announceFailedHeartbeats) { - _this._listenerManager.announceStatus(status); - } - if (status.error && _this._config.autoNetworkDetection && _this._isOnline) { - _this._isOnline = false; - _this.disconnect(); - _this._listenerManager.announceNetworkDown(); - _this.reconnect(); - } - if (!status.error && _this._config.announceSuccessfulHeartbeats) { - _this._listenerManager.announceStatus(status); - } - }; - this._heartbeatEndpoint({ - channels: heartbeatChannels, - channelGroups: heartbeatChannelGroups, - state: presenceState, - }, onHeartbeat.bind(this)); }; - default_1.prototype._startSubscribeLoop = function () { - var _this = this; - this._stopSubscribeLoop(); - var presenceState = {}; - var channels = []; - var channelGroups = []; - Object.keys(this._channels).forEach(function (channel) { - var channelState = _this._channels[channel].state; - if (Object.keys(channelState).length) { - presenceState[channel] = channelState; - } - channels.push(channel); - }); - Object.keys(this._presenceChannels).forEach(function (channel) { - channels.push("".concat(channel, "-pnpres")); - }); - Object.keys(this._channelGroups).forEach(function (channelGroup) { - var channelGroupState = _this._channelGroups[channelGroup].state; - if (Object.keys(channelGroupState).length) { - presenceState[channelGroup] = channelGroupState; - } - channelGroups.push(channelGroup); - }); - Object.keys(this._presenceChannelGroups).forEach(function (channelGroup) { - channelGroups.push("".concat(channelGroup, "-pnpres")); + // endregion + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + // region Decryption + WebCryptoModule.prototype.decrypt = function (data) { + var encryptedData = typeof data === 'string' ? decode(data) : data; + var header = CryptorHeader.tryParse(encryptedData); + var cryptor = this.getCryptor(header); + var metadata = header.length > 0 + ? encryptedData.slice(header.length - header.metadataLength, header.length) + : null; + if (encryptedData.slice(header.length).byteLength <= 0) + throw new Error('Decryption error: empty content'); + return cryptor.decrypt({ + data: encryptedData.slice(header.length), + metadata: metadata, }); - if (channels.length === 0 && channelGroups.length === 0) { - return; - } - var subscribeArgs = { - channels: channels, - channelGroups: channelGroups, - state: presenceState, - timetoken: this._currentTimetoken, - filterExpression: this._config.filterExpression, - region: this._region, - }; - this._subscribeCall = this._subscribeEndpoint(subscribeArgs, this._processSubscribeResponse.bind(this)); }; - default_1.prototype._processSubscribeResponse = function (status, payload) { - var _this = this; - if (status.error) { - // if error comes from request abort, ignore - if (status.errorData && status.errorData.message === 'Aborted') { - return; - } - // if we timeout from server, restart the loop. - if (status.category === categories.PNTimeoutCategory) { - this._startSubscribeLoop(); - } - else if (status.category === categories.PNNetworkIssuesCategory) { - // we lost internet connection, alert the reconnection manager and terminate all loops - this.disconnect(); - if (status.error && this._config.autoNetworkDetection && this._isOnline) { - this._isOnline = false; - this._listenerManager.announceNetworkDown(); - } - this._reconnectionManager.onReconnection(function () { - if (_this._config.autoNetworkDetection && !_this._isOnline) { - _this._isOnline = true; - _this._listenerManager.announceNetworkUp(); - } - _this.reconnect(); - _this._subscriptionStatusAnnounced = true; - var reconnectedAnnounce = { - category: categories.PNReconnectedCategory, - operation: status.operation, - lastTimetoken: _this._lastTimetoken, - currentTimetoken: _this._currentTimetoken, - }; - _this._listenerManager.announceStatus(reconnectedAnnounce); - }); - this._reconnectionManager.startPolling(); - this._listenerManager.announceStatus(status); - } - else if (status.category === categories.PNBadRequestCategory) { - this._stopHeartbeatTimer(); - this._listenerManager.announceStatus(status); - } - else { - this._listenerManager.announceStatus(status); - } - return; - } - if (this._storedTimetoken) { - this._currentTimetoken = this._storedTimetoken; - this._storedTimetoken = null; - } - else { - this._lastTimetoken = this._currentTimetoken; - this._currentTimetoken = payload.metadata.timetoken; - } - if (!this._subscriptionStatusAnnounced) { - var connectedAnnounce = {}; - connectedAnnounce.category = categories.PNConnectedCategory; - connectedAnnounce.operation = status.operation; - connectedAnnounce.affectedChannels = this._pendingChannelSubscriptions; - connectedAnnounce.subscribedChannels = this.getSubscribedChannels(); - connectedAnnounce.affectedChannelGroups = this._pendingChannelGroupSubscriptions; - connectedAnnounce.lastTimetoken = this._lastTimetoken; - connectedAnnounce.currentTimetoken = this._currentTimetoken; - this._subscriptionStatusAnnounced = true; - this._listenerManager.announceStatus(connectedAnnounce); - // clear the pending connections list - this._pendingChannelSubscriptions = []; - this._pendingChannelGroupSubscriptions = []; - } - var messages = payload.messages || []; - var _a = this._config, requestMessageCountThreshold = _a.requestMessageCountThreshold, dedupeOnSubscribe = _a.dedupeOnSubscribe; - if (requestMessageCountThreshold && messages.length >= requestMessageCountThreshold) { - var countAnnouncement = {}; - countAnnouncement.category = categories.PNRequestMessageCountExceededCategory; - countAnnouncement.operation = status.operation; - this._listenerManager.announceStatus(countAnnouncement); - } - messages.forEach(function (message) { - message.channel; - message.subscriptionMatch; - if (dedupeOnSubscribe) { - if (_this._dedupingManager.isDuplicate(message)) { - return; + WebCryptoModule.prototype.decryptFile = function (file, File) { + return __awaiter(this, void 0, void 0, function () { + var data, header, cryptor, fileData, metadata, _a, _b; + var _c; + return __generator(this, function (_d) { + switch (_d.label) { + case 0: return [4 /*yield*/, file.data.arrayBuffer()]; + case 1: + data = _d.sent(); + header = CryptorHeader.tryParse(data); + cryptor = this.getCryptor(header); + /** + * Files handled differently in case of Legacy cryptor. + * (as long as we support legacy need to check on instance type) + */ + if ((cryptor === null || cryptor === void 0 ? void 0 : cryptor.identifier) === CryptorHeader.LEGACY_IDENTIFIER) + return [2 /*return*/, cryptor.decryptFile(file, File)]; + return [4 /*yield*/, this.getFileData(data)]; + case 2: + fileData = _d.sent(); + metadata = fileData.slice(header.length - header.metadataLength, header.length); + _b = (_a = File).create; + _c = { + name: file.name + }; + return [4 /*yield*/, this.defaultCryptor.decryptFileData({ + data: data.slice(header.length), + metadata: metadata, + })]; + case 3: return [2 /*return*/, _b.apply(_a, [(_c.data = _d.sent(), + _c)])]; } - _this._dedupingManager.addEntry(message); - } - _this._eventEmitter.emitEvent(message); + }); }); - this._region = payload.metadata.region; - this._startSubscribeLoop(); }; - default_1.prototype._stopSubscribeLoop = function () { - if (this._subscribeCall) { - if (typeof this._subscribeCall.abort === 'function') { - this._subscribeCall.abort(); - } - this._subscribeCall = null; + // endregion + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + // region Helpers + /** + * Retrieve registered cryptor by its identifier. + * + * @param id - Unique cryptor identifier. + * + * @returns Registered cryptor with specified identifier. + * + * @throws Error if cryptor with specified {@link id} can't be found. + */ + WebCryptoModule.prototype.getCryptorFromId = function (id) { + var cryptor = this.getAllCryptors().find(function (cryptor) { return id === cryptor.identifier; }); + if (cryptor) + return cryptor; + throw Error('Unknown cryptor error'); + }; + /** + * Retrieve cryptor by its identifier. + * + * @param header - Header with cryptor-defined data or raw cryptor identifier. + * + * @returns Cryptor which correspond to provided {@link header}. + */ + WebCryptoModule.prototype.getCryptor = function (header) { + if (typeof header === 'string') { + var cryptor = this.getAllCryptors().find(function (cryptor) { return cryptor.identifier === header; }); + if (cryptor) + return cryptor; + throw new Error('Unknown cryptor error'); + } + else if (header instanceof CryptorHeaderV1) { + return this.getCryptorFromId(header.identifier); } }; - default_1.prototype._renameEvent = function (e) { - return e === 'set' ? 'updated' : 'removed'; + /** + * Create cryptor header data. + * + * @param encrypted - Encryption data object as source for header data. + * + * @returns Binary representation of the cryptor header data. + */ + WebCryptoModule.prototype.getHeaderData = function (encrypted) { + if (!encrypted.metadata) + return; + var header = CryptorHeader.from(this.defaultCryptor.identifier, encrypted.metadata); + var headerData = new Uint8Array(header.length); + var pos = 0; + headerData.set(header.data, pos); + pos += header.length - encrypted.metadata.byteLength; + headerData.set(new Uint8Array(encrypted.metadata), pos); + return headerData.buffer; }; - default_1.prototype._renameChannelField = function (announce) { - var channel = announce.channel, eventData = __rest(announce, ["channel"]); - eventData.spaceId = channel; - return eventData; + /** + * Merge two {@link ArrayBuffer} instances. + * + * @param ab1 - First {@link ArrayBuffer}. + * @param ab2 - Second {@link ArrayBuffer}. + * + * @returns Merged data as {@link ArrayBuffer}. + */ + WebCryptoModule.prototype.concatArrayBuffer = function (ab1, ab2) { + var tmp = new Uint8Array(ab1.byteLength + ab2.byteLength); + tmp.set(new Uint8Array(ab1), 0); + tmp.set(new Uint8Array(ab2), ab1.byteLength); + return tmp.buffer; }; - return default_1; - }()); - - /* */ - var OPERATIONS = { - PNTimeOperation: 'PNTimeOperation', - PNHistoryOperation: 'PNHistoryOperation', - PNDeleteMessagesOperation: 'PNDeleteMessagesOperation', - PNFetchMessagesOperation: 'PNFetchMessagesOperation', - PNMessageCounts: 'PNMessageCountsOperation', - // pubsub - PNSubscribeOperation: 'PNSubscribeOperation', - PNUnsubscribeOperation: 'PNUnsubscribeOperation', - PNPublishOperation: 'PNPublishOperation', - PNSignalOperation: 'PNSignalOperation', - // Actions API - PNAddMessageActionOperation: 'PNAddActionOperation', - PNRemoveMessageActionOperation: 'PNRemoveMessageActionOperation', - PNGetMessageActionsOperation: 'PNGetMessageActionsOperation', - // Objects API - PNCreateUserOperation: 'PNCreateUserOperation', - PNUpdateUserOperation: 'PNUpdateUserOperation', - PNDeleteUserOperation: 'PNDeleteUserOperation', - PNGetUserOperation: 'PNGetUsersOperation', - PNGetUsersOperation: 'PNGetUsersOperation', - PNCreateSpaceOperation: 'PNCreateSpaceOperation', - PNUpdateSpaceOperation: 'PNUpdateSpaceOperation', - PNDeleteSpaceOperation: 'PNDeleteSpaceOperation', - PNGetSpaceOperation: 'PNGetSpacesOperation', - PNGetSpacesOperation: 'PNGetSpacesOperation', - PNGetMembersOperation: 'PNGetMembersOperation', - PNUpdateMembersOperation: 'PNUpdateMembersOperation', - PNGetMembershipsOperation: 'PNGetMembershipsOperation', - PNUpdateMembershipsOperation: 'PNUpdateMembershipsOperation', - // File Upload API v1 - PNListFilesOperation: 'PNListFilesOperation', - PNGenerateUploadUrlOperation: 'PNGenerateUploadUrlOperation', - PNPublishFileOperation: 'PNPublishFileOperation', - PNGetFileUrlOperation: 'PNGetFileUrlOperation', - PNDownloadFileOperation: 'PNDownloadFileOperation', - // Objects API v2 - // UUID - PNGetAllUUIDMetadataOperation: 'PNGetAllUUIDMetadataOperation', - PNGetUUIDMetadataOperation: 'PNGetUUIDMetadataOperation', - PNSetUUIDMetadataOperation: 'PNSetUUIDMetadataOperation', - PNRemoveUUIDMetadataOperation: 'PNRemoveUUIDMetadataOperation', - // channel - PNGetAllChannelMetadataOperation: 'PNGetAllChannelMetadataOperation', - PNGetChannelMetadataOperation: 'PNGetChannelMetadataOperation', - PNSetChannelMetadataOperation: 'PNSetChannelMetadataOperation', - PNRemoveChannelMetadataOperation: 'PNRemoveChannelMetadataOperation', - // member - // PNGetMembersOperation: 'PNGetMembersOperation', - PNSetMembersOperation: 'PNSetMembersOperation', - // PNGetMembershipsOperation: 'PNGetMembersOperation', - PNSetMembershipsOperation: 'PNSetMembershipsOperation', - // push - PNPushNotificationEnabledChannelsOperation: 'PNPushNotificationEnabledChannelsOperation', - PNRemoveAllPushNotificationsOperation: 'PNRemoveAllPushNotificationsOperation', - // - // presence - PNWhereNowOperation: 'PNWhereNowOperation', - PNSetStateOperation: 'PNSetStateOperation', - PNHereNowOperation: 'PNHereNowOperation', - PNGetStateOperation: 'PNGetStateOperation', - PNHeartbeatOperation: 'PNHeartbeatOperation', - // - // channel group - PNChannelGroupsOperation: 'PNChannelGroupsOperation', - PNRemoveGroupOperation: 'PNRemoveGroupOperation', - PNChannelsForGroupOperation: 'PNChannelsForGroupOperation', - PNAddChannelsToGroupOperation: 'PNAddChannelsToGroupOperation', - PNRemoveChannelsFromGroupOperation: 'PNRemoveChannelsFromGroupOperation', - // - // PAM - PNAccessManagerGrant: 'PNAccessManagerGrant', - PNAccessManagerGrantToken: 'PNAccessManagerGrantToken', - PNAccessManagerAudit: 'PNAccessManagerAudit', - PNAccessManagerRevokeToken: 'PNAccessManagerRevokeToken', - // - // subscription utilities - PNHandshakeOperation: 'PNHandshakeOperation', - PNReceiveMessagesOperation: 'PNReceiveMessagesOperation', - }; - - /* */ - var default_1$6 = /** @class */ (function () { - function default_1(configuration) { - this._maximumSamplesCount = 100; - this._trackedLatencies = {}; - this._latencies = {}; - this._telemetryExcludeOperations = [ - OPERATIONS.PNSubscribeOperation, - OPERATIONS.PNReceiveMessagesOperation, - OPERATIONS.PNHandshakeOperation, - ]; - this._maximumSamplesCount = configuration.maximumSamplesCount || this._maximumSamplesCount; - } /** - * Compose object with latency information of recently used API endpoints. + * Retrieve file content. * - * @return {Object} Object with request query key/value pairs. + * @param file - Content of the {@link PubNub} File object. + * + * @returns Normalized file {@link data} as {@link ArrayBuffer}; */ - default_1.prototype.operationsLatencyForRequest = function () { - var _this = this; - var latencies = {}; - Object.keys(this._latencies).forEach(function (endpointName) { - var operationLatencies = _this._latencies[endpointName]; - var averageLatency = _this._averageLatency(operationLatencies); - if (averageLatency > 0) { - latencies["l_".concat(endpointName)] = averageLatency; - } + WebCryptoModule.prototype.getFileData = function (file) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + if (file instanceof ArrayBuffer) + return [2 /*return*/, file]; + else if (file instanceof PubNubFile) + return [2 /*return*/, file.toArrayBuffer()]; + throw new Error('Cannot decrypt/encrypt file. In browsers file encrypt/decrypt supported for string, ArrayBuffer or Blob'); + }); }); - return latencies; }; - default_1.prototype.startLatencyMeasure = function (operationType, identifier) { - if (this._telemetryExcludeOperations.includes(operationType) || !identifier) { + /** + * {@link LegacyCryptor|Legacy} cryptor identifier. + */ + WebCryptoModule.LEGACY_IDENTIFIER = ''; + return WebCryptoModule; + }(AbstractCryptoModule)); + /** + * CryptorHeader Utility + */ + var CryptorHeader = /** @class */ (function () { + function CryptorHeader() { + } + CryptorHeader.from = function (id, metadata) { + if (id === CryptorHeader.LEGACY_IDENTIFIER) return; - } - this._trackedLatencies[identifier] = Date.now(); + return new CryptorHeaderV1(id, metadata.byteLength); }; - default_1.prototype.stopLatencyMeasure = function (operationType, identifier) { - if (this._telemetryExcludeOperations.includes(operationType) || !identifier) { - return; - } - var endpointName = this._endpointName(operationType); - /** @type Array */ - var endpointLatencies = this._latencies[endpointName]; - var startDate = this._trackedLatencies[identifier]; - if (!endpointLatencies) { - this._latencies[endpointName] = []; - endpointLatencies = this._latencies[endpointName]; - } - endpointLatencies.push(Date.now() - startDate); - // Truncate samples count if there is more then configured. - if (endpointLatencies.length > this._maximumSamplesCount) { - endpointLatencies.splice(0, endpointLatencies.length - this._maximumSamplesCount); + CryptorHeader.tryParse = function (data) { + var encryptedData = new Uint8Array(data); + var sentinel; + var version = null; + if (encryptedData.byteLength >= 4) { + sentinel = encryptedData.slice(0, 4); + if (this.decoder.decode(sentinel) !== CryptorHeader.SENTINEL) + return WebCryptoModule.LEGACY_IDENTIFIER; } - delete this._trackedLatencies[identifier]; - }; - default_1.prototype._averageLatency = function (latencies) { - var arrayReduce = function (accumulatedLatency, latency) { return accumulatedLatency + latency; }; - return Math.floor(latencies.reduce(arrayReduce, 0) / latencies.length); - }; - default_1.prototype._endpointName = function (operationType) { - var operation = null; - switch (operationType) { - case OPERATIONS.PNPublishOperation: - operation = 'pub'; - break; - case OPERATIONS.PNSignalOperation: - operation = 'sig'; - break; - case OPERATIONS.PNHistoryOperation: - case OPERATIONS.PNFetchMessagesOperation: - case OPERATIONS.PNDeleteMessagesOperation: - case OPERATIONS.PNMessageCounts: - operation = 'hist'; - break; - case OPERATIONS.PNUnsubscribeOperation: - case OPERATIONS.PNWhereNowOperation: - case OPERATIONS.PNHereNowOperation: - case OPERATIONS.PNHeartbeatOperation: - case OPERATIONS.PNSetStateOperation: - case OPERATIONS.PNGetStateOperation: - operation = 'pres'; - break; - case OPERATIONS.PNAddChannelsToGroupOperation: - case OPERATIONS.PNRemoveChannelsFromGroupOperation: - case OPERATIONS.PNChannelGroupsOperation: - case OPERATIONS.PNRemoveGroupOperation: - case OPERATIONS.PNChannelsForGroupOperation: - operation = 'cg'; - break; - case OPERATIONS.PNPushNotificationEnabledChannelsOperation: - case OPERATIONS.PNRemoveAllPushNotificationsOperation: - operation = 'push'; - break; - case OPERATIONS.PNCreateUserOperation: - case OPERATIONS.PNUpdateUserOperation: - case OPERATIONS.PNDeleteUserOperation: - case OPERATIONS.PNGetUserOperation: - case OPERATIONS.PNGetUsersOperation: - case OPERATIONS.PNCreateSpaceOperation: - case OPERATIONS.PNUpdateSpaceOperation: - case OPERATIONS.PNDeleteSpaceOperation: - case OPERATIONS.PNGetSpaceOperation: - case OPERATIONS.PNGetSpacesOperation: - case OPERATIONS.PNGetMembersOperation: - case OPERATIONS.PNUpdateMembersOperation: - case OPERATIONS.PNGetMembershipsOperation: - case OPERATIONS.PNUpdateMembershipsOperation: - operation = 'obj'; - break; - case OPERATIONS.PNAddMessageActionOperation: - case OPERATIONS.PNRemoveMessageActionOperation: - case OPERATIONS.PNGetMessageActionsOperation: - operation = 'msga'; - break; - case OPERATIONS.PNAccessManagerGrant: - case OPERATIONS.PNAccessManagerAudit: - operation = 'pam'; - break; - case OPERATIONS.PNAccessManagerGrantToken: - case OPERATIONS.PNAccessManagerRevokeToken: - operation = 'pamv3'; - break; - default: - operation = 'time'; - break; + if (encryptedData.byteLength >= 5) + version = encryptedData[4]; + else + throw new Error('Decryption error: invalid header version'); + if (version > CryptorHeader.MAX_VERSION) + throw new Error('Decryption error: Unknown cryptor error'); + var identifier; + var pos = 5 + CryptorHeader.IDENTIFIER_LENGTH; + if (encryptedData.byteLength >= pos) + identifier = encryptedData.slice(5, pos); + else + throw new Error('Decryption error: invalid crypto identifier'); + var metadataLength = null; + if (encryptedData.byteLength >= pos + 1) + metadataLength = encryptedData[pos]; + else + throw new Error('Decryption error: invalid metadata length'); + pos += 1; + if (metadataLength === 255 && encryptedData.byteLength >= pos + 2) { + metadataLength = new Uint16Array(encryptedData.slice(pos, pos + 2)).reduce(function (acc, val) { return (acc << 8) + val; }, 0); } - return operation; + return new CryptorHeaderV1(this.decoder.decode(identifier), metadataLength); }; - return default_1; + CryptorHeader.SENTINEL = 'PNED'; + CryptorHeader.LEGACY_IDENTIFIER = ''; + CryptorHeader.IDENTIFIER_LENGTH = 4; + CryptorHeader.VERSION = 1; + CryptorHeader.MAX_VERSION = 1; + CryptorHeader.decoder = new TextDecoder(); + return CryptorHeader; }()); - - /* */ - var BaseNotificationPayload = /** @class */ (function () { - function BaseNotificationPayload(payload, title, body) { - this._payload = payload; - this._setDefaultPayloadStructure(); - this.title = title; - this.body = body; + // v1 CryptorHeader + var CryptorHeaderV1 = /** @class */ (function () { + function CryptorHeaderV1(id, metadataLength) { + this._identifier = id; + this._metadataLength = metadataLength; } - Object.defineProperty(BaseNotificationPayload.prototype, "payload", { + Object.defineProperty(CryptorHeaderV1.prototype, "identifier", { get: function () { - return this._payload; + return this._identifier; }, - enumerable: false, - configurable: true - }); - Object.defineProperty(BaseNotificationPayload.prototype, "title", { set: function (value) { - this._title = value; + this._identifier = value; }, enumerable: false, configurable: true }); - Object.defineProperty(BaseNotificationPayload.prototype, "subtitle", { + Object.defineProperty(CryptorHeaderV1.prototype, "metadataLength", { + get: function () { + return this._metadataLength; + }, set: function (value) { - this._subtitle = value; + this._metadataLength = value; }, enumerable: false, configurable: true }); - Object.defineProperty(BaseNotificationPayload.prototype, "body", { - set: function (value) { - this._body = value; + Object.defineProperty(CryptorHeaderV1.prototype, "version", { + get: function () { + return CryptorHeader.VERSION; }, enumerable: false, configurable: true }); - Object.defineProperty(BaseNotificationPayload.prototype, "badge", { - set: function (value) { - this._badge = value; + Object.defineProperty(CryptorHeaderV1.prototype, "length", { + get: function () { + return (CryptorHeader.SENTINEL.length + + 1 + + CryptorHeader.IDENTIFIER_LENGTH + + (this.metadataLength < 255 ? 1 : 3) + + this.metadataLength); }, enumerable: false, configurable: true }); - Object.defineProperty(BaseNotificationPayload.prototype, "sound", { - set: function (value) { - this._sound = value; + Object.defineProperty(CryptorHeaderV1.prototype, "data", { + get: function () { + var pos = 0; + var header = new Uint8Array(this.length); + var encoder = new TextEncoder(); + header.set(encoder.encode(CryptorHeader.SENTINEL)); + pos += CryptorHeader.SENTINEL.length; + header[pos] = this.version; + pos++; + if (this.identifier) + header.set(encoder.encode(this.identifier), pos); + var metadataLength = this.metadataLength; + pos += CryptorHeader.IDENTIFIER_LENGTH; + if (metadataLength < 255) + header[pos] = metadataLength; + else + header.set([255, metadataLength >> 8, metadataLength & 0xff], pos); + return header; }, enumerable: false, configurable: true }); - BaseNotificationPayload.prototype._setDefaultPayloadStructure = function () { - // Empty. - }; - BaseNotificationPayload.prototype.toObject = function () { - return {}; - }; - return BaseNotificationPayload; + CryptorHeaderV1.IDENTIFIER_LENGTH = 4; + CryptorHeaderV1.SENTINEL = 'PNED'; + return CryptorHeaderV1; }()); - var APNSNotificationPayload = /** @class */ (function (_super) { - __extends(APNSNotificationPayload, _super); - function APNSNotificationPayload() { - return _super !== null && _super.apply(this, arguments) || this; + + function stringifyBufferKeys(obj) { + var isObject = function (value) { return value && typeof value === 'object' && value.constructor === Object; }; + var isString = function (value) { return typeof value === 'string' || value instanceof String; }; + var isNumber = function (value) { return typeof value === 'number' && isFinite(value); }; + if (!isObject(obj)) { + return obj; } - Object.defineProperty(APNSNotificationPayload.prototype, "configurations", { - set: function (value) { - if (!value || !value.length) - return; - this._configurations = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(APNSNotificationPayload.prototype, "notification", { - get: function () { - return this._payload.aps; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(APNSNotificationPayload.prototype, "title", { - get: function () { - return this._title; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.aps.alert.title = value; - this._title = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(APNSNotificationPayload.prototype, "subtitle", { - get: function () { - return this._subtitle; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.aps.alert.subtitle = value; - this._subtitle = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(APNSNotificationPayload.prototype, "body", { - get: function () { - return this._body; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.aps.alert.body = value; - this._body = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(APNSNotificationPayload.prototype, "badge", { - get: function () { - return this._badge; - }, - set: function (value) { - if (value === undefined || value === null) - return; - this._payload.aps.badge = value; - this._badge = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(APNSNotificationPayload.prototype, "sound", { - get: function () { - return this._sound; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.aps.sound = value; - this._sound = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(APNSNotificationPayload.prototype, "silent", { - set: function (value) { - this._isSilent = value; - }, - enumerable: false, - configurable: true + var normalizedObject = {}; + Object.keys(obj).forEach(function (key) { + var keyIsString = isString(key); + var stringifiedKey = key; + var value = obj[key]; + if (Array.isArray(key) || (keyIsString && key.indexOf(',') >= 0)) { + var bytes = keyIsString ? key.split(',') : key; + stringifiedKey = bytes.reduce(function (string, byte) { + string += String.fromCharCode(byte); + return string; + }, ''); + } + else if (isNumber(key) || (keyIsString && !isNaN(key))) { + stringifiedKey = String.fromCharCode(keyIsString ? parseInt(key, 10) : 10); + } + normalizedObject[stringifiedKey] = isObject(value) ? stringifyBufferKeys(value) : value; }); - APNSNotificationPayload.prototype._setDefaultPayloadStructure = function () { - this._payload.aps = { alert: {} }; - }; - APNSNotificationPayload.prototype.toObject = function () { - var _this = this; - var payload = __assign({}, this._payload); - /** @type {{alert: Object, badge: number, sound: string}} */ - var aps = payload.aps; - var alert = aps.alert; - if (this._isSilent) { - aps['content-available'] = 1; + return normalizedObject; + } + + var uuid = {exports: {}}; + + /*! lil-uuid - v0.1 - MIT License - https://github.com/lil-js/uuid */ + uuid.exports; + + (function (module, exports) { + (function (root, factory) { + { + factory(exports); + if (module !== null) { + module.exports = exports.uuid; + } + } + }(commonjsGlobal, function (exports) { + var VERSION = '0.1.0'; + var uuidRegex = { + '3': /^[0-9A-F]{8}-[0-9A-F]{4}-3[0-9A-F]{3}-[0-9A-F]{4}-[0-9A-F]{12}$/i, + '4': /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i, + '5': /^[0-9A-F]{8}-[0-9A-F]{4}-5[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i, + all: /^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i + }; + + function uuid() { + var uuid = '', i, random; + for (i = 0; i < 32; i++) { + random = Math.random() * 16 | 0; + if (i === 8 || i === 12 || i === 16 || i === 20) uuid += '-'; + uuid += (i === 12 ? 4 : (i === 16 ? (random & 3 | 8) : random)).toString(16); + } + return uuid + } + + function isUUID(str, version) { + var pattern = uuidRegex[version || 'all']; + return pattern && pattern.test(str) || false + } + + uuid.isUUID = isUUID; + uuid.VERSION = VERSION; + + exports.uuid = uuid; + exports.isUUID = isUUID; + })); + } (uuid, uuid.exports)); + + var uuidExports = uuid.exports; + var uuidGenerator$1 = /*@__PURE__*/getDefaultExportFromCjs(uuidExports); + + var uuidGenerator = { + createUUID: function () { + if (uuidGenerator$1.uuid) { + return uuidGenerator$1.uuid(); } - if (this._apnsPushType === 'apns2') { - if (!this._configurations || !this._configurations.length) { - throw new ReferenceError('APNS2 configuration is missing'); + return uuidGenerator$1(); + }, + }; + + /** + * {@link PubNub} client configuration module. + */ + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults + /** + * Whether encryption (if set) should use random initialization vector or not. + */ + var USE_RANDOM_INITIALIZATION_VECTOR = true; + /** + * Create {@link PubNub} client private configuration object. + * + * @param base - User- and platform-provided configuration. + * @param setupCryptoModule - Platform-provided {@link CryptoModule} configuration block. + * + * @returns `PubNub` client private configuration. + */ + var makeConfiguration = function (base, setupCryptoModule) { + var _a, _b, _c; + // Ensure that retry policy has proper configuration (if has been set). + (_a = base.retryConfiguration) === null || _a === void 0 ? void 0 : _a.validate(); + (_b = base.useRandomIVs) !== null && _b !== void 0 ? _b : (base.useRandomIVs = USE_RANDOM_INITIALIZATION_VECTOR); + // Override origin value. + base.origin = standardOrigin((_c = base.ssl) !== null && _c !== void 0 ? _c : false, base.origin); + var clientConfiguration = __assign(__assign({}, base), { _pnsdkSuffix: {}, _instanceId: "pn-".concat(uuidGenerator.createUUID()), _cryptoModule: undefined, _cipherKey: undefined, _setupCryptoModule: setupCryptoModule, get instanceId() { + if (this.useInstanceId) + return this._instanceId; + return undefined; + }, getUserId: function () { + return this.userId; + }, setUserId: function (value) { + if (!value || typeof value !== 'string' || value.trim().length === 0) + throw new Error('Missing or invalid userId parameter. Provide a valid string userId'); + this.userId = value; + }, getAuthKey: function () { + return this.authKey; + }, setAuthKey: function (authKey) { + this.authKey = authKey; + }, getFilterExpression: function () { + return this.filterExpression; + }, setFilterExpression: function (expression) { + this.filterExpression = expression; + }, get cipherKey() { + return this._cipherKey; + }, setCipherKey: function (key) { + this._cipherKey = key; + if (!key && this._cryptoModule) { + this._cryptoModule = undefined; + return; } - var configurations_1 = []; - this._configurations.forEach(function (configuration) { - configurations_1.push(_this._objectFromAPNS2Configuration(configuration)); + else if (!key || !this._setupCryptoModule) + return; + this._cryptoModule = this._setupCryptoModule({ + cipherKey: key, + useRandomIVs: base.useRandomIVs, + customEncrypt: this.customEncrypt, + customDecrypt: this.customDecrypt, }); - if (configurations_1.length) { - payload.pn_push = configurations_1; - } - } - if (!alert || !Object.keys(alert).length) { - delete aps.alert; - } - if (this._isSilent) { - delete aps.alert; - delete aps.badge; - delete aps.sound; - alert = {}; - } - return this._isSilent || Object.keys(alert).length ? payload : null; - }; - APNSNotificationPayload.prototype._objectFromAPNS2Configuration = function (configuration) { - var _this = this; - if (!configuration.targets || !configuration.targets.length) { - throw new ReferenceError('At least one APNS2 target should be provided'); - } - var targets = []; - configuration.targets.forEach(function (target) { - targets.push(_this._objectFromAPNSTarget(target)); - }); - var collapseId = configuration.collapseId, expirationDate = configuration.expirationDate; - var objectifiedConfiguration = { auth_method: 'token', targets: targets, version: 'v2' }; - if (collapseId && collapseId.length) { - objectifiedConfiguration.collapse_id = collapseId; - } - if (expirationDate) { - objectifiedConfiguration.expiration = expirationDate.toISOString(); - } - return objectifiedConfiguration; - }; - APNSNotificationPayload.prototype._objectFromAPNSTarget = function (target) { - if (!target.topic || !target.topic.length) { - throw new TypeError("Target 'topic' undefined."); - } - var topic = target.topic, _a = target.environment, environment = _a === void 0 ? 'development' : _a, _b = target.excludedDevices, excludedDevices = _b === void 0 ? [] : _b; - var objectifiedTarget = { topic: topic, environment: environment }; - if (excludedDevices.length) { - objectifiedTarget.excluded_devices = excludedDevices; - } - return objectifiedTarget; - }; - return APNSNotificationPayload; - }(BaseNotificationPayload)); - var MPNSNotificationPayload = /** @class */ (function (_super) { - __extends(MPNSNotificationPayload, _super); - function MPNSNotificationPayload() { - return _super !== null && _super.apply(this, arguments) || this; - } - Object.defineProperty(MPNSNotificationPayload.prototype, "backContent", { - get: function () { - return this._backContent; + }, get cryptoModule() { + return this._cryptoModule; }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.back_content = value; - this._backContent = value; + get useRandomIVs() { + return base.useRandomIVs; + }, getPresenceTimeout: function () { + return this.presenceTimeout; + }, getHeartbeatInterval: function () { + return this.heartbeatInterval; + }, setHeartbeatInterval: function (interval) { + this.heartbeatInterval = interval; + }, getTransactionTimeout: function () { + return this.transactionalRequestTimeout; + }, getSubscribeTimeout: function () { + return this.subscribeRequestTimeout; + }, get PubNubFile() { + return base.PubNubFile; }, - enumerable: false, - configurable: true - }); - Object.defineProperty(MPNSNotificationPayload.prototype, "backTitle", { - get: function () { - return this._backTitle; + get version() { + return '7.6.0'; + }, getVersion: function () { + return this.version; + }, _addPnsdkSuffix: function (name, suffix) { + this._pnsdkSuffix[name] = "".concat(suffix); + }, _getPnsdkSuffix: function (separator) { + return Object.values(this._pnsdkSuffix).join(separator); + }, + // -------------------------------------------------------- + // ---------------------- Deprecated ---------------------- + // -------------------------------------------------------- + // region Deprecated + getUUID: function () { + return this.getUserId(); + }, setUUID: function (value) { + this.setUserId(value); + }, get customEncrypt() { + return base.customEncrypt; }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.back_title = value; - this._backTitle = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(MPNSNotificationPayload.prototype, "count", { - get: function () { - return this._count; - }, - set: function (value) { - if (value === undefined || value === null) - return; - this._payload.count = value; - this._count = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(MPNSNotificationPayload.prototype, "title", { - get: function () { - return this._title; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.title = value; - this._title = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(MPNSNotificationPayload.prototype, "type", { - get: function () { - return this._type; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.type = value; - this._type = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(MPNSNotificationPayload.prototype, "subtitle", { - get: function () { - return this.backTitle; - }, - set: function (value) { - this.backTitle = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(MPNSNotificationPayload.prototype, "body", { - get: function () { - return this.backContent; - }, - set: function (value) { - this.backContent = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(MPNSNotificationPayload.prototype, "badge", { - get: function () { - return this.count; - }, - set: function (value) { - this.count = value; - }, - enumerable: false, - configurable: true - }); - MPNSNotificationPayload.prototype.toObject = function () { - return Object.keys(this._payload).length ? __assign({}, this._payload) : null; - }; - return MPNSNotificationPayload; - }(BaseNotificationPayload)); - var FCMNotificationPayload = /** @class */ (function (_super) { - __extends(FCMNotificationPayload, _super); - function FCMNotificationPayload() { - return _super !== null && _super.apply(this, arguments) || this; + get customDecrypt() { + return base.customDecrypt; + } }); + // Setup `CryptoModule` if possible. + if (base.cipherKey) + clientConfiguration.setCipherKey(base.cipherKey); + return clientConfiguration; + }; + /** + * Decide {@lin PubNub} service REST API origin. + * + * @param secure - Whether preferred to use secured connection or not. + * @param origin - User-provided or default origin. + * + * @returns `PubNub` REST API endpoints origin. + */ + var standardOrigin = function (secure, origin) { + var protocol = secure ? 'https://' : 'http://'; + if (typeof origin === 'string') + return "".concat(protocol).concat(origin); + return "".concat(protocol).concat(origin[Math.floor(Math.random() * origin.length)]); + }; + + /** + * {@link PubNub} client configuration module. + */ + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults + /** + * Whether secured connection should be used by or not. + */ + var USE_SSL = true; + /** + * Whether PubNub client should catch up subscription after network issues. + */ + var RESTORE = false; + /** + * Whether network availability change should be announced with `PNNetworkDownCategory` and + * `PNNetworkUpCategory` state or not. + */ + var AUTO_NETWORK_DETECTION = false; + /** + * Whether messages should be de-duplicated before announcement or not. + */ + var DEDUPE_ON_SUBSCRIBE = false; + /** + * Maximum cache which should be used for message de-duplication functionality. + */ + var DEDUPE_CACHE_SIZE = 100; + /** + * Maximum number of file message publish retries. + */ + var FILE_PUBLISH_RETRY_LIMIT = 5; + /** + * Whether subscription event engine should be used or not. + */ + var ENABLE_EVENT_ENGINE = false; + /** + * Whether configured user presence state should be maintained by the PubNub client or not. + */ + var MAINTAIN_PRESENCE_STATE = true; + /** + * Whether PubNub client should try to utilize existing TCP connection for new requests or not. + */ + var KEEP_ALIVE$1 = false; + /** + * Whether verbose logging should be enabled or not. + */ + var USE_VERBOSE_LOGGING = false; + /** + * Whether leave events should be suppressed or not. + */ + var SUPPRESS_LEAVE_EVENTS = false; + /** + * Whether heartbeat request failure should be announced or not. + */ + var ANNOUNCE_HEARTBEAT_FAILURE = true; + /** + * Whether heartbeat request success should be announced or not. + */ + var ANNOUNCE_HEARTBEAT_SUCCESS = false; + /** + * Whether PubNub client instance id should be added to the requests or not. + */ + var USE_INSTANCE_ID = false; + /** + * Whether unique identifier should be added to the request or not. + */ + var USE_REQUEST_ID = false; + /** + * Transactional requests timeout. + */ + var TRANSACTIONAL_REQUEST_TIMEOUT = 15; + /** + * Subscription request timeout. + */ + var SUBSCRIBE_REQUEST_TIMEOUT = 310; + /** + * Default user presence timeout. + */ + var PRESENCE_TIMEOUT = 300; + /** + * Minimum user presence timeout. + */ + var PRESENCE_TIMEOUT_MINIMUM = 20; + /** + * Apply configuration default values. + * + * @param configuration - User-provided configuration. + */ + var setDefaults$1 = function (configuration) { + var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m; + // Copy configuration. + var configurationCopy = __assign({}, configuration); + (_a = configurationCopy.logVerbosity) !== null && _a !== void 0 ? _a : (configurationCopy.logVerbosity = USE_VERBOSE_LOGGING); + (_b = configurationCopy.ssl) !== null && _b !== void 0 ? _b : (configurationCopy.ssl = USE_SSL); + (_c = configurationCopy.transactionalRequestTimeout) !== null && _c !== void 0 ? _c : (configurationCopy.transactionalRequestTimeout = TRANSACTIONAL_REQUEST_TIMEOUT); + (_d = configurationCopy.subscribeRequestTimeout) !== null && _d !== void 0 ? _d : (configurationCopy.subscribeRequestTimeout = SUBSCRIBE_REQUEST_TIMEOUT); + (_e = configurationCopy.restore) !== null && _e !== void 0 ? _e : (configurationCopy.restore = RESTORE); + (_f = configurationCopy.useInstanceId) !== null && _f !== void 0 ? _f : (configurationCopy.useInstanceId = USE_INSTANCE_ID); + (_g = configurationCopy.suppressLeaveEvents) !== null && _g !== void 0 ? _g : (configurationCopy.suppressLeaveEvents = SUPPRESS_LEAVE_EVENTS); + (_h = configurationCopy.requestMessageCountThreshold) !== null && _h !== void 0 ? _h : (configurationCopy.requestMessageCountThreshold = DEDUPE_CACHE_SIZE); + (_j = configurationCopy.autoNetworkDetection) !== null && _j !== void 0 ? _j : (configurationCopy.autoNetworkDetection = AUTO_NETWORK_DETECTION); + (_k = configurationCopy.enableEventEngine) !== null && _k !== void 0 ? _k : (configurationCopy.enableEventEngine = ENABLE_EVENT_ENGINE); + (_l = configurationCopy.maintainPresenceState) !== null && _l !== void 0 ? _l : (configurationCopy.maintainPresenceState = MAINTAIN_PRESENCE_STATE); + (_m = configurationCopy.keepAlive) !== null && _m !== void 0 ? _m : (configurationCopy.keepAlive = KEEP_ALIVE$1); + // Generate default origin subdomains. + if (!configurationCopy.origin) + configurationCopy.origin = Array.from({ length: 20 }, function (_, i) { return "ps".concat(i + 1, ".pndsn.com"); }); + var keySet = { + subscribeKey: configurationCopy.subscribeKey, + publishKey: configurationCopy.publishKey, + secretKey: configurationCopy.secretKey, + }; + if (configurationCopy.presenceTimeout && configurationCopy.presenceTimeout < PRESENCE_TIMEOUT_MINIMUM) { + configurationCopy.presenceTimeout = PRESENCE_TIMEOUT_MINIMUM; + // eslint-disable-next-line no-console + console.log('WARNING: Presence timeout is less than the minimum. Using minimum value: ', PRESENCE_TIMEOUT_MINIMUM); + } + if (configurationCopy.presenceTimeout) { + configurationCopy.heartbeatInterval = configurationCopy.presenceTimeout / 2 - 1; + } + else + configurationCopy.presenceTimeout = PRESENCE_TIMEOUT; + // Apply extended configuration defaults. + var announceSuccessfulHeartbeats = ANNOUNCE_HEARTBEAT_SUCCESS; + var announceFailedHeartbeats = ANNOUNCE_HEARTBEAT_FAILURE; + var fileUploadPublishRetryLimit = FILE_PUBLISH_RETRY_LIMIT; + var dedupeOnSubscribe = DEDUPE_ON_SUBSCRIBE; + var maximumCacheSize = DEDUPE_CACHE_SIZE; + var useRequestId = USE_REQUEST_ID; + // @ts-expect-error Not documented legacy configuration options. + if (configurationCopy.dedupeOnSubscribe && typeof configurationCopy.dedupeOnSubscribe === 'boolean') { + // @ts-expect-error Not documented legacy configuration options. + dedupeOnSubscribe = configurationCopy.dedupeOnSubscribe; + } + // @ts-expect-error Not documented legacy configuration options. + if (configurationCopy.useRequestId && typeof configurationCopy.useRequestId === 'boolean') { + // @ts-expect-error Not documented legacy configuration options. + useRequestId = configurationCopy.useRequestId; } - Object.defineProperty(FCMNotificationPayload.prototype, "notification", { - get: function () { - return this._payload.notification; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(FCMNotificationPayload.prototype, "data", { - get: function () { - return this._payload.data; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(FCMNotificationPayload.prototype, "title", { - get: function () { - return this._title; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.notification.title = value; - this._title = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(FCMNotificationPayload.prototype, "body", { - get: function () { - return this._body; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.notification.body = value; - this._body = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(FCMNotificationPayload.prototype, "sound", { - get: function () { - return this._sound; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.notification.sound = value; - this._sound = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(FCMNotificationPayload.prototype, "icon", { - get: function () { - return this._icon; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.notification.icon = value; - this._icon = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(FCMNotificationPayload.prototype, "tag", { - get: function () { - return this._tag; - }, - set: function (value) { - if (!value || !value.length) - return; - this._payload.notification.tag = value; - this._tag = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(FCMNotificationPayload.prototype, "silent", { - set: function (value) { - this._isSilent = value; - }, - enumerable: false, - configurable: true - }); - FCMNotificationPayload.prototype._setDefaultPayloadStructure = function () { - this._payload.notification = {}; - this._payload.data = {}; - }; - FCMNotificationPayload.prototype.toObject = function () { - var data = __assign({}, this._payload.data); - var notification = null; - var payload = {}; - /** - * Check whether additional data has been passed outside of 'data' object - * and put it into it if required. - */ - if (Object.keys(this._payload).length > 2) { - var _a = this._payload; _a.notification; _a.data; var additionalData = __rest(_a, ["notification", "data"]); - data = __assign(__assign({}, data), additionalData); - } - if (this._isSilent) { - data.notification = this._payload.notification; - } - else { - notification = this._payload.notification; - } - if (Object.keys(data).length) { - payload.data = data; - } - if (notification && Object.keys(notification).length) { - payload.notification = notification; - } - return Object.keys(payload).length ? payload : null; - }; - return FCMNotificationPayload; - }(BaseNotificationPayload)); - var NotificationsPayload = /** @class */ (function () { - function NotificationsPayload(title, body) { - this._payload = { apns: {}, mpns: {}, fcm: {} }; - this._title = title; - this._body = body; - this.apns = new APNSNotificationPayload(this._payload.apns, title, body); - this.mpns = new MPNSNotificationPayload(this._payload.mpns, title, body); - this.fcm = new FCMNotificationPayload(this._payload.fcm, title, body); - } - Object.defineProperty(NotificationsPayload.prototype, "debugging", { - set: function (value) { - this._debugging = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(NotificationsPayload.prototype, "title", { - get: function () { - return this._title; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(NotificationsPayload.prototype, "body", { - get: function () { - return this._body; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(NotificationsPayload.prototype, "subtitle", { - get: function () { - return this._subtitle; - }, - set: function (value) { - this._subtitle = value; - this.apns.subtitle = value; - this.mpns.subtitle = value; - this.fcm.subtitle = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(NotificationsPayload.prototype, "badge", { - get: function () { - return this._badge; - }, - set: function (value) { - this._badge = value; - this.apns.badge = value; - this.mpns.badge = value; - this.fcm.badge = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(NotificationsPayload.prototype, "sound", { - get: function () { - return this._sound; - }, - set: function (value) { - this._sound = value; - this.apns.sound = value; - this.mpns.sound = value; - this.fcm.sound = value; - }, - enumerable: false, - configurable: true - }); - /** - * Build notifications platform for requested platforms. - * - * @param {Array} platforms - List of platforms for which payload - * should be added to final dictionary. Supported values: gcm, apns, apns2, - * mpns. - * - * @returns {Object} Object with data, which can be sent with publish method - * call and trigger remote notifications for specified platforms. - */ - NotificationsPayload.prototype.buildPayload = function (platforms) { - var payload = {}; - if (platforms.includes('apns') || platforms.includes('apns2')) { - this.apns._apnsPushType = platforms.includes('apns') ? 'apns' : 'apns2'; - var apnsPayload = this.apns.toObject(); - if (apnsPayload && Object.keys(apnsPayload).length) { - payload.pn_apns = apnsPayload; - } - } - if (platforms.includes('mpns')) { - var mpnsPayload = this.mpns.toObject(); - if (mpnsPayload && Object.keys(mpnsPayload).length) { - payload.pn_mpns = mpnsPayload; - } - } - if (platforms.includes('fcm')) { - var fcmPayload = this.fcm.toObject(); - if (fcmPayload && Object.keys(fcmPayload).length) { - payload.pn_gcm = fcmPayload; - } - } - if (Object.keys(payload).length && this._debugging) { - payload.pn_debug = true; - } - return payload; - }; - return NotificationsPayload; - }()); - - var default_1$5 = /** @class */ (function () { - function default_1() { - this._listeners = []; - } - default_1.prototype.addListener = function (newListener) { - if (this._listeners.includes(newListener)) { - return; - } - this._listeners.push(newListener); - }; - default_1.prototype.removeListener = function (deprecatedListener) { - var newListeners = []; - this._listeners.forEach(function (listener) { - if (listener !== deprecatedListener) - newListeners.push(listener); - }); - this._listeners = newListeners; - }; - default_1.prototype.removeAllListeners = function () { - this._listeners = []; - }; - default_1.prototype.announcePresence = function (announce) { - this._listeners.forEach(function (listener) { - if (listener.presence) - listener.presence(announce); - }); - }; - default_1.prototype.announceStatus = function (announce) { - this._listeners.forEach(function (listener) { - if (listener.status) - listener.status(announce); - }); - }; - default_1.prototype.announceMessage = function (announce) { - this._listeners.forEach(function (listener) { - if (listener.message) - listener.message(announce); - }); - }; - default_1.prototype.announceSignal = function (announce) { - this._listeners.forEach(function (listener) { - if (listener.signal) - listener.signal(announce); - }); - }; - default_1.prototype.announceMessageAction = function (announce) { - this._listeners.forEach(function (listener) { - if (listener.messageAction) - listener.messageAction(announce); - }); - }; - default_1.prototype.announceFile = function (announce) { - this._listeners.forEach(function (listener) { - if (listener.file) - listener.file(announce); - }); - }; - default_1.prototype.announceObjects = function (announce) { - this._listeners.forEach(function (listener) { - if (listener.objects) - listener.objects(announce); - }); - }; - default_1.prototype.announceUser = function (announce) { - this._listeners.forEach(function (listener) { - if (listener.user) - listener.user(announce); - }); - }; - default_1.prototype.announceSpace = function (announce) { - this._listeners.forEach(function (listener) { - if (listener.space) - listener.space(announce); - }); - }; - default_1.prototype.announceMembership = function (announce) { - this._listeners.forEach(function (listener) { - if (listener.membership) - listener.membership(announce); - }); - }; - default_1.prototype.announceNetworkUp = function () { - var networkStatus = {}; - networkStatus.category = categories.PNNetworkUpCategory; - this.announceStatus(networkStatus); - }; - default_1.prototype.announceNetworkDown = function () { - var networkStatus = {}; - networkStatus.category = categories.PNNetworkDownCategory; - this.announceStatus(networkStatus); - }; - return default_1; - }()); - - var default_1$4 = /** @class */ (function () { - function default_1(config, cbor) { - this._config = config; - this._cbor = cbor; - } - default_1.prototype.setToken = function (token) { - if (token && token.length > 0) { - this._token = token; - } - else { - this._token = undefined; - } + if ( + // @ts-expect-error Not documented legacy configuration options. + configurationCopy.announceSuccessfulHeartbeats && + // @ts-expect-error Not documented legacy configuration options. + typeof configurationCopy.announceSuccessfulHeartbeats === 'boolean') { + // @ts-expect-error Not documented legacy configuration options. + announceSuccessfulHeartbeats = configurationCopy.announceSuccessfulHeartbeats; + } + // @ts-expect-error Not documented legacy configuration options. + if (configurationCopy.announceFailedHeartbeats && typeof configurationCopy.announceFailedHeartbeats === 'boolean') { + // @ts-expect-error Not documented legacy configuration options. + announceFailedHeartbeats = configurationCopy.announceFailedHeartbeats; + } + if ( + // @ts-expect-error Not documented legacy configuration options. + configurationCopy.fileUploadPublishRetryLimit && + // @ts-expect-error Not documented legacy configuration options. + typeof configurationCopy.fileUploadPublishRetryLimit === 'number') { + // @ts-expect-error Not documented legacy configuration options. + fileUploadPublishRetryLimit = configurationCopy.fileUploadPublishRetryLimit; + } + return __assign(__assign({}, configurationCopy), { keySet: keySet, dedupeOnSubscribe: dedupeOnSubscribe, maximumCacheSize: maximumCacheSize, useRequestId: useRequestId, announceSuccessfulHeartbeats: announceSuccessfulHeartbeats, announceFailedHeartbeats: announceFailedHeartbeats, fileUploadPublishRetryLimit: fileUploadPublishRetryLimit }); + }; + + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults + /** + * Whether PubNub client should update its state using browser's reachability events or not. + * + * If the browser fails to detect the network changes from Wi-Fi to LAN and vice versa, or you get + * reconnection issues, set the flag to `false`. This allows the SDK reconnection logic to take over. + */ + var LISTEN_TO_BROWSER_NETWORK_EVENTS = true; + /** + * Whether PubNub client should try utilize existing TCP connection for new requests or not. + */ + var KEEP_ALIVE = true; + /** + * Apply configuration default values. + * + * @param configuration - User-provided configuration. + */ + var setDefaults = function (configuration) { + var _a, _b; + return __assign(__assign({}, setDefaults$1(configuration)), { + // Set platform-specific options. + listenToBrowserNetworkEvents: (_a = configuration.listenToBrowserNetworkEvents) !== null && _a !== void 0 ? _a : LISTEN_TO_BROWSER_NETWORK_EVENTS, keepAlive: (_b = configuration.keepAlive) !== null && _b !== void 0 ? _b : KEEP_ALIVE }); + }; + + var default_1$2 = /** @class */ (function () { + function default_1(cbor) { + this._cbor = cbor; + } + default_1.prototype.setToken = function (token) { + if (token && token.length > 0) { + this._token = token; + } + else { + this._token = undefined; + } }; default_1.prototype.getToken = function () { return this._token; @@ -3226,42 +3269,50 @@ return default_1; }()); - function objectToList(o) { - var l = []; - Object.keys(o).forEach(function (key) { return l.push(key); }); - return l; - } - function encodeString(input) { + /** + * Enum representing possible transport methods for HTTP requests. + * + * @enum {number} + */ + var TransportMethod; + (function (TransportMethod) { + /** + * Request will be sent using `GET` method. + */ + TransportMethod["GET"] = "GET"; + /** + * Request will be sent using `POST` method. + */ + TransportMethod["POST"] = "POST"; + /** + * Request will be sent using `PATCH` method. + */ + TransportMethod["PATCH"] = "PATCH"; + /** + * Request will be sent using `DELETE` method. + */ + TransportMethod["DELETE"] = "DELETE"; + /** + * Local request. + * + * Request won't be sent to the service and probably used to compute URL. + */ + TransportMethod["LOCAL"] = "LOCAL"; + })(TransportMethod || (TransportMethod = {})); + + /** + * Percent-encode input string. + * + * **Note:** Encode content in accordance of the `PubNub` service requirements. + * + * @param input - Source string or number for encoding. + * + * @returns Percent-encoded string. + */ + var encodeString = function (input) { return encodeURIComponent(input).replace(/[!~*'()]/g, function (x) { return "%".concat(x.charCodeAt(0).toString(16).toUpperCase()); }); - } - function objectToListSorted(o) { - return objectToList(o).sort(); - } - function signPamFromParams(params) { - var l = objectToListSorted(params); - return l.map(function (paramKey) { return "".concat(paramKey, "=").concat(encodeString(params[paramKey])); }).join('&'); - } - function endsWith(searchString, suffix) { - return searchString.indexOf(suffix, this.length - suffix.length) !== -1; - } - function createPromise() { - var successResolve; - var failureResolve; - var promise = new Promise(function (fulfill, reject) { - successResolve = fulfill; - failureResolve = reject; - }); - return { promise: promise, reject: failureResolve, fulfill: successResolve }; - } - function stringToArrayBuffer(str) { - var buf = new ArrayBuffer(str.length * 2); - var bufView = new Uint16Array(buf); - for (var i = 0, strLen = str.length; i < strLen; i++) { - bufView[i] = str.charCodeAt(i); - } - return buf; - } - function removeSingleOccurance(source, elementsToRemove) { + }; + var removeSingleOccurance = function (source, elementsToRemove) { var removed = Object.fromEntries(elementsToRemove.map(function (prop) { return [prop, false]; })); return source.filter(function (e) { if (elementsToRemove.includes(e) && !removed[e]) { @@ -3270,3521 +3321,2692 @@ } return true; }); - } - function findUniqueCommonElements(a, b) { + }; + var findUniqueCommonElements = function (a, b) { return __spreadArray([], __read(a), false).filter(function (value) { return b.includes(value) && a.indexOf(value) === a.lastIndexOf(value) && b.indexOf(value) === b.lastIndexOf(value); }); - } - var utils$5 = { - signPamFromParams: signPamFromParams, - endsWith: endsWith, - createPromise: createPromise, - encodeString: encodeString, - stringToArrayBuffer: stringToArrayBuffer, - removeSingleOccurance: removeSingleOccurance, - findUniqueCommonElements: findUniqueCommonElements, }; - var PubNubError = /** @class */ (function (_super) { - __extends(PubNubError, _super); - function PubNubError(message, status) { - var _newTarget = this.constructor; - var _this = _super.call(this, message) || this; - _this.name = _this.constructor.name; - _this.status = status; - _this.message = message; - Object.setPrototypeOf(_this, _newTarget.prototype); - return _this; - } - return PubNubError; - }(Error)); - function createError(errorPayload, type) { - errorPayload.type = type; - errorPayload.error = true; - return errorPayload; - } - function createValidationError(message) { - return createError({ message: message }, 'validationError'); - } - function decideURL(endpoint, modules, incomingParams) { - if (endpoint.usePost && endpoint.usePost(modules, incomingParams)) { - return endpoint.postURL(modules, incomingParams); - } - if (endpoint.usePatch && endpoint.usePatch(modules, incomingParams)) { - return endpoint.patchURL(modules, incomingParams); - } - if (endpoint.useGetFile && endpoint.useGetFile(modules, incomingParams)) { - return endpoint.getFileURL(modules, incomingParams); - } - return endpoint.getURL(modules, incomingParams); - } - function generatePNSDK(config) { - if (config.sdkName) { - return config.sdkName; - } - var base = "PubNub-JS-".concat(config.sdkFamily); - if (config.partnerId) { - base += "-".concat(config.partnerId); - } - base += "/".concat(config.getVersion()); - var pnsdkSuffix = config._getPnsdkSuffix(' '); - if (pnsdkSuffix.length > 0) { - base += pnsdkSuffix; - } - return base; - } - function getHttpMethod(modules, endpoint, incomingParams) { - if (endpoint.usePost && endpoint.usePost(modules, incomingParams)) { - return 'POST'; - } - if (endpoint.usePatch && endpoint.usePatch(modules, incomingParams)) { - return 'PATCH'; + var RequestSignature = /** @class */ (function () { + function RequestSignature(publishKey, secretKey, hasher) { + this.publishKey = publishKey; + this.secretKey = secretKey; + this.hasher = hasher; } - if (endpoint.useDelete && endpoint.useDelete(modules, incomingParams)) { - return 'DELETE'; - } - if (endpoint.useGetFile && endpoint.useGetFile(modules, incomingParams)) { - return 'GETFILE'; + /** + * Compute request signature. + * + * @param req - Request which will be used to compute signature. + * @returns {string} `v2` request signature. + */ + RequestSignature.prototype.signature = function (req) { + var method = req.path.startsWith('/publish') ? TransportMethod.GET : req.method; + var signatureInput = "".concat(method, "\n").concat(this.publishKey, "\n").concat(req.path, "\n").concat(this.queryParameters(req.queryParameters), "\n"); + if (method === TransportMethod.POST || method === TransportMethod.PATCH) { + var body = req.body; + var payload = void 0; + if (body && body instanceof ArrayBuffer) { + payload = RequestSignature.textDecoder.decode(body); + } + else if (body && typeof body !== 'object') { + payload = body; + } + if (payload) + signatureInput += payload; + } + return "v2.".concat(this.hasher(signatureInput, this.secretKey)) + .replace(/\+/g, '-') + .replace(/\//g, '_') + .replace(/=+$/, ''); + }; + /** + * Prepare request query parameters for signature. + * + * @param query - Key / value pair of the request query parameters. + * @private + */ + RequestSignature.prototype.queryParameters = function (query) { + return Object.keys(query) + .sort() + .map(function (key) { + var queryValue = query[key]; + if (!Array.isArray(queryValue)) + return "".concat(key, "=").concat(encodeString(queryValue)); + return queryValue + .sort() + .map(function (value) { return "".concat(key, "=").concat(encodeString(value)); }) + .join('&'); + }) + .join('&'); + }; + RequestSignature.textDecoder = new TextDecoder('utf-8'); + return RequestSignature; + }()); + var PubNubMiddleware = /** @class */ (function () { + function PubNubMiddleware(configuration) { + this.configuration = configuration; + var keySet = configuration.clientConfiguration.keySet, shaHMAC = configuration.shaHMAC; + if (keySet.secretKey && shaHMAC) + this.signatureGenerator = new RequestSignature(keySet.publishKey, keySet.secretKey, shaHMAC); } - return 'GET'; - } - function signRequest(modules, url, outgoingParams, incomingParams, endpoint) { - var config = modules.config, crypto = modules.crypto; - var httpMethod = getHttpMethod(modules, endpoint, incomingParams); - outgoingParams.timestamp = Math.floor(new Date().getTime() / 1000); - // This is because of a server-side bug, old publish using post should be deprecated - if (endpoint.getOperation() === 'PNPublishOperation' && - endpoint.usePost && - endpoint.usePost(modules, incomingParams)) { - httpMethod = 'GET'; - } - if (httpMethod === 'GETFILE') { - httpMethod = 'GET'; - } - var signInput = "".concat(httpMethod, "\n").concat(config.publishKey, "\n").concat(url, "\n").concat(utils$5.signPamFromParams(outgoingParams), "\n"); - if (httpMethod === 'POST') { - var payload = endpoint.postPayload(modules, incomingParams); - if (typeof payload === 'string') { - signInput += payload; - } - else { - signInput += JSON.stringify(payload); - } + PubNubMiddleware.prototype.makeSendable = function (req) { + return this.configuration.transport.makeSendable(this.request(req)); + }; + PubNubMiddleware.prototype.request = function (req) { + var _a; + var clientConfiguration = this.configuration.clientConfiguration; + if (!req.queryParameters) + req.queryParameters = {}; + // Modify request with required information. + if (clientConfiguration.useInstanceId) + req.queryParameters['instanceid'] = clientConfiguration.instanceId; + if (!req.queryParameters['uuid']) + req.queryParameters['uuid'] = clientConfiguration.userId; + req.queryParameters['requestid'] = req.identifier; + req.queryParameters['pnsdk'] = this.generatePNSDK(); + (_a = req.origin) !== null && _a !== void 0 ? _a : (req.origin = clientConfiguration.origin); + // Authenticate request if required. + this.authenticateRequest(req); + // Sign request if it is required. + this.signRequest(req); + return req; + }; + PubNubMiddleware.prototype.authenticateRequest = function (req) { + var _a; + // Access management endpoints doesn't need authentication (signature required instead). + if (req.path.startsWith('/v2/auth/') || req.path.startsWith('/v3/pam/') || req.path.startsWith('/time')) + return; + var _b = this.configuration, clientConfiguration = _b.clientConfiguration, tokenManager = _b.tokenManager; + var accessKey = (_a = tokenManager.getToken()) !== null && _a !== void 0 ? _a : clientConfiguration.authKey; + if (accessKey) + req.queryParameters['auth'] = accessKey; + }; + /** + * Compute and append request signature. + * + * @param req - Transport request with information which should be used to generate signature. + */ + PubNubMiddleware.prototype.signRequest = function (req) { + if (!this.signatureGenerator || req.path.startsWith('/time')) + return; + req.queryParameters['timestamp'] = String(Math.floor(new Date().getTime() / 1000)); + req.queryParameters['signature'] = this.signatureGenerator.signature(req); + }; + /** + * Compose `pnsdk` query parameter. + * + * SDK provides ability to set custom name or append vendor information to the `pnsdk` query + * parameter. + * + * @returns Finalized `pnsdk` query parameter value. + */ + PubNubMiddleware.prototype.generatePNSDK = function () { + var clientConfiguration = this.configuration.clientConfiguration; + if (clientConfiguration.sdkName) + return clientConfiguration.sdkName; + var base = "PubNub-JS-".concat(clientConfiguration.sdkFamily); + if (clientConfiguration.partnerId) + base += "-".concat(clientConfiguration.partnerId); + base += "/".concat(clientConfiguration.version); + var pnsdkSuffix = clientConfiguration._getPnsdkSuffix(' '); + if (pnsdkSuffix.length > 0) + base += pnsdkSuffix; + return base; + }; + return PubNubMiddleware; + }()); + + /** + * Request processing status categories. + */ + var StatusCategory; + (function (StatusCategory) { + /** + * Call failed when network was unable to complete the call. + */ + StatusCategory["PNNetworkIssuesCategory"] = "PNNetworkIssuesCategory"; + /** + * Network call timed out. + */ + StatusCategory["PNTimeoutCategory"] = "PNTimeoutCategory"; + /** + * Request has been cancelled. + */ + StatusCategory["PNCancelledCategory"] = "PNCancelledCategory"; + /** + * Server responded with bad response. + */ + StatusCategory["PNBadRequestCategory"] = "PNBadRequestCategory"; + /** + * Server responded with access denied. + */ + StatusCategory["PNAccessDeniedCategory"] = "PNAccessDeniedCategory"; + /** + * Something strange happened; please check the logs. + */ + StatusCategory["PNUnknownCategory"] = "PNUnknownCategory"; + // -------------------------------------------------------- + // --------------------- Network status ------------------- + // -------------------------------------------------------- + /** + * SDK will announce when the network appears to be connected again. + */ + StatusCategory["PNNetworkUpCategory"] = "PNNetworkUpCategory"; + /** + * SDK will announce when the network appears to down. + */ + StatusCategory["PNNetworkDownCategory"] = "PNNetworkDownCategory"; + // -------------------------------------------------------- + // -------------------- Real-time events ------------------ + // -------------------------------------------------------- + /** + * PubNub client reconnected to the real-time updates stream. + */ + StatusCategory["PNReconnectedCategory"] = "PNReconnectedCategory"; + /** + * PubNub client connected to the real-time updates stream. + */ + StatusCategory["PNConnectedCategory"] = "PNConnectedCategory"; + /** + * Received real-time updates exceed specified threshold. + * + * After temporary disconnection and catchup, this category means that potentially some + * real-time updates have been pushed into `storage` and need to be requested separately. + */ + StatusCategory["PNRequestMessageCountExceededCategory"] = "PNRequestMessageCountExceededCategory"; + /** + * PubNub client disconnected from the real-time updates streams. + */ + StatusCategory["PNDisconnectedCategory"] = "PNDisconnectedCategory"; + /** + * PubNub client wasn't able to connect to the real-time updates streams. + */ + StatusCategory["PNConnectionErrorCategory"] = "PNConnectionErrorCategory"; + /** + * PubNub client unexpectedly disconnected from the real-time updates streams. + */ + StatusCategory["PNDisconnectedUnexpectedlyCategory"] = "PNDisconnectedUnexpectedlyCategory"; + })(StatusCategory || (StatusCategory = {})); + var StatusCategory$1 = StatusCategory; + + // PubNub client API common types. + /** + * PubNub REST API call error. + */ + var PubNubAPIError = /** @class */ (function (_super) { + __extends(PubNubAPIError, _super); + /** + * Construct PubNub endpoint error. + * + * @param message - Short API call error description. + * @param category - Error category. + * @param statusCode - Response HTTP status code. + * @param errorData - Error information. + */ + function PubNubAPIError(message, category, statusCode, errorData) { + var _this = _super.call(this, message) || this; + _this.category = category; + _this.statusCode = statusCode; + _this.errorData = errorData; + _this.name = _this.constructor.name; + return _this; } - else if (httpMethod === 'PATCH') { - var payload = endpoint.patchPayload(modules, incomingParams); - if (typeof payload === 'string') { - signInput += payload; - } - else { - signInput += JSON.stringify(payload); + /** + * Construct API from known error object or {@link PubNub} service error response. + * + * @param errorOrResponse - `Error` or service error response object from which error information + * should be extracted. + * @param data - Preprocessed service error response. + * + * @returns `PubNubAPIError` object with known error category and additional information (if + * available). + */ + PubNubAPIError.create = function (errorOrResponse, data) { + if (errorOrResponse instanceof Error) + return PubNubAPIError.createFromError(errorOrResponse); + else + return PubNubAPIError.createFromServiceResponse(errorOrResponse, data); + }; + /** + * Create API error instance from other error object. + * + * @param error - `Error` object provided by network provider (mostly) or other {@link PubNub} client components. + * + * @returns `PubNubAPIError` object with known error category and additional information (if + * available). + */ + PubNubAPIError.createFromError = function (error) { + var category = StatusCategory$1.PNUnknownCategory; + var message = 'Unknown error'; + var errorName = 'Error'; + if (!error) + return new PubNubAPIError(message, category, 0); + if (error instanceof Error) { + message = error.message; + errorName = error.name; + } + if (errorName === 'AbortError') { + category = StatusCategory$1.PNCancelledCategory; + message = 'Request cancelled'; + } + else if (errorName === 'FetchError') { + var errorCode = error.code; + if (errorCode in ['ECONNREFUSED', 'ENOTFOUND', 'ECONNRESET', 'EAI_AGAIN']) + category = StatusCategory$1.PNNetworkIssuesCategory; + if (errorCode === 'ECONNREFUSED') + message = 'Connection refused'; + else if (errorCode === 'ENOTFOUND') + message = 'Server not found'; + else if (errorCode === 'ECONNRESET') + message = 'Connection reset by peer'; + else if (errorCode === 'EAI_AGAIN') + message = 'Name resolution error'; + else if (errorCode === 'ETIMEDOUT') { + category = StatusCategory$1.PNTimeoutCategory; + message = 'Request timeout'; + } + else + message = "Unknown system error: ".concat(error); + } + else if (message === 'Request timeout') + category = StatusCategory$1.PNTimeoutCategory; + return new PubNubAPIError(message, category, 0, error); + }; + /** + * Construct API from known {@link PubNub} service error response. + * + * @param response - Service error response object from which error information should be + * extracted. + * @param data - Preprocessed service error response. + * + * @returns `PubNubAPIError` object with known error category and additional information (if + * available). + */ + PubNubAPIError.createFromServiceResponse = function (response, data) { + var category = StatusCategory$1.PNUnknownCategory; + var errorData; + var message = 'Unknown error'; + var status = response.status; + if (status === 402) + message = 'Not available for used key set. Contact support@pubnub.com'; + else if (status === 400) { + category = StatusCategory$1.PNBadRequestCategory; + message = 'Bad request'; + } + else if (status === 403) { + category = StatusCategory$1.PNAccessDeniedCategory; + message = 'Access denied'; + } + // Try get more information about error from service response. + if (data && data.byteLength > 0) { + var decoded = new TextDecoder().decode(data); + if (response.headers['content-type'].includes('application/json')) { + try { + var errorResponse = JSON.parse(decoded); + if (typeof errorResponse === 'object' && !Array.isArray(errorResponse)) { + if ('error' in errorResponse && + errorResponse.error === 1 && + 'status' in errorResponse && + typeof errorResponse.status === 'number' && + 'message' in errorResponse && + 'service' in errorResponse) { + errorData = errorResponse; + status = errorResponse.status; + } + if ('error' in errorResponse && + typeof errorResponse.error === 'object' && + !Array.isArray(errorResponse.error) && + 'message' in errorResponse.error) { + errorData = errorResponse.error; + } + } + } + catch (_) { + errorData = decoded; + } + } + else + errorData = decoded; } - } - var signature = "v2.".concat(crypto.HMACSHA256(signInput)); - signature = signature.replace(/\+/g, '-'); - signature = signature.replace(/\//g, '_'); - signature = signature.replace(/=+$/, ''); - outgoingParams.signature = signature; - } - function endpointCreator (modules, endpoint) { - var args = []; - for (var _i = 2; _i < arguments.length; _i++) { - args[_i - 2] = arguments[_i]; - } - var networking = modules.networking, config = modules.config, telemetryManager = modules.telemetryManager, tokenManager = modules.tokenManager; - var requestId = uuidGenerator.createUUID(); - var callback = null; - var promiseComponent = null; - var incomingParams = {}; - if (endpoint.getOperation() === OPERATIONS.PNTimeOperation || - endpoint.getOperation() === OPERATIONS.PNChannelGroupsOperation) { - callback = args[0]; - } - else { - incomingParams = args[0]; - callback = args[1]; - } - // bridge in Promise support. - if (typeof Promise !== 'undefined' && !callback) { - promiseComponent = utils$5.createPromise(); - } - var validationResult = endpoint.validateParams(modules, incomingParams); - if (validationResult) { - if (callback) { - return callback(createValidationError(validationResult)); + return new PubNubAPIError(message, category, status, errorData); + }; + /** + * Convert API error object to API callback status object. + * + * @param operation - Request operation during which error happened. + * + * @returns Pre-formatted API callback status object. + */ + PubNubAPIError.prototype.toStatus = function (operation) { + return { + error: true, + category: this.category, + operation: operation, + statusCode: this.statusCode, + errorData: this.errorData, + }; + }; + return PubNubAPIError; + }(Error)); + + /* global window */ + /** + * Web Transport provider module. + */ + /** + * Class representing a fetch-based Web Worker transport provider. + */ + var WebTransport = /** @class */ (function () { + function WebTransport(keepAlive, logVerbosity) { + if (keepAlive === void 0) { keepAlive = false; } + this.keepAlive = keepAlive; + this.logVerbosity = logVerbosity; + this.setupWorker(); + } + WebTransport.prototype.makeSendable = function (req) { + var _this = this; + var controller; + var sendRequestEvent = { + type: 'send-request', + request: req, + }; + if (req.cancellable) { + controller = { + abort: function () { + var cancelRequest = { + type: 'cancel-request', + identifier: req.identifier, + }; + // Cancel active request with specified identifier. + _this.worker.postMessage(cancelRequest); + }, + }; } - if (promiseComponent) { - promiseComponent.reject(new PubNubError('Validation failed, check status for details', createValidationError(validationResult))); - return promiseComponent.promise; + return [ + new Promise(function (resolve, reject) { + // Associate Promise resolution / reject with request identifier for future usage in + // `onmessage` handler block to return results. + _this.callbacks.set(req.identifier, { resolve: resolve, reject: reject }); + // Trigger request processing by Web Worker. + _this.worker.postMessage(sendRequestEvent); + }), + controller, + ]; + }; + WebTransport.prototype.request = function (req) { + return req; + }; + /** + * Complete PubNub Web Worker setup. + */ + WebTransport.prototype.setupWorker = function () { + var _this = this; + this.worker = new Worker(URL.createObjectURL(new Blob(["/**\n * Web Worker module.\n */\nvar __assign = (this && this.__assign) || function () {\n __assign = Object.assign || function(t) {\n for (var s, i = 1, n = arguments.length; i < n; i++) {\n s = arguments[i];\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))\n t[p] = s[p];\n }\n return t;\n };\n return __assign.apply(this, arguments);\n};\nvar __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\n return new (P || (P = Promise))(function (resolve, reject) {\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\n step((generator = generator.apply(thisArg, _arguments || [])).next());\n });\n};\nvar __generator = (this && this.__generator) || function (thisArg, body) {\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\n return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\n function verb(n) { return function (v) { return step([n, v]); }; }\n function step(op) {\n if (f) throw new TypeError(\"Generator is already executing.\");\n while (g && (g = 0, op[0] && (_ = 0)), _) try {\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\n if (y = 0, t) op = [op[0] & 2, t.value];\n switch (op[0]) {\n case 0: case 1: t = op; break;\n case 4: _.label++; return { value: op[1], done: false };\n case 5: _.label++; y = op[1]; op = [0]; continue;\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\n default:\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\n if (t[2]) _.ops.pop();\n _.trys.pop(); continue;\n }\n op = body.call(thisArg, _);\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\n }\n};\n// endregion\n// endregion\n/**\n * Map of request identifiers to their abort controllers.\n *\n * **Note:** Because of message-based nature of interaction it will be impossible to pass actual {@link AbortController}\n * to the transport provider code.\n */\nvar abortControllers = new Map();\n/**\n * Service `ArrayBuffer` response decoder.\n */\nvar decoder = new TextDecoder();\n/**\n * Whether verbose logging enabled or not.\n */\nvar logVerbosity = false;\n/**\n * If set to `true`, SDK will use the same TCP connection for each HTTP request, instead of\n * opening a new one for each new request.\n *\n * @default `true`\n */\nvar keepAlive = true;\n// --------------------------------------------------------\n// ------------------- Event Handlers ---------------------\n// --------------------------------------------------------\n// region Event Handlers\n/**\n * Handle signals from the PubNub core.\n *\n * @param event - Event object from the PubNub Core with instructions for worker.\n */\nself.onmessage = function (event) {\n var data = event.data;\n if (data.type === 'setup') {\n logVerbosity = data.logVerbosity;\n keepAlive = data.keepAlive;\n }\n else if (data.type === 'send-request') {\n sendRequestEventHandler(data.request);\n }\n if (data.type === 'cancel-request') {\n var controller = abortControllers.get(data.identifier);\n // Abort request if possible.\n if (controller) {\n abortControllers.delete(data.identifier);\n controller.abort();\n }\n }\n event.data;\n};\n/**\n * Handle request send event.\n *\n * @param req - Data for {@link Request} creation and scheduling.\n */\nvar sendRequestEventHandler = function (req) {\n (function () { return __awaiter(void 0, void 0, void 0, function () {\n var request, timestamp, start, requestTimeout;\n var _a;\n return __generator(this, function (_b) {\n switch (_b.label) {\n case 0: return [4 /*yield*/, requestFromTransportRequest(req)];\n case 1:\n request = _b.sent();\n timestamp = new Date().toISOString();\n start = new Date().getTime();\n if (req.cancellable)\n abortControllers.set(req.identifier, new AbortController());\n requestTimeout = new Promise(function (_, reject) {\n var timeoutId = setTimeout(function () {\n // Clean up.\n abortControllers.delete(req.identifier);\n clearTimeout(timeoutId);\n reject(new Error('Request timeout'));\n }, req.timeout * 1000);\n });\n if (logVerbosity)\n notifyRequestProcessing('start', request, timestamp, req.queryParameters);\n Promise.race([\n fetch(request, { signal: (_a = abortControllers.get(req.identifier)) === null || _a === void 0 ? void 0 : _a.signal, keepalive: keepAlive }),\n requestTimeout,\n ])\n .then(function (response) {\n if (parseInt(response.headers.get('Content-Length'), 10) > 0) {\n return response.arrayBuffer().then(function (buffer) { return [response, buffer]; });\n }\n return [response, undefined];\n })\n .then(function (response) {\n if (logVerbosity) {\n var contentType = response[0].headers.get('Content-Type');\n var timestampDone = new Date().toISOString();\n var now = new Date().getTime();\n var elapsed = now - start;\n var body = void 0;\n if (contentType &&\n (contentType.includes('application/json') ||\n contentType.includes('text/plain') ||\n contentType.includes('text/html'))) {\n body = decoder.decode(response[1]);\n }\n notifyRequestProcessing('end', request, timestampDone, req.queryParameters, body, elapsed);\n }\n // Treat 4xx and 5xx status codes as errors.\n if (response[0].status >= 400)\n postMessage(requestProcessingError(req.identifier, request.url, undefined, response));\n else\n postMessage(requestProcessingSuccess(req.identifier, request.url, response));\n })\n .catch(function (error) { return postMessage(requestProcessingError(error, request.url)); });\n return [2 /*return*/];\n }\n });\n }); })();\n};\n// endregion\n// --------------------------------------------------------\n// ----------------------- Helpers ------------------------\n// --------------------------------------------------------\n// region Helpers\nvar notifyRequestProcessing = function (type, request, timestamp, query, response, duration) {\n var event;\n var url = request.url.split('?')[0];\n if (type === 'start') {\n event = {\n type: 'request-progress-start',\n url: url,\n query: query,\n timestamp: timestamp,\n };\n }\n else {\n event = {\n type: 'request-progress-end',\n url: url,\n query: query,\n response: response,\n timestamp: timestamp,\n duration: duration,\n };\n }\n postMessage(event);\n};\n/**\n * Create processing success event from service response.\n *\n * @param identifier - Identifier of the processed request.\n * @param url - Url which has been used to perform request.\n * @param res - Service response for used REST API endpoint along with response body.\n *\n * @returns Request processing success event object.\n */\nvar requestProcessingSuccess = function (identifier, url, res) {\n var response = res[0], body = res[1];\n var contentLength = parseInt(response.headers.get('Content-Length'), 10);\n var contentType = response.headers.get('Content-Type');\n var headers = {};\n // Copy Headers object content into plain Record.\n response.headers.forEach(function (value, key) { return (headers[key] = value.toLowerCase()); });\n return {\n type: 'request-process-success',\n identifier: identifier,\n url: url,\n response: {\n contentLength: contentLength,\n contentType: contentType,\n headers: headers,\n status: response.status,\n body: body,\n },\n };\n};\n/**\n * Create processing error event from service response.\n *\n * @param identifier - Identifier of the failed request.\n * @param url - Url which has been used to perform request.\n * @param [error] - Client-side request processing error (for example network issues).\n * @param [res] - Service error response (for example permissions error or malformed\n * payload) along with service body.\n *\n * @returns Request processing error event object.\n */\nvar requestProcessingError = function (identifier, url, error, res) {\n // User service response as error information source.\n if (res) {\n return __assign(__assign({}, requestProcessingSuccess(identifier, url, res)), { type: 'request-process-error' });\n }\n var type = 'NETWORK_ISSUE';\n var message = 'Unknown error';\n var name = 'Error';\n if (error && error instanceof Error) {\n message = error.message;\n name = error.name;\n }\n if (name === 'AbortError') {\n message = 'Request aborted';\n type = 'ABORTED';\n }\n else if (message === 'Request timeout')\n type = 'TIMEOUT';\n return {\n type: 'request-process-error',\n identifier: identifier,\n url: url,\n error: { name: name, type: type, message: message },\n };\n};\n/**\n * Creates a Request object from a given {@link TransportRequest} object.\n *\n * @param req - The {@link TransportRequest} object containing request information.\n *\n * @returns {@link Request} object generated from the {@link TransportRequest} object.\n */\nvar requestFromTransportRequest = function (req) { return __awaiter(void 0, void 0, Promise, function () {\n var headers, body, path, _i, _a, _b, key, value, fileData, formData, _c, _d, _e, key, value;\n var _f;\n return __generator(this, function (_g) {\n switch (_g.label) {\n case 0:\n headers = undefined;\n path = req.path;\n if (req.headers) {\n headers = {};\n for (_i = 0, _a = Object.entries(req.headers); _i < _a.length; _i++) {\n _b = _a[_i], key = _b[0], value = _b[1];\n headers[key] = value;\n }\n }\n if (req.queryParameters && Object.keys(req.queryParameters).length !== 0)\n path = \"\".concat(path, \"?\").concat(queryStringFromObject(req.queryParameters));\n if (!(req.body && typeof req.body === 'object')) return [3 /*break*/, 4];\n if (!(req.body instanceof ArrayBuffer)) return [3 /*break*/, 1];\n body = req.body;\n return [3 /*break*/, 3];\n case 1: return [4 /*yield*/, req.body.toArrayBuffer()];\n case 2:\n fileData = _g.sent();\n formData = new FormData();\n for (_c = 0, _d = Object.entries((_f = req.formData) !== null && _f !== void 0 ? _f : {}); _c < _d.length; _c++) {\n _e = _d[_c], key = _e[0], value = _e[1];\n formData.append(key, value);\n }\n formData.append('file', new Blob([fileData], { type: req.body.mimeType }), req.body.name);\n body = formData;\n _g.label = 3;\n case 3: return [3 /*break*/, 5];\n case 4:\n body = req.body;\n _g.label = 5;\n case 5: return [2 /*return*/, new Request(\"\".concat(req.origin).concat(path), {\n method: req.method,\n headers: headers,\n redirect: 'follow',\n body: body,\n })];\n }\n });\n}); };\nvar queryStringFromObject = function (query) {\n return Object.keys(query)\n .map(function (key) {\n var queryValue = query[key];\n if (!Array.isArray(queryValue))\n return \"\".concat(key, \"=\").concat(encodeString(queryValue));\n return queryValue.map(function (value) { return \"\".concat(key, \"=\").concat(encodeString(value)); }).join('&');\n })\n .join('&');\n};\n/**\n * Percent-encode input string.\n *\n * **Note:** Encode content in accordance of the `PubNub` service requirements.\n *\n * @param input - Source string or number for encoding.\n *\n * @returns Percent-encoded string.\n */\nvar encodeString = function (input) {\n return encodeURIComponent(input).replace(/[!~*'()]/g, function (x) { return \"%\".concat(x.charCodeAt(0).toString(16).toUpperCase()); });\n};\nexport {};\n// endregion\n"], { type: 'application/javascript' })), { + name: '/pubnub', + type: 'module', + }); + this.callbacks = new Map(); + // Complete Web Worker initialization. + var setupEvent = { + type: 'setup', + logVerbosity: this.logVerbosity, + keepAlive: this.keepAlive, + }; + this.worker.postMessage(setupEvent); + this.worker.onmessage = function (event) { + var data = event.data; + if (data.type === 'request-progress-start' || data.type === 'request-progress-end') { + _this.logRequestProgress(data); + } + else if (data.type === 'request-process-success' || data.type === 'request-process-error') { + var _a = _this.callbacks.get(data.identifier), resolve = _a.resolve, reject = _a.reject; + if (data.type === 'request-process-success') { + resolve({ + status: data.response.status, + url: data.url, + headers: data.response.headers, + body: data.response.body, + }); + } + else { + var category = StatusCategory$1.PNUnknownCategory; + var message = 'Unknown error'; + // Handle client-side issues (if any). + if (data.error) { + if (data.error.type === 'NETWORK_ISSUE') + category = StatusCategory$1.PNNetworkIssuesCategory; + else if (data.error.type === 'TIMEOUT') + category = StatusCategory$1.PNTimeoutCategory; + message = data.error.message; + } + // Handle service error response. + else if (data.response) { + return reject(PubNubAPIError.create({ + url: data.url, + headers: data.response.headers, + body: data.response.body, + status: data.response.status, + })); + } + reject(new PubNubAPIError(message, category, 0)); + } + } + }; + }; + /** + * Print request progress information. + * + * @param information - Request progress information from Web Worker. + */ + WebTransport.prototype.logRequestProgress = function (information) { + var _a, _b; + if (information.type === 'request-progress-start') { + console.log('<<<<<'); + console.log("[".concat(information.timestamp, "]"), '\n', information.url, '\n', JSON.stringify((_a = information.query) !== null && _a !== void 0 ? _a : {})); + console.log('-----'); } - return; - } - var outgoingParams = endpoint.prepareParams(modules, incomingParams); - var url = decideURL(endpoint, modules, incomingParams); - var callInstance; - var networkingParams = { - url: url, - operation: endpoint.getOperation(), - timeout: endpoint.getRequestTimeout(modules), - headers: endpoint.getRequestHeaders ? endpoint.getRequestHeaders() : {}, - ignoreBody: typeof endpoint.ignoreBody === 'function' ? endpoint.ignoreBody(modules) : false, - forceBuffered: typeof endpoint.forceBuffered === 'function' ? endpoint.forceBuffered(modules, incomingParams) : null, - abortSignal: typeof endpoint.getAbortSignal === 'function' ? endpoint.getAbortSignal(modules, incomingParams) : null, - }; - outgoingParams.uuid = config.UUID; - outgoingParams.pnsdk = generatePNSDK(config); - // Add telemetry information (if there is any available). - var telemetryLatencies = telemetryManager.operationsLatencyForRequest(); - if (Object.keys(telemetryLatencies).length) { - outgoingParams = __assign(__assign({}, outgoingParams), telemetryLatencies); - } - if (config.useInstanceId) { - outgoingParams.instanceid = config.instanceId; - } - if (config.useRequestId) { - outgoingParams.requestid = requestId; - } - if (endpoint.isAuthSupported()) { - var tokenOrKey = tokenManager.getToken() || config.getAuthKey(); - if (tokenOrKey) { - outgoingParams.auth = tokenOrKey; + else { + console.log('>>>>>>'); + console.log("[".concat(information.timestamp, " / ").concat(information.duration, "]"), '\n', information.url, '\n', JSON.stringify((_b = information.query) !== null && _b !== void 0 ? _b : {}), '\n', information.response); + console.log('-----'); } + }; + return WebTransport; + }()); + + /** + * Events listener manager module. + */ + /** + * Real-time listeners' manager. + */ + var ListenerManager = /** @class */ (function () { + function ListenerManager() { + /** + * List of registered event listeners. + */ + this.listeners = []; + // endregion } - if (config.secretKey) { - signRequest(modules, url, outgoingParams, incomingParams, endpoint); - } - var onResponse = function (status, payload) { - if (status.error) { - if (endpoint.handleError) { - endpoint.handleError(modules, incomingParams, status); - } - if (callback) { - callback(status); - } - else if (promiseComponent) { - promiseComponent.reject(new PubNubError('PubNub call failed, check status for details', status)); - } + /** + * Register new real-time events listener. + * + * @param listener - Listener with event callbacks to handle different types of events. + */ + ListenerManager.prototype.addListener = function (listener) { + if (this.listeners.includes(listener)) return; - } - // Stop endpoint latency tracking. - telemetryManager.stopLatencyMeasure(endpoint.getOperation(), requestId); - var responseP = endpoint.handleResponse(modules, payload, incomingParams); - if (typeof (responseP === null || responseP === void 0 ? void 0 : responseP.then) !== 'function') { - responseP = Promise.resolve(responseP); - } - responseP - .then(function (result) { - if (callback) { - callback(status, result); - } - else if (promiseComponent) { - promiseComponent.fulfill(result); - } - }) - .catch(function (e) { - if (callback) { - var errorData = e; - if (endpoint.getOperation() === OPERATIONS.PNSubscribeOperation) { - errorData = { - statusCode: 400, - error: true, - operation: endpoint.getOperation(), - errorData: e, - category: categories.PNUnknownCategory, - }; - } - callback(errorData, null); - } - else if (promiseComponent) { - promiseComponent.reject(new PubNubError('PubNub call failed, check status for details', e)); - } + this.listeners.push(listener); + }; + /** + * Remove real-time event listener. + * + * @param listener - Event listeners which should be removed. + */ + ListenerManager.prototype.removeListener = function (listener) { + this.listeners = this.listeners.filter(function (storedListener) { return storedListener !== listener; }); + }; + /** + * Clear all real-time event listeners. + */ + ListenerManager.prototype.removeAllListeners = function () { + this.listeners = []; + }; + /** + * Announce PubNub client status change event. + * + * @param status - PubNub client status. + */ + ListenerManager.prototype.announceStatus = function (status) { + this.listeners.forEach(function (listener) { + if (listener.status) + listener.status(status); }); }; - // Start endpoint latency tracking. - telemetryManager.startLatencyMeasure(endpoint.getOperation(), requestId); - if (getHttpMethod(modules, endpoint, incomingParams) === 'POST') { - var payload = endpoint.postPayload(modules, incomingParams); - callInstance = networking.POST(outgoingParams, payload, networkingParams, onResponse); - } - else if (getHttpMethod(modules, endpoint, incomingParams) === 'PATCH') { - var payload = endpoint.patchPayload(modules, incomingParams); - callInstance = networking.PATCH(outgoingParams, payload, networkingParams, onResponse); - } - else if (getHttpMethod(modules, endpoint, incomingParams) === 'DELETE') { - callInstance = networking.DELETE(outgoingParams, networkingParams, onResponse); - } - else if (getHttpMethod(modules, endpoint, incomingParams) === 'GETFILE') { - callInstance = networking.GETFILE(outgoingParams, networkingParams, onResponse); - } - else { - callInstance = networking.GET(outgoingParams, networkingParams, onResponse); - } - if (endpoint.getOperation() === OPERATIONS.PNSubscribeOperation) { - return callInstance; - } - if (promiseComponent) { - return promiseComponent.promise; - } - } - - /* */ - function getOperation$s() { - return OPERATIONS.PNAddChannelsToGroupOperation; - } - function validateParams$s(modules, incomingParams) { - var channels = incomingParams.channels, channelGroup = incomingParams.channelGroup; - var config = modules.config; - if (!channelGroup) - return 'Missing Channel Group'; - if (!channels || channels.length === 0) - return 'Missing Channels'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL$q(modules, incomingParams) { - var channelGroup = incomingParams.channelGroup; - var config = modules.config; - return "/v1/channel-registration/sub-key/".concat(config.subscribeKey, "/channel-group/").concat(utils$5.encodeString(channelGroup)); - } - function getRequestTimeout$s(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$s() { - return true; - } - function prepareParams$s(modules, incomingParams) { - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a; - return { - add: channels.join(','), + /** + * Announce channel presence change event. + * + * @param presence - Channel presence change information. + */ + ListenerManager.prototype.announcePresence = function (presence) { + this.listeners.forEach(function (listener) { + if (listener.presence) + listener.presence(presence); + }); }; - } - function handleResponse$s() { - return {}; - } - - var addChannelsChannelGroupConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$s, - validateParams: validateParams$s, - getURL: getURL$q, - getRequestTimeout: getRequestTimeout$s, - isAuthSupported: isAuthSupported$s, - prepareParams: prepareParams$s, - handleResponse: handleResponse$s - }); - - /* */ - function getOperation$r() { - return OPERATIONS.PNRemoveChannelsFromGroupOperation; - } - function validateParams$r(modules, incomingParams) { - var channels = incomingParams.channels, channelGroup = incomingParams.channelGroup; - var config = modules.config; - if (!channelGroup) - return 'Missing Channel Group'; - if (!channels || channels.length === 0) - return 'Missing Channels'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL$p(modules, incomingParams) { - var channelGroup = incomingParams.channelGroup; - var config = modules.config; - return "/v1/channel-registration/sub-key/".concat(config.subscribeKey, "/channel-group/").concat(utils$5.encodeString(channelGroup)); - } - function getRequestTimeout$r(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$r() { - return true; - } - function prepareParams$r(modules, incomingParams) { - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a; - return { - remove: channels.join(','), + /** + * Announce real-time message event. + * + * @param message - Received real-time message. + */ + ListenerManager.prototype.announceMessage = function (message) { + this.listeners.forEach(function (listener) { + if (listener.message) + listener.message(message); + }); }; - } - function handleResponse$r() { - return {}; - } - - var removeChannelsChannelGroupConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$r, - validateParams: validateParams$r, - getURL: getURL$p, - getRequestTimeout: getRequestTimeout$r, - isAuthSupported: isAuthSupported$r, - prepareParams: prepareParams$r, - handleResponse: handleResponse$r - }); - - /* */ - function getOperation$q() { - return OPERATIONS.PNRemoveGroupOperation; - } - function validateParams$q(modules, incomingParams) { - var channelGroup = incomingParams.channelGroup; - var config = modules.config; - if (!channelGroup) - return 'Missing Channel Group'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL$o(modules, incomingParams) { - var channelGroup = incomingParams.channelGroup; - var config = modules.config; - return "/v1/channel-registration/sub-key/".concat(config.subscribeKey, "/channel-group/").concat(utils$5.encodeString(channelGroup), "/remove"); - } - function isAuthSupported$q() { - return true; - } - function getRequestTimeout$q(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function prepareParams$q() { - return {}; - } - function handleResponse$q() { - return {}; - } - - var deleteChannelGroupConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$q, - validateParams: validateParams$q, - getURL: getURL$o, - isAuthSupported: isAuthSupported$q, - getRequestTimeout: getRequestTimeout$q, - prepareParams: prepareParams$q, - handleResponse: handleResponse$q - }); - - /* */ - function getOperation$p() { - return OPERATIONS.PNChannelGroupsOperation; - } - function validateParams$p(modules) { - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL$n(modules) { - var config = modules.config; - return "/v1/channel-registration/sub-key/".concat(config.subscribeKey, "/channel-group"); - } - function getRequestTimeout$p(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$p() { - return true; - } - function prepareParams$p() { - return {}; - } - function handleResponse$p(modules, serverResponse) { - return { - groups: serverResponse.payload.groups, + /** + * Announce real-time signal event. + * + * @param signal - Received real-time signal. + */ + ListenerManager.prototype.announceSignal = function (signal) { + this.listeners.forEach(function (listener) { + if (listener.signal) + listener.signal(signal); + }); }; - } - - var listChannelGroupsConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$p, - validateParams: validateParams$p, - getURL: getURL$n, - getRequestTimeout: getRequestTimeout$p, - isAuthSupported: isAuthSupported$p, - prepareParams: prepareParams$p, - handleResponse: handleResponse$p - }); - - /* */ - function getOperation$o() { - return OPERATIONS.PNChannelsForGroupOperation; - } - function validateParams$o(modules, incomingParams) { - var channelGroup = incomingParams.channelGroup; - var config = modules.config; - if (!channelGroup) - return 'Missing Channel Group'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL$m(modules, incomingParams) { - var channelGroup = incomingParams.channelGroup; - var config = modules.config; - return "/v1/channel-registration/sub-key/".concat(config.subscribeKey, "/channel-group/").concat(utils$5.encodeString(channelGroup)); - } - function getRequestTimeout$o(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$o() { - return true; - } - function prepareParams$o() { - return {}; - } - function handleResponse$o(modules, serverResponse) { - return { - channels: serverResponse.payload.channels, + /** + * Announce message actions change event. + * + * @param messageAction - Message action change information. + */ + ListenerManager.prototype.announceMessageAction = function (messageAction) { + this.listeners.forEach(function (listener) { + if (listener.messageAction) + listener.messageAction(messageAction); + }); }; - } - - var listChannelsInChannelGroupConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$o, - validateParams: validateParams$o, - getURL: getURL$m, - getRequestTimeout: getRequestTimeout$o, - isAuthSupported: isAuthSupported$o, - prepareParams: prepareParams$o, - handleResponse: handleResponse$o - }); - - /* */ - function getOperation$n() { - return OPERATIONS.PNPushNotificationEnabledChannelsOperation; - } - function validateParams$n(modules, incomingParams) { - var device = incomingParams.device, pushGateway = incomingParams.pushGateway, channels = incomingParams.channels, topic = incomingParams.topic; - var config = modules.config; - if (!device) - return 'Missing Device ID (device)'; - if (!pushGateway) - return 'Missing GW Type (pushGateway: gcm, apns or apns2)'; - if (pushGateway === 'apns2' && !topic) - return 'Missing APNS2 topic'; - if (!channels || channels.length === 0) - return 'Missing Channels'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL$l(modules, incomingParams) { - var device = incomingParams.device, pushGateway = incomingParams.pushGateway; - var config = modules.config; - if (pushGateway === 'apns2') { - return "/v2/push/sub-key/".concat(config.subscribeKey, "/devices-apns2/").concat(device); - } - return "/v1/push/sub-key/".concat(config.subscribeKey, "/devices/").concat(device); - } - function getRequestTimeout$n(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$n() { - return true; - } - function prepareParams$n(modules, incomingParams) { - var pushGateway = incomingParams.pushGateway, _a = incomingParams.channels, channels = _a === void 0 ? [] : _a, _b = incomingParams.environment, environment = _b === void 0 ? 'development' : _b, topic = incomingParams.topic; - var parameters = { type: pushGateway, add: channels.join(',') }; - if (pushGateway === 'apns2') { - parameters = __assign(__assign({}, parameters), { environment: environment, topic: topic }); - delete parameters.type; - } - return parameters; - } - function handleResponse$n() { - return {}; - } - - var addPushChannelsConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$n, - validateParams: validateParams$n, - getURL: getURL$l, - getRequestTimeout: getRequestTimeout$n, - isAuthSupported: isAuthSupported$n, - prepareParams: prepareParams$n, - handleResponse: handleResponse$n - }); - - /* */ - function getOperation$m() { - return OPERATIONS.PNPushNotificationEnabledChannelsOperation; - } - function validateParams$m(modules, incomingParams) { - var device = incomingParams.device, pushGateway = incomingParams.pushGateway, channels = incomingParams.channels, topic = incomingParams.topic; - var config = modules.config; - if (!device) - return 'Missing Device ID (device)'; - if (!pushGateway) - return 'Missing GW Type (pushGateway: gcm, apns or apns2)'; - if (pushGateway === 'apns2' && !topic) - return 'Missing APNS2 topic'; - if (!channels || channels.length === 0) - return 'Missing Channels'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL$k(modules, incomingParams) { - var device = incomingParams.device, pushGateway = incomingParams.pushGateway; - var config = modules.config; - if (pushGateway === 'apns2') { - return "/v2/push/sub-key/".concat(config.subscribeKey, "/devices-apns2/").concat(device); - } - return "/v1/push/sub-key/".concat(config.subscribeKey, "/devices/").concat(device); - } - function getRequestTimeout$m(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$m() { - return true; - } - function prepareParams$m(modules, incomingParams) { - var pushGateway = incomingParams.pushGateway, _a = incomingParams.channels, channels = _a === void 0 ? [] : _a, _b = incomingParams.environment, environment = _b === void 0 ? 'development' : _b, topic = incomingParams.topic; - var parameters = { type: pushGateway, remove: channels.join(',') }; - if (pushGateway === 'apns2') { - parameters = __assign(__assign({}, parameters), { environment: environment, topic: topic }); - delete parameters.type; - } - return parameters; - } - function handleResponse$m() { - return {}; - } - - var removePushChannelsConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$m, - validateParams: validateParams$m, - getURL: getURL$k, - getRequestTimeout: getRequestTimeout$m, - isAuthSupported: isAuthSupported$m, - prepareParams: prepareParams$m, - handleResponse: handleResponse$m - }); - - function getOperation$l() { - return OPERATIONS.PNPushNotificationEnabledChannelsOperation; - } - function validateParams$l(modules, incomingParams) { - var device = incomingParams.device, pushGateway = incomingParams.pushGateway, topic = incomingParams.topic; - var config = modules.config; - if (!device) - return 'Missing Device ID (device)'; - if (!pushGateway) - return 'Missing GW Type (pushGateway: gcm, apns or apns2)'; - if (pushGateway === 'apns2' && !topic) - return 'Missing APNS2 topic'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL$j(modules, incomingParams) { - var device = incomingParams.device, pushGateway = incomingParams.pushGateway; - var config = modules.config; - if (pushGateway === 'apns2') { - return "/v2/push/sub-key/".concat(config.subscribeKey, "/devices-apns2/").concat(device); - } - return "/v1/push/sub-key/".concat(config.subscribeKey, "/devices/").concat(device); - } - function getRequestTimeout$l(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$l() { - return true; - } - function prepareParams$l(modules, incomingParams) { - var pushGateway = incomingParams.pushGateway, _a = incomingParams.environment, environment = _a === void 0 ? 'development' : _a, topic = incomingParams.topic; - var parameters = { type: pushGateway }; - if (pushGateway === 'apns2') { - parameters = __assign(__assign({}, parameters), { environment: environment, topic: topic }); - delete parameters.type; - } - return parameters; - } - function handleResponse$l(modules, serverResponse) { - return { channels: serverResponse }; - } - - var listPushChannelsConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$l, - validateParams: validateParams$l, - getURL: getURL$j, - getRequestTimeout: getRequestTimeout$l, - isAuthSupported: isAuthSupported$l, - prepareParams: prepareParams$l, - handleResponse: handleResponse$l - }); - - /* */ - function getOperation$k() { - return OPERATIONS.PNRemoveAllPushNotificationsOperation; - } - function validateParams$k(modules, incomingParams) { - var device = incomingParams.device, pushGateway = incomingParams.pushGateway, topic = incomingParams.topic; - var config = modules.config; - if (!device) - return 'Missing Device ID (device)'; - if (!pushGateway) - return 'Missing GW Type (pushGateway: gcm, apns or apns2)'; - if (pushGateway === 'apns2' && !topic) - return 'Missing APNS2 topic'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL$i(modules, incomingParams) { - var device = incomingParams.device, pushGateway = incomingParams.pushGateway; - var config = modules.config; - if (pushGateway === 'apns2') { - return "/v2/push/sub-key/".concat(config.subscribeKey, "/devices-apns2/").concat(device, "/remove"); - } - return "/v1/push/sub-key/".concat(config.subscribeKey, "/devices/").concat(device, "/remove"); - } - function getRequestTimeout$k(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$k() { - return true; - } - function prepareParams$k(modules, incomingParams) { - var pushGateway = incomingParams.pushGateway, _a = incomingParams.environment, environment = _a === void 0 ? 'development' : _a, topic = incomingParams.topic; - var parameters = { type: pushGateway }; - if (pushGateway === 'apns2') { - parameters = __assign(__assign({}, parameters), { environment: environment, topic: topic }); - delete parameters.type; - } - return parameters; - } - function handleResponse$k() { - return {}; - } - - var removeDevicePushConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$k, - validateParams: validateParams$k, - getURL: getURL$i, - getRequestTimeout: getRequestTimeout$k, - isAuthSupported: isAuthSupported$k, - prepareParams: prepareParams$k, - handleResponse: handleResponse$k - }); - - /* */ - function getOperation$j() { - return OPERATIONS.PNUnsubscribeOperation; - } - function validateParams$j(modules) { - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL$h(modules, incomingParams) { - var config = modules.config; - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a; - var stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return "/v2/presence/sub-key/".concat(config.subscribeKey, "/channel/").concat(utils$5.encodeString(stringifiedChannels), "/leave"); - } - function getRequestTimeout$j(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$j() { - return true; - } - function prepareParams$j(modules, incomingParams) { - var _a = incomingParams.channelGroups, channelGroups = _a === void 0 ? [] : _a; - var params = {}; - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); - } - return params; - } - function handleResponse$j() { - return {}; - } - - var presenceLeaveEndpointConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$j, - validateParams: validateParams$j, - getURL: getURL$h, - getRequestTimeout: getRequestTimeout$j, - isAuthSupported: isAuthSupported$j, - prepareParams: prepareParams$j, - handleResponse: handleResponse$j - }); - - /* */ - function getOperation$i() { - return OPERATIONS.PNWhereNowOperation; - } - function validateParams$i(modules) { - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL$g(modules, incomingParams) { - var config = modules.config; - var _a = incomingParams.uuid, uuid = _a === void 0 ? config.UUID : _a; - return "/v2/presence/sub-key/".concat(config.subscribeKey, "/uuid/").concat(utils$5.encodeString(uuid)); - } - function getRequestTimeout$i(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$i() { - return true; - } - function prepareParams$i() { - return {}; - } - function handleResponse$i(modules, serverResponse) { - // This is a quick fix for when the server does not include a payload - // in where now responses - if (!serverResponse.payload) { - return { channels: [] }; - } - return { channels: serverResponse.payload.channels }; - } - - var presenceWhereNowEndpointConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$i, - validateParams: validateParams$i, - getURL: getURL$g, - getRequestTimeout: getRequestTimeout$i, - isAuthSupported: isAuthSupported$i, - prepareParams: prepareParams$i, - handleResponse: handleResponse$i - }); - - /* */ - function getOperation$h() { - return OPERATIONS.PNHeartbeatOperation; - } - function validateParams$h(modules) { - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL$f(modules, incomingParams) { - var config = modules.config; - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a; - var stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return "/v2/presence/sub-key/".concat(config.subscribeKey, "/channel/").concat(utils$5.encodeString(stringifiedChannels), "/heartbeat"); - } - function isAuthSupported$h() { - return true; - } - function getRequestTimeout$h(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function prepareParams$h(modules, incomingParams) { - var _a = incomingParams.channelGroups, channelGroups = _a === void 0 ? [] : _a, state = incomingParams.state; - var config = modules.config; - var params = {}; - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); - } - if (state) { - params.state = JSON.stringify(state); - } - params.heartbeat = config.getPresenceTimeout(); - return params; - } - function handleResponse$h() { - return {}; - } - - var presenceHeartbeatEndpointConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$h, - validateParams: validateParams$h, - getURL: getURL$f, - isAuthSupported: isAuthSupported$h, - getRequestTimeout: getRequestTimeout$h, - prepareParams: prepareParams$h, - handleResponse: handleResponse$h - }); - - /* */ - function getOperation$g() { - return OPERATIONS.PNGetStateOperation; - } - function validateParams$g(modules) { - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL$e(modules, incomingParams) { - var config = modules.config; - var _a = incomingParams.uuid, uuid = _a === void 0 ? config.UUID : _a, _b = incomingParams.channels, channels = _b === void 0 ? [] : _b; - var stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return "/v2/presence/sub-key/".concat(config.subscribeKey, "/channel/").concat(utils$5.encodeString(stringifiedChannels), "/uuid/").concat(uuid); - } - function getRequestTimeout$g(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$g() { - return true; - } - function prepareParams$g(modules, incomingParams) { - var _a = incomingParams.channelGroups, channelGroups = _a === void 0 ? [] : _a; - var params = {}; - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); - } - return params; - } - function handleResponse$g(modules, serverResponse, incomingParams) { - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a, _b = incomingParams.channelGroups, channelGroups = _b === void 0 ? [] : _b; - var channelsResponse = {}; - if (channels.length === 1 && channelGroups.length === 0) { - channelsResponse[channels[0]] = serverResponse.payload; - } - else { - channelsResponse = serverResponse.payload; - } - return { channels: channelsResponse }; - } - - var presenceGetStateConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$g, - validateParams: validateParams$g, - getURL: getURL$e, - getRequestTimeout: getRequestTimeout$g, - isAuthSupported: isAuthSupported$g, - prepareParams: prepareParams$g, - handleResponse: handleResponse$g - }); - - function getOperation$f() { - return OPERATIONS.PNSetStateOperation; - } - function validateParams$f(modules, incomingParams) { - var config = modules.config; - var state = incomingParams.state, _a = incomingParams.channels, channels = _a === void 0 ? [] : _a, _b = incomingParams.channelGroups, channelGroups = _b === void 0 ? [] : _b; - if (!state) - return 'Missing State'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - if (channels.length === 0 && channelGroups.length === 0) { - return 'Please provide a list of channels and/or channel-groups'; - } - } - function getURL$d(modules, incomingParams) { - var config = modules.config; - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a; - var stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return "/v2/presence/sub-key/".concat(config.subscribeKey, "/channel/").concat(utils$5.encodeString(stringifiedChannels), "/uuid/").concat(utils$5.encodeString(config.UUID), "/data"); - } - function getRequestTimeout$f(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$f() { - return true; - } - function prepareParams$f(modules, incomingParams) { - var state = incomingParams.state, _a = incomingParams.channelGroups, channelGroups = _a === void 0 ? [] : _a; - var params = {}; - params.state = JSON.stringify(state); - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); - } - return params; - } - function handleResponse$f(modules, serverResponse) { - return { state: serverResponse.payload }; - } - - var presenceSetStateConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$f, - validateParams: validateParams$f, - getURL: getURL$d, - getRequestTimeout: getRequestTimeout$f, - isAuthSupported: isAuthSupported$f, - prepareParams: prepareParams$f, - handleResponse: handleResponse$f - }); - - function getOperation$e() { - return OPERATIONS.PNHereNowOperation; - } - function validateParams$e(modules) { - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL$c(modules, incomingParams) { - var config = modules.config; - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a, _b = incomingParams.channelGroups, channelGroups = _b === void 0 ? [] : _b; - var baseURL = "/v2/presence/sub-key/".concat(config.subscribeKey); - if (channels.length > 0 || channelGroups.length > 0) { - var stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - baseURL += "/channel/".concat(utils$5.encodeString(stringifiedChannels)); - } - return baseURL; - } - function getRequestTimeout$e(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$e() { - return true; - } - function prepareParams$e(modules, incomingParams) { - var _a = incomingParams.channelGroups, channelGroups = _a === void 0 ? [] : _a, _b = incomingParams.includeUUIDs, includeUUIDs = _b === void 0 ? true : _b, _c = incomingParams.includeState, includeState = _c === void 0 ? false : _c, _d = incomingParams.queryParameters, queryParameters = _d === void 0 ? {} : _d; - var params = {}; - if (!includeUUIDs) - params.disable_uuids = 1; - if (includeState) - params.state = 1; - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); - } - params = __assign(__assign({}, params), queryParameters); - return params; - } - function handleResponse$e(modules, serverResponse, incomingParams) { - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a, _b = incomingParams.channelGroups, channelGroups = _b === void 0 ? [] : _b, _c = incomingParams.includeUUIDs, includeUUIDs = _c === void 0 ? true : _c, _d = incomingParams.includeState, includeState = _d === void 0 ? false : _d; - var prepareSingularChannel = function () { - var response = {}; - var occupantsList = []; - response.totalChannels = 1; - response.totalOccupancy = serverResponse.occupancy; - response.channels = {}; - response.channels[channels[0]] = { - occupants: occupantsList, - name: channels[0], - occupancy: serverResponse.occupancy, - }; - // We have had issues in the past with server returning responses - // that contain no uuids array - if (includeUUIDs && serverResponse.uuids) { - serverResponse.uuids.forEach(function (uuidEntry) { - if (includeState) { - occupantsList.push({ state: uuidEntry.state, uuid: uuidEntry.uuid }); - } - else { - occupantsList.push({ state: null, uuid: uuidEntry }); - } - }); - } - return response; - }; - var prepareMultipleChannel = function () { - var response = {}; - response.totalChannels = serverResponse.payload.total_channels; - response.totalOccupancy = serverResponse.payload.total_occupancy; - response.channels = {}; - Object.keys(serverResponse.payload.channels).forEach(function (channelName) { - var channelEntry = serverResponse.payload.channels[channelName]; - var occupantsList = []; - response.channels[channelName] = { - occupants: occupantsList, - name: channelName, - occupancy: channelEntry.occupancy, - }; - if (includeUUIDs) { - channelEntry.uuids.forEach(function (uuidEntry) { - if (includeState) { - occupantsList.push({ - state: uuidEntry.state, - uuid: uuidEntry.uuid, - }); - } - else { - occupantsList.push({ state: null, uuid: uuidEntry }); - } + /** + * Announce fie share event. + * + * @param file - Shared file information. + */ + ListenerManager.prototype.announceFile = function (file) { + this.listeners.forEach(function (listener) { + if (listener.file) + listener.file(file); + }); + }; + /** + * Announce App Context Object change event. + * + * @param object - App Context change information. + */ + ListenerManager.prototype.announceObjects = function (object) { + this.listeners.forEach(function (listener) { + if (listener.objects) + listener.objects(object); + }); + }; + /** + * Announce network up status. + */ + ListenerManager.prototype.announceNetworkUp = function () { + this.listeners.forEach(function (listener) { + if (listener.status) { + listener.status({ + category: StatusCategory$1.PNNetworkUpCategory, }); } - return response; }); - return response; }; - var response; - if (channels.length > 1 || channelGroups.length > 0 || (channelGroups.length === 0 && channels.length === 0)) { - response = prepareMultipleChannel(); - } - else { - response = prepareSingularChannel(); - } - return response; - } - function handleError(modules, params, status) { - if (status.statusCode === 402 && !this.getURL(modules, params).includes('channel')) { - status.errorData.message = - 'You have tried to perform a Global Here Now operation, ' + - 'your keyset configuration does not support that. Please provide a channel, ' + - 'or enable the Global Here Now feature from the Portal.'; - } - } - - var presenceHereNowConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$e, - validateParams: validateParams$e, - getURL: getURL$c, - getRequestTimeout: getRequestTimeout$e, - isAuthSupported: isAuthSupported$e, - prepareParams: prepareParams$e, - handleResponse: handleResponse$e, - handleError: handleError - }); - - /* */ - function getOperation$d() { - return OPERATIONS.PNAddMessageActionOperation; - } - function validateParams$d(_a, incomingParams) { - var config = _a.config; - var action = incomingParams.action, channel = incomingParams.channel, messageTimetoken = incomingParams.messageTimetoken; - if (!messageTimetoken) - return 'Missing message timetoken'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - if (!channel) - return 'Missing message channel'; - if (!action) - return 'Missing Action'; - if (!action.value) - return 'Missing Action.value'; - if (!action.type) - return 'Missing Action.type'; - if (action.type.length > 15) - return 'Action.type value exceed maximum length of 15'; - } - function usePost$2() { - return true; - } - function postURL$2(_a, incomingParams) { - var config = _a.config; - var channel = incomingParams.channel, messageTimetoken = incomingParams.messageTimetoken; - return "/v1/message-actions/".concat(config.subscribeKey, "/channel/").concat(utils$5.encodeString(channel), "/message/").concat(messageTimetoken); - } - function getRequestTimeout$d(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function getRequestHeaders() { - return { 'Content-Type': 'application/json' }; - } - function isAuthSupported$d() { - return true; - } - function prepareParams$d() { - return {}; - } - function postPayload$2(modules, incomingParams) { - return incomingParams.action; - } - function handleResponse$d(modules, addMessageActionResponse) { - return { data: addMessageActionResponse.data }; - } - - var addMessageActionEndpointConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$d, - validateParams: validateParams$d, - usePost: usePost$2, - postURL: postURL$2, - getRequestTimeout: getRequestTimeout$d, - getRequestHeaders: getRequestHeaders, - isAuthSupported: isAuthSupported$d, - prepareParams: prepareParams$d, - postPayload: postPayload$2, - handleResponse: handleResponse$d - }); - - /* */ - function getOperation$c() { - return OPERATIONS.PNRemoveMessageActionOperation; - } - function validateParams$c(_a, incomingParams) { - var config = _a.config; - var channel = incomingParams.channel, actionTimetoken = incomingParams.actionTimetoken, messageTimetoken = incomingParams.messageTimetoken; - if (!messageTimetoken) - return 'Missing message timetoken'; - if (!actionTimetoken) - return 'Missing action timetoken'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - if (!channel) - return 'Missing message channel'; - } - function useDelete$1() { - return true; - } - function getURL$b(_a, incomingParams) { - var config = _a.config; - var channel = incomingParams.channel, actionTimetoken = incomingParams.actionTimetoken, messageTimetoken = incomingParams.messageTimetoken; - return "/v1/message-actions/".concat(config.subscribeKey, "/channel/").concat(utils$5.encodeString(channel), "/message/").concat(messageTimetoken, "/action/").concat(actionTimetoken); - } - function getRequestTimeout$c(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$c() { - return true; - } - function prepareParams$c() { - return {}; - } - function handleResponse$c(modules, removeMessageActionResponse) { - return { data: removeMessageActionResponse.data }; - } + /** + * Announce network down status. + */ + ListenerManager.prototype.announceNetworkDown = function () { + this.listeners.forEach(function (listener) { + if (listener.status) { + listener.status({ + category: StatusCategory$1.PNNetworkDownCategory, + }); + } + }); + }; + // -------------------------------------------------------- + // ---------------------- Deprecated ---------------------- + // -------------------------------------------------------- + // region Deprecated + /** + * Announce User App Context Object change event. + * + * @param user - User App Context change information. + * + * @deprecated Use {@link announceObjects} method instead. + */ + ListenerManager.prototype.announceUser = function (user) { + this.listeners.forEach(function (listener) { + if (listener.user) + listener.user(user); + }); + }; + /** + * Announce Space App Context Object change event. + * + * @param space - Space App Context change information. + * + * @deprecated Use {@link announceObjects} method instead. + */ + ListenerManager.prototype.announceSpace = function (space) { + this.listeners.forEach(function (listener) { + if (listener.space) + listener.space(space); + }); + }; + /** + * Announce VSP Membership App Context Object change event. + * + * @param membership - VSP Membership App Context change information. + * + * @deprecated Use {@link announceObjects} method instead. + */ + ListenerManager.prototype.announceMembership = function (membership) { + this.listeners.forEach(function (listener) { + if (listener.membership) + listener.membership(membership); + }); + }; + return ListenerManager; + }()); - var removeMessageActionEndpointConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$c, - validateParams: validateParams$c, - useDelete: useDelete$1, - getURL: getURL$b, - getRequestTimeout: getRequestTimeout$c, - isAuthSupported: isAuthSupported$c, - prepareParams: prepareParams$c, - handleResponse: handleResponse$c - }); + /** + * Subscription reconnection-manager. + * + * **Note:** Reconnection manger rely on legacy time-based availability check. + */ + var ReconnectionManager = /** @class */ (function () { + function ReconnectionManager(time) { + this.time = time; + } + /** + * Configure reconnection handler. + * + * @param callback - Successful availability check notify callback. + */ + ReconnectionManager.prototype.onReconnect = function (callback) { + this.callback = callback; + }; + /** + * Start periodic "availability" check. + */ + ReconnectionManager.prototype.startPolling = function () { + var _this = this; + this.timeTimer = setInterval(function () { return _this.callTime(); }, 3000); + }; + /** + * Stop periodic "availability" check. + */ + ReconnectionManager.prototype.stopPolling = function () { + if (this.timeTimer) + clearInterval(this.timeTimer); + this.timeTimer = null; + }; + ReconnectionManager.prototype.callTime = function () { + var _this = this; + this.time(function (status) { + if (!status.error) { + _this.stopPolling(); + if (_this.callback) + _this.callback(); + } + }); + }; + return ReconnectionManager; + }()); /* */ - function getOperation$b() { - return OPERATIONS.PNGetMessageActionsOperation; - } - function validateParams$b(_a, incomingParams) { - var config = _a.config; - var channel = incomingParams.channel; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - if (!channel) - return 'Missing message channel'; - } - function getURL$a(_a, incomingParams) { - var config = _a.config; - var channel = incomingParams.channel; - return "/v1/message-actions/".concat(config.subscribeKey, "/channel/").concat(utils$5.encodeString(channel)); - } - function getRequestTimeout$b(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$b() { - return true; - } - function prepareParams$b(modules, incomingParams) { - var limit = incomingParams.limit, start = incomingParams.start, end = incomingParams.end; - var outgoingParams = {}; - if (limit) - outgoingParams.limit = limit; - if (start) - outgoingParams.start = start; - if (end) - outgoingParams.end = end; - return outgoingParams; - } - function handleResponse$b(modules, getMessageActionsResponse) { - /** @type GetMessageActionsResponse */ - var response = { data: getMessageActionsResponse.data, start: null, end: null }; - if (response.data.length) { - response.end = response.data[response.data.length - 1].actionTimetoken; - response.start = response.data[0].actionTimetoken; - } - return response; - } - - var getMessageActionEndpointConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$b, - validateParams: validateParams$b, - getURL: getURL$a, - getRequestTimeout: getRequestTimeout$b, - isAuthSupported: isAuthSupported$b, - prepareParams: prepareParams$b, - handleResponse: handleResponse$b - }); - - /** */ - var endpoint$j = { - getOperation: function () { return OPERATIONS.PNListFilesOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { - return "channel can't be empty"; - } - }, - getURL: function (_a, params) { - var config = _a.config; - return "/v1/files/".concat(config.subscribeKey, "/channels/").concat(utils$5.encodeString(params.channel), "/files"); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_, params) { - var outParams = {}; - if (params.limit) { - outParams.limit = params.limit; - } - if (params.next) { - outParams.next = params.next; - } - return outParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - next: response.next, - count: response.count, - }); }, + var hashCode = function (payload) { + var hash = 0; + if (payload.length === 0) + return hash; + for (var i = 0; i < payload.length; i += 1) { + var character = payload.charCodeAt(i); + hash = (hash << 5) - hash + character; // eslint-disable-line + hash = hash & hash; // eslint-disable-line + } + return hash; }; - - /** */ - var endpoint$i = { - getOperation: function () { return OPERATIONS.PNGenerateUploadUrlOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { - return "channel can't be empty"; - } - if (!(params === null || params === void 0 ? void 0 : params.name)) { - return "name can't be empty"; - } - }, - usePost: function () { return true; }, - postURL: function (_a, params) { - var config = _a.config; - return "/v1/files/".concat(config.subscribeKey, "/channels/").concat(utils$5.encodeString(params.channel), "/generate-upload-url"); - }, - postPayload: function (_, params) { return ({ - name: params.name, - }); }, - getRequestTimeout: function (_a) { + var default_1$1 = /** @class */ (function () { + function default_1(_a) { var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function () { return ({}); }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - file_upload_request: response.file_upload_request, - }); }, - }; - - /** */ - var preparePayload = function (modules, payload) { - var stringifiedPayload = JSON.stringify(payload); - if (modules.cryptoModule) { - var encrypted = modules.cryptoModule.encrypt(stringifiedPayload); - stringifiedPayload = typeof encrypted === 'string' ? encrypted : encode$1(encrypted); - stringifiedPayload = JSON.stringify(stringifiedPayload); + this.hashHistory = []; + this._config = config; } - return stringifiedPayload || ''; - }; - var endpoint$h = { - getOperation: function () { return OPERATIONS.PNPublishFileOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { - return "channel can't be empty"; - } - if (!(params === null || params === void 0 ? void 0 : params.fileId)) { - return "file id can't be empty"; - } - if (!(params === null || params === void 0 ? void 0 : params.fileName)) { - return "file name can't be empty"; - } - }, - getURL: function (modules, params) { - var _a = modules.config, publishKey = _a.publishKey, subscribeKey = _a.subscribeKey; - var message = { - message: params.message, - file: { - name: params.fileName, - id: params.fileId, - }, - }; - var payload = preparePayload(modules, message); - return "/v1/files/publish-file/".concat(publishKey, "/").concat(subscribeKey, "/0/").concat(utils$5.encodeString(params.channel), "/0/").concat(utils$5.encodeString(payload)); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_, params) { - var outParams = {}; - if (params.ttl) { - outParams.ttl = params.ttl; - } - if (params.storeInHistory !== undefined) { - outParams.store = params.storeInHistory ? '1' : '0'; - } - if (params.meta && typeof params.meta === 'object') { - outParams.meta = JSON.stringify(params.meta); - } - return outParams; - }, - handleResponse: function (_, response) { return ({ - timetoken: response['2'], - }); }, - }; - - var sendFile = function (_a) { - var _this = this; - var generateUploadUrl = _a.generateUploadUrl, publishFile = _a.publishFile, _b = _a.modules, PubNubFile = _b.PubNubFile, config = _b.config, cryptography = _b.cryptography, cryptoModule = _b.cryptoModule, networking = _b.networking; - return function (_a) { - var channel = _a.channel, input = _a.file, message = _a.message, cipherKey = _a.cipherKey, meta = _a.meta, ttl = _a.ttl, storeInHistory = _a.storeInHistory; - return __awaiter(_this, void 0, void 0, function () { - var file, _b, _c, url, formFields, _d, id, name, _e, formFieldsWithMimeType, result, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, e_1, errorBody, reason, retries, wasSuccessful, publishResult; - return __generator(this, function (_t) { - switch (_t.label) { - case 0: - if (!channel) { - throw new PubNubError('Validation failed, check status for details', createValidationError("channel can't be empty")); - } - if (!input) { - throw new PubNubError('Validation failed, check status for details', createValidationError("file can't be empty")); - } - file = PubNubFile.create(input); - return [4 /*yield*/, generateUploadUrl({ channel: channel, name: file.name })]; - case 1: - _b = _t.sent(), _c = _b.file_upload_request, url = _c.url, formFields = _c.form_fields, _d = _b.data, id = _d.id, name = _d.name; - if (!(PubNubFile.supportsEncryptFile && (cipherKey || cryptoModule))) return [3 /*break*/, 6]; - if (!(cipherKey == null)) return [3 /*break*/, 3]; - return [4 /*yield*/, cryptoModule.encryptFile(file, PubNubFile)]; - case 2: - _e = _t.sent(); - return [3 /*break*/, 5]; - case 3: return [4 /*yield*/, cryptography.encryptFile(cipherKey, file, PubNubFile)]; - case 4: - _e = _t.sent(); - _t.label = 5; - case 5: - file = _e; - _t.label = 6; - case 6: - formFieldsWithMimeType = formFields; - if (file.mimeType) { - formFieldsWithMimeType = formFields.map(function (entry) { - if (entry.key === 'Content-Type') - return { key: entry.key, value: file.mimeType }; - return entry; - }); - } - _t.label = 7; - case 7: - _t.trys.push([7, 21, , 22]); - if (!(PubNubFile.supportsFileUri && input.uri)) return [3 /*break*/, 10]; - _g = (_f = networking).POSTFILE; - _h = [url, formFieldsWithMimeType]; - return [4 /*yield*/, file.toFileUri()]; - case 8: return [4 /*yield*/, _g.apply(_f, _h.concat([_t.sent()]))]; - case 9: - result = _t.sent(); - return [3 /*break*/, 20]; - case 10: - if (!PubNubFile.supportsFile) return [3 /*break*/, 13]; - _k = (_j = networking).POSTFILE; - _l = [url, formFieldsWithMimeType]; - return [4 /*yield*/, file.toFile()]; - case 11: return [4 /*yield*/, _k.apply(_j, _l.concat([_t.sent()]))]; - case 12: - result = _t.sent(); - return [3 /*break*/, 20]; - case 13: - if (!PubNubFile.supportsBuffer) return [3 /*break*/, 16]; - _o = (_m = networking).POSTFILE; - _p = [url, formFieldsWithMimeType]; - return [4 /*yield*/, file.toBuffer()]; - case 14: return [4 /*yield*/, _o.apply(_m, _p.concat([_t.sent()]))]; - case 15: - result = _t.sent(); - return [3 /*break*/, 20]; - case 16: - if (!PubNubFile.supportsBlob) return [3 /*break*/, 19]; - _r = (_q = networking).POSTFILE; - _s = [url, formFieldsWithMimeType]; - return [4 /*yield*/, file.toBlob()]; - case 17: return [4 /*yield*/, _r.apply(_q, _s.concat([_t.sent()]))]; - case 18: - result = _t.sent(); - return [3 /*break*/, 20]; - case 19: throw new Error('Unsupported environment'); - case 20: return [3 /*break*/, 22]; - case 21: - e_1 = _t.sent(); - if (e_1.response && typeof e_1.response.text === 'string') { - errorBody = e_1.response.text; - reason = /(.*)<\/Message>/gi.exec(errorBody); - throw new PubNubError(reason ? "Upload to bucket failed: ".concat(reason[1]) : 'Upload to bucket failed.', e_1); - } - else { - throw new PubNubError('Upload to bucket failed.', e_1); - } - case 22: - if (result.status !== 204) { - throw new PubNubError('Upload to bucket was unsuccessful', result); - } - retries = config.fileUploadPublishRetryLimit; - wasSuccessful = false; - publishResult = { timetoken: '0' }; - _t.label = 23; - case 23: - _t.trys.push([23, 25, , 26]); - return [4 /*yield*/, publishFile({ - channel: channel, - message: message, - fileId: id, - fileName: name, - meta: meta, - storeInHistory: storeInHistory, - ttl: ttl, - })]; - case 24: - /* eslint-disable-next-line no-await-in-loop */ - publishResult = _t.sent(); - wasSuccessful = true; - return [3 /*break*/, 26]; - case 25: - _t.sent(); - retries -= 1; - return [3 /*break*/, 26]; - case 26: - if (!wasSuccessful && retries > 0) return [3 /*break*/, 23]; - _t.label = 27; - case 27: - if (!wasSuccessful) { - throw new PubNubError('Publish failed. You may want to execute that operation manually using pubnub.publishFile', { - channel: channel, - id: id, - name: name, - }); - } - else { - return [2 /*return*/, { - timetoken: publishResult.timetoken, - id: id, - name: name, - }]; - } - } - }); - }); + default_1.prototype.getKey = function (message) { + var hashedPayload = hashCode(JSON.stringify(message.payload)).toString(); + var timetoken = message.publishMetaData.publishTimetoken; + return "".concat(timetoken, "-").concat(hashedPayload); }; - }; - var sendFileFunction = (function (deps) { - var f = sendFile(deps); - return function (params, cb) { - var resultP = f(params); - if (typeof cb === 'function') { - resultP.then(function (result) { return cb(null, result); }).catch(function (error) { return cb(error, null); }); - return resultP; + default_1.prototype.isDuplicate = function (message) { + return this.hashHistory.includes(this.getKey(message)); + }; + default_1.prototype.addEntry = function (message) { + if (this.hashHistory.length >= this._config.maximumCacheSize) { + this.hashHistory.shift(); } - return resultP; + this.hashHistory.push(this.getKey(message)); }; - }); - - /** */ - var getFileUrlFunction = (function (modules, _a) { - var channel = _a.channel, id = _a.id, name = _a.name; - var config = modules.config, networking = modules.networking, tokenManager = modules.tokenManager; - if (!channel) { - throw new PubNubError('Validation failed, check status for details', createValidationError("channel can't be empty")); - } - if (!id) { - throw new PubNubError('Validation failed, check status for details', createValidationError("file id can't be empty")); - } - if (!name) { - throw new PubNubError('Validation failed, check status for details', createValidationError("file name can't be empty")); - } - var url = "/v1/files/".concat(config.subscribeKey, "/channels/").concat(utils$5.encodeString(channel), "/files/").concat(id, "/").concat(name); - var params = {}; - params.uuid = config.getUUID(); - params.pnsdk = generatePNSDK(config); - var tokenOrKey = tokenManager.getToken() || config.getAuthKey(); - if (tokenOrKey) { - params.auth = tokenOrKey; - } - if (config.secretKey) { - signRequest(modules, url, params, {}, { - getOperation: function () { return 'PubNubGetFileUrlOperation'; }, - }); - } - var queryParams = Object.keys(params) - .map(function (key) { return "".concat(encodeURIComponent(key), "=").concat(encodeURIComponent(params[key])); }) - .join('&'); - if (queryParams !== '') { - return "".concat(networking.getStandardOrigin()).concat(url, "?").concat(queryParams); - } - return "".concat(networking.getStandardOrigin()).concat(url); - }); + default_1.prototype.clearHistory = function () { + this.hashHistory = []; + }; + return default_1; + }()); - // Download_file.js - var endpoint$g = { - getOperation: function () { return OPERATIONS.PNDownloadFileOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { - return "channel can't be empty"; - } - if (!(params === null || params === void 0 ? void 0 : params.name)) { - return "name can't be empty"; + /** + * Subscription manager module. + */ + /** + * Subscription loop manager. + */ + var SubscriptionManager = /** @class */ (function () { + function SubscriptionManager(configuration, listenerManager, eventEmitter, subscribeCall, heartbeatCall, leaveCall, time) { + this.configuration = configuration; + this.listenerManager = listenerManager; + this.eventEmitter = eventEmitter; + this.subscribeCall = subscribeCall; + this.heartbeatCall = heartbeatCall; + this.leaveCall = leaveCall; + this.reconnectionManager = new ReconnectionManager(time); + this.dedupingManager = new default_1$1({ config: this.configuration }); + this.heartbeatChannelGroups = {}; + this.heartbeatChannels = {}; + this.presenceChannelGroups = {}; + this.presenceChannels = {}; + this.heartbeatTimer = null; + this.presenceState = {}; + this.pendingChannelGroupSubscriptions = []; + this.pendingChannelSubscriptions = []; + this.channelGroups = {}; + this.channels = {}; + this.currentTimetoken = '0'; + this.lastTimetoken = '0'; + this.storedTimetoken = null; + this.subscriptionStatusAnnounced = false; + this.isOnline = true; + } + Object.defineProperty(SubscriptionManager.prototype, "subscribedChannels", { + // region Information + get: function () { + return Object.keys(this.channels); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(SubscriptionManager.prototype, "subscribedChannelGroups", { + get: function () { + return Object.keys(this.channelGroups); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(SubscriptionManager.prototype, "abort", { + set: function (call) { + this._subscribeAbort = call; + }, + enumerable: false, + configurable: true + }); + // endregion + // region Subscription + SubscriptionManager.prototype.disconnect = function () { + this.stopSubscribeLoop(); + this.stopHeartbeatTimer(); + this.reconnectionManager.stopPolling(); + }; + SubscriptionManager.prototype.reconnect = function () { + this.startSubscribeLoop(); + this.startHeartbeatTimer(); + }; + /** + * Update channels and groups used in subscription loop. + * + * @param parameters - Subscribe configuration parameters. + */ + SubscriptionManager.prototype.subscribe = function (parameters) { + var _this = this; + var channels = parameters.channels, channelGroups = parameters.channelGroups, timetoken = parameters.timetoken, _a = parameters.withPresence, withPresence = _a === void 0 ? false : _a, _b = parameters.withHeartbeats, withHeartbeats = _b === void 0 ? false : _b; + if (timetoken) { + this.lastTimetoken = this.currentTimetoken; + this.currentTimetoken = timetoken; } - if (!(params === null || params === void 0 ? void 0 : params.id)) { - return "id can't be empty"; + if (this.currentTimetoken !== '0' && this.currentTimetoken !== 0) { + this.storedTimetoken = this.currentTimetoken; + this.currentTimetoken = 0; } - }, - useGetFile: function () { return true; }, - getFileURL: function (_a, params) { - var config = _a.config; - return "/v1/files/".concat(config.subscribeKey, "/channels/").concat(utils$5.encodeString(params.channel), "/files/").concat(params.id, "/").concat(params.name); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - ignoreBody: function () { return true; }, - forceBuffered: function () { return true; }, - prepareParams: function () { return ({}); }, - handleResponse: function (_a, res, params) { - var PubNubFile = _a.PubNubFile, config = _a.config, cryptography = _a.cryptography, cryptoModule = _a.cryptoModule; - return __awaiter(void 0, void 0, void 0, function () { - var body, _b; - var _c, _d; - return __generator(this, function (_e) { - switch (_e.label) { - case 0: - body = res.response.body; - if (!(PubNubFile.supportsEncryptFile && (params.cipherKey || cryptoModule))) return [3 /*break*/, 5]; - if (!(params.cipherKey == null)) return [3 /*break*/, 2]; - return [4 /*yield*/, cryptoModule.decryptFile(PubNubFile.create({ data: body, name: params.name }), PubNubFile)]; - case 1: - _b = (_e.sent()).data; - return [3 /*break*/, 4]; - case 2: return [4 /*yield*/, cryptography.decrypt((_c = params.cipherKey) !== null && _c !== void 0 ? _c : config.cipherKey, body)]; - case 3: - _b = _e.sent(); - _e.label = 4; - case 4: - body = _b; - _e.label = 5; - case 5: return [2 /*return*/, PubNubFile.create({ - data: body, - name: (_d = res.response.name) !== null && _d !== void 0 ? _d : params.name, - mimeType: res.response.type, - })]; - } - }); + channels === null || channels === void 0 ? void 0 : channels.forEach(function (channel) { + _this.pendingChannelSubscriptions.push(channel); + _this.channels[channel] = {}; + if (withPresence) + _this.presenceChannels[channel] = {}; + if (withHeartbeats || _this.configuration.getHeartbeatInterval()) + _this.heartbeatChannels[channel] = {}; }); - }, - }; - - /** */ - var endpoint$f = { - getOperation: function () { return OPERATIONS.PNListFilesOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { - return "channel can't be empty"; - } - if (!(params === null || params === void 0 ? void 0 : params.id)) { - return "file id can't be empty"; - } - if (!(params === null || params === void 0 ? void 0 : params.name)) { - return "file name can't be empty"; - } - }, - useDelete: function () { return true; }, - getURL: function (_a, params) { - var config = _a.config; - return "/v1/files/".concat(config.subscribeKey, "/channels/").concat(utils$5.encodeString(params.channel), "/files/").concat(params.id, "/").concat(params.name); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function () { return ({}); }, - handleResponse: function (_, response) { return ({ - status: response.status, - }); }, - }; - - var endpoint$e = { - getOperation: function () { return OPERATIONS.PNGetAllUUIDMetadataOperation; }, - validateParams: function () { - // No required parameters. - }, - getURL: function (_a) { - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/uuids"); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_modules, params) { - var _a, _b, _c, _d, _e, _f, _g, _h, _j; - var queryParams = {}; - queryParams.include = ['status', 'type']; - if (params === null || params === void 0 ? void 0 : params.include) { - if ((_a = params.include) === null || _a === void 0 ? void 0 : _a.customFields) { - queryParams.include.push('custom'); + channelGroups === null || channelGroups === void 0 ? void 0 : channelGroups.forEach(function (group) { + _this.pendingChannelGroupSubscriptions.push(group); + _this.channelGroups[group] = {}; + if (withPresence) + _this.presenceChannelGroups[group] = {}; + if (withHeartbeats || _this.configuration.getHeartbeatInterval()) + _this.heartbeatChannelGroups[group] = {}; + }); + this.subscriptionStatusAnnounced = false; + this.reconnect(); + }; + SubscriptionManager.prototype.unsubscribe = function (parameters, isOffline) { + var _this = this; + var channels = parameters.channels, channelGroups = parameters.channelGroups; + var actualChannelGroups = []; + var actualChannels = []; + channels === null || channels === void 0 ? void 0 : channels.forEach(function (channel) { + if (channel in _this.channels) { + delete _this.channels[channel]; + actualChannels.push(channel); + if (channel in _this.heartbeatChannels) + delete _this.heartbeatChannels[channel]; } + if (channel in _this.presenceState) + delete _this.presenceState[channel]; + if (channel in _this.presenceChannels) { + delete _this.presenceChannels[channel]; + actualChannels.push(channel); + } + }); + channelGroups === null || channelGroups === void 0 ? void 0 : channelGroups.forEach(function (group) { + if (group in _this.channelGroups) { + delete _this.channelGroups[group]; + actualChannelGroups.push(group); + if (group in _this.heartbeatChannelGroups) + delete _this.heartbeatChannelGroups[group]; + } + if (group in _this.presenceState) + delete _this.presenceState[group]; + if (group in _this.presenceChannelGroups) { + delete _this.presenceChannelGroups[group]; + actualChannelGroups.push(group); + } + }); + // There is no need to unsubscribe to empty list of data sources. + if (actualChannels.length === 0 && actualChannelGroups.length === 0) + return; + if (this.configuration.suppressLeaveEvents === false && !isOffline) { + this.leaveCall({ channels: actualChannels, channelGroups: actualChannelGroups }, function (status) { + _this.listenerManager.announceStatus(__assign(__assign({}, status), { affectedChannels: actualChannels, affectedChannelGroups: actualChannelGroups, currentTimetoken: _this.currentTimetoken, lastTimetoken: _this.lastTimetoken })); + }); } - queryParams.include = queryParams.include.join(','); - if ((_b = params === null || params === void 0 ? void 0 : params.include) === null || _b === void 0 ? void 0 : _b.totalCount) { - queryParams.count = (_c = params.include) === null || _c === void 0 ? void 0 : _c.totalCount; - } - if ((_d = params === null || params === void 0 ? void 0 : params.page) === null || _d === void 0 ? void 0 : _d.next) { - queryParams.start = (_e = params.page) === null || _e === void 0 ? void 0 : _e.next; - } - if ((_f = params === null || params === void 0 ? void 0 : params.page) === null || _f === void 0 ? void 0 : _f.prev) { - queryParams.end = (_g = params.page) === null || _g === void 0 ? void 0 : _g.prev; + if (Object.keys(this.channels).length === 0 && + Object.keys(this.presenceChannels).length === 0 && + Object.keys(this.channelGroups).length === 0 && + Object.keys(this.presenceChannelGroups).length === 0) { + this.lastTimetoken = 0; + this.currentTimetoken = 0; + this.storedTimetoken = null; + this.region = null; + this.reconnectionManager.stopPolling(); } - if (params === null || params === void 0 ? void 0 : params.filter) { - queryParams.filter = params.filter; + this.reconnect(); + }; + SubscriptionManager.prototype.unsubscribeAll = function (isOffline) { + this.unsubscribe({ + channels: this.subscribedChannels, + channelGroups: this.subscribedChannelGroups, + }, isOffline); + }; + SubscriptionManager.prototype.startSubscribeLoop = function () { + var _this = this; + this.stopSubscribeLoop(); + var channelGroups = __spreadArray([], __read(Object.keys(this.channelGroups)), false); + var channels = __spreadArray([], __read(Object.keys(this.channels)), false); + Object.keys(this.presenceChannelGroups).forEach(function (group) { return channelGroups.push("".concat(group, "-pnpres")); }); + Object.keys(this.presenceChannels).forEach(function (channel) { return channels.push("".concat(channel, "-pnpres")); }); + // There is no need to start subscription loop for empty list of data sources. + if (channels.length === 0 && channelGroups.length === 0) + return; + this.subscribeCall({ + channels: channels, + channelGroups: channelGroups, + state: this.presenceState, + timetoken: this.currentTimetoken, + region: this.region !== null ? this.region : undefined, + filterExpression: this.configuration.filterExpression, + }, function (status, result) { + _this.processSubscribeResponse(status, result); + }); + }; + SubscriptionManager.prototype.stopSubscribeLoop = function () { + if (this._subscribeAbort) { + this._subscribeAbort(); + this._subscribeAbort = null; } - queryParams.limit = (_h = params === null || params === void 0 ? void 0 : params.limit) !== null && _h !== void 0 ? _h : 100; - if (params === null || params === void 0 ? void 0 : params.sort) { - queryParams.sort = Object.entries((_j = params.sort) !== null && _j !== void 0 ? _j : {}).map(function (_a) { - var _b = __read$1(_a, 2), key = _b[0], value = _b[1]; - if (value === 'asc' || value === 'desc') { - return "".concat(key, ":").concat(value); + }; + /** + * Process subscribe REST API endpoint response. + */ + SubscriptionManager.prototype.processSubscribeResponse = function (status, result) { + var _this = this; + if (status.error) { + // Ignore aborted request. + if (typeof status.errorData === 'object' && 'name' in status.errorData && status.errorData.name === 'AbortError') + return; + if (status.category === StatusCategory$1.PNTimeoutCategory) { + this.startSubscribeLoop(); + } + else if (status.category === StatusCategory$1.PNNetworkIssuesCategory) { + this.disconnect(); + if (status.error && this.configuration.autoNetworkDetection && this.isOnline) { + this.isOnline = false; + this.listenerManager.announceNetworkDown(); } - return key; - }); - } - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - totalCount: response.totalCount, - next: response.next, - prev: response.prev, - }); }, - }; - - /** */ - var endpoint$d = { - getOperation: function () { return OPERATIONS.PNGetUUIDMetadataOperation; }, - validateParams: function () { - // No required parameters. - }, - getURL: function (_a, params) { - var _b; - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/uuids/").concat(utils$5.encodeString((_b = params === null || params === void 0 ? void 0 : params.uuid) !== null && _b !== void 0 ? _b : config.getUUID())); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_a, params) { - var _b, _c; - var config = _a.config; - var queryParams = {}; - queryParams.uuid = (_b = params === null || params === void 0 ? void 0 : params.uuid) !== null && _b !== void 0 ? _b : config.getUUID(); - queryParams.include = ['status', 'type', 'custom']; - if (params === null || params === void 0 ? void 0 : params.include) { - if (((_c = params.include) === null || _c === void 0 ? void 0 : _c.customFields) === false) { - queryParams.include.pop(); + this.reconnectionManager.onReconnect(function () { + if (_this.configuration.autoNetworkDetection && !_this.isOnline) { + _this.isOnline = true; + _this.listenerManager.announceNetworkUp(); + } + _this.reconnect(); + _this.subscriptionStatusAnnounced = true; + var reconnectedAnnounce = { + category: StatusCategory$1.PNReconnectedCategory, + operation: status.operation, + lastTimetoken: _this.lastTimetoken, + currentTimetoken: _this.currentTimetoken, + }; + _this.listenerManager.announceStatus(reconnectedAnnounce); + }); + this.reconnectionManager.startPolling(); + this.listenerManager.announceStatus(status); } - } - queryParams.include = queryParams.include.join(','); - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - }); }, - }; - - /** */ - var endpoint$c = { - getOperation: function () { return OPERATIONS.PNSetUUIDMetadataOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.data)) { - return 'Data cannot be empty'; - } - }, - usePatch: function () { return true; }, - patchURL: function (_a, params) { - var _b; - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/uuids/").concat(utils$5.encodeString((_b = params.uuid) !== null && _b !== void 0 ? _b : config.getUUID())); - }, - patchPayload: function (_, params) { return params.data; }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_a, params) { - var _b, _c; - var config = _a.config; - var queryParams = {}; - queryParams.uuid = (_b = params === null || params === void 0 ? void 0 : params.uuid) !== null && _b !== void 0 ? _b : config.getUUID(); - queryParams.include = ['status', 'type', 'custom']; - if (params === null || params === void 0 ? void 0 : params.include) { - if (((_c = params.include) === null || _c === void 0 ? void 0 : _c.customFields) === false) { - queryParams.include.pop(); + else if (status.category === StatusCategory$1.PNBadRequestCategory) { + this.stopHeartbeatTimer(); + this.listenerManager.announceStatus(status); } - } - queryParams.include = queryParams.include.join(','); - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - }); }, - }; - - /** */ - var endpoint$b = { - getOperation: function () { return OPERATIONS.PNRemoveUUIDMetadataOperation; }, - validateParams: function () { - // No required parameters. - }, - getURL: function (_a, params) { - var _b; - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/uuids/").concat(utils$5.encodeString((_b = params === null || params === void 0 ? void 0 : params.uuid) !== null && _b !== void 0 ? _b : config.getUUID())); - }, - useDelete: function () { return true; }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_a, params) { - var _b; - var config = _a.config; - return ({ - uuid: (_b = params === null || params === void 0 ? void 0 : params.uuid) !== null && _b !== void 0 ? _b : config.getUUID(), - }); - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - }); }, - }; - - var endpoint$a = { - getOperation: function () { return OPERATIONS.PNGetAllChannelMetadataOperation; }, - validateParams: function () { - // No required parameters. - }, - getURL: function (_a) { - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/channels"); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_modules, params) { - var _a, _b, _c, _d, _e, _f, _g, _h, _j; - var queryParams = {}; - queryParams.include = ['status', 'type']; - if (params === null || params === void 0 ? void 0 : params.include) { - if ((_a = params.include) === null || _a === void 0 ? void 0 : _a.customFields) { - queryParams.include.push('custom'); + else { + this.listenerManager.announceStatus(status); } + return; } - queryParams.include = queryParams.include.join(','); - if ((_b = params === null || params === void 0 ? void 0 : params.include) === null || _b === void 0 ? void 0 : _b.totalCount) { - queryParams.count = (_c = params.include) === null || _c === void 0 ? void 0 : _c.totalCount; - } - if ((_d = params === null || params === void 0 ? void 0 : params.page) === null || _d === void 0 ? void 0 : _d.next) { - queryParams.start = (_e = params.page) === null || _e === void 0 ? void 0 : _e.next; + if (this.storedTimetoken) { + this.currentTimetoken = this.storedTimetoken; + this.storedTimetoken = null; } - if ((_f = params === null || params === void 0 ? void 0 : params.page) === null || _f === void 0 ? void 0 : _f.prev) { - queryParams.end = (_g = params.page) === null || _g === void 0 ? void 0 : _g.prev; + else { + this.lastTimetoken = this.currentTimetoken; + this.currentTimetoken = result.cursor.timetoken; + } + if (!this.subscriptionStatusAnnounced) { + var connected = { + category: StatusCategory$1.PNConnectedCategory, + operation: status.operation, + affectedChannels: this.pendingChannelSubscriptions, + subscribedChannels: this.subscribedChannels, + affectedChannelGroups: this.pendingChannelGroupSubscriptions, + lastTimetoken: this.lastTimetoken, + currentTimetoken: this.currentTimetoken, + }; + this.subscriptionStatusAnnounced = true; + this.listenerManager.announceStatus(connected); + // Clear pending channels and groups. + this.pendingChannelGroupSubscriptions = []; + this.pendingChannelSubscriptions = []; + } + var messages = result.messages; + var _a = this.configuration, requestMessageCountThreshold = _a.requestMessageCountThreshold, dedupeOnSubscribe = _a.dedupeOnSubscribe; + if (requestMessageCountThreshold && messages.length >= requestMessageCountThreshold) { + this.listenerManager.announceStatus({ + category: StatusCategory$1.PNRequestMessageCountExceededCategory, + operation: status.operation, + }); } - if (params === null || params === void 0 ? void 0 : params.filter) { - queryParams.filter = params.filter; + messages.forEach(function (message) { + if (dedupeOnSubscribe) { + if (_this.dedupingManager.isDuplicate(message)) + return; + _this.dedupingManager.addEntry(message); + } + _this.eventEmitter.emitEvent(message); + }); + this.region = result.cursor.region; + this.startSubscribeLoop(); + }; + // endregion + // region Presence + /** + * Update `uuid` state which should be sent with subscribe request. + * + * @param parameters - Channels and groups with state which should be associated to `uuid`. + */ + SubscriptionManager.prototype.setState = function (parameters) { + var _this = this; + var state = parameters.state, channels = parameters.channels, channelGroups = parameters.channelGroups; + channels === null || channels === void 0 ? void 0 : channels.forEach(function (channel) { return channel in _this.channels && (_this.presenceState[channel] = state); }); + channelGroups === null || channelGroups === void 0 ? void 0 : channelGroups.forEach(function (group) { return group in _this.channelGroups && (_this.presenceState[group] = state); }); + }; + /** + * Manual presence management. + * + * @param parameters - Desired presence state for provided list of channels and groups. + */ + SubscriptionManager.prototype.changePresence = function (parameters) { + var _this = this; + var connected = parameters.connected, channels = parameters.channels, channelGroups = parameters.channelGroups; + if (connected) { + channels === null || channels === void 0 ? void 0 : channels.forEach(function (channel) { return (_this.heartbeatChannels[channel] = {}); }); + channelGroups === null || channelGroups === void 0 ? void 0 : channelGroups.forEach(function (group) { return (_this.heartbeatChannelGroups[group] = {}); }); } - queryParams.limit = (_h = params === null || params === void 0 ? void 0 : params.limit) !== null && _h !== void 0 ? _h : 100; - if (params === null || params === void 0 ? void 0 : params.sort) { - queryParams.sort = Object.entries((_j = params.sort) !== null && _j !== void 0 ? _j : {}).map(function (_a) { - var _b = __read$1(_a, 2), key = _b[0], value = _b[1]; - if (value === 'asc' || value === 'desc') { - return "".concat(key, ":").concat(value); - } - return key; + else { + channels === null || channels === void 0 ? void 0 : channels.forEach(function (channel) { + if (channel in _this.heartbeatChannels) + delete _this.heartbeatChannels[channel]; }); + channelGroups === null || channelGroups === void 0 ? void 0 : channelGroups.forEach(function (group) { + if (group in _this.heartbeatChannelGroups) + delete _this.heartbeatChannelGroups[group]; + }); + if (this.configuration.suppressLeaveEvents === false) { + this.leaveCall({ channels: channels, channelGroups: channelGroups }, function (status) { return _this.listenerManager.announceStatus(status); }); + } } - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - totalCount: response.totalCount, - prev: response.prev, - next: response.next, - }); }, - }; - - var endpoint$9 = { - getOperation: function () { return OPERATIONS.PNGetChannelMetadataOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { - return 'Channel cannot be empty'; - } - }, - getURL: function (_a, params) { - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/channels/").concat(utils$5.encodeString(params.channel)); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_, params) { - var _a; - var queryParams = {}; - queryParams.include = ['status', 'type', 'custom']; - if (params === null || params === void 0 ? void 0 : params.include) { - if (((_a = params.include) === null || _a === void 0 ? void 0 : _a.customFields) === false) { - queryParams.include.pop(); - } - } - queryParams.include = queryParams.include.join(','); - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - }); }, - }; - - /** */ - var endpoint$8 = { - getOperation: function () { return OPERATIONS.PNSetChannelMetadataOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { - return 'Channel cannot be empty'; - } - if (!(params === null || params === void 0 ? void 0 : params.data)) { - return 'Data cannot be empty'; - } - }, - usePatch: function () { return true; }, - patchURL: function (_a, params) { - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/channels/").concat(utils$5.encodeString(params.channel)); - }, - patchPayload: function (_, params) { return params.data; }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_, params) { - var _a; - var queryParams = {}; - queryParams.include = ['status', 'type', 'custom']; - if (params === null || params === void 0 ? void 0 : params.include) { - if (((_a = params.include) === null || _a === void 0 ? void 0 : _a.customFields) === false) { - queryParams.include.pop(); + this.reconnect(); + }; + SubscriptionManager.prototype.startHeartbeatTimer = function () { + var _this = this; + this.stopHeartbeatTimer(); + var heartbeatInterval = this.configuration.getHeartbeatInterval(); + if (!heartbeatInterval || heartbeatInterval === 0) + return; + this.sendHeartbeat(); + this.heartbeatTimer = setInterval(function () { return _this.sendHeartbeat(); }, heartbeatInterval * 1000); + }; + /** + * Stop heartbeat. + * + * Stop timer which trigger {@link HeartbeatRequest} sending with configured presence intervals. + */ + SubscriptionManager.prototype.stopHeartbeatTimer = function () { + if (!this.heartbeatTimer) + return; + clearInterval(this.heartbeatTimer); + this.heartbeatTimer = null; + }; + /** + * Send heartbeat request. + */ + SubscriptionManager.prototype.sendHeartbeat = function () { + var _this = this; + var heartbeatChannelGroups = Object.keys(this.heartbeatChannelGroups); + var heartbeatChannels = Object.keys(this.heartbeatChannels); + // There is no need to start heartbeat loop if there is no channels and groups to use. + if (heartbeatChannels.length === 0 && heartbeatChannelGroups.length === 0) + return; + this.heartbeatCall({ + channels: heartbeatChannels, + channelGroups: heartbeatChannelGroups, + heartbeat: this.configuration.getPresenceTimeout(), + state: this.presenceState, + }, function (status) { + if (status.error && _this.configuration.announceFailedHeartbeats) + _this.listenerManager.announceStatus(status); + if (status.error && _this.configuration.autoNetworkDetection && _this.isOnline) { + _this.isOnline = false; + _this.disconnect(); + _this.listenerManager.announceNetworkDown(); + _this.reconnect(); } - } - queryParams.include = queryParams.include.join(','); - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - }); }, - }; - - /** */ - var endpoint$7 = { - getOperation: function () { return OPERATIONS.PNRemoveChannelMetadataOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { - return 'Channel cannot be empty'; - } - }, - getURL: function (_a, params) { - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/channels/").concat(utils$5.encodeString(params.channel)); - }, - useDelete: function () { return true; }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function () { return ({}); }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - }); }, - }; + if (!status.error && _this.configuration.announceSuccessfulHeartbeats) + _this.listenerManager.announceNetworkUp(); + }); + }; + return SubscriptionManager; + }()); - /** */ - var endpoint$6 = { - getOperation: function () { return OPERATIONS.PNGetMembersOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { - return 'channel cannot be empty'; + /* */ + /* eslint max-classes-per-file: ["error", 5] */ + var BaseNotificationPayload = /** @class */ (function () { + function BaseNotificationPayload(payload, title, body) { + this._payload = payload; + this._setDefaultPayloadStructure(); + this.title = title; + this.body = body; + } + Object.defineProperty(BaseNotificationPayload.prototype, "payload", { + get: function () { + return this._payload; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(BaseNotificationPayload.prototype, "title", { + set: function (value) { + this._title = value; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(BaseNotificationPayload.prototype, "subtitle", { + set: function (value) { + this._subtitle = value; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(BaseNotificationPayload.prototype, "body", { + set: function (value) { + this._body = value; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(BaseNotificationPayload.prototype, "badge", { + set: function (value) { + this._badge = value; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(BaseNotificationPayload.prototype, "sound", { + set: function (value) { + this._sound = value; + }, + enumerable: false, + configurable: true + }); + BaseNotificationPayload.prototype._setDefaultPayloadStructure = function () { + // Empty. + }; + BaseNotificationPayload.prototype.toObject = function () { + return {}; + }; + return BaseNotificationPayload; + }()); + var APNSNotificationPayload = /** @class */ (function (_super) { + __extends(APNSNotificationPayload, _super); + function APNSNotificationPayload() { + return _super !== null && _super.apply(this, arguments) || this; + } + Object.defineProperty(APNSNotificationPayload.prototype, "configurations", { + set: function (value) { + if (!value || !value.length) + return; + this._configurations = value; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(APNSNotificationPayload.prototype, "notification", { + get: function () { + return this._payload.aps; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(APNSNotificationPayload.prototype, "title", { + get: function () { + return this._title; + }, + set: function (value) { + if (!value || !value.length) + return; + this._payload.aps.alert.title = value; + this._title = value; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(APNSNotificationPayload.prototype, "subtitle", { + get: function () { + return this._subtitle; + }, + set: function (value) { + if (!value || !value.length) + return; + this._payload.aps.alert.subtitle = value; + this._subtitle = value; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(APNSNotificationPayload.prototype, "body", { + get: function () { + return this._body; + }, + set: function (value) { + if (!value || !value.length) + return; + this._payload.aps.alert.body = value; + this._body = value; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(APNSNotificationPayload.prototype, "badge", { + get: function () { + return this._badge; + }, + set: function (value) { + if (value === undefined || value === null) + return; + this._payload.aps.badge = value; + this._badge = value; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(APNSNotificationPayload.prototype, "sound", { + get: function () { + return this._sound; + }, + set: function (value) { + if (!value || !value.length) + return; + this._payload.aps.sound = value; + this._sound = value; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(APNSNotificationPayload.prototype, "silent", { + set: function (value) { + this._isSilent = value; + }, + enumerable: false, + configurable: true + }); + APNSNotificationPayload.prototype._setDefaultPayloadStructure = function () { + this._payload.aps = { alert: {} }; + }; + APNSNotificationPayload.prototype.toObject = function () { + var _this = this; + var payload = __assign({}, this._payload); + /** @type {{alert: Object, badge: number, sound: string}} */ + var aps = payload.aps; + var alert = aps.alert; + if (this._isSilent) { + aps['content-available'] = 1; } - }, - getURL: function (_a, params) { - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/channels/").concat(utils$5.encodeString(params.channel), "/uuids"); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_modules, params) { - var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p; - var queryParams = {}; - queryParams.include = []; - if (params === null || params === void 0 ? void 0 : params.include) { - if ((_a = params.include) === null || _a === void 0 ? void 0 : _a.statusField) { - queryParams.include.push('status'); - } - if ((_b = params.include) === null || _b === void 0 ? void 0 : _b.customFields) { - queryParams.include.push('custom'); - } - if ((_c = params.include) === null || _c === void 0 ? void 0 : _c.UUIDFields) { - queryParams.include.push('uuid'); - } - if ((_d = params.include) === null || _d === void 0 ? void 0 : _d.customUUIDFields) { - queryParams.include.push('uuid.custom'); - } - if ((_e = params.include) === null || _e === void 0 ? void 0 : _e.UUIDStatusField) { - queryParams.include.push('uuid.status'); + if (this._apnsPushType === 'apns2') { + if (!this._configurations || !this._configurations.length) { + throw new ReferenceError('APNS2 configuration is missing'); } - if ((_f = params.include) === null || _f === void 0 ? void 0 : _f.UUIDTypeField) { - queryParams.include.push('uuid.type'); + var configurations_1 = []; + this._configurations.forEach(function (configuration) { + configurations_1.push(_this._objectFromAPNS2Configuration(configuration)); + }); + if (configurations_1.length) { + payload.pn_push = configurations_1; } } - queryParams.include = queryParams.include.join(','); - if ((_g = params === null || params === void 0 ? void 0 : params.include) === null || _g === void 0 ? void 0 : _g.totalCount) { - queryParams.count = (_h = params.include) === null || _h === void 0 ? void 0 : _h.totalCount; - } - if ((_j = params === null || params === void 0 ? void 0 : params.page) === null || _j === void 0 ? void 0 : _j.next) { - queryParams.start = (_k = params.page) === null || _k === void 0 ? void 0 : _k.next; + if (!alert || !Object.keys(alert).length) { + delete aps.alert; } - if ((_l = params === null || params === void 0 ? void 0 : params.page) === null || _l === void 0 ? void 0 : _l.prev) { - queryParams.end = (_m = params.page) === null || _m === void 0 ? void 0 : _m.prev; + if (this._isSilent) { + delete aps.alert; + delete aps.badge; + delete aps.sound; + alert = {}; } - if (params === null || params === void 0 ? void 0 : params.filter) { - queryParams.filter = params.filter; + return this._isSilent || Object.keys(alert).length ? payload : null; + }; + APNSNotificationPayload.prototype._objectFromAPNS2Configuration = function (configuration) { + var _this = this; + if (!configuration.targets || !configuration.targets.length) { + throw new ReferenceError('At least one APNS2 target should be provided'); } - queryParams.limit = (_o = params === null || params === void 0 ? void 0 : params.limit) !== null && _o !== void 0 ? _o : 100; - if (params === null || params === void 0 ? void 0 : params.sort) { - queryParams.sort = Object.entries((_p = params.sort) !== null && _p !== void 0 ? _p : {}).map(function (_a) { - var _b = __read$1(_a, 2), key = _b[0], value = _b[1]; - if (value === 'asc' || value === 'desc') { - return "".concat(key, ":").concat(value); - } - return key; - }); + var targets = []; + configuration.targets.forEach(function (target) { + targets.push(_this._objectFromAPNSTarget(target)); + }); + var collapseId = configuration.collapseId, expirationDate = configuration.expirationDate; + var objectifiedConfiguration = { auth_method: 'token', targets: targets, version: 'v2' }; + if (collapseId && collapseId.length) { + objectifiedConfiguration.collapse_id = collapseId; } - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - totalCount: response.totalCount, - prev: response.prev, - next: response.next, - }); }, - }; - - var endpoint$5 = { - getOperation: function () { return OPERATIONS.PNSetMembersOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { - return 'Channel cannot be empty'; - } - if (!(params === null || params === void 0 ? void 0 : params.uuids) || (params === null || params === void 0 ? void 0 : params.uuids.length) === 0) { - return 'UUIDs cannot be empty'; - } - }, - usePatch: function () { return true; }, - patchURL: function (_a, params) { - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/channels/").concat(utils$5.encodeString(params.channel), "/uuids"); - }, - patchPayload: function (_, params) { - var _a; - return (_a = { - set: [], - delete: [] - }, - _a[params.type] = params.uuids.map(function (uuid) { - if (typeof uuid === 'string') { - return { - uuid: { - id: uuid, - }, - }; - } - return { - uuid: { id: uuid.id }, - custom: uuid.custom, - status: uuid.status, - }; - }), - _a); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_modules, params) { - var _a, _b, _c, _d, _e, _f, _g, _h, _j; - var queryParams = {}; - queryParams.include = ['uuid.status', 'uuid.type', 'type']; - if (params === null || params === void 0 ? void 0 : params.include) { - if ((_a = params.include) === null || _a === void 0 ? void 0 : _a.customFields) { - queryParams.include.push('custom'); - } - if ((_b = params.include) === null || _b === void 0 ? void 0 : _b.customUUIDFields) { - queryParams.include.push('uuid.custom'); - } - if ((_c = params.include) === null || _c === void 0 ? void 0 : _c.UUIDFields) { - queryParams.include.push('uuid'); - } - } - queryParams.include = queryParams.include.join(','); - if ((_d = params === null || params === void 0 ? void 0 : params.include) === null || _d === void 0 ? void 0 : _d.totalCount) { - queryParams.count = true; - } - if ((_e = params === null || params === void 0 ? void 0 : params.page) === null || _e === void 0 ? void 0 : _e.next) { - queryParams.start = (_f = params.page) === null || _f === void 0 ? void 0 : _f.next; - } - if ((_g = params === null || params === void 0 ? void 0 : params.page) === null || _g === void 0 ? void 0 : _g.prev) { - queryParams.end = (_h = params.page) === null || _h === void 0 ? void 0 : _h.prev; - } - if (params === null || params === void 0 ? void 0 : params.filter) { - queryParams.filter = params.filter; - } - if (params.limit != null) { - queryParams.limit = params.limit; - } - if (params === null || params === void 0 ? void 0 : params.sort) { - queryParams.sort = Object.entries((_j = params.sort) !== null && _j !== void 0 ? _j : {}).map(function (_a) { - var _b = __read$1(_a, 2), key = _b[0], value = _b[1]; - if (value === 'asc' || value === 'desc') { - return "".concat(key, ":").concat(value); - } - return key; - }); - } - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - totalCount: response.totalCount, - prev: response.prev, - next: response.next, - }); }, - }; - - var endpoint$4 = { - getOperation: function () { return OPERATIONS.PNGetMembershipsOperation; }, - validateParams: function () { - // No required parameters. - }, - getURL: function (_a, params) { - var _b; - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/uuids/").concat(utils$5.encodeString((_b = params === null || params === void 0 ? void 0 : params.uuid) !== null && _b !== void 0 ? _b : config.getUUID()), "/channels"); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_modules, params) { - var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p; - var queryParams = {}; - queryParams.include = []; - if (params === null || params === void 0 ? void 0 : params.include) { - if ((_a = params.include) === null || _a === void 0 ? void 0 : _a.statusField) { - queryParams.include.push('status'); - } - if ((_b = params.include) === null || _b === void 0 ? void 0 : _b.customFields) { - queryParams.include.push('custom'); - } - if ((_c = params.include) === null || _c === void 0 ? void 0 : _c.channelFields) { - queryParams.include.push('channel'); - } - if ((_d = params.include) === null || _d === void 0 ? void 0 : _d.customChannelFields) { - queryParams.include.push('channel.custom'); - } - if ((_e = params.include) === null || _e === void 0 ? void 0 : _e.channelStatusField) { - queryParams.include.push('channel.status'); - } - if ((_f = params.include) === null || _f === void 0 ? void 0 : _f.channelTypeField) { - queryParams.include.push('channel.type'); - } - } - queryParams.include = queryParams.include.join(','); - if ((_g = params === null || params === void 0 ? void 0 : params.include) === null || _g === void 0 ? void 0 : _g.totalCount) { - queryParams.count = (_h = params.include) === null || _h === void 0 ? void 0 : _h.totalCount; - } - if ((_j = params === null || params === void 0 ? void 0 : params.page) === null || _j === void 0 ? void 0 : _j.next) { - queryParams.start = (_k = params.page) === null || _k === void 0 ? void 0 : _k.next; - } - if ((_l = params === null || params === void 0 ? void 0 : params.page) === null || _l === void 0 ? void 0 : _l.prev) { - queryParams.end = (_m = params.page) === null || _m === void 0 ? void 0 : _m.prev; - } - if (params === null || params === void 0 ? void 0 : params.filter) { - queryParams.filter = params.filter; - } - queryParams.limit = (_o = params === null || params === void 0 ? void 0 : params.limit) !== null && _o !== void 0 ? _o : 100; - if (params === null || params === void 0 ? void 0 : params.sort) { - queryParams.sort = Object.entries((_p = params.sort) !== null && _p !== void 0 ? _p : {}).map(function (_a) { - var _b = __read$1(_a, 2), key = _b[0], value = _b[1]; - if (value === 'asc' || value === 'desc') { - return "".concat(key, ":").concat(value); - } - return key; - }); - } - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - totalCount: response.totalCount, - prev: response.prev, - next: response.next, - }); }, - }; - - /** */ - var endpoint$3 = { - getOperation: function () { return OPERATIONS.PNSetMembershipsOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channels) || (params === null || params === void 0 ? void 0 : params.channels.length) === 0) { - return 'Channels cannot be empty'; - } - }, - usePatch: function () { return true; }, - patchURL: function (_a, params) { - var _b; - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/uuids/").concat(utils$5.encodeString((_b = params.uuid) !== null && _b !== void 0 ? _b : config.getUUID()), "/channels"); - }, - patchPayload: function (_, params) { - var _a; - return (_a = { - set: [], - delete: [] - }, - _a[params.type] = params.channels.map(function (channel) { - if (typeof channel === 'string') { - return { - channel: { - id: channel, - }, - }; - } - return { - channel: { id: channel.id }, - custom: channel.custom, - status: channel.status, - }; - }), - _a); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_modules, params) { - var _a, _b, _c, _d, _e, _f, _g, _h, _j; - var queryParams = {}; - queryParams.include = ['channel.status', 'channel.type', 'status']; - if (params === null || params === void 0 ? void 0 : params.include) { - if ((_a = params.include) === null || _a === void 0 ? void 0 : _a.customFields) { - queryParams.include.push('custom'); - } - if ((_b = params.include) === null || _b === void 0 ? void 0 : _b.customChannelFields) { - queryParams.include.push('channel.custom'); - } - if ((_c = params.include) === null || _c === void 0 ? void 0 : _c.channelFields) { - queryParams.include.push('channel'); - } - } - queryParams.include = queryParams.include.join(','); - if ((_d = params === null || params === void 0 ? void 0 : params.include) === null || _d === void 0 ? void 0 : _d.totalCount) { - queryParams.count = true; - } - if ((_e = params === null || params === void 0 ? void 0 : params.page) === null || _e === void 0 ? void 0 : _e.next) { - queryParams.start = (_f = params.page) === null || _f === void 0 ? void 0 : _f.next; - } - if ((_g = params === null || params === void 0 ? void 0 : params.page) === null || _g === void 0 ? void 0 : _g.prev) { - queryParams.end = (_h = params.page) === null || _h === void 0 ? void 0 : _h.prev; - } - if (params === null || params === void 0 ? void 0 : params.filter) { - queryParams.filter = params.filter; + if (expirationDate) { + objectifiedConfiguration.expiration = expirationDate.toISOString(); } - if (params.limit != null) { - queryParams.limit = params.limit; + return objectifiedConfiguration; + }; + APNSNotificationPayload.prototype._objectFromAPNSTarget = function (target) { + if (!target.topic || !target.topic.length) { + throw new TypeError("Target 'topic' undefined."); } - if (params === null || params === void 0 ? void 0 : params.sort) { - queryParams.sort = Object.entries((_j = params.sort) !== null && _j !== void 0 ? _j : {}).map(function (_a) { - var _b = __read$1(_a, 2), key = _b[0], value = _b[1]; - if (value === 'asc' || value === 'desc') { - return "".concat(key, ":").concat(value); - } - return key; - }); + var topic = target.topic, _a = target.environment, environment = _a === void 0 ? 'development' : _a, _b = target.excludedDevices, excludedDevices = _b === void 0 ? [] : _b; + var objectifiedTarget = { topic: topic, environment: environment }; + if (excludedDevices.length) { + objectifiedTarget.excluded_devices = excludedDevices; } - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - totalCount: response.totalCount, - prev: response.prev, - next: response.next, - }); }, - }; - - /* */ - function getOperation$a() { - return OPERATIONS.PNAccessManagerAudit; - } - function validateParams$a(modules) { - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL$9(modules) { - var config = modules.config; - return "/v2/auth/audit/sub-key/".concat(config.subscribeKey); - } - function getRequestTimeout$a(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$a() { - return false; - } - function prepareParams$a(modules, incomingParams) { - var channel = incomingParams.channel, channelGroup = incomingParams.channelGroup, _a = incomingParams.authKeys, authKeys = _a === void 0 ? [] : _a; - var params = {}; - if (channel) { - params.channel = channel; - } - if (channelGroup) { - params['channel-group'] = channelGroup; - } - if (authKeys.length > 0) { - params.auth = authKeys.join(','); - } - return params; - } - function handleResponse$a(modules, serverResponse) { - return serverResponse.payload; - } - - var auditEndpointConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$a, - validateParams: validateParams$a, - getURL: getURL$9, - getRequestTimeout: getRequestTimeout$a, - isAuthSupported: isAuthSupported$a, - prepareParams: prepareParams$a, - handleResponse: handleResponse$a - }); - - /* */ - function getOperation$9() { - return OPERATIONS.PNAccessManagerGrant; - } - function validateParams$9(modules, incomingParams) { - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - if (!config.publishKey) - return 'Missing Publish Key'; - if (!config.secretKey) - return 'Missing Secret Key'; - if (incomingParams.uuids != null && !incomingParams.authKeys) { - return 'authKeys are required for grant request on uuids'; - } - if (incomingParams.uuids != null && (incomingParams.channels != null || incomingParams.channelGroups != null)) { - return 'Both channel/channelgroup and uuid cannot be used in the same request'; - } - } - function getURL$8(modules) { - var config = modules.config; - return "/v2/auth/grant/sub-key/".concat(config.subscribeKey); - } - function getRequestTimeout$9(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$9() { - return false; - } - function prepareParams$9(modules, incomingParams) { - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a, _b = incomingParams.channelGroups, channelGroups = _b === void 0 ? [] : _b, _c = incomingParams.uuids, uuids = _c === void 0 ? [] : _c, ttl = incomingParams.ttl, _d = incomingParams.read, read = _d === void 0 ? false : _d, _e = incomingParams.write, write = _e === void 0 ? false : _e, _f = incomingParams.manage, manage = _f === void 0 ? false : _f, _g = incomingParams.get, get = _g === void 0 ? false : _g, _h = incomingParams.join, join = _h === void 0 ? false : _h, _j = incomingParams.update, update = _j === void 0 ? false : _j, _k = incomingParams.authKeys, authKeys = _k === void 0 ? [] : _k; - var deleteParam = incomingParams.delete; - var params = {}; - params.r = read ? '1' : '0'; - params.w = write ? '1' : '0'; - params.m = manage ? '1' : '0'; - params.d = deleteParam ? '1' : '0'; - params.g = get ? '1' : '0'; - params.j = join ? '1' : '0'; - params.u = update ? '1' : '0'; - if (channels.length > 0) { - params.channel = channels.join(','); - } - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); - } - if (authKeys.length > 0) { - params.auth = authKeys.join(','); - } - if (uuids.length > 0) { - params['target-uuid'] = uuids.join(','); - } - if (ttl || ttl === 0) { - params.ttl = ttl; - } - return params; - } - function handleResponse$9() { - return {}; - } - - var grantEndpointConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$9, - validateParams: validateParams$9, - getURL: getURL$8, - getRequestTimeout: getRequestTimeout$9, - isAuthSupported: isAuthSupported$9, - prepareParams: prepareParams$9, - handleResponse: handleResponse$9 - }); - - function getOperation$8() { - return OPERATIONS.PNAccessManagerGrantToken; - } - function hasVspTerms(incomingParams) { - var _a, _b, _c, _d; - var hasAuthorizedUserId = (incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.authorizedUserId) !== undefined; - var hasUserResources = ((_a = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.resources) === null || _a === void 0 ? void 0 : _a.users) !== undefined; - var hasSpaceResources = ((_b = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.resources) === null || _b === void 0 ? void 0 : _b.spaces) !== undefined; - var hasUserPatterns = ((_c = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.patterns) === null || _c === void 0 ? void 0 : _c.users) !== undefined; - var hasSpacePatterns = ((_d = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.patterns) === null || _d === void 0 ? void 0 : _d.spaces) !== undefined; - return hasUserPatterns || hasUserResources || hasSpacePatterns || hasSpaceResources || hasAuthorizedUserId; - } - function extractPermissions(permissions) { - var permissionsResult = 0; - if (permissions.join) { - permissionsResult |= 128; - } - if (permissions.update) { - permissionsResult |= 64; - } - if (permissions.get) { - permissionsResult |= 32; - } - if (permissions.delete) { - permissionsResult |= 8; - } - if (permissions.manage) { - permissionsResult |= 4; - } - if (permissions.write) { - permissionsResult |= 2; - } - if (permissions.read) { - permissionsResult |= 1; + return objectifiedTarget; + }; + return APNSNotificationPayload; + }(BaseNotificationPayload)); + var MPNSNotificationPayload = /** @class */ (function (_super) { + __extends(MPNSNotificationPayload, _super); + function MPNSNotificationPayload() { + return _super !== null && _super.apply(this, arguments) || this; } - return permissionsResult; - } - function prepareMessagePayloadVsp(_modules, _a) { - var ttl = _a.ttl, resources = _a.resources, patterns = _a.patterns, meta = _a.meta, authorizedUserId = _a.authorizedUserId; - var params = { - ttl: 0, - permissions: { - resources: { - channels: {}, - groups: {}, - uuids: {}, - users: {}, - spaces: {}, // not used, needed for api backward compatibility - }, - patterns: { - channels: {}, - groups: {}, - uuids: {}, - users: {}, - spaces: {}, // not used, needed for api backward compatibility - }, - meta: {}, + Object.defineProperty(MPNSNotificationPayload.prototype, "backContent", { + get: function () { + return this._backContent; + }, + set: function (value) { + if (!value || !value.length) + return; + this._payload.back_content = value; + this._backContent = value; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(MPNSNotificationPayload.prototype, "backTitle", { + get: function () { + return this._backTitle; + }, + set: function (value) { + if (!value || !value.length) + return; + this._payload.back_title = value; + this._backTitle = value; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(MPNSNotificationPayload.prototype, "count", { + get: function () { + return this._count; + }, + set: function (value) { + if (value === undefined || value === null) + return; + this._payload.count = value; + this._count = value; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(MPNSNotificationPayload.prototype, "title", { + get: function () { + return this._title; + }, + set: function (value) { + if (!value || !value.length) + return; + this._payload.title = value; + this._title = value; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(MPNSNotificationPayload.prototype, "type", { + get: function () { + return this._type; + }, + set: function (value) { + if (!value || !value.length) + return; + this._payload.type = value; + this._type = value; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(MPNSNotificationPayload.prototype, "subtitle", { + get: function () { + return this.backTitle; + }, + set: function (value) { + this.backTitle = value; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(MPNSNotificationPayload.prototype, "body", { + get: function () { + return this.backContent; }, + set: function (value) { + this.backContent = value; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(MPNSNotificationPayload.prototype, "badge", { + get: function () { + return this.count; + }, + set: function (value) { + this.count = value; + }, + enumerable: false, + configurable: true + }); + MPNSNotificationPayload.prototype.toObject = function () { + return Object.keys(this._payload).length ? __assign({}, this._payload) : null; }; - if (resources) { - var users_1 = resources.users, spaces_1 = resources.spaces, groups_1 = resources.groups; - if (users_1) { - Object.keys(users_1).forEach(function (userID) { - params.permissions.resources.uuids[userID] = extractPermissions(users_1[userID]); - }); - } - if (spaces_1) { - Object.keys(spaces_1).forEach(function (spaceId) { - params.permissions.resources.channels[spaceId] = extractPermissions(spaces_1[spaceId]); - }); - } - if (groups_1) { - Object.keys(groups_1).forEach(function (group) { - params.permissions.resources.groups[group] = extractPermissions(groups_1[group]); - }); - } + return MPNSNotificationPayload; + }(BaseNotificationPayload)); + var FCMNotificationPayload = /** @class */ (function (_super) { + __extends(FCMNotificationPayload, _super); + function FCMNotificationPayload() { + return _super !== null && _super.apply(this, arguments) || this; } - if (patterns) { - var users_2 = patterns.users, spaces_2 = patterns.spaces, groups_2 = patterns.groups; - if (users_2) { - Object.keys(users_2).forEach(function (userId) { - params.permissions.patterns.uuids[userId] = extractPermissions(users_2[userId]); - }); - } - if (spaces_2) { - Object.keys(spaces_2).forEach(function (spaceId) { - params.permissions.patterns.channels[spaceId] = extractPermissions(spaces_2[spaceId]); - }); - } - if (groups_2) { - Object.keys(groups_2).forEach(function (group) { - params.permissions.patterns.groups[group] = extractPermissions(groups_2[group]); - }); - } - } - if (ttl || ttl === 0) { - params.ttl = ttl; - } - if (meta) { - params.permissions.meta = meta; - } - if (authorizedUserId) { - params.permissions.uuid = "".concat(authorizedUserId); // ensure this is a string - } - return params; - } - function prepareMessagePayload$2(_modules, incomingParams) { - if (hasVspTerms(incomingParams)) { - return prepareMessagePayloadVsp(_modules, incomingParams); - } - var ttl = incomingParams.ttl, resources = incomingParams.resources, patterns = incomingParams.patterns, meta = incomingParams.meta, authorized_uuid = incomingParams.authorized_uuid; - var params = { - ttl: 0, - permissions: { - resources: { - channels: {}, - groups: {}, - uuids: {}, - users: {}, - spaces: {}, // not used, needed for api backward compatibility - }, - patterns: { - channels: {}, - groups: {}, - uuids: {}, - users: {}, - spaces: {}, // not used, needed for api backward compatibility - }, - meta: {}, + Object.defineProperty(FCMNotificationPayload.prototype, "notification", { + get: function () { + return this._payload.notification; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(FCMNotificationPayload.prototype, "data", { + get: function () { + return this._payload.data; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(FCMNotificationPayload.prototype, "title", { + get: function () { + return this._title; + }, + set: function (value) { + if (!value || !value.length) + return; + this._payload.notification.title = value; + this._title = value; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(FCMNotificationPayload.prototype, "body", { + get: function () { + return this._body; + }, + set: function (value) { + if (!value || !value.length) + return; + this._payload.notification.body = value; + this._body = value; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(FCMNotificationPayload.prototype, "sound", { + get: function () { + return this._sound; + }, + set: function (value) { + if (!value || !value.length) + return; + this._payload.notification.sound = value; + this._sound = value; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(FCMNotificationPayload.prototype, "icon", { + get: function () { + return this._icon; + }, + set: function (value) { + if (!value || !value.length) + return; + this._payload.notification.icon = value; + this._icon = value; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(FCMNotificationPayload.prototype, "tag", { + get: function () { + return this._tag; }, + set: function (value) { + if (!value || !value.length) + return; + this._payload.notification.tag = value; + this._tag = value; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(FCMNotificationPayload.prototype, "silent", { + set: function (value) { + this._isSilent = value; + }, + enumerable: false, + configurable: true + }); + FCMNotificationPayload.prototype._setDefaultPayloadStructure = function () { + this._payload.notification = {}; + this._payload.data = {}; }; - if (resources) { - var uuids_1 = resources.uuids, channels_1 = resources.channels, groups_3 = resources.groups; - if (uuids_1) { - Object.keys(uuids_1).forEach(function (uuid) { - params.permissions.resources.uuids[uuid] = extractPermissions(uuids_1[uuid]); - }); - } - if (channels_1) { - Object.keys(channels_1).forEach(function (channel) { - params.permissions.resources.channels[channel] = extractPermissions(channels_1[channel]); - }); + FCMNotificationPayload.prototype.toObject = function () { + var data = __assign({}, this._payload.data); + var notification = null; + var payload = {}; + /** + * Check whether additional data has been passed outside of 'data' object + * and put it into it if required. + */ + if (Object.keys(this._payload).length > 2) { + var _a = this._payload; _a.notification; _a.data; var additionalData = __rest(_a, ["notification", "data"]); + data = __assign(__assign({}, data), additionalData); } - if (groups_3) { - Object.keys(groups_3).forEach(function (group) { - params.permissions.resources.groups[group] = extractPermissions(groups_3[group]); - }); + if (this._isSilent) { + data.notification = this._payload.notification; } - } - if (patterns) { - var uuids_2 = patterns.uuids, channels_2 = patterns.channels, groups_4 = patterns.groups; - if (uuids_2) { - Object.keys(uuids_2).forEach(function (uuid) { - params.permissions.patterns.uuids[uuid] = extractPermissions(uuids_2[uuid]); - }); + else { + notification = this._payload.notification; } - if (channels_2) { - Object.keys(channels_2).forEach(function (channel) { - params.permissions.patterns.channels[channel] = extractPermissions(channels_2[channel]); - }); + if (Object.keys(data).length) { + payload.data = data; } - if (groups_4) { - Object.keys(groups_4).forEach(function (group) { - params.permissions.patterns.groups[group] = extractPermissions(groups_4[group]); - }); + if (notification && Object.keys(notification).length) { + payload.notification = notification; } + return Object.keys(payload).length ? payload : null; + }; + return FCMNotificationPayload; + }(BaseNotificationPayload)); + var NotificationsPayload = /** @class */ (function () { + function NotificationsPayload(title, body) { + this._payload = { apns: {}, mpns: {}, fcm: {} }; + this._title = title; + this._body = body; + this.apns = new APNSNotificationPayload(this._payload.apns, title, body); + this.mpns = new MPNSNotificationPayload(this._payload.mpns, title, body); + this.fcm = new FCMNotificationPayload(this._payload.fcm, title, body); } - if (ttl || ttl === 0) { - params.ttl = ttl; - } - if (meta) { - params.permissions.meta = meta; - } - if (authorized_uuid) { - params.permissions.uuid = "".concat(authorized_uuid); // ensure this is a string - } - return params; - } - function validateParams$8(modules, incomingParams) { - var _a, _b, _c, _d, _e, _f; - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - if (!config.publishKey) - return 'Missing Publish Key'; - if (!config.secretKey) - return 'Missing Secret Key'; - if (!incomingParams.resources && !incomingParams.patterns) - return 'Missing either Resources or Patterns.'; - var hasAuthorizedUuid = (incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.authorized_uuid) !== undefined; - var hasUuidResources = ((_a = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.resources) === null || _a === void 0 ? void 0 : _a.uuids) !== undefined; - var hasChannelResources = ((_b = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.resources) === null || _b === void 0 ? void 0 : _b.channels) !== undefined; - var hasGroupResources = ((_c = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.resources) === null || _c === void 0 ? void 0 : _c.groups) !== undefined; - var hasUuidPatterns = ((_d = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.patterns) === null || _d === void 0 ? void 0 : _d.uuids) !== undefined; - var hasChannelPatterns = ((_e = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.patterns) === null || _e === void 0 ? void 0 : _e.channels) !== undefined; - var hasGroupPatterns = ((_f = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.patterns) === null || _f === void 0 ? void 0 : _f.groups) !== undefined; - var hasLegacyTerms = hasAuthorizedUuid || - hasUuidResources || - hasUuidPatterns || - hasChannelResources || - hasChannelPatterns || - hasGroupResources || - hasGroupPatterns; - if (hasVspTerms(incomingParams) && hasLegacyTerms) { - return ('Cannot mix `users`, `spaces` and `authorizedUserId` ' + - 'with `uuids`, `channels`, `groups` and `authorized_uuid`'); - } - if ((incomingParams.resources && - (!incomingParams.resources.uuids || Object.keys(incomingParams.resources.uuids).length === 0) && - (!incomingParams.resources.channels || Object.keys(incomingParams.resources.channels).length === 0) && - (!incomingParams.resources.groups || Object.keys(incomingParams.resources.groups).length === 0) && - (!incomingParams.resources.users || Object.keys(incomingParams.resources.users).length === 0) && - (!incomingParams.resources.spaces || Object.keys(incomingParams.resources.spaces).length === 0)) || - (incomingParams.patterns && - (!incomingParams.patterns.uuids || Object.keys(incomingParams.patterns.uuids).length === 0) && - (!incomingParams.patterns.channels || Object.keys(incomingParams.patterns.channels).length === 0) && - (!incomingParams.patterns.groups || Object.keys(incomingParams.patterns.groups).length === 0) && - (!incomingParams.patterns.users || Object.keys(incomingParams.patterns.users).length === 0) && - (!incomingParams.patterns.spaces || Object.keys(incomingParams.patterns.spaces).length === 0))) { - return 'Missing values for either Resources or Patterns.'; - } - } - function postURL$1(modules) { - var config = modules.config; - return "/v3/pam/".concat(config.subscribeKey, "/grant"); - } - function usePost$1() { - return true; - } - function getRequestTimeout$8(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$8() { - return false; - } - function prepareParams$8() { - return {}; - } - function postPayload$1(modules, incomingParams) { - return prepareMessagePayload$2(modules, incomingParams); - } - function handleResponse$8(modules, response) { - var token = response.data.token; - return token; - } - - var grantTokenEndpointConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$8, - extractPermissions: extractPermissions, - validateParams: validateParams$8, - postURL: postURL$1, - usePost: usePost$1, - getRequestTimeout: getRequestTimeout$8, - isAuthSupported: isAuthSupported$8, - prepareParams: prepareParams$8, - postPayload: postPayload$1, - handleResponse: handleResponse$8 - }); - - /** */ - var endpoint$2 = { - getOperation: function () { return OPERATIONS.PNAccessManagerRevokeToken; }, - validateParams: function (modules, token) { - var secretKey = modules.config.secretKey; - if (!secretKey) { - return 'Missing Secret Key'; + Object.defineProperty(NotificationsPayload.prototype, "debugging", { + set: function (value) { + this._debugging = value; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(NotificationsPayload.prototype, "title", { + get: function () { + return this._title; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(NotificationsPayload.prototype, "body", { + get: function () { + return this._body; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(NotificationsPayload.prototype, "subtitle", { + get: function () { + return this._subtitle; + }, + set: function (value) { + this._subtitle = value; + this.apns.subtitle = value; + this.mpns.subtitle = value; + this.fcm.subtitle = value; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(NotificationsPayload.prototype, "badge", { + get: function () { + return this._badge; + }, + set: function (value) { + this._badge = value; + this.apns.badge = value; + this.mpns.badge = value; + this.fcm.badge = value; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(NotificationsPayload.prototype, "sound", { + get: function () { + return this._sound; + }, + set: function (value) { + this._sound = value; + this.apns.sound = value; + this.mpns.sound = value; + this.fcm.sound = value; + }, + enumerable: false, + configurable: true + }); + /** + * Build notifications platform for requested platforms. + * + * @param {Array} platforms - List of platforms for which payload + * should be added to final dictionary. Supported values: gcm, apns, apns2, + * mpns. + * + * @returns {Object} Object with data, which can be sent with publish method + * call and trigger remote notifications for specified platforms. + */ + NotificationsPayload.prototype.buildPayload = function (platforms) { + var payload = {}; + if (platforms.includes('apns') || platforms.includes('apns2')) { + this.apns._apnsPushType = platforms.includes('apns') ? 'apns' : 'apns2'; + var apnsPayload = this.apns.toObject(); + if (apnsPayload && Object.keys(apnsPayload).length) { + payload.pn_apns = apnsPayload; + } } - if (!token) { - return "token can't be empty"; + if (platforms.includes('mpns')) { + var mpnsPayload = this.mpns.toObject(); + if (mpnsPayload && Object.keys(mpnsPayload).length) { + payload.pn_mpns = mpnsPayload; + } } - }, - getURL: function (_a, token) { - var config = _a.config; - return "/v3/pam/".concat(config.subscribeKey, "/grant/").concat(utils$5.encodeString(token)); - }, - useDelete: function () { return true; }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return false; }, - prepareParams: function (_a) { - var config = _a.config; - return ({ - uuid: config.getUUID(), - }); - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - }); }, - }; - - /* */ - function prepareMessagePayload$1(modules, messagePayload) { - var stringifiedPayload = JSON.stringify(messagePayload); - if (modules.cryptoModule) { - var encrypted = modules.cryptoModule.encrypt(stringifiedPayload); - stringifiedPayload = typeof encrypted === 'string' ? encrypted : encode$1(encrypted); - stringifiedPayload = JSON.stringify(stringifiedPayload); - } - return stringifiedPayload || ''; - } - function getOperation$7() { - return OPERATIONS.PNPublishOperation; - } - function validateParams$7(_a, incomingParams) { - var config = _a.config; - var message = incomingParams.message, channel = incomingParams.channel; - if (!channel) - return 'Missing Channel'; - if (!message) - return 'Missing Message'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function usePost(modules, incomingParams) { - var _a = incomingParams.sendByPost, sendByPost = _a === void 0 ? false : _a; - return sendByPost; - } - function getURL$7(modules, incomingParams) { - var config = modules.config; - var channel = incomingParams.channel, message = incomingParams.message; - var stringifiedPayload = prepareMessagePayload$1(modules, message); - return "/publish/".concat(config.publishKey, "/").concat(config.subscribeKey, "/0/").concat(utils$5.encodeString(channel), "/0/").concat(utils$5.encodeString(stringifiedPayload)); - } - function postURL(modules, incomingParams) { - var config = modules.config; - var channel = incomingParams.channel; - return "/publish/".concat(config.publishKey, "/").concat(config.subscribeKey, "/0/").concat(utils$5.encodeString(channel), "/0"); - } - function getRequestTimeout$7(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$7() { - return true; - } - function postPayload(modules, incomingParams) { - var message = incomingParams.message; - return prepareMessagePayload$1(modules, message); - } - function prepareParams$7(modules, incomingParams) { - var meta = incomingParams.meta, _a = incomingParams.replicate, replicate = _a === void 0 ? true : _a, storeInHistory = incomingParams.storeInHistory, ttl = incomingParams.ttl; - var params = {}; - if (storeInHistory != null) { - if (storeInHistory) { - params.store = '1'; + if (platforms.includes('fcm')) { + var fcmPayload = this.fcm.toObject(); + if (fcmPayload && Object.keys(fcmPayload).length) { + payload.pn_gcm = fcmPayload; + } } - else { - params.store = '0'; + if (Object.keys(payload).length && this._debugging) { + payload.pn_debug = true; } - } - if (ttl) { - params.ttl = ttl; - } - if (replicate === false) { - params.norep = 'true'; - } - if (meta && typeof meta === 'object') { - params.meta = JSON.stringify(meta); - } - return params; - } - function handleResponse$7(modules, serverResponse) { - return { timetoken: serverResponse[2] }; - } - - var publishEndpointConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$7, - validateParams: validateParams$7, - usePost: usePost, - getURL: getURL$7, - postURL: postURL, - getRequestTimeout: getRequestTimeout$7, - isAuthSupported: isAuthSupported$7, - postPayload: postPayload, - prepareParams: prepareParams$7, - handleResponse: handleResponse$7 - }); - - /* */ - function prepareMessagePayload(modules, messagePayload) { - var stringifiedPayload = JSON.stringify(messagePayload); - return stringifiedPayload; - } - function getOperation$6() { - return OPERATIONS.PNSignalOperation; - } - function validateParams$6(_a, incomingParams) { - var config = _a.config; - var message = incomingParams.message, channel = incomingParams.channel; - if (!channel) - return 'Missing Channel'; - if (!message) - return 'Missing Message'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL$6(modules, incomingParams) { - var config = modules.config; - var channel = incomingParams.channel, message = incomingParams.message; - var stringifiedPayload = prepareMessagePayload(modules, message); - return "/signal/".concat(config.publishKey, "/").concat(config.subscribeKey, "/0/").concat(utils$5.encodeString(channel), "/0/").concat(utils$5.encodeString(stringifiedPayload)); - } - function getRequestTimeout$6(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$6() { - return true; - } - function prepareParams$6() { - var params = {}; - return params; - } - function handleResponse$6(modules, serverResponse) { - return { timetoken: serverResponse[2] }; - } - - var signalEndpointConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$6, - validateParams: validateParams$6, - getURL: getURL$6, - getRequestTimeout: getRequestTimeout$6, - isAuthSupported: isAuthSupported$6, - prepareParams: prepareParams$6, - handleResponse: handleResponse$6 - }); - - /* */ - function __processMessage$1(modules, message) { - var result = {}; - if (!modules.cryptoModule) { - result.payload = message; - return result; - } - try { - var decryptedData = modules.cryptoModule.decrypt(message); - var decryptedPayload = decryptedData instanceof ArrayBuffer ? JSON.parse(new TextDecoder().decode(decryptedData)) : decryptedData; - result.payload = decryptedPayload; - return result; - } - catch (e) { - if (modules.config.logVerbosity && console && console.log) - console.log('decryption error', e.message); - result.payload = message; - result.error = "Error while decrypting message content: ".concat(e.message); - } - return result; - } - function getOperation$5() { - return OPERATIONS.PNHistoryOperation; - } - function validateParams$5(modules, incomingParams) { - var channel = incomingParams.channel; - var config = modules.config; - if (!channel) - return 'Missing channel'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL$5(modules, incomingParams) { - var channel = incomingParams.channel; - var config = modules.config; - return "/v2/history/sub-key/".concat(config.subscribeKey, "/channel/").concat(utils$5.encodeString(channel)); - } - function getRequestTimeout$5(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$5() { - return true; - } - function prepareParams$5(modules, incomingParams) { - var start = incomingParams.start, end = incomingParams.end, reverse = incomingParams.reverse, _a = incomingParams.count, count = _a === void 0 ? 100 : _a, _b = incomingParams.stringifiedTimeToken, stringifiedTimeToken = _b === void 0 ? false : _b, _c = incomingParams.includeMeta, includeMeta = _c === void 0 ? false : _c; - var outgoingParams = { - include_token: 'true', - }; - outgoingParams.count = count; - if (start) - outgoingParams.start = start; - if (end) - outgoingParams.end = end; - if (stringifiedTimeToken) - outgoingParams.string_message_token = 'true'; - if (reverse != null) - outgoingParams.reverse = reverse.toString(); - if (includeMeta) - outgoingParams.include_meta = 'true'; - return outgoingParams; - } - function handleResponse$5(modules, serverResponse) { - var response = { - messages: [], - startTimeToken: serverResponse[1], - endTimeToken: serverResponse[2], - }; - if (Array.isArray(serverResponse[0])) { - serverResponse[0].forEach(function (serverHistoryItem) { - var processedMessgeResult = __processMessage$1(modules, serverHistoryItem.message); - var item = { - timetoken: serverHistoryItem.timetoken, - entry: processedMessgeResult.payload, - }; - if (serverHistoryItem.meta) { - item.meta = serverHistoryItem.meta; - } - if (processedMessgeResult.error) - item.error = processedMessgeResult.error; - response.messages.push(item); - }); - } - return response; - } - - var historyEndpointConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$5, - validateParams: validateParams$5, - getURL: getURL$5, - getRequestTimeout: getRequestTimeout$5, - isAuthSupported: isAuthSupported$5, - prepareParams: prepareParams$5, - handleResponse: handleResponse$5 - }); - - /* */ - function getOperation$4() { - return OPERATIONS.PNDeleteMessagesOperation; - } - function validateParams$4(modules, incomingParams) { - var channel = incomingParams.channel; - var config = modules.config; - if (!channel) - return 'Missing channel'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function useDelete() { - return true; - } - function getURL$4(modules, incomingParams) { - var channel = incomingParams.channel; - var config = modules.config; - return "/v3/history/sub-key/".concat(config.subscribeKey, "/channel/").concat(utils$5.encodeString(channel)); - } - function getRequestTimeout$4(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$4() { - return true; - } - function prepareParams$4(modules, incomingParams) { - var start = incomingParams.start, end = incomingParams.end; - var outgoingParams = {}; - if (start) - outgoingParams.start = start; - if (end) - outgoingParams.end = end; - return outgoingParams; - } - function handleResponse$4(modules, serverResponse) { - return serverResponse.payload; - } - - var deleteMessagesEndpointConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$4, - validateParams: validateParams$4, - useDelete: useDelete, - getURL: getURL$4, - getRequestTimeout: getRequestTimeout$4, - isAuthSupported: isAuthSupported$4, - prepareParams: prepareParams$4, - handleResponse: handleResponse$4 - }); - - function getOperation$3() { - return OPERATIONS.PNMessageCounts; - } - function validateParams$3(modules, incomingParams) { - var channels = incomingParams.channels, timetoken = incomingParams.timetoken, channelTimetokens = incomingParams.channelTimetokens; - var config = modules.config; - if (!channels) - return 'Missing channel'; - if (timetoken && channelTimetokens) - return 'timetoken and channelTimetokens are incompatible together'; - if (channelTimetokens && channelTimetokens.length > 1 && channels.length !== channelTimetokens.length) { - return 'Length of channelTimetokens and channels do not match'; - } - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL$3(modules, incomingParams) { - var channels = incomingParams.channels; - var config = modules.config; - var stringifiedChannels = channels.join(','); - return "/v3/history/sub-key/".concat(config.subscribeKey, "/message-counts/").concat(utils$5.encodeString(stringifiedChannels)); - } - function getRequestTimeout$3(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$3() { - return true; - } - function prepareParams$3(modules, incomingParams) { - var timetoken = incomingParams.timetoken, channelTimetokens = incomingParams.channelTimetokens; - var outgoingParams = {}; - if (channelTimetokens && channelTimetokens.length === 1) { - var _a = __read$1(channelTimetokens, 1), tt = _a[0]; - outgoingParams.timetoken = tt; - } - else if (channelTimetokens) { - outgoingParams.channelsTimetoken = channelTimetokens.join(','); - } - else if (timetoken) { - outgoingParams.timetoken = timetoken; - } - return outgoingParams; - } - function handleResponse$3(modules, serverResponse) { - return { channels: serverResponse.channels }; - } - - var messageCountsEndpointConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$3, - validateParams: validateParams$3, - getURL: getURL$3, - getRequestTimeout: getRequestTimeout$3, - isAuthSupported: isAuthSupported$3, - prepareParams: prepareParams$3, - handleResponse: handleResponse$3 - }); + return payload; + }; + return NotificationsPayload; + }()); - /* */ - function __processMessage(modules, message) { - var result = {}; - if (!modules.cryptoModule) { - result.payload = message; - return result; - } - try { - var decryptedData = modules.cryptoModule.decrypt(message); - var decryptedPayload = decryptedData instanceof ArrayBuffer ? JSON.parse(new TextDecoder().decode(decryptedData)) : decryptedData; - result.payload = decryptedPayload; - return result; - } - catch (e) { - if (modules.config.logVerbosity && console && console.log) - console.log('decryption error', e.message); - result.payload = message; - result.error = "Error while decrypting message content: ".concat(e.message); - } - return result; - } - function getOperation$2() { - return OPERATIONS.PNFetchMessagesOperation; - } - function validateParams$2(modules, incomingParams) { - var channels = incomingParams.channels, _a = incomingParams.includeMessageActions, includeMessageActions = _a === void 0 ? false : _a; - var config = modules.config; - if (!channels || channels.length === 0) - return 'Missing channels'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - if (includeMessageActions && channels.length > 1) { - throw new TypeError('History can return actions data for a single channel only. ' + - 'Either pass a single channel or disable the includeMessageActions flag.'); + /** + * Base REST API request class. + */ + var AbstractRequest = /** @class */ (function () { + /** + * Construct base request. + * + * Constructed request by default won't be cancellable and performed using `GET` HTTP method. + * + * @param params - Request configuration parameters. + */ + function AbstractRequest(params) { + this.params = params; + this._cancellationController = null; } - } - function getURL$2(modules, incomingParams) { - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a, _b = incomingParams.includeMessageActions, includeMessageActions = _b === void 0 ? false : _b; - var config = modules.config; - var endpoint = !includeMessageActions ? 'history' : 'history-with-actions'; - var stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return "/v3/".concat(endpoint, "/sub-key/").concat(config.subscribeKey, "/channel/").concat(utils$5.encodeString(stringifiedChannels)); - } - function getRequestTimeout$2(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function isAuthSupported$2() { - return true; - } - function prepareParams$2(modules, incomingParams) { - var channels = incomingParams.channels, start = incomingParams.start, end = incomingParams.end, includeMessageActions = incomingParams.includeMessageActions, count = incomingParams.count, _a = incomingParams.stringifiedTimeToken, stringifiedTimeToken = _a === void 0 ? false : _a, _b = incomingParams.includeMeta, includeMeta = _b === void 0 ? false : _b, includeUuid = incomingParams.includeUuid, _c = incomingParams.includeUUID, includeUUID = _c === void 0 ? true : _c, _d = incomingParams.includeMessageType, includeMessageType = _d === void 0 ? true : _d; - var outgoingParams = {}; - if (count) { - outgoingParams.max = count; - } - else { - outgoingParams.max = channels.length > 1 || includeMessageActions === true ? 25 : 100; - } - if (start) - outgoingParams.start = start; - if (end) - outgoingParams.end = end; - if (stringifiedTimeToken) - outgoingParams.string_message_token = 'true'; - if (includeMeta) - outgoingParams.include_meta = 'true'; - if (includeUUID && includeUuid !== false) - outgoingParams.include_uuid = 'true'; - if (includeMessageType) - outgoingParams.include_message_type = 'true'; - return outgoingParams; - } - function handleResponse$2(modules, serverResponse) { - var response = { - channels: {}, - }; - Object.keys(serverResponse.channels || {}).forEach(function (channelName) { - response.channels[channelName] = []; - (serverResponse.channels[channelName] || []).forEach(function (messageEnvelope) { - var announce = {}; - var processedMessgeResult = __processMessage(modules, messageEnvelope.message); - announce.channel = channelName; - announce.timetoken = messageEnvelope.timetoken; - announce.message = processedMessgeResult.payload; - announce.messageType = messageEnvelope.message_type; - announce.uuid = messageEnvelope.uuid; - if (messageEnvelope.actions) { - announce.actions = messageEnvelope.actions; - // This should be kept for few updates for existing clients consistency. - announce.data = messageEnvelope.actions; - } - if (messageEnvelope.meta) { - announce.meta = messageEnvelope.meta; - } - if (processedMessgeResult.error) - announce.error = processedMessgeResult.error; - response.channels[channelName].push(announce); - }); + Object.defineProperty(AbstractRequest.prototype, "cancellationController", { + /** + * Retrieve configured cancellation controller. + * + * @returns Cancellation controller. + */ + get: function () { + return this._cancellationController; + }, + /** + * Update request cancellation controller. + * + * Controller itself provided by transport provider implementation and set only when request + * sending has been scheduled. + * + * @param controller - Cancellation controller or `null` to reset it. + */ + set: function (controller) { + this._cancellationController = controller; + }, + enumerable: false, + configurable: true }); - if (serverResponse.more) { - response.more = serverResponse.more; - } - return response; - } - - var fetchMessagesEndpointConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$2, - validateParams: validateParams$2, - getURL: getURL$2, - getRequestTimeout: getRequestTimeout$2, - isAuthSupported: isAuthSupported$2, - prepareParams: prepareParams$2, - handleResponse: handleResponse$2 - }); - - /* */ - function getOperation$1() { - return OPERATIONS.PNTimeOperation; - } - function getURL$1() { - return '/time/0'; - } - function getRequestTimeout$1(_a) { - var config = _a.config; - return config.getTransactionTimeout(); - } - function prepareParams$1() { - return {}; - } - function isAuthSupported$1() { - return false; - } - function handleResponse$1(modules, serverResponse) { - return { - timetoken: serverResponse[0], + /** + * Abort request if possible. + */ + AbstractRequest.prototype.abort = function () { + if (this.cancellationController) + this.cancellationController.abort(); }; - } - function validateParams$1() { - // pass - } - - var timeEndpointConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation$1, - getURL: getURL$1, - getRequestTimeout: getRequestTimeout$1, - prepareParams: prepareParams$1, - isAuthSupported: isAuthSupported$1, - handleResponse: handleResponse$1, - validateParams: validateParams$1 - }); - - /* */ - function getOperation() { - return OPERATIONS.PNSubscribeOperation; - } - function validateParams(modules) { - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - } - function getURL(modules, incomingParams) { - var config = modules.config; - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a; - var stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return "/v2/subscribe/".concat(config.subscribeKey, "/").concat(utils$5.encodeString(stringifiedChannels), "/0"); - } - function getRequestTimeout(_a) { - var config = _a.config; - return config.getSubscribeTimeout(); - } - function isAuthSupported() { - return true; - } - function prepareParams(_a, incomingParams) { - var config = _a.config; - var state = incomingParams.state, _b = incomingParams.channelGroups, channelGroups = _b === void 0 ? [] : _b, timetoken = incomingParams.timetoken, filterExpression = incomingParams.filterExpression, region = incomingParams.region; - var params = { - heartbeat: config.getPresenceTimeout(), + /** + * Target REST API endpoint operation type. + */ + AbstractRequest.prototype.operation = function () { + throw Error('Should be implemented by subclass.'); }; - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); - } - if (filterExpression && filterExpression.length > 0) { - params['filter-expr'] = filterExpression; - } - if (Object.keys(state).length) { - params.state = JSON.stringify(state); - } - if (timetoken) { - params.tt = timetoken; - } - if (region) { - params.tr = region; - } - return params; - } - function handleResponse(modules, serverResponse) { - var messages = []; - serverResponse.m.forEach(function (rawMessage) { - var publishMetaData = { - publishTimetoken: rawMessage.p.t, - region: rawMessage.p.r, - }; - var parsedMessage = { - shard: parseInt(rawMessage.a, 10), - subscriptionMatch: rawMessage.b, - channel: rawMessage.c, - messageType: rawMessage.e, - payload: rawMessage.d, - flags: rawMessage.f, - issuingClientId: rawMessage.i, - subscribeKey: rawMessage.k, - originationTimetoken: rawMessage.o, - userMetadata: rawMessage.u, - publishMetaData: publishMetaData, - }; - messages.push(parsedMessage); - }); - var metadata = { - timetoken: serverResponse.t.t, - region: serverResponse.t.r, + /** + * Validate user-provided data before scheduling request. + * + * @returns Error message if request can't be sent without missing or malformed parameters. + */ + AbstractRequest.prototype.validate = function () { + return undefined; }; - return { messages: messages, metadata: metadata }; - } - - var subscribeEndpointConfig = /*#__PURE__*/Object.freeze({ - __proto__: null, - getOperation: getOperation, - validateParams: validateParams, - getURL: getURL, - getRequestTimeout: getRequestTimeout, - isAuthSupported: isAuthSupported, - prepareParams: prepareParams, - handleResponse: handleResponse - }); - - var endpoint$1 = { - getOperation: function () { return OPERATIONS.PNHandshakeOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channels) && !(params === null || params === void 0 ? void 0 : params.channelGroups)) { - return 'channels and channleGroups both should not be empty'; - } - }, - getURL: function (_a, params) { - var config = _a.config; - var _b = params.channels, channels = _b === void 0 ? [] : _b; - var stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return "/v2/subscribe/".concat(config.subscribeKey, "/").concat(utils$5.encodeString(stringifiedChannels), "/0"); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getSubscribeTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_, params) { - var outParams = {}; - if (params.channelGroups && params.channelGroups.length > 0) { - outParams['channel-group'] = params.channelGroups.join(','); - } - outParams.tt = 0; - if (params.state) { - outParams.state = JSON.stringify(params.state); - } - if (params.filterExpression && params.filterExpression.length > 0) { - outParams['filter-expr'] = params.filterExpression; - } - outParams.ee = ''; - return outParams; - }, - handleResponse: function (_, response) { return ({ - region: response.t.r, - timetoken: response.t.t, - }); }, - }; - - var endpoint = { - getOperation: function () { return OPERATIONS.PNReceiveMessagesOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channels) && !(params === null || params === void 0 ? void 0 : params.channelGroups)) { - return 'channels and channleGroups both should not be empty'; - } - if (!(params === null || params === void 0 ? void 0 : params.timetoken)) { - return 'timetoken can not be empty'; - } - if (!(params === null || params === void 0 ? void 0 : params.region)) { - return 'region can not be empty'; - } - }, - getURL: function (_a, params) { - var config = _a.config; - var _b = params.channels, channels = _b === void 0 ? [] : _b; - var stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return "/v2/subscribe/".concat(config.subscribeKey, "/").concat(utils$5.encodeString(stringifiedChannels), "/0"); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getSubscribeTimeout(); - }, - isAuthSupported: function () { return true; }, - getAbortSignal: function (_, params) { return params.abortSignal; }, - prepareParams: function (_, params) { - var outParams = {}; - if (params.channelGroups && params.channelGroups.length > 0) { - outParams['channel-group'] = params.channelGroups.join(','); - } - if (params.filterExpression && params.filterExpression.length > 0) { - outParams['filter-expr'] = params.filterExpression; - } - outParams.tt = params.timetoken; - outParams.tr = params.region; - outParams.ee = ''; - return outParams; - }, - handleResponse: function (_, response) { - var parsedMessages = []; - response.m.forEach(function (envelope) { - var parsedMessage = { - shard: parseInt(envelope.a, 10), - subscriptionMatch: envelope.b, - channel: envelope.c, - messageType: envelope.e, - payload: envelope.d, - flags: envelope.f, - issuingClientId: envelope.i, - subscribeKey: envelope.k, - originationTimetoken: envelope.o, - publishMetaData: { - timetoken: envelope.p.t, - region: envelope.p.r, - }, - }; - parsedMessages.push(parsedMessage); + /** + * Parse service response. + * + * @param _response - Raw service response which should be parsed. + */ + AbstractRequest.prototype.parse = function (_response) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + throw Error('Should be implemented by subclass.'); + }); }); - return { - messages: parsedMessages, - metadata: { - region: response.t.r, - timetoken: response.t.t, - }, - }; - }, - }; - - var Subject = /** @class */ (function () { - function Subject(sync) { - if (sync === void 0) { sync = false; } - this.sync = sync; - this.listeners = new Set(); - } - Subject.prototype.subscribe = function (listener) { - var _this = this; - this.listeners.add(listener); - return function () { - _this.listeners.delete(listener); - }; }; - Subject.prototype.notify = function (event) { - var _this = this; - var wrapper = function () { - _this.listeners.forEach(function (listener) { - listener(event); - }); + /** + * Create platform-agnostic request object. + * + * @returns Request object which can be processed using platform-specific requirements. + */ + AbstractRequest.prototype.request = function () { + var _a, _b, _c, _d; + var request = { + method: (_b = (_a = this.params) === null || _a === void 0 ? void 0 : _a.method) !== null && _b !== void 0 ? _b : TransportMethod.GET, + path: this.path, + queryParameters: this.queryParameters, + cancellable: (_d = (_c = this.params) === null || _c === void 0 ? void 0 : _c.cancellable) !== null && _d !== void 0 ? _d : false, + timeout: 10000, + identifier: uuidGenerator.createUUID(), }; - if (this.sync) { - wrapper(); + // Attach headers (if required). + var headers = this.headers; + if (headers) + request.headers = headers; + // Attach body (if required). + if (request.method === TransportMethod.POST || request.method === TransportMethod.PATCH) { + var _e = __read([this.body, this.formData], 2), body = _e[0], formData = _e[1]; + if (formData) + request.formData = formData; + if (body) + request.body = body; + } + return request; + }; + Object.defineProperty(AbstractRequest.prototype, "headers", { + /** + * Target REST API endpoint request headers getter. + * + * @returns Key/value headers which should be used with request. + */ + get: function () { + return undefined; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(AbstractRequest.prototype, "path", { + /** + * Target REST API endpoint request path getter. + * + * @returns REST API path. + */ + get: function () { + throw Error('`path` getter should be implemented by subclass.'); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(AbstractRequest.prototype, "queryParameters", { + /** + * Target REST API endpoint request query parameters getter. + * + * @returns Key/value pairs which should be appended to the REST API path. + */ + get: function () { + return {}; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(AbstractRequest.prototype, "formData", { + get: function () { + return undefined; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(AbstractRequest.prototype, "body", { + /** + * Target REST API Request body payload getter. + * + * @returns Buffer of stringified data which should be sent with `POST` or `PATCH` request. + */ + get: function () { + return undefined; + }, + enumerable: false, + configurable: true + }); + /** + * Deserialize service response. + * + * @param response - Transparent response object with headers and body information. + * + * @returns Deserialized data or `undefined` in case of `JSON.parse(..)` error. + */ + AbstractRequest.prototype.deserializeResponse = function (response) { + var contentType = response.headers['content-type']; + if (contentType.indexOf('javascript') === -1 || contentType.indexOf('json') === -1) + return undefined; + var json = AbstractRequest.decoder.decode(response.body); + try { + var parsedJson = JSON.parse(json); + return parsedJson; } - else { - setTimeout(wrapper, 0); + catch (error) { + console.error('Error parsing JSON response:', error); + return undefined; } }; - return Subject; + /** + * Service `ArrayBuffer` response decoder. + */ + AbstractRequest.decoder = new TextDecoder(); + return AbstractRequest; }()); - /* eslint-disable @typescript-eslint/no-explicit-any */ - var State = /** @class */ (function () { - function State(label) { - this.label = label; - this.transitionMap = new Map(); - this.enterEffects = []; - this.exitEffects = []; + /* */ + var RequestOperation; + (function (RequestOperation) { + // -------------------------------------------------------- + // ---------------------- Publish API --------------------- + // -------------------------------------------------------- + /** + * Data publish REST API operation. + */ + RequestOperation["PNPublishOperation"] = "PNPublishOperation"; + /** + * Signal sending REST API operation. + */ + RequestOperation["PNSignalOperation"] = "PNSignalOperation"; + // -------------------------------------------------------- + // --------------------- Subscribe API -------------------- + // -------------------------------------------------------- + /** + * Subscribe for real-time updates REST API operation. + * + * User's presence change on specified entities will trigger `join` event. + */ + RequestOperation["PNSubscribeOperation"] = "PNSubscribeOperation"; + /** + * Unsubscribe from real-time updates REST API operation. + * + * User's presence change on specified entities will trigger `leave` event. + */ + RequestOperation["PNUnsubscribeOperation"] = "PNUnsubscribeOperation"; + // -------------------------------------------------------- + // --------------------- Presence API --------------------- + // -------------------------------------------------------- + /** + * Fetch user's presence information REST API operation. + */ + RequestOperation["PNWhereNowOperation"] = "PNWhereNowOperation"; + /** + * Fetch channel's presence information REST API operation. + */ + RequestOperation["PNHereNowOperation"] = "PNHereNowOperation"; + /** + * Update user's information associated with specified channel REST API operation. + */ + RequestOperation["PNSetStateOperation"] = "PNSetStateOperation"; + /** + * Fetch user's information associated with the specified channel REST API operation. + */ + RequestOperation["PNGetStateOperation"] = "PNGetStateOperation"; + /** + * Announce presence on managed channels REST API operation. + */ + RequestOperation["PNHeartbeatOperation"] = "PNHeartbeatOperation"; + // -------------------------------------------------------- + // ----------------- Message Reaction API ----------------- + // -------------------------------------------------------- + /** + * Add a reaction to the specified message REST API operation. + */ + RequestOperation["PNAddMessageActionOperation"] = "PNAddActionOperation"; + /** + * Remove reaction from the specified message REST API operation. + */ + RequestOperation["PNRemoveMessageActionOperation"] = "PNRemoveMessageActionOperation"; + /** + * Fetch reactions for specific message REST API operation. + */ + RequestOperation["PNGetMessageActionsOperation"] = "PNGetMessageActionsOperation"; + RequestOperation["PNTimeOperation"] = "PNTimeOperation"; + // -------------------------------------------------------- + // ---------------------- Storage API --------------------- + // -------------------------------------------------------- + /** + * Channel history REST API operation. + */ + RequestOperation["PNHistoryOperation"] = "PNHistoryOperation"; + /** + * Delete messages from channel history REST API operation. + */ + RequestOperation["PNDeleteMessagesOperation"] = "PNDeleteMessagesOperation"; + /** + * History for channels REST API operation. + */ + RequestOperation["PNFetchMessagesOperation"] = "PNFetchMessagesOperation"; + /** + * Number of messages for channels in specified time frame REST API operation. + */ + RequestOperation["PNMessageCounts"] = "PNMessageCountsOperation"; + // -------------------------------------------------------- + // -------------------- App Context API ------------------- + // -------------------------------------------------------- + /** + * Fetch users metadata REST API operation. + */ + RequestOperation["PNGetAllUUIDMetadataOperation"] = "PNGetAllUUIDMetadataOperation"; + /** + * Fetch user metadata REST API operation. + */ + RequestOperation["PNGetUUIDMetadataOperation"] = "PNGetUUIDMetadataOperation"; + /** + * Set user metadata REST API operation. + */ + RequestOperation["PNSetUUIDMetadataOperation"] = "PNSetUUIDMetadataOperation"; + /** + * Remove user metadata REST API operation. + */ + RequestOperation["PNRemoveUUIDMetadataOperation"] = "PNRemoveUUIDMetadataOperation"; + /** + * Fetch channels metadata REST API operation. + */ + RequestOperation["PNGetAllChannelMetadataOperation"] = "PNGetAllChannelMetadataOperation"; + /** + * Fetch channel metadata REST API operation. + */ + RequestOperation["PNGetChannelMetadataOperation"] = "PNGetChannelMetadataOperation"; + /** + * Set channel metadata REST API operation. + */ + RequestOperation["PNSetChannelMetadataOperation"] = "PNSetChannelMetadataOperation"; + /** + * Remove channel metadata REST API operation. + */ + RequestOperation["PNRemoveChannelMetadataOperation"] = "PNRemoveChannelMetadataOperation"; + /** + * Fetch channel members REST API operation. + */ + RequestOperation["PNGetMembersOperation"] = "PNGetMembersOperation"; + /** + * Update channel members REST API operation. + */ + RequestOperation["PNSetMembersOperation"] = "PNSetMembersOperation"; + /** + * Fetch channel memberships REST API operation. + */ + RequestOperation["PNGetMembershipsOperation"] = "PNGetMembershipsOperation"; + /** + * Update channel memberships REST API operation. + */ + RequestOperation["PNSetMembershipsOperation"] = "PNSetMembershipsOperation"; + // -------------------------------------------------------- + // -------------------- File Upload API ------------------- + // -------------------------------------------------------- + /** + * Fetch list of files sent to the channel REST API operation. + */ + RequestOperation["PNListFilesOperation"] = "PNListFilesOperation"; + /** + * Retrieve file upload URL REST API operation. + */ + RequestOperation["PNGenerateUploadUrlOperation"] = "PNGenerateUploadUrlOperation"; + /** + * Upload file to the channel REST API operation. + */ + RequestOperation["PNPublishFileOperation"] = "PNPublishFileOperation"; + /** + * Publish File Message to the channel REST API operation. + */ + RequestOperation["PNPublishFileMessageOperation"] = "PNPublishFileMessageOperation"; + /** + * Retrieve file download URL REST API operation. + */ + RequestOperation["PNGetFileUrlOperation"] = "PNGetFileUrlOperation"; + /** + * Download file from the channel REST API operation. + */ + RequestOperation["PNDownloadFileOperation"] = "PNDownloadFileOperation"; + /** + * Delete file sent to the channel REST API operation. + */ + RequestOperation["PNDeleteFileOperation"] = "PNDeleteFileOperation"; + // -------------------------------------------------------- + // -------------------- Mobile Push API ------------------- + // -------------------------------------------------------- + /** + * Register channels with device push notifications REST API operation. + */ + RequestOperation["PNAddPushNotificationEnabledChannelsOperation"] = "PNAddPushNotificationEnabledChannelsOperation"; + /** + * Unregister channels with device push notifications REST API operation. + */ + RequestOperation["PNRemovePushNotificationEnabledChannelsOperation"] = "PNRemovePushNotificationEnabledChannelsOperation"; + /** + * Fetch list of channels with enabled push notifications for device REST API operation. + */ + RequestOperation["PNPushNotificationEnabledChannelsOperation"] = "PNPushNotificationEnabledChannelsOperation"; + /** + * Disable push notifications for device REST API operation. + */ + RequestOperation["PNRemoveAllPushNotificationsOperation"] = "PNRemoveAllPushNotificationsOperation"; + // -------------------------------------------------------- + // ------------------ Channel Groups API ------------------ + // -------------------------------------------------------- + /** + * Fetch channels groups list REST API operation. + */ + RequestOperation["PNChannelGroupsOperation"] = "PNChannelGroupsOperation"; + /** + * Remove specified channel group REST API operation. + */ + RequestOperation["PNRemoveGroupOperation"] = "PNRemoveGroupOperation"; + /** + * Fetch list of channels for the specified channel group REST API operation. + */ + RequestOperation["PNChannelsForGroupOperation"] = "PNChannelsForGroupOperation"; + /** + * Add list of channels to the specified channel group REST API operation. + */ + RequestOperation["PNAddChannelsToGroupOperation"] = "PNAddChannelsToGroupOperation"; + /** + * Remove list of channels from the specified channel group REST API operation. + */ + RequestOperation["PNRemoveChannelsFromGroupOperation"] = "PNRemoveChannelsFromGroupOperation"; + // -------------------------------------------------------- + // ----------------------- PAM API ------------------------ + // -------------------------------------------------------- + /** + * Generate authorized token REST API operation. + */ + RequestOperation["PNAccessManagerGrant"] = "PNAccessManagerGrant"; + /** + * Generate authorized token REST API operation. + */ + RequestOperation["PNAccessManagerGrantToken"] = "PNAccessManagerGrantToken"; + RequestOperation["PNAccessManagerAudit"] = "PNAccessManagerAudit"; + /** + * Revoke authorized token REST API operation. + */ + RequestOperation["PNAccessManagerRevokeToken"] = "PNAccessManagerRevokeToken"; + // + // -------------------------------------------------------- + // ---------------- Subscription Utility ------------------ + // -------------------------------------------------------- + RequestOperation["PNHandshakeOperation"] = "PNHandshakeOperation"; + RequestOperation["PNReceiveMessagesOperation"] = "PNReceiveMessagesOperation"; + })(RequestOperation || (RequestOperation = {})); + var RequestOperation$1 = RequestOperation; + + /** + * Subscription REST API module. + */ + // -------------------------------------------------------- + // ---------------------- Defaults ------------------------ + // -------------------------------------------------------- + // region Defaults + /** + * Whether should subscribe to channels / groups presence announcements or not. + */ + var WITH_PRESENCE = false; + // endregion + // -------------------------------------------------------- + // ------------------------ Types ------------------------- + // -------------------------------------------------------- + // region Types + /** + * PubNub-defined event types by payload. + */ + var PubNubEventType; + (function (PubNubEventType) { + /** + * Presence change event. + */ + PubNubEventType[PubNubEventType["Presence"] = -2] = "Presence"; + /** + * Regular message event. + * + * **Note:** This is default type assigned for non-presence events if `e` field is missing. + */ + PubNubEventType[PubNubEventType["Message"] = -1] = "Message"; + /** + * Signal data event. + */ + PubNubEventType[PubNubEventType["Signal"] = 1] = "Signal"; + /** + * App Context object event. + */ + PubNubEventType[PubNubEventType["AppContext"] = 2] = "AppContext"; + /** + * Message reaction event. + */ + PubNubEventType[PubNubEventType["MessageAction"] = 3] = "MessageAction"; + /** + * Files event. + */ + PubNubEventType[PubNubEventType["Files"] = 4] = "Files"; + })(PubNubEventType || (PubNubEventType = {})); + // endregion + /** + * Base subscription request implementation. + * + * Subscription request used in small variations in two cases: + * - subscription manager + * - event engine + */ + var BaseSubscribeRequest = /** @class */ (function (_super) { + __extends(BaseSubscribeRequest, _super); + function BaseSubscribeRequest(parameters) { + var _a, _b, _c; + var _d, _e, _f; + var _this = _super.call(this, { cancellable: true }) || this; + _this.parameters = parameters; + // Apply default request parameters. + (_a = (_d = _this.parameters).withPresence) !== null && _a !== void 0 ? _a : (_d.withPresence = WITH_PRESENCE); + (_b = (_e = _this.parameters).channelGroups) !== null && _b !== void 0 ? _b : (_e.channelGroups = []); + (_c = (_f = _this.parameters).channels) !== null && _c !== void 0 ? _c : (_f.channels = []); + return _this; } - State.prototype.transition = function (context, event) { - var _a; - if (this.transitionMap.has(event.type)) { - return (_a = this.transitionMap.get(event.type)) === null || _a === void 0 ? void 0 : _a(context, event); - } - return undefined; + BaseSubscribeRequest.prototype.operation = function () { + return RequestOperation$1.PNSubscribeOperation; }; - State.prototype.on = function (eventType, transition) { - this.transitionMap.set(eventType, transition); - return this; + BaseSubscribeRequest.prototype.validate = function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channels = _a.channels, channelGroups = _a.channelGroups; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!channels && !channelGroups) + return '`channels` and `channelGroups` both should not be empty'; }; - State.prototype.with = function (context, effects) { - return [this, context, effects !== null && effects !== void 0 ? effects : []]; + BaseSubscribeRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse, events; + var _this = this; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + events = serviceResponse.m.map(function (envelope) { + var eventType = envelope.e; + // Resolve missing event type. + eventType !== null && eventType !== void 0 ? eventType : (eventType = envelope.c.endsWith('-pnpres') ? PubNubEventType.Presence : PubNubEventType.Message); + // Check whether payload is string (potentially encrypted data). + if (typeof envelope.d === 'string') { + if (eventType == PubNubEventType.Message) { + return { + type: PubNubEventType.Message, + data: _this.messageFromEnvelope(envelope), + }; + } + return { + type: PubNubEventType.Files, + data: _this.fileFromEnvelope(envelope), + }; + } + else if (eventType === PubNubEventType.Presence) { + return { + type: PubNubEventType.Presence, + data: _this.presenceEventFromEnvelope(envelope), + }; + } + else if (eventType == PubNubEventType.Signal) { + return { + type: PubNubEventType.Signal, + data: _this.signalFromEnvelope(envelope), + }; + } + else if (eventType === PubNubEventType.AppContext) { + return { + type: PubNubEventType.AppContext, + data: _this.appContextFromEnvelope(envelope), + }; + } + else if (eventType === PubNubEventType.MessageAction) { + return { + type: PubNubEventType.MessageAction, + data: _this.messageActionFromEnvelope(envelope), + }; + } + return { + type: PubNubEventType.Files, + data: _this.fileFromEnvelope(envelope), + }; + }); + return [2 /*return*/, { + cursor: { timetoken: serviceResponse.t.t, region: serviceResponse.t.r }, + messages: events, + }]; + }); + }); }; - State.prototype.onEnter = function (effect) { - this.enterEffects.push(effect); - return this; + // -------------------------------------------------------- + // ------------------ Envelope parsing -------------------- + // -------------------------------------------------------- + // region Envelope parsing + BaseSubscribeRequest.prototype.presenceEventFromEnvelope = function (envelope) { + var payload = envelope.d; + var _a = __read(this.subscriptionChannelFromEnvelope(envelope), 2), channel = _a[0], subscription = _a[1]; + // Clean up channel and subscription name from presence suffix. + channel = channel.replace('-pnpres', ''); + if (subscription) + subscription = subscription.replace('-pnpres', ''); + // Backward compatibility with deprecated properties. + var actualChannel = subscription !== null ? channel : null; + var subscribedChannel = subscription !== null ? subscription : channel; + return __assign({ channel: channel, subscription: subscription, actualChannel: actualChannel, subscribedChannel: subscribedChannel, timetoken: envelope.p.t }, payload); + }; + BaseSubscribeRequest.prototype.messageFromEnvelope = function (envelope) { + var _a = __read(this.subscriptionChannelFromEnvelope(envelope), 2), channel = _a[0], subscription = _a[1]; + var _b = __read(this.decryptedData(envelope.d), 2), message = _b[0], decryptionError = _b[1]; + // Backward compatibility with deprecated properties. + var actualChannel = subscription !== null ? channel : null; + var subscribedChannel = subscription !== null ? subscription : channel; + // Basic message event payload. + var event = { + channel: channel, + subscription: subscription, + actualChannel: actualChannel, + subscribedChannel: subscribedChannel, + timetoken: envelope.p.t, + publisher: envelope.i, + userMetadata: envelope.u, + message: message, + }; + if (decryptionError) + event.error = decryptionError; + return event; }; - State.prototype.onExit = function (effect) { - this.exitEffects.push(effect); - return this; + BaseSubscribeRequest.prototype.signalFromEnvelope = function (envelope) { + var _a = __read(this.subscriptionChannelFromEnvelope(envelope), 2), channel = _a[0], subscription = _a[1]; + return { + channel: channel, + subscription: subscription, + timetoken: envelope.p.t, + publisher: envelope.i, + userMetadata: envelope.u, + message: envelope.d, + }; }; - return State; - }()); - - /* eslint-disable @typescript-eslint/no-explicit-any */ - var Engine = /** @class */ (function (_super) { - __extends(Engine, _super); - function Engine() { - return _super !== null && _super.apply(this, arguments) || this; - } - Engine.prototype.describe = function (label) { - return new State(label); + BaseSubscribeRequest.prototype.messageActionFromEnvelope = function (envelope) { + var _a = __read(this.subscriptionChannelFromEnvelope(envelope), 2), channel = _a[0], subscription = _a[1]; + var action = envelope.d; + return { + channel: channel, + subscription: subscription, + timetoken: envelope.p.t, + publisher: envelope.i, + event: action.event, + data: __assign(__assign({}, action.data), { uuid: envelope.i }), + }; }; - Engine.prototype.start = function (initialState, initialContext) { - this.currentState = initialState; - this.currentContext = initialContext; - this.notify({ - type: 'engineStarted', - state: initialState, - context: initialContext, - }); - return; + BaseSubscribeRequest.prototype.appContextFromEnvelope = function (envelope) { + var _a = __read(this.subscriptionChannelFromEnvelope(envelope), 2), channel = _a[0], subscription = _a[1]; + var object = envelope.d; + return { + channel: channel, + subscription: subscription, + timetoken: envelope.p.t, + message: object, + }; }; - Engine.prototype.transition = function (event) { - var e_1, _a, e_2, _b, e_3, _c; - if (!this.currentState) { - throw new Error('Start the engine first'); + BaseSubscribeRequest.prototype.fileFromEnvelope = function (envelope) { + var _a = __read(this.subscriptionChannelFromEnvelope(envelope), 2), channel = _a[0], subscription = _a[1]; + var _b = __read(this.decryptedData(envelope.d), 2), file = _b[0], decryptionError = _b[1]; + var errorMessage = decryptionError; + // Basic file event payload. + var event = { + channel: channel, + subscription: subscription, + timetoken: envelope.p.t, + publisher: envelope.i, + userMetadata: envelope.u, + }; + if (!file) + errorMessage !== null && errorMessage !== void 0 ? errorMessage : (errorMessage = "File information payload is missing."); + else if (typeof file === 'string') + errorMessage !== null && errorMessage !== void 0 ? errorMessage : (errorMessage = "Unexpected file information payload data type."); + else { + event.message = file.message; + if (file.file) { + event.file = { + id: file.file.id, + name: file.file.name, + url: this.parameters.getFileUrl({ id: file.file.id, name: file.file.name, channel: channel }), + }; + } } - this.notify({ - type: 'eventReceived', - event: event, - }); - var transition = this.currentState.transition(this.currentContext, event); - if (transition) { - var _d = __read$1(transition, 3), newState = _d[0], newContext = _d[1], effects = _d[2]; - try { - for (var _e = __values(this.currentState.exitEffects), _f = _e.next(); !_f.done; _f = _e.next()) { - var effect = _f.value; - this.notify({ - type: 'invocationDispatched', - invocation: effect(this.currentContext), - }); - } + if (errorMessage) + event.error = errorMessage; + return event; + }; + // endregion + BaseSubscribeRequest.prototype.subscriptionChannelFromEnvelope = function (envelope) { + return [envelope.c, envelope.b === undefined || envelope.b === envelope.c ? null : envelope.b]; + }; + /** + * Decrypt provided `data`. + * + * @param [data] - Message or file information which should be decrypted if possible. + * + * @returns Tuple with decrypted data and decryption error (if any). + */ + BaseSubscribeRequest.prototype.decryptedData = function (data) { + if (!this.parameters.crypto || typeof data !== 'string') + return [data, undefined]; + var payload; + var error; + try { + var decryptedData = this.parameters.crypto.decrypt(data); + payload = + decryptedData instanceof ArrayBuffer + ? JSON.parse(SubscribeRequest.decoder.decode(decryptedData)) + : decryptedData; + } + catch (err) { + payload = null; + error = "Error while decrypting file message content: ".concat(err.message); + } + return [(payload !== null && payload !== void 0 ? payload : data), error]; + }; + return BaseSubscribeRequest; + }(AbstractRequest)); + /** + * Subscribe request. + */ + var SubscribeRequest = /** @class */ (function (_super) { + __extends(SubscribeRequest, _super); + function SubscribeRequest() { + return _super !== null && _super.apply(this, arguments) || this; + } + Object.defineProperty(SubscribeRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channels = _a.channels; + return "/v2/subscribe/".concat(subscribeKey, "/").concat(encodeString(channels.length > 0 ? channels.join(',') : ','), "/0"); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(SubscribeRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, channelGroups = _a.channelGroups, filterExpression = _a.filterExpression, state = _a.state, timetoken = _a.timetoken, region = _a.region; + var query = {}; + if (channelGroups && channelGroups.length > 0) + query['channel-group'] = channelGroups.join(','); + if (filterExpression && filterExpression.length > 0) + query['filter-expr'] = filterExpression; + if (state && Object.keys(state).length > 0) + query['state'] = JSON.stringify(state); + if (typeof timetoken === 'string') { + if (timetoken && timetoken.length > 0) + query['tt'] = timetoken; + } + else if (timetoken && timetoken > 0) + query['tt'] = timetoken; + if (region) + query['tr'] = region; + return query; + }, + enumerable: false, + configurable: true + }); + return SubscribeRequest; + }(BaseSubscribeRequest)); + + var EventEmitter = /** @class */ (function () { + function EventEmitter(listenerManager) { + this.listenerManager = listenerManager; + /** + * Map of channels to listener callbacks for them. + */ + this.channelListenerMap = new Map(); + /** + * Map of channel group names to the listener callbacks for them. + */ + this.groupListenerMap = new Map(); + } + /** + * Emit specific real-time event. + * + * Proper listener will be notified basing on event `type`. + * + * @param event - Received real-time event. + */ + EventEmitter.prototype.emitEvent = function (event) { + if (event.type === PubNubEventType.Message) { + this.listenerManager.announceMessage(event.data); + this.announce('message', event.data, event.data.channel, event.data.subscription); + } + else if (event.type === PubNubEventType.Signal) { + this.listenerManager.announceSignal(event.data); + this.announce('signal', event.data, event.data.channel, event.data.subscription); + } + else if (event.type === PubNubEventType.Presence) { + this.listenerManager.announcePresence(event.data); + this.announce('presence', event.data, event.data.channel, event.data.subscription); + } + else if (event.type === PubNubEventType.AppContext) { + var objectEvent = event.data; + var object = objectEvent.message; + this.listenerManager.announceObjects(objectEvent); + this.announce('objects', objectEvent, objectEvent.channel, objectEvent.subscription); + if (object.type === 'uuid') { + objectEvent.message; var channel = objectEvent.channel, restEvent = __rest(objectEvent, ["message", "channel"]); + var event_1 = object.event; object.type; var restObject = __rest(object, ["event", "type"]); + var userEvent = __assign(__assign({}, restEvent), { spaceId: channel, message: __assign(__assign({}, restObject), { event: event_1 === 'set' ? 'updated' : 'removed', type: 'user' }) }); + this.listenerManager.announceUser(userEvent); + this.announce('user', userEvent, userEvent.spaceId, userEvent.subscription); } - catch (e_1_1) { e_1 = { error: e_1_1 }; } - finally { - try { - if (_f && !_f.done && (_a = _e.return)) _a.call(_e); - } - finally { if (e_1) throw e_1.error; } + else if (object.type === 'channel') { + objectEvent.message; var channel = objectEvent.channel, restEvent = __rest(objectEvent, ["message", "channel"]); + var event_2 = object.event; object.type; var restObject = __rest(object, ["event", "type"]); + var spaceEvent = __assign(__assign({}, restEvent), { spaceId: channel, message: __assign(__assign({}, restObject), { event: event_2 === 'set' ? 'updated' : 'removed', type: 'space' }) }); + this.listenerManager.announceSpace(spaceEvent); + this.announce('space', spaceEvent, spaceEvent.spaceId, spaceEvent.subscription); + } + else if (object.type === 'membership') { + objectEvent.message; var channel = objectEvent.channel, restEvent = __rest(objectEvent, ["message", "channel"]); + var event_3 = object.event, data = object.data, restObject = __rest(object, ["event", "data"]); + var uuid = data.uuid, channelMeta = data.channel, restData = __rest(data, ["uuid", "channel"]); + var membershipEvent = __assign(__assign({}, restEvent), { spaceId: channel, message: __assign(__assign({}, restObject), { event: event_3 === 'set' ? 'updated' : 'removed', data: __assign(__assign({}, restData), { user: uuid, space: channelMeta }) }) }); + this.listenerManager.announceMembership(membershipEvent); + this.announce('membership', membershipEvent, membershipEvent.spaceId, membershipEvent.subscription); + } + } + else if (event.type === PubNubEventType.MessageAction) { + this.listenerManager.announceMessageAction(event.data); + this.announce('messageAction', event.data, event.data.channel, event.data.subscription); + } + else if (event.type === PubNubEventType.Files) { + this.listenerManager.announceFile(event.data); + this.announce('file', event.data, event.data.channel, event.data.subscription); + } + }; + /** + * Register real-time event listener for specific channels and groups. + * + * @param listener - Listener with event callbacks to handle different types of events. + * @param channels - List of channels for which listener should be registered. + * @param groups - List of channel groups for which listener should be registered. + */ + EventEmitter.prototype.addListener = function (listener, channels, groups) { + var _this = this; + // Register event-listener listener globally. + if (!(channels && groups)) { + this.listenerManager.addListener(listener); + } + else { + channels === null || channels === void 0 ? void 0 : channels.forEach(function (channel) { + if (_this.channelListenerMap.has(channel)) { + var channelListeners = _this.channelListenerMap.get(channel); + if (!channelListeners.includes(listener)) + channelListeners.push(listener); + } + else + _this.channelListenerMap.set(channel, [listener]); + }); + groups === null || groups === void 0 ? void 0 : groups.forEach(function (group) { + if (_this.groupListenerMap.has(group)) { + var groupListeners = _this.groupListenerMap.get(group); + if (!groupListeners.includes(listener)) + groupListeners.push(listener); + } + else + _this.groupListenerMap.set(group, [listener]); + }); + } + }; + /** + * Remove real-time event listener. + * + * @param listener - Event listeners which should be removed. + * @param channels - List of channels for which listener should be removed. + * @param groups - List of channel groups for which listener should be removed. + */ + EventEmitter.prototype.removeListener = function (listener, channels, groups) { + var _this = this; + if (!(channels && groups)) { + this.listenerManager.removeListener(listener); + } + else { + channels === null || channels === void 0 ? void 0 : channels.forEach(function (channel) { + if (_this.channelListenerMap.has(channel)) { + _this.channelListenerMap.set(channel, _this.channelListenerMap.get(channel).filter(function (channelListener) { return channelListener !== listener; })); + } + }); + groups === null || groups === void 0 ? void 0 : groups.forEach(function (group) { + if (_this.groupListenerMap.has(group)) { + _this.groupListenerMap.set(group, _this.groupListenerMap.get(group).filter(function (groupListener) { return groupListener !== listener; })); + } + }); + } + }; + /** + * Clear all real-time event listeners. + */ + EventEmitter.prototype.removeAllListeners = function () { + this.listenerManager.removeAllListeners(); + this.channelListenerMap.clear(); + this.groupListenerMap.clear(); + }; + /** + * Announce real-time event to all listeners. + * + * @param type - Type of event which should be announced. + * @param event - Announced real-time event payload. + * @param channel - Name of the channel for which registered listeners should be notified. + * @param group - Name of the channel group for which registered listeners should be notified. + */ + EventEmitter.prototype.announce = function (type, event, channel, group) { + if (event && this.channelListenerMap.has(channel)) + this.channelListenerMap.get(channel).forEach(function (listener) { + var typedListener = listener[type]; + // @ts-expect-error Dynamic events mapping. + if (typedListener) + typedListener(event); + }); + if (group && this.groupListenerMap.has(group)) + this.groupListenerMap.get(group).forEach(function (listener) { + var typedListener = listener[type]; + // @ts-expect-error Dynamic events mapping. + if (typedListener) + typedListener(event); + }); + }; + return EventEmitter; + }()); + + var Subject = /** @class */ (function () { + function Subject(sync) { + if (sync === void 0) { sync = false; } + this.sync = sync; + this.listeners = new Set(); + } + Subject.prototype.subscribe = function (listener) { + var _this = this; + this.listeners.add(listener); + return function () { + _this.listeners.delete(listener); + }; + }; + Subject.prototype.notify = function (event) { + var _this = this; + var wrapper = function () { + _this.listeners.forEach(function (listener) { + listener(event); + }); + }; + if (this.sync) { + wrapper(); + } + else { + setTimeout(wrapper, 0); + } + }; + return Subject; + }()); + + /* eslint-disable @typescript-eslint/no-explicit-any */ + var State = /** @class */ (function () { + function State(label) { + this.label = label; + this.transitionMap = new Map(); + this.enterEffects = []; + this.exitEffects = []; + } + State.prototype.transition = function (context, event) { + var _a; + if (this.transitionMap.has(event.type)) { + return (_a = this.transitionMap.get(event.type)) === null || _a === void 0 ? void 0 : _a(context, event); + } + return undefined; + }; + State.prototype.on = function (eventType, transition) { + this.transitionMap.set(eventType, transition); + return this; + }; + State.prototype.with = function (context, effects) { + return [this, context, effects !== null && effects !== void 0 ? effects : []]; + }; + State.prototype.onEnter = function (effect) { + this.enterEffects.push(effect); + return this; + }; + State.prototype.onExit = function (effect) { + this.exitEffects.push(effect); + return this; + }; + return State; + }()); + + /* eslint-disable @typescript-eslint/no-explicit-any */ + var Engine = /** @class */ (function (_super) { + __extends(Engine, _super); + function Engine() { + return _super !== null && _super.apply(this, arguments) || this; + } + Engine.prototype.describe = function (label) { + return new State(label); + }; + Engine.prototype.start = function (initialState, initialContext) { + this.currentState = initialState; + this.currentContext = initialContext; + this.notify({ + type: 'engineStarted', + state: initialState, + context: initialContext, + }); + return; + }; + Engine.prototype.transition = function (event) { + var e_1, _a, e_2, _b, e_3, _c; + if (!this.currentState) { + throw new Error('Start the engine first'); + } + this.notify({ + type: 'eventReceived', + event: event, + }); + var transition = this.currentState.transition(this.currentContext, event); + if (transition) { + var _d = __read(transition, 3), newState = _d[0], newContext = _d[1], effects = _d[2]; + try { + for (var _e = __values(this.currentState.exitEffects), _f = _e.next(); !_f.done; _f = _e.next()) { + var effect = _f.value; + this.notify({ + type: 'invocationDispatched', + invocation: effect(this.currentContext), + }); + } + } + catch (e_1_1) { e_1 = { error: e_1_1 }; } + finally { + try { + if (_f && !_f.done && (_a = _e.return)) _a.call(_e); + } + finally { if (e_1) throw e_1.error; } } var oldState = this.currentState; this.currentState = newState; @@ -6868,7 +6090,7 @@ var e_1, _a; try { for (var _b = __values(this.instances.entries()), _c = _b.next(); !_c.done; _c = _b.next()) { - var _d = __read$1(_c.value, 2), key = _d[0], instance = _d[1]; + var _d = __read(_c.value, 2), key = _d[0], instance = _d[1]; instance.cancel(); this.instances.delete(key); } @@ -6893,7 +6115,7 @@ } return { type: type, - payload: fn === null || fn === void 0 ? void 0 : fn.apply(void 0, __spreadArray$1([], __read$1(args), false)), + payload: fn === null || fn === void 0 ? void 0 : fn.apply(void 0, __spreadArray([], __read(args), false)), }; }; creator.type = type; @@ -6905,7 +6127,7 @@ for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } - return { type: type, payload: fn.apply(void 0, __spreadArray$1([], __read$1(args), false)), managed: false }; + return { type: type, payload: fn.apply(void 0, __spreadArray([], __read(args), false)), managed: false }; }; creator.type = type; return creator; @@ -6916,7 +6138,7 @@ for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } - return { type: type, payload: fn.apply(void 0, __spreadArray$1([], __read$1(args), false)), managed: true }; + return { type: type, payload: fn.apply(void 0, __spreadArray([], __read(args), false)), managed: true }; }; creator.type = type; creator.cancel = { type: 'CANCEL', payload: type, managed: false }; @@ -6937,7 +6159,7 @@ var AbortSignal = /** @class */ (function (_super) { __extends(AbortSignal, _super); function AbortSignal() { - var _this = _super !== null && _super.apply(this, arguments) || this; + var _this = _super.apply(this, __spreadArray([], __read(arguments), false)) || this; _this._aborted = false; return _this; } @@ -6992,1027 +6214,350 @@ }; }; - var handshake = createManagedEffect('HANDSHAKE', function (channels, groups) { return ({ + var reconnect$1 = createEvent('RECONNECT', function () { return ({}); }); + var disconnect$1 = createEvent('DISCONNECT', function () { return ({}); }); + var joined = createEvent('JOINED', function (channels, groups) { return ({ channels: channels, groups: groups, }); }); - var receiveMessages = createManagedEffect('RECEIVE_MESSAGES', function (channels, groups, cursor) { return ({ channels: channels, groups: groups, cursor: cursor }); }); - var emitMessages = createEffect('EMIT_MESSAGES', function (events) { return events; }); - var emitStatus$1 = createEffect('EMIT_STATUS', function (status) { return status; }); - var receiveReconnect = createManagedEffect('RECEIVE_RECONNECT', function (context) { return context; }); - var handshakeReconnect = createManagedEffect('HANDSHAKE_RECONNECT', function (context) { return context; }); - - var subscriptionChange = createEvent('SUBSCRIPTION_CHANGED', function (channels, groups) { return ({ + var left = createEvent('LEFT', function (channels, groups) { return ({ channels: channels, groups: groups, }); }); - var restore = createEvent('SUBSCRIPTION_RESTORED', function (channels, groups, timetoken, region) { return ({ + var leftAll = createEvent('LEFT_ALL', function () { return ({}); }); + var heartbeatSuccess = createEvent('HEARTBEAT_SUCCESS', function (statusCode) { return ({ statusCode: statusCode }); }); + var heartbeatFailure = createEvent('HEARTBEAT_FAILURE', function (error) { return error; }); + var heartbeatGiveup = createEvent('HEARTBEAT_GIVEUP', function () { return ({}); }); + var timesUp = createEvent('TIMES_UP', function () { return ({}); }); + + var heartbeat = createEffect('HEARTBEAT', function (channels, groups) { return ({ channels: channels, groups: groups, - cursor: { - timetoken: timetoken, - region: region !== null && region !== void 0 ? region : 0, - }, - }); }); - var handshakeSuccess = createEvent('HANDSHAKE_SUCCESS', function (cursor) { return cursor; }); - var handshakeFailure = createEvent('HANDSHAKE_FAILURE', function (error) { return error; }); - var handshakeReconnectSuccess = createEvent('HANDSHAKE_RECONNECT_SUCCESS', function (cursor) { return ({ - cursor: cursor, - }); }); - var handshakeReconnectFailure = createEvent('HANDSHAKE_RECONNECT_FAILURE', function (error) { return error; }); - var handshakeReconnectGiveup = createEvent('HANDSHAKE_RECONNECT_GIVEUP', function (error) { return error; }); - var receiveSuccess = createEvent('RECEIVE_SUCCESS', function (cursor, events) { return ({ - cursor: cursor, - events: events, - }); }); - var receiveFailure = createEvent('RECEIVE_FAILURE', function (error) { return error; }); - var receiveReconnectSuccess = createEvent('RECEIVE_RECONNECT_SUCCESS', function (cursor, events) { return ({ - cursor: cursor, - events: events, }); }); - var receiveReconnectFailure = createEvent('RECEIVE_RECONNECT_FAILURE', function (error) { return error; }); - var receiveReconnectGiveup = createEvent('RECEIVING_RECONNECT_GIVEUP', function (error) { return error; }); - var disconnect$1 = createEvent('DISCONNECT', function () { return ({}); }); - var reconnect$1 = createEvent('RECONNECT', function (timetoken, region) { return ({ - cursor: { - timetoken: timetoken !== null && timetoken !== void 0 ? timetoken : '', - region: region !== null && region !== void 0 ? region : 0, - }, + var leave = createEffect('LEAVE', function (channels, groups) { return ({ + channels: channels, + groups: groups, }); }); - var unsubscribeAll = createEvent('UNSUBSCRIBE_ALL', function () { return ({}); }); + // TODO: Find out actual `status` type. + /* eslint-disable @typescript-eslint/no-explicit-any */ + var emitStatus$1 = createEffect('EMIT_STATUS', function (status) { return status; }); + var wait = createManagedEffect('WAIT', function () { return ({}); }); + var delayedHeartbeat = createManagedEffect('DELAYED_HEARTBEAT', function (context) { return context; }); - var EventEngineDispatcher = /** @class */ (function (_super) { - __extends(EventEngineDispatcher, _super); - function EventEngineDispatcher(engine, dependencies) { + var PresenceEventEngineDispatcher = /** @class */ (function (_super) { + __extends(PresenceEventEngineDispatcher, _super); + function PresenceEventEngineDispatcher(engine, dependencies) { var _this = _super.call(this, dependencies) || this; - _this.on(handshake.type, asyncHandler(function (payload, abortSignal, _a) { - var handshake = _a.handshake, presenceState = _a.presenceState, config = _a.config; - return __awaiter(_this, void 0, void 0, function () { - var result, e_1; - return __generator(this, function (_b) { - switch (_b.label) { - case 0: - abortSignal.throwIfAborted(); - _b.label = 1; - case 1: - _b.trys.push([1, 3, , 4]); - return [4 /*yield*/, handshake(__assign({ abortSignal: abortSignal, channels: payload.channels, channelGroups: payload.groups, filterExpression: config.filterExpression }, (config.maintainPresenceState && { state: presenceState })))]; - case 2: - result = _b.sent(); - return [2 /*return*/, engine.transition(handshakeSuccess(result))]; - case 3: - e_1 = _b.sent(); - if (e_1 instanceof Error && e_1.message === 'Aborted') { - return [2 /*return*/]; - } - if (e_1 instanceof PubNubError) { - return [2 /*return*/, engine.transition(handshakeFailure(e_1))]; - } - return [3 /*break*/, 4]; - case 4: return [2 /*return*/]; - } - }); - }); - })); - _this.on(receiveMessages.type, asyncHandler(function (payload, abortSignal, _a) { - var receiveMessages = _a.receiveMessages, config = _a.config; - return __awaiter(_this, void 0, void 0, function () { - var result, error_1; - return __generator(this, function (_b) { - switch (_b.label) { - case 0: - abortSignal.throwIfAborted(); - _b.label = 1; - case 1: - _b.trys.push([1, 3, , 4]); - return [4 /*yield*/, receiveMessages({ - abortSignal: abortSignal, - channels: payload.channels, - channelGroups: payload.groups, - timetoken: payload.cursor.timetoken, - region: payload.cursor.region, - filterExpression: config.filterExpression, - })]; - case 2: - result = _b.sent(); - engine.transition(receiveSuccess(result.metadata, result.messages)); - return [3 /*break*/, 4]; - case 3: - error_1 = _b.sent(); - if (error_1 instanceof Error && error_1.message === 'Aborted') { - return [2 /*return*/]; - } - if (error_1 instanceof PubNubError && !abortSignal.aborted) { - return [2 /*return*/, engine.transition(receiveFailure(error_1))]; - } - return [3 /*break*/, 4]; - case 4: return [2 /*return*/]; - } - }); + _this.on(heartbeat.type, asyncHandler(function (payload_1, _1, _a) { return __awaiter(_this, [payload_1, _1, _a], void 0, function (payload, _, _b) { + var e_1; + var heartbeat = _b.heartbeat, presenceState = _b.presenceState, config = _b.config; + return __generator(this, function (_c) { + switch (_c.label) { + case 0: + _c.trys.push([0, 2, , 3]); + return [4 /*yield*/, heartbeat(__assign(__assign({ channels: payload.channels, channelGroups: payload.groups }, (config.maintainPresenceState && { state: presenceState })), { heartbeat: config.presenceTimeout }))]; + case 1: + _c.sent(); + engine.transition(heartbeatSuccess(200)); + return [3 /*break*/, 3]; + case 2: + e_1 = _c.sent(); + if (e_1 instanceof PubNubError) { + return [2 /*return*/, engine.transition(heartbeatFailure(e_1))]; + } + return [3 /*break*/, 3]; + case 3: return [2 /*return*/]; + } }); - })); - _this.on(emitMessages.type, asyncHandler(function (payload, _, _a) { - var emitMessages = _a.emitMessages; - return __awaiter(_this, void 0, void 0, function () { - return __generator(this, function (_b) { - if (payload.length > 0) { - emitMessages(payload); + }); })); + _this.on(leave.type, asyncHandler(function (payload_1, _1, _a) { return __awaiter(_this, [payload_1, _1, _a], void 0, function (payload, _, _b) { + var leave = _b.leave, config = _b.config; + return __generator(this, function (_c) { + if (!config.suppressLeaveEvents) { + try { + leave({ + channels: payload.channels, + channelGroups: payload.groups, + }); } - return [2 /*return*/]; - }); - }); - })); - _this.on(emitStatus$1.type, asyncHandler(function (payload, _, _a) { - var emitStatus = _a.emitStatus; - return __awaiter(_this, void 0, void 0, function () { - return __generator(this, function (_b) { - emitStatus(payload); - return [2 /*return*/]; - }); + catch (e) { } + } + return [2 /*return*/]; }); - })); - _this.on(receiveReconnect.type, asyncHandler(function (payload, abortSignal, _a) { - var receiveMessages = _a.receiveMessages, delay = _a.delay, config = _a.config; - return __awaiter(_this, void 0, void 0, function () { - var result, error_2; - return __generator(this, function (_b) { - switch (_b.label) { - case 0: - if (!(config.retryConfiguration && config.retryConfiguration.shouldRetry(payload.reason, payload.attempts))) return [3 /*break*/, 6]; - abortSignal.throwIfAborted(); - return [4 /*yield*/, delay(config.retryConfiguration.getDelay(payload.attempts, payload.reason))]; - case 1: - _b.sent(); - abortSignal.throwIfAborted(); - _b.label = 2; - case 2: - _b.trys.push([2, 4, , 5]); - return [4 /*yield*/, receiveMessages({ - abortSignal: abortSignal, - channels: payload.channels, - channelGroups: payload.groups, - timetoken: payload.cursor.timetoken, - region: payload.cursor.region, - filterExpression: config.filterExpression, - })]; - case 3: - result = _b.sent(); - return [2 /*return*/, engine.transition(receiveReconnectSuccess(result.metadata, result.messages))]; - case 4: - error_2 = _b.sent(); - if (error_2 instanceof Error && error_2.message === 'Aborted') { - return [2 /*return*/]; - } - if (error_2 instanceof PubNubError) { - return [2 /*return*/, engine.transition(receiveReconnectFailure(error_2))]; - } - return [3 /*break*/, 5]; - case 5: return [3 /*break*/, 7]; - case 6: return [2 /*return*/, engine.transition(receiveReconnectGiveup(new PubNubError(config.retryConfiguration.getGiveupReason(payload.reason, payload.attempts))))]; - case 7: return [2 /*return*/]; - } - }); + }); })); + _this.on(wait.type, asyncHandler(function (_1, abortSignal_1, _a) { return __awaiter(_this, [_1, abortSignal_1, _a], void 0, function (_, abortSignal, _b) { + var heartbeatDelay = _b.heartbeatDelay; + return __generator(this, function (_c) { + switch (_c.label) { + case 0: + abortSignal.throwIfAborted(); + return [4 /*yield*/, heartbeatDelay()]; + case 1: + _c.sent(); + abortSignal.throwIfAborted(); + return [2 /*return*/, engine.transition(timesUp())]; + } }); - })); - _this.on(handshakeReconnect.type, asyncHandler(function (payload, abortSignal, _a) { - var handshake = _a.handshake, delay = _a.delay, presenceState = _a.presenceState, config = _a.config; - return __awaiter(_this, void 0, void 0, function () { - var result, error_3; - return __generator(this, function (_b) { - switch (_b.label) { - case 0: - if (!(config.retryConfiguration && config.retryConfiguration.shouldRetry(payload.reason, payload.attempts))) return [3 /*break*/, 6]; - abortSignal.throwIfAborted(); - return [4 /*yield*/, delay(config.retryConfiguration.getDelay(payload.attempts, payload.reason))]; - case 1: - _b.sent(); - abortSignal.throwIfAborted(); - _b.label = 2; - case 2: - _b.trys.push([2, 4, , 5]); - return [4 /*yield*/, handshake(__assign({ abortSignal: abortSignal, channels: payload.channels, channelGroups: payload.groups, filterExpression: config.filterExpression }, (config.maintainPresenceState && { state: presenceState })))]; - case 3: - result = _b.sent(); - return [2 /*return*/, engine.transition(handshakeReconnectSuccess(result))]; - case 4: - error_3 = _b.sent(); - if (error_3 instanceof Error && error_3.message === 'Aborted') { - return [2 /*return*/]; - } - if (error_3 instanceof PubNubError) { - return [2 /*return*/, engine.transition(handshakeReconnectFailure(error_3))]; - } - return [3 /*break*/, 5]; - case 5: return [3 /*break*/, 7]; - case 6: return [2 /*return*/, engine.transition(handshakeReconnectGiveup(new PubNubError(config.retryConfiguration.getGiveupReason(payload.reason, payload.attempts))))]; - case 7: return [2 /*return*/]; - } - }); + }); })); + _this.on(delayedHeartbeat.type, asyncHandler(function (payload_1, abortSignal_1, _a) { return __awaiter(_this, [payload_1, abortSignal_1, _a], void 0, function (payload, abortSignal, _b) { + var e_2; + var heartbeat = _b.heartbeat, retryDelay = _b.retryDelay, presenceState = _b.presenceState, config = _b.config; + return __generator(this, function (_c) { + switch (_c.label) { + case 0: + if (!(config.retryConfiguration && config.retryConfiguration.shouldRetry(payload.reason, payload.attempts))) return [3 /*break*/, 6]; + abortSignal.throwIfAborted(); + return [4 /*yield*/, retryDelay(config.retryConfiguration.getDelay(payload.attempts, payload.reason))]; + case 1: + _c.sent(); + abortSignal.throwIfAborted(); + _c.label = 2; + case 2: + _c.trys.push([2, 4, , 5]); + return [4 /*yield*/, heartbeat(__assign(__assign({ channels: payload.channels, channelGroups: payload.groups }, (config.maintainPresenceState && { state: presenceState })), { heartbeat: config.presenceTimeout }))]; + case 3: + _c.sent(); + return [2 /*return*/, engine.transition(heartbeatSuccess(200))]; + case 4: + e_2 = _c.sent(); + if (e_2 instanceof Error && e_2.message === 'Aborted') { + return [2 /*return*/]; + } + if (e_2 instanceof PubNubError) { + return [2 /*return*/, engine.transition(heartbeatFailure(e_2))]; + } + return [3 /*break*/, 5]; + case 5: return [3 /*break*/, 7]; + case 6: return [2 /*return*/, engine.transition(heartbeatGiveup())]; + case 7: return [2 /*return*/]; + } }); - })); + }); })); + _this.on(emitStatus$1.type, asyncHandler(function (payload_1, _1, _a) { return __awaiter(_this, [payload_1, _1, _a], void 0, function (payload, _, _b) { + var _c; + var emitStatus = _b.emitStatus, config = _b.config; + return __generator(this, function (_d) { + if (config.announceFailedHeartbeats && ((_c = payload === null || payload === void 0 ? void 0 : payload.status) === null || _c === void 0 ? void 0 : _c.error) === true) { + emitStatus(payload.status); + } + else if (config.announceSuccessfulHeartbeats && payload.statusCode === 200) { + emitStatus(__assign(__assign({}, payload), { operation: RequestOperation$1.PNHeartbeatOperation, error: false })); + } + return [2 /*return*/]; + }); + }); })); return _this; } - return EventEngineDispatcher; + return PresenceEventEngineDispatcher; }(Dispatcher)); - var HandshakeFailedState = new State('HANDSHAKE_FAILED'); - HandshakeFailedState.on(subscriptionChange.type, function (context, event) { - return HandshakingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: context.cursor, + var HeartbeatStoppedState = new State('HEARTBEAT_STOPPED'); + HeartbeatStoppedState.on(joined.type, function (context, event) { + return HeartbeatStoppedState.with({ + channels: __spreadArray(__spreadArray([], __read(context.channels), false), __read(event.payload.channels), false), + groups: __spreadArray(__spreadArray([], __read(context.groups), false), __read(event.payload.groups), false), }); }); - HandshakeFailedState.on(reconnect$1.type, function (context, event) { - return HandshakingState.with({ + HeartbeatStoppedState.on(left.type, function (context, event) { + return HeartbeatStoppedState.with({ + channels: context.channels.filter(function (channel) { return !event.payload.channels.includes(channel); }), + groups: context.groups.filter(function (group) { return !event.payload.groups.includes(group); }), + }); + }); + HeartbeatStoppedState.on(reconnect$1.type, function (context, _) { + return HeartbeatingState.with({ channels: context.channels, groups: context.groups, - cursor: event.payload.cursor || context.cursor, }); }); - HandshakeFailedState.on(restore.type, function (context, event) { - var _a, _b; - return HandshakingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: { - timetoken: event.payload.cursor.timetoken, - region: event.payload.cursor.region ? event.payload.cursor.region : (_b = (_a = context === null || context === void 0 ? void 0 : context.cursor) === null || _a === void 0 ? void 0 : _a.region) !== null && _b !== void 0 ? _b : 0, - }, + HeartbeatStoppedState.on(leftAll.type, function (context, _) { return HeartbeatInactiveState.with(undefined); }); + + var HeartbeatCooldownState = new State('HEARTBEAT_COOLDOWN'); + HeartbeatCooldownState.onEnter(function () { return wait(); }); + HeartbeatCooldownState.onExit(function () { return wait.cancel; }); + HeartbeatCooldownState.on(timesUp.type, function (context, _) { + return HeartbeatingState.with({ + channels: context.channels, + groups: context.groups, }); }); - HandshakeFailedState.on(unsubscribeAll.type, function (_) { return UnsubscribedState.with(); }); - - var HandshakeStoppedState = new State('HANDSHAKE_STOPPED'); - HandshakeStoppedState.on(subscriptionChange.type, function (context, event) { - return HandshakeStoppedState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: context.cursor, + HeartbeatCooldownState.on(joined.type, function (context, event) { + return HeartbeatingState.with({ + channels: __spreadArray(__spreadArray([], __read(context.channels), false), __read(event.payload.channels), false), + groups: __spreadArray(__spreadArray([], __read(context.groups), false), __read(event.payload.groups), false), }); }); - HandshakeStoppedState.on(reconnect$1.type, function (context, event) { - return HandshakingState.with(__assign(__assign({}, context), { cursor: event.payload.cursor || context.cursor })); + HeartbeatCooldownState.on(left.type, function (context, event) { + return HeartbeatingState.with({ + channels: context.channels.filter(function (channel) { return !event.payload.channels.includes(channel); }), + groups: context.groups.filter(function (group) { return !event.payload.groups.includes(group); }), + }, [leave(event.payload.channels, event.payload.groups)]); }); - HandshakeStoppedState.on(restore.type, function (context, event) { - var _a; - return HandshakeStoppedState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: { - timetoken: event.payload.cursor.timetoken, - region: event.payload.cursor.region || ((_a = context === null || context === void 0 ? void 0 : context.cursor) === null || _a === void 0 ? void 0 : _a.region) || 0, - }, - }); + HeartbeatCooldownState.on(disconnect$1.type, function (context) { + return HeartbeatStoppedState.with({ + channels: context.channels, + groups: context.groups, + }, [leave(context.channels, context.groups)]); + }); + HeartbeatCooldownState.on(leftAll.type, function (context, _) { + return HeartbeatInactiveState.with(undefined, [leave(context.channels, context.groups)]); }); - HandshakeStoppedState.on(unsubscribeAll.type, function (_) { return UnsubscribedState.with(); }); - var ReceiveFailedState = new State('RECEIVE_FAILED'); - ReceiveFailedState.on(reconnect$1.type, function (context, event) { - var _a; - return HandshakingState.with({ + var HeartbeatFailedState = new State('HEARTBEAT_FAILED'); + HeartbeatFailedState.on(joined.type, function (context, event) { + return HeartbeatingState.with({ + channels: __spreadArray(__spreadArray([], __read(context.channels), false), __read(event.payload.channels), false), + groups: __spreadArray(__spreadArray([], __read(context.groups), false), __read(event.payload.groups), false), + }); + }); + HeartbeatFailedState.on(left.type, function (context, event) { + return HeartbeatingState.with({ + channels: context.channels.filter(function (channel) { return !event.payload.channels.includes(channel); }), + groups: context.groups.filter(function (group) { return !event.payload.groups.includes(group); }), + }, [leave(event.payload.channels, event.payload.groups)]); + }); + HeartbeatFailedState.on(reconnect$1.type, function (context, _) { + return HeartbeatingState.with({ channels: context.channels, groups: context.groups, - cursor: { - timetoken: !!event.payload.cursor.timetoken ? (_a = event.payload.cursor) === null || _a === void 0 ? void 0 : _a.timetoken : context.cursor.timetoken, - region: event.payload.cursor.region || context.cursor.region, - }, }); }); - ReceiveFailedState.on(subscriptionChange.type, function (context, event) { - return HandshakingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: context.cursor, - }); + HeartbeatFailedState.on(disconnect$1.type, function (context, _) { + return HeartbeatStoppedState.with({ + channels: context.channels, + groups: context.groups, + }, [leave(context.channels, context.groups)]); }); - ReceiveFailedState.on(restore.type, function (context, event) { - return HandshakingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: { - timetoken: event.payload.cursor.timetoken, - region: event.payload.cursor.region || context.cursor.region, - }, - }); + HeartbeatFailedState.on(leftAll.type, function (context, _) { + return HeartbeatInactiveState.with(undefined, [leave(context.channels, context.groups)]); }); - ReceiveFailedState.on(unsubscribeAll.type, function (_) { return UnsubscribedState.with(undefined); }); - var ReceiveStoppedState = new State('RECEIVE_STOPPED'); - ReceiveStoppedState.on(subscriptionChange.type, function (context, event) { - return ReceiveStoppedState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: context.cursor, + var HearbeatReconnectingState = new State('HEARBEAT_RECONNECTING'); + HearbeatReconnectingState.onEnter(function (context) { return delayedHeartbeat(context); }); + HearbeatReconnectingState.onExit(function () { return delayedHeartbeat.cancel; }); + HearbeatReconnectingState.on(joined.type, function (context, event) { + return HeartbeatingState.with({ + channels: __spreadArray(__spreadArray([], __read(context.channels), false), __read(event.payload.channels), false), + groups: __spreadArray(__spreadArray([], __read(context.groups), false), __read(event.payload.groups), false), }); }); - ReceiveStoppedState.on(restore.type, function (context, event) { - return ReceiveStoppedState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: { - timetoken: event.payload.cursor.timetoken, - region: event.payload.cursor.region || context.cursor.region, - }, - }); + HearbeatReconnectingState.on(left.type, function (context, event) { + return HeartbeatingState.with({ + channels: context.channels.filter(function (channel) { return !event.payload.channels.includes(channel); }), + groups: context.groups.filter(function (group) { return !event.payload.groups.includes(group); }), + }, [leave(event.payload.channels, event.payload.groups)]); }); - ReceiveStoppedState.on(reconnect$1.type, function (context, event) { - var _a; - return HandshakingState.with({ + HearbeatReconnectingState.on(disconnect$1.type, function (context, _) { + HeartbeatStoppedState.with({ channels: context.channels, groups: context.groups, - cursor: { - timetoken: !!event.payload.cursor.timetoken ? (_a = event.payload.cursor) === null || _a === void 0 ? void 0 : _a.timetoken : context.cursor.timetoken, - region: event.payload.cursor.region || context.cursor.region, - }, - }); + }, [leave(context.channels, context.groups)]); }); - ReceiveStoppedState.on(unsubscribeAll.type, function () { return UnsubscribedState.with(undefined); }); - - var ReceiveReconnectingState = new State('RECEIVE_RECONNECTING'); - ReceiveReconnectingState.onEnter(function (context) { return receiveReconnect(context); }); - ReceiveReconnectingState.onExit(function () { return receiveReconnect.cancel; }); - ReceiveReconnectingState.on(receiveReconnectSuccess.type, function (context, event) { - return ReceivingState.with({ + HearbeatReconnectingState.on(heartbeatSuccess.type, function (context, event) { + return HeartbeatCooldownState.with({ channels: context.channels, groups: context.groups, - cursor: event.payload.cursor, - }, [emitMessages(event.payload.events)]); + }); }); - ReceiveReconnectingState.on(receiveReconnectFailure.type, function (context, event) { - return ReceiveReconnectingState.with(__assign(__assign({}, context), { attempts: context.attempts + 1, reason: event.payload })); + HearbeatReconnectingState.on(heartbeatFailure.type, function (context, event) { + return HearbeatReconnectingState.with(__assign(__assign({}, context), { attempts: context.attempts + 1, reason: event.payload })); }); - ReceiveReconnectingState.on(receiveReconnectGiveup.type, function (context, event) { - var _a; - return ReceiveFailedState.with({ - groups: context.groups, + HearbeatReconnectingState.on(heartbeatGiveup.type, function (context, event) { + return HeartbeatFailedState.with({ channels: context.channels, - cursor: context.cursor, - reason: event.payload, - }, [emitStatus$1({ category: categories.PNDisconnectedUnexpectedlyCategory, error: (_a = event.payload) === null || _a === void 0 ? void 0 : _a.message })]); + groups: context.groups, + }); }); - ReceiveReconnectingState.on(disconnect$1.type, function (context) { - return ReceiveStoppedState.with({ + HearbeatReconnectingState.on(leftAll.type, function (context, _) { + return HeartbeatInactiveState.with(undefined, [leave(context.channels, context.groups)]); + }); + + var HeartbeatingState = new State('HEARTBEATING'); + HeartbeatingState.onEnter(function (context) { return heartbeat(context.channels, context.groups); }); + HeartbeatingState.on(heartbeatSuccess.type, function (context, event) { + return HeartbeatCooldownState.with({ channels: context.channels, groups: context.groups, - cursor: context.cursor, - }, [emitStatus$1({ category: categories.PNDisconnectedCategory })]); - }); - ReceiveReconnectingState.on(restore.type, function (context, event) { - return ReceivingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: { - timetoken: event.payload.cursor.timetoken, - region: event.payload.cursor.region || context.cursor.region, - }, }); }); - ReceiveReconnectingState.on(subscriptionChange.type, function (context, event) { - return ReceivingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: context.cursor, + HeartbeatingState.on(joined.type, function (context, event) { + return HeartbeatingState.with({ + channels: __spreadArray(__spreadArray([], __read(context.channels), false), __read(event.payload.channels), false), + groups: __spreadArray(__spreadArray([], __read(context.groups), false), __read(event.payload.groups), false), }); }); - ReceiveReconnectingState.on(unsubscribeAll.type, function (_) { - return UnsubscribedState.with(undefined, [emitStatus$1({ category: categories.PNDisconnectedCategory })]); + HeartbeatingState.on(left.type, function (context, event) { + return HeartbeatingState.with({ + channels: context.channels.filter(function (channel) { return !event.payload.channels.includes(channel); }), + groups: context.groups.filter(function (group) { return !event.payload.groups.includes(group); }), + }, [leave(event.payload.channels, event.payload.groups)]); }); - - var ReceivingState = new State('RECEIVING'); - ReceivingState.onEnter(function (context) { return receiveMessages(context.channels, context.groups, context.cursor); }); - ReceivingState.onExit(function () { return receiveMessages.cancel; }); - ReceivingState.on(receiveSuccess.type, function (context, event) { - return ReceivingState.with({ channels: context.channels, groups: context.groups, cursor: event.payload.cursor }, [ - emitMessages(event.payload.events), - ]); + HeartbeatingState.on(heartbeatFailure.type, function (context, event) { + return HearbeatReconnectingState.with(__assign(__assign({}, context), { attempts: 0, reason: event.payload })); }); - ReceivingState.on(subscriptionChange.type, function (context, event) { - if (event.payload.channels.length === 0 && event.payload.groups.length === 0) { - return UnsubscribedState.with(undefined); - } - return ReceivingState.with({ - cursor: context.cursor, + HeartbeatingState.on(disconnect$1.type, function (context) { + return HeartbeatStoppedState.with({ + channels: context.channels, + groups: context.groups, + }, [leave(context.channels, context.groups)]); + }); + HeartbeatingState.on(leftAll.type, function (context, _) { + return HeartbeatInactiveState.with(undefined, [leave(context.channels, context.groups)]); + }); + + var HeartbeatInactiveState = new State('HEARTBEAT_INACTIVE'); + HeartbeatInactiveState.on(joined.type, function (_, event) { + return HeartbeatingState.with({ channels: event.payload.channels, groups: event.payload.groups, }); }); - ReceivingState.on(restore.type, function (context, event) { - if (event.payload.channels.length === 0 && event.payload.groups.length === 0) { - return UnsubscribedState.with(undefined); - } - return ReceivingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: { - timetoken: event.payload.cursor.timetoken, - region: event.payload.cursor.region || context.cursor.region, - }, - }); - }); - ReceivingState.on(receiveFailure.type, function (context, event) { - return ReceiveReconnectingState.with(__assign(__assign({}, context), { attempts: 0, reason: event.payload })); - }); - ReceivingState.on(disconnect$1.type, function (context) { - return ReceiveStoppedState.with({ - channels: context.channels, - groups: context.groups, - cursor: context.cursor, - }, [emitStatus$1({ category: categories.PNDisconnectedCategory })]); - }); - ReceivingState.on(unsubscribeAll.type, function (_) { - return UnsubscribedState.with(undefined, [emitStatus$1({ category: categories.PNDisconnectedCategory })]); - }); - - var HandshakeReconnectingState = new State('HANDSHAKE_RECONNECTING'); - HandshakeReconnectingState.onEnter(function (context) { return handshakeReconnect(context); }); - HandshakeReconnectingState.onExit(function () { return handshakeReconnect.cancel; }); - HandshakeReconnectingState.on(handshakeReconnectSuccess.type, function (context, event) { - var _a, _b; - var cursor = { - timetoken: !!((_a = context.cursor) === null || _a === void 0 ? void 0 : _a.timetoken) ? (_b = context.cursor) === null || _b === void 0 ? void 0 : _b.timetoken : event.payload.cursor.timetoken, - region: event.payload.cursor.region, - }; - return ReceivingState.with({ - channels: context.channels, - groups: context.groups, - cursor: cursor, - }, [emitStatus$1({ category: categories.PNConnectedCategory })]); - }); - HandshakeReconnectingState.on(handshakeReconnectFailure.type, function (context, event) { - return HandshakeReconnectingState.with(__assign(__assign({}, context), { attempts: context.attempts + 1, reason: event.payload })); - }); - HandshakeReconnectingState.on(handshakeReconnectGiveup.type, function (context, event) { - var _a; - return HandshakeFailedState.with({ - groups: context.groups, - channels: context.channels, - cursor: context.cursor, - reason: event.payload, - }, [emitStatus$1({ category: categories.PNConnectionErrorCategory, error: (_a = event.payload) === null || _a === void 0 ? void 0 : _a.message })]); - }); - HandshakeReconnectingState.on(disconnect$1.type, function (context) { - return HandshakeStoppedState.with({ - channels: context.channels, - groups: context.groups, - cursor: context.cursor, - }); - }); - HandshakeReconnectingState.on(subscriptionChange.type, function (context, event) { - return HandshakingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: context.cursor, - }); - }); - HandshakeReconnectingState.on(restore.type, function (context, event) { - var _a, _b; - return HandshakingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: { - timetoken: event.payload.cursor.timetoken, - region: ((_a = event.payload.cursor) === null || _a === void 0 ? void 0 : _a.region) || ((_b = context === null || context === void 0 ? void 0 : context.cursor) === null || _b === void 0 ? void 0 : _b.region) || 0, - }, - }); - }); - HandshakeReconnectingState.on(unsubscribeAll.type, function (_) { return UnsubscribedState.with(undefined); }); - - var HandshakingState = new State('HANDSHAKING'); - HandshakingState.onEnter(function (context) { return handshake(context.channels, context.groups); }); - HandshakingState.onExit(function () { return handshake.cancel; }); - HandshakingState.on(subscriptionChange.type, function (context, event) { - if (event.payload.channels.length === 0 && event.payload.groups.length === 0) { - return UnsubscribedState.with(undefined); - } - return HandshakingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: context.cursor, - }); - }); - HandshakingState.on(handshakeSuccess.type, function (context, event) { - var _a, _b; - return ReceivingState.with({ - channels: context.channels, - groups: context.groups, - cursor: { - timetoken: !!((_a = context === null || context === void 0 ? void 0 : context.cursor) === null || _a === void 0 ? void 0 : _a.timetoken) ? (_b = context === null || context === void 0 ? void 0 : context.cursor) === null || _b === void 0 ? void 0 : _b.timetoken : event.payload.timetoken, - region: event.payload.region, - }, - }, [ - emitStatus$1({ - category: categories.PNConnectedCategory, - }), - ]); - }); - HandshakingState.on(handshakeFailure.type, function (context, event) { - return HandshakeReconnectingState.with({ - channels: context.channels, - groups: context.groups, - cursor: context.cursor, - attempts: 0, - reason: event.payload, - }); - }); - HandshakingState.on(disconnect$1.type, function (context) { - return HandshakeStoppedState.with({ - channels: context.channels, - groups: context.groups, - cursor: context.cursor, - }); - }); - HandshakingState.on(restore.type, function (context, event) { - var _a; - return HandshakingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: { - timetoken: event.payload.cursor.timetoken, - region: event.payload.cursor.region || ((_a = context === null || context === void 0 ? void 0 : context.cursor) === null || _a === void 0 ? void 0 : _a.region) || 0, - }, - }); - }); - HandshakingState.on(unsubscribeAll.type, function (_) { return UnsubscribedState.with(); }); - - var UnsubscribedState = new State('UNSUBSCRIBED'); - UnsubscribedState.on(subscriptionChange.type, function (_, event) { - return HandshakingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - }); - }); - UnsubscribedState.on(restore.type, function (_, event) { - return HandshakingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - cursor: event.payload.cursor, - }); - }); - var EventEngine = /** @class */ (function () { - function EventEngine(dependencies) { + var PresenceEventEngine = /** @class */ (function () { + function PresenceEventEngine(dependencies) { var _this = this; + this.dependencies = dependencies; this.engine = new Engine(); this.channels = []; this.groups = []; - this.dependencies = dependencies; - this.dispatcher = new EventEngineDispatcher(this.engine, dependencies); + this.dispatcher = new PresenceEventEngineDispatcher(this.engine, dependencies); this._unsubscribeEngine = this.engine.subscribe(function (change) { if (change.type === 'invocationDispatched') { _this.dispatcher.dispatch(change.invocation); } }); - this.engine.start(UnsubscribedState, undefined); + this.engine.start(HeartbeatInactiveState, undefined); } - Object.defineProperty(EventEngine.prototype, "_engine", { + Object.defineProperty(PresenceEventEngine.prototype, "_engine", { get: function () { return this.engine; }, enumerable: false, configurable: true }); - EventEngine.prototype.subscribe = function (_a) { - var _this = this; - var channels = _a.channels, channelGroups = _a.channelGroups, timetoken = _a.timetoken, withPresence = _a.withPresence; - this.channels = __spreadArray$1(__spreadArray$1([], __read$1(this.channels), false), __read$1((channels !== null && channels !== void 0 ? channels : [])), false); - this.groups = __spreadArray$1(__spreadArray$1([], __read$1(this.groups), false), __read$1((channelGroups !== null && channelGroups !== void 0 ? channelGroups : [])), false); - if (withPresence) { - this.channels.map(function (c) { return _this.channels.push("".concat(c, "-pnpres")); }); - this.groups.map(function (g) { return _this.groups.push("".concat(g, "-pnpres")); }); - } - if (timetoken) { - this.engine.transition(restore(Array.from(new Set(__spreadArray$1(__spreadArray$1([], __read$1(this.channels), false), __read$1((channels !== null && channels !== void 0 ? channels : [])), false))), Array.from(new Set(__spreadArray$1(__spreadArray$1([], __read$1(this.groups), false), __read$1((channelGroups !== null && channelGroups !== void 0 ? channelGroups : [])), false))), timetoken)); - } - else { - this.engine.transition(subscriptionChange(Array.from(new Set(__spreadArray$1(__spreadArray$1([], __read$1(this.channels), false), __read$1((channels !== null && channels !== void 0 ? channels : [])), false))), Array.from(new Set(__spreadArray$1(__spreadArray$1([], __read$1(this.groups), false), __read$1((channelGroups !== null && channelGroups !== void 0 ? channelGroups : [])), false))))); - } - if (this.dependencies.join) { - this.dependencies.join({ - channels: Array.from(new Set(this.channels.filter(function (c) { return !c.endsWith('-pnpres'); }))), - groups: Array.from(new Set(this.groups.filter(function (g) { return !g.endsWith('-pnpres'); }))), - }); - } + PresenceEventEngine.prototype.join = function (_a) { + var channels = _a.channels, groups = _a.groups; + this.channels = __spreadArray(__spreadArray([], __read(this.channels), false), __read((channels !== null && channels !== void 0 ? channels : [])), false); + this.groups = __spreadArray(__spreadArray([], __read(this.groups), false), __read((groups !== null && groups !== void 0 ? groups : [])), false); + this.engine.transition(joined(this.channels.slice(0), this.groups.slice(0))); }; - EventEngine.prototype.unsubscribe = function (_a) { + PresenceEventEngine.prototype.leave = function (_a) { var _this = this; - var _b = _a.channels, channels = _b === void 0 ? [] : _b, _c = _a.channelGroups, channelGroups = _c === void 0 ? [] : _c; - var filteredChannels = utils$5.removeSingleOccurance(this.channels, __spreadArray$1(__spreadArray$1([], __read$1(channels), false), __read$1(channels.map(function (c) { return "".concat(c, "-pnpres"); })), false)); - var filteredGroups = utils$5.removeSingleOccurance(this.groups, __spreadArray$1(__spreadArray$1([], __read$1(channelGroups), false), __read$1(channelGroups.map(function (c) { return "".concat(c, "-pnpres"); })), false)); - if (new Set(this.channels).size !== new Set(filteredChannels).size || - new Set(this.groups).size !== new Set(filteredGroups).size) { - var channelsToLeave = utils$5.findUniqueCommonElements(this.channels, channels); - var groupstoLeave = utils$5.findUniqueCommonElements(this.groups, channelGroups); - if (this.dependencies.presenceState) { - channelsToLeave === null || channelsToLeave === void 0 ? void 0 : channelsToLeave.forEach(function (c) { return delete _this.dependencies.presenceState[c]; }); - groupstoLeave === null || groupstoLeave === void 0 ? void 0 : groupstoLeave.forEach(function (g) { return delete _this.dependencies.presenceState[g]; }); - } - this.channels = filteredChannels; - this.groups = filteredGroups; - this.engine.transition(subscriptionChange(Array.from(new Set(this.channels.slice(0))), Array.from(new Set(this.groups.slice(0))))); - if (this.dependencies.leave) { - this.dependencies.leave({ - channels: channelsToLeave.slice(0), - groups: groupstoLeave.slice(0), - }); - } - } - }; - EventEngine.prototype.unsubscribeAll = function () { - this.channels = []; - this.groups = []; + var channels = _a.channels, groups = _a.groups; if (this.dependencies.presenceState) { - this.dependencies.presenceState = {}; - } - this.engine.transition(subscriptionChange(this.channels.slice(0), this.groups.slice(0))); - if (this.dependencies.leaveAll) { - this.dependencies.leaveAll(); - } - }; - EventEngine.prototype.reconnect = function (_a) { - var timetoken = _a.timetoken, region = _a.region; - this.engine.transition(reconnect$1(timetoken, region)); - }; - EventEngine.prototype.disconnect = function () { - this.engine.transition(disconnect$1()); - if (this.dependencies.leaveAll) { - this.dependencies.leaveAll(); + channels === null || channels === void 0 ? void 0 : channels.forEach(function (c) { return delete _this.dependencies.presenceState[c]; }); + groups === null || groups === void 0 ? void 0 : groups.forEach(function (g) { return delete _this.dependencies.presenceState[g]; }); } + this.engine.transition(left(channels !== null && channels !== void 0 ? channels : [], groups !== null && groups !== void 0 ? groups : [])); }; - EventEngine.prototype.getSubscribedChannels = function () { - return this.channels.slice(0); - }; - EventEngine.prototype.getSubscribedChannelGroups = function () { - return this.groups.slice(0); + PresenceEventEngine.prototype.leaveAll = function () { + this.engine.transition(leftAll()); }; - EventEngine.prototype.dispose = function () { - this.disconnect(); + PresenceEventEngine.prototype.dispose = function () { this._unsubscribeEngine(); this.dispatcher.dispose(); }; - return EventEngine; - }()); - - var reconnect = createEvent('RECONNECT', function () { return ({}); }); - var disconnect = createEvent('DISCONNECT', function () { return ({}); }); - var joined = createEvent('JOINED', function (channels, groups) { return ({ - channels: channels, - groups: groups, - }); }); - var left = createEvent('LEFT', function (channels, groups) { return ({ - channels: channels, - groups: groups, - }); }); - var leftAll = createEvent('LEFT_ALL', function () { return ({}); }); - var heartbeatSuccess = createEvent('HEARTBEAT_SUCCESS', function (statusCode) { return ({ statusCode: statusCode }); }); - var heartbeatFailure = createEvent('HEARTBEAT_FAILURE', function (error) { return error; }); - var heartbeatGiveup = createEvent('HEARTBEAT_GIVEUP', function () { return ({}); }); - var timesUp = createEvent('TIMES_UP', function () { return ({}); }); - - var heartbeat = createEffect('HEARTBEAT', function (channels, groups) { return ({ - channels: channels, - groups: groups, - }); }); - var leave = createEffect('LEAVE', function (channels, groups) { return ({ - channels: channels, - groups: groups, - }); }); - var emitStatus = createEffect('EMIT_STATUS', function (status) { return status; }); - var wait = createManagedEffect('WAIT', function () { return ({}); }); - var delayedHeartbeat = createManagedEffect('DELAYED_HEARTBEAT', function (context) { return context; }); - - var PresenceEventEngineDispatcher = /** @class */ (function (_super) { - __extends(PresenceEventEngineDispatcher, _super); - function PresenceEventEngineDispatcher(engine, dependencies) { - var _this = _super.call(this, dependencies) || this; - _this.on(heartbeat.type, asyncHandler(function (payload, _, _a) { - var heartbeat = _a.heartbeat, presenceState = _a.presenceState, config = _a.config; - return __awaiter(_this, void 0, void 0, function () { - var e_1; - return __generator(this, function (_b) { - switch (_b.label) { - case 0: - _b.trys.push([0, 2, , 3]); - return [4 /*yield*/, heartbeat(__assign({ channels: payload.channels, channelGroups: payload.groups }, (config.maintainPresenceState && { state: presenceState })))]; - case 1: - _b.sent(); - engine.transition(heartbeatSuccess(200)); - return [3 /*break*/, 3]; - case 2: - e_1 = _b.sent(); - if (e_1 instanceof PubNubError) { - return [2 /*return*/, engine.transition(heartbeatFailure(e_1))]; - } - return [3 /*break*/, 3]; - case 3: return [2 /*return*/]; - } - }); - }); - })); - _this.on(leave.type, asyncHandler(function (payload, _, _a) { - var leave = _a.leave, config = _a.config; - return __awaiter(_this, void 0, void 0, function () { - return __generator(this, function (_b) { - switch (_b.label) { - case 0: - if (!!config.suppressLeaveEvents) return [3 /*break*/, 4]; - _b.label = 1; - case 1: - _b.trys.push([1, 3, , 4]); - return [4 /*yield*/, leave({ - channels: payload.channels, - channelGroups: payload.groups, - })]; - case 2: - _b.sent(); - return [3 /*break*/, 4]; - case 3: - _b.sent(); - return [3 /*break*/, 4]; - case 4: return [2 /*return*/]; - } - }); - }); - })); - _this.on(wait.type, asyncHandler(function (_, abortSignal, _a) { - var heartbeatDelay = _a.heartbeatDelay; - return __awaiter(_this, void 0, void 0, function () { - return __generator(this, function (_b) { - switch (_b.label) { - case 0: - abortSignal.throwIfAborted(); - return [4 /*yield*/, heartbeatDelay()]; - case 1: - _b.sent(); - abortSignal.throwIfAborted(); - return [2 /*return*/, engine.transition(timesUp())]; - } - }); - }); - })); - _this.on(delayedHeartbeat.type, asyncHandler(function (payload, abortSignal, _a) { - var heartbeat = _a.heartbeat, retryDelay = _a.retryDelay, presenceState = _a.presenceState, config = _a.config; - return __awaiter(_this, void 0, void 0, function () { - var e_3; - return __generator(this, function (_b) { - switch (_b.label) { - case 0: - if (!(config.retryConfiguration && config.retryConfiguration.shouldRetry(payload.reason, payload.attempts))) return [3 /*break*/, 6]; - abortSignal.throwIfAborted(); - return [4 /*yield*/, retryDelay(config.retryConfiguration.getDelay(payload.attempts, payload.reason))]; - case 1: - _b.sent(); - abortSignal.throwIfAborted(); - _b.label = 2; - case 2: - _b.trys.push([2, 4, , 5]); - return [4 /*yield*/, heartbeat(__assign({ channels: payload.channels, channelGroups: payload.groups }, (config.maintainPresenceState && { state: presenceState })))]; - case 3: - _b.sent(); - return [2 /*return*/, engine.transition(heartbeatSuccess(200))]; - case 4: - e_3 = _b.sent(); - if (e_3 instanceof Error && e_3.message === 'Aborted') { - return [2 /*return*/]; - } - if (e_3 instanceof PubNubError) { - return [2 /*return*/, engine.transition(heartbeatFailure(e_3))]; - } - return [3 /*break*/, 5]; - case 5: return [3 /*break*/, 7]; - case 6: return [2 /*return*/, engine.transition(heartbeatGiveup())]; - case 7: return [2 /*return*/]; - } - }); - }); - })); - _this.on(emitStatus.type, asyncHandler(function (payload, _, _a) { - var emitStatus = _a.emitStatus, config = _a.config; - return __awaiter(_this, void 0, void 0, function () { - var _b; - return __generator(this, function (_c) { - if (config.announceFailedHeartbeats && ((_b = payload === null || payload === void 0 ? void 0 : payload.status) === null || _b === void 0 ? void 0 : _b.error) === true) { - emitStatus(payload.status); - } - else if (config.announceSuccessfulHeartbeats && payload.statusCode === 200) { - emitStatus(__assign(__assign({}, payload), { operation: OPERATIONS.PNHeartbeatOperation, error: false })); - } - return [2 /*return*/]; - }); - }); - })); - return _this; - } - return PresenceEventEngineDispatcher; - }(Dispatcher)); - - var HeartbeatStoppedState = new State('HEARTBEAT_STOPPED'); - HeartbeatStoppedState.on(joined.type, function (context, event) { - return HeartbeatStoppedState.with({ - channels: __spreadArray$1(__spreadArray$1([], __read$1(context.channels), false), __read$1(event.payload.channels), false), - groups: __spreadArray$1(__spreadArray$1([], __read$1(context.groups), false), __read$1(event.payload.groups), false), - }); - }); - HeartbeatStoppedState.on(left.type, function (context, event) { - return HeartbeatStoppedState.with({ - channels: context.channels.filter(function (channel) { return !event.payload.channels.includes(channel); }), - groups: context.groups.filter(function (group) { return !event.payload.groups.includes(group); }), - }); - }); - HeartbeatStoppedState.on(reconnect.type, function (context, _) { - return HeartbeatingState.with({ - channels: context.channels, - groups: context.groups, - }); - }); - HeartbeatStoppedState.on(leftAll.type, function (context, _) { return HeartbeatInactiveState.with(undefined); }); - - var HeartbeatCooldownState = new State('HEARTBEAT_COOLDOWN'); - HeartbeatCooldownState.onEnter(function () { return wait(); }); - HeartbeatCooldownState.onExit(function () { return wait.cancel; }); - HeartbeatCooldownState.on(timesUp.type, function (context, _) { - return HeartbeatingState.with({ - channels: context.channels, - groups: context.groups, - }); - }); - HeartbeatCooldownState.on(joined.type, function (context, event) { - return HeartbeatingState.with({ - channels: __spreadArray$1(__spreadArray$1([], __read$1(context.channels), false), __read$1(event.payload.channels), false), - groups: __spreadArray$1(__spreadArray$1([], __read$1(context.groups), false), __read$1(event.payload.groups), false), - }); - }); - HeartbeatCooldownState.on(left.type, function (context, event) { - return HeartbeatingState.with({ - channels: context.channels.filter(function (channel) { return !event.payload.channels.includes(channel); }), - groups: context.groups.filter(function (group) { return !event.payload.groups.includes(group); }), - }, [leave(event.payload.channels, event.payload.groups)]); - }); - HeartbeatCooldownState.on(disconnect.type, function (context) { - return HeartbeatStoppedState.with({ - channels: context.channels, - groups: context.groups, - }, [leave(context.channels, context.groups)]); - }); - HeartbeatCooldownState.on(leftAll.type, function (context, _) { - return HeartbeatInactiveState.with(undefined, [leave(context.channels, context.groups)]); - }); - - var HeartbeatFailedState = new State('HEARTBEAT_FAILED'); - HeartbeatFailedState.on(joined.type, function (context, event) { - return HeartbeatingState.with({ - channels: __spreadArray$1(__spreadArray$1([], __read$1(context.channels), false), __read$1(event.payload.channels), false), - groups: __spreadArray$1(__spreadArray$1([], __read$1(context.groups), false), __read$1(event.payload.groups), false), - }); - }); - HeartbeatFailedState.on(left.type, function (context, event) { - return HeartbeatingState.with({ - channels: context.channels.filter(function (channel) { return !event.payload.channels.includes(channel); }), - groups: context.groups.filter(function (group) { return !event.payload.groups.includes(group); }), - }, [leave(event.payload.channels, event.payload.groups)]); - }); - HeartbeatFailedState.on(reconnect.type, function (context, _) { - return HeartbeatingState.with({ - channels: context.channels, - groups: context.groups, - }); - }); - HeartbeatFailedState.on(disconnect.type, function (context, _) { - return HeartbeatStoppedState.with({ - channels: context.channels, - groups: context.groups, - }, [leave(context.channels, context.groups)]); - }); - HeartbeatFailedState.on(leftAll.type, function (context, _) { - return HeartbeatInactiveState.with(undefined, [leave(context.channels, context.groups)]); - }); - - var HearbeatReconnectingState = new State('HEARBEAT_RECONNECTING'); - HearbeatReconnectingState.onEnter(function (context) { return delayedHeartbeat(context); }); - HearbeatReconnectingState.onExit(function () { return delayedHeartbeat.cancel; }); - HearbeatReconnectingState.on(joined.type, function (context, event) { - return HeartbeatingState.with({ - channels: __spreadArray$1(__spreadArray$1([], __read$1(context.channels), false), __read$1(event.payload.channels), false), - groups: __spreadArray$1(__spreadArray$1([], __read$1(context.groups), false), __read$1(event.payload.groups), false), - }); - }); - HearbeatReconnectingState.on(left.type, function (context, event) { - return HeartbeatingState.with({ - channels: context.channels.filter(function (channel) { return !event.payload.channels.includes(channel); }), - groups: context.groups.filter(function (group) { return !event.payload.groups.includes(group); }), - }, [leave(event.payload.channels, event.payload.groups)]); - }); - HearbeatReconnectingState.on(disconnect.type, function (context, _) { - HeartbeatStoppedState.with({ - channels: context.channels, - groups: context.groups, - }, [leave(context.channels, context.groups)]); - }); - HearbeatReconnectingState.on(heartbeatSuccess.type, function (context, event) { - return HeartbeatCooldownState.with({ - channels: context.channels, - groups: context.groups, - }); - }); - HearbeatReconnectingState.on(heartbeatFailure.type, function (context, event) { - return HearbeatReconnectingState.with(__assign(__assign({}, context), { attempts: context.attempts + 1, reason: event.payload })); - }); - HearbeatReconnectingState.on(heartbeatGiveup.type, function (context, event) { - return HeartbeatFailedState.with({ - channels: context.channels, - groups: context.groups, - }); - }); - HearbeatReconnectingState.on(leftAll.type, function (context, _) { - return HeartbeatInactiveState.with(undefined, [leave(context.channels, context.groups)]); - }); - - var HeartbeatingState = new State('HEARTBEATING'); - HeartbeatingState.onEnter(function (context) { return heartbeat(context.channels, context.groups); }); - HeartbeatingState.on(heartbeatSuccess.type, function (context, event) { - return HeartbeatCooldownState.with({ - channels: context.channels, - groups: context.groups, - }); - }); - HeartbeatingState.on(joined.type, function (context, event) { - return HeartbeatingState.with({ - channels: __spreadArray$1(__spreadArray$1([], __read$1(context.channels), false), __read$1(event.payload.channels), false), - groups: __spreadArray$1(__spreadArray$1([], __read$1(context.groups), false), __read$1(event.payload.groups), false), - }); - }); - HeartbeatingState.on(left.type, function (context, event) { - return HeartbeatingState.with({ - channels: context.channels.filter(function (channel) { return !event.payload.channels.includes(channel); }), - groups: context.groups.filter(function (group) { return !event.payload.groups.includes(group); }), - }, [leave(event.payload.channels, event.payload.groups)]); - }); - HeartbeatingState.on(heartbeatFailure.type, function (context, event) { - return HearbeatReconnectingState.with(__assign(__assign({}, context), { attempts: 0, reason: event.payload })); - }); - HeartbeatingState.on(disconnect.type, function (context) { - return HeartbeatStoppedState.with({ - channels: context.channels, - groups: context.groups, - }, [leave(context.channels, context.groups)]); - }); - HeartbeatingState.on(leftAll.type, function (context, _) { - return HeartbeatInactiveState.with(undefined, [leave(context.channels, context.groups)]); - }); - - var HeartbeatInactiveState = new State('HEARTBEAT_INACTIVE'); - HeartbeatInactiveState.on(joined.type, function (_, event) { - return HeartbeatingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - }); - }); - - var PresenceEventEngine = /** @class */ (function () { - function PresenceEventEngine(dependencies) { - var _this = this; - this.engine = new Engine(); - this.channels = []; - this.groups = []; - this.dispatcher = new PresenceEventEngineDispatcher(this.engine, dependencies); - this.dependencies = dependencies; - this._unsubscribeEngine = this.engine.subscribe(function (change) { - if (change.type === 'invocationDispatched') { - _this.dispatcher.dispatch(change.invocation); - } - }); - this.engine.start(HeartbeatInactiveState, undefined); - } - Object.defineProperty(PresenceEventEngine.prototype, "_engine", { - get: function () { - return this.engine; - }, - enumerable: false, - configurable: true - }); - PresenceEventEngine.prototype.join = function (_a) { - var channels = _a.channels, groups = _a.groups; - this.channels = __spreadArray$1(__spreadArray$1([], __read$1(this.channels), false), __read$1((channels !== null && channels !== void 0 ? channels : [])), false); - this.groups = __spreadArray$1(__spreadArray$1([], __read$1(this.groups), false), __read$1((groups !== null && groups !== void 0 ? groups : [])), false); - this.engine.transition(joined(this.channels.slice(0), this.groups.slice(0))); - }; - PresenceEventEngine.prototype.leave = function (_a) { - var _this = this; - var channels = _a.channels, groups = _a.groups; - if (this.dependencies.presenceState) { - channels === null || channels === void 0 ? void 0 : channels.forEach(function (c) { return delete _this.dependencies.presenceState[c]; }); - groups === null || groups === void 0 ? void 0 : groups.forEach(function (g) { return delete _this.dependencies.presenceState[g]; }); - } - this.engine.transition(left(channels !== null && channels !== void 0 ? channels : [], groups !== null && groups !== void 0 ? groups : [])); - }; - PresenceEventEngine.prototype.leaveAll = function () { - this.engine.transition(leftAll()); - }; - PresenceEventEngine.prototype.dispose = function () { - this._unsubscribeEngine(); - this.dispatcher.dispose(); - }; - return PresenceEventEngine; + return PresenceEventEngine; }()); var RetryPolicy = /** @class */ (function () { @@ -8022,6 +6567,8 @@ return { delay: configuration.delay, maximumRetry: configuration.maximumRetry, + // TODO: Find out actual `error` type. + /* eslint-disable @typescript-eslint/no-explicit-any */ shouldRetry: function (error, attempt) { var _a; if (((_a = error === null || error === void 0 ? void 0 : error.status) === null || _a === void 0 ? void 0 : _a.statusCode) === 403) { @@ -8034,6 +6581,8 @@ var delay = (_a = reason.retryAfter) !== null && _a !== void 0 ? _a : this.delay; return (delay + Math.random()) * 1000; }, + // TODO: Find out actual `error` type. + /* eslint-disable @typescript-eslint/no-explicit-any */ getGiveupReason: function (error, attempt) { var _a; if (this.maximumRetry <= attempt) { @@ -8044,6 +6593,10 @@ } return 'unknown error'; }, + validate: function () { + if (this.maximumRetry > 10) + throw new Error('Maximum retry for linear retry policy can not be more than 10'); + }, }; }; RetryPolicy.ExponentialRetryPolicy = function (configuration) { @@ -8051,9 +6604,9 @@ minimumDelay: configuration.minimumDelay, maximumDelay: configuration.maximumDelay, maximumRetry: configuration.maximumRetry, - shouldRetry: function (error, attempt) { + shouldRetry: function (reason, attempt) { var _a; - if (((_a = error === null || error === void 0 ? void 0 : error.status) === null || _a === void 0 ? void 0 : _a.statusCode) === 403) { + if (((_a = reason === null || reason === void 0 ? void 0 : reason.status) === null || _a === void 0 ? void 0 : _a.statusCode) === 403) { return false; } return this.maximumRetry > attempt; @@ -8063,6564 +6616,7146 @@ var delay = (_a = reason.retryAfter) !== null && _a !== void 0 ? _a : Math.min(Math.pow(2, attempt), this.maximumDelay); return (delay + Math.random()) * 1000; }, - getGiveupReason: function (error, attempt) { + getGiveupReason: function (reason, attempt) { var _a; if (this.maximumRetry <= attempt) { - return 'retry attempts exhaused.'; + return 'retry attempts exhausted.'; } - if (((_a = error === null || error === void 0 ? void 0 : error.status) === null || _a === void 0 ? void 0 : _a.statusCode) === 403) { + if (((_a = reason === null || reason === void 0 ? void 0 : reason.status) === null || _a === void 0 ? void 0 : _a.statusCode) === 403) { return 'forbidden operation.'; } return 'unknown error'; }, + validate: function () { + if (this.minimumDelay < 2) + throw new Error('Minimum delay can not be set less than 2 seconds for retry'); + else if (this.maximumDelay) + throw new Error('Maximum delay can not be set more than 150 seconds for retry'); + else if (this.maximumRetry > 6) + throw new Error('Maximum retry for exponential retry policy can not be more than 6'); + }, }; }; return RetryPolicy; }()); - var EventEmitter = /** @class */ (function () { - function EventEmitter(_a) { - var modules = _a.modules, listenerManager = _a.listenerManager, getFileUrl = _a.getFileUrl; - this.modules = modules; - this.listenerManager = listenerManager; - this.getFileUrl = getFileUrl; - this._channelListenerMap = new Map(); - this._groupListenerMap = new Map(); - if (modules.cryptoModule) - this._decoder = new TextDecoder(); - } - EventEmitter.prototype.emitEvent = function (e) { - var channel = e.channel, publishMetaData = e.publishMetaData; - var subscriptionMatch = e.subscriptionMatch; - if (channel === subscriptionMatch) { - subscriptionMatch = null; - } - if (e.channel.endsWith('-pnpres')) { - var announce = {}; - announce.channel = null; - announce.subscription = null; - if (channel) { - announce.channel = channel.substring(0, channel.lastIndexOf('-pnpres')); - } - if (subscriptionMatch) { - announce.subscription = subscriptionMatch.substring(0, subscriptionMatch.lastIndexOf('-pnpres')); - } - announce.action = e.payload.action; - announce.state = e.payload.data; - announce.timetoken = publishMetaData.publishTimetoken; - announce.occupancy = e.payload.occupancy; - announce.uuid = e.payload.uuid; - announce.timestamp = e.payload.timestamp; - if (e.payload.join) { - announce.join = e.payload.join; - } - if (e.payload.leave) { - announce.leave = e.payload.leave; - } - if (e.payload.timeout) { - announce.timeout = e.payload.timeout; - } - // deprecated --> - announce.actualChannel = subscriptionMatch != null ? channel : null; - announce.subscribedChannel = subscriptionMatch != null ? subscriptionMatch : channel; - // <-- deprecated - this.listenerManager.announcePresence(announce); - this._announce('presence', announce, announce.channel, announce.subscription); - } - else if (e.messageType === 1) { - var announce = {}; - announce.channel = null; - announce.subscription = null; - announce.channel = channel; - announce.subscription = subscriptionMatch; - announce.timetoken = publishMetaData.publishTimetoken; - announce.publisher = e.issuingClientId; - if (e.userMetadata) { - announce.userMetadata = e.userMetadata; - } - announce.message = e.payload; - this.listenerManager.announceSignal(announce); - this._announce('signal', announce, announce.channel, announce.subscription); - } - else if (e.messageType === 2) { - var announce = {}; - announce.channel = null; - announce.subscription = null; - announce.channel = channel; - announce.subscription = subscriptionMatch; - announce.timetoken = publishMetaData.publishTimetoken; - announce.publisher = e.issuingClientId; - if (e.userMetadata) { - announce.userMetadata = e.userMetadata; - } - announce.message = { - event: e.payload.event, - type: e.payload.type, - data: e.payload.data, - }; - this.listenerManager.announceObjects(announce); - this._announce('objects', announce, announce.channel, announce.subscription); - if (e.payload.type === 'uuid') { - var eventData = this._renameChannelField(announce); - var userEvent = __assign(__assign({}, eventData), { message: __assign(__assign({}, eventData.message), { event: this._renameEvent(eventData.message.event), type: 'user' }) }); - this.listenerManager.announceUser(userEvent); - this._announce('user', userEvent, announce.channel, announce.subscription); - } - else if (message.payload.type === 'channel') { - var eventData = this._renameChannelField(announce); - var spaceEvent = __assign(__assign({}, eventData), { message: __assign(__assign({}, eventData.message), { event: this._renameEvent(eventData.message.event), type: 'space' }) }); - this.listenerManager.announceSpace(spaceEvent); - this._announce('space', spaceEvent, announce.channel, announce.subscription); - } - else if (message.payload.type === 'membership') { - var eventData = this._renameChannelField(announce); - var _a = eventData.message.data, user = _a.uuid, space = _a.channel, membershipData = __rest(_a, ["uuid", "channel"]); - membershipData.user = user; - membershipData.space = space; - var membershipEvent = __assign(__assign({}, eventData), { message: __assign(__assign({}, eventData.message), { event: this._renameEvent(eventData.message.event), data: membershipData }) }); - this.listenerManager.announceMembership(membershipEvent); - this._announce('membership', membershipEvent, announce.channel, announce.subscription); - } - } - else if (e.messageType === 3) { - var announce = {}; - announce.channel = channel; - announce.subscription = subscriptionMatch; - announce.timetoken = publishMetaData.publishTimetoken; - announce.publisher = e.issuingClientId; - announce.data = { - messageTimetoken: e.payload.data.messageTimetoken, - actionTimetoken: e.payload.data.actionTimetoken, - type: e.payload.data.type, - uuid: e.issuingClientId, - value: e.payload.data.value, - }; - announce.event = e.payload.event; - this.listenerManager.announceMessageAction(announce); - this._announce('messageAction', announce, announce.channel, announce.subscription); - } - else if (e.messageType === 4) { - var announce = {}; - announce.channel = channel; - announce.subscription = subscriptionMatch; - announce.timetoken = publishMetaData.publishTimetoken; - announce.publisher = e.issuingClientId; - var msgPayload = e.payload; - if (this.modules.cryptoModule) { - var decryptedPayload = void 0; - try { - var decryptedData = this.modules.cryptoModule.decrypt(e.payload); - decryptedPayload = - decryptedData instanceof ArrayBuffer ? JSON.parse(this._decoder.decode(decryptedData)) : decryptedData; - } - catch (e) { - decryptedPayload = null; - announce.error = "Error while decrypting message content: ".concat(e.message); - } - if (decryptedPayload !== null) { - msgPayload = decryptedPayload; - } - } - if (e.userMetadata) { - announce.userMetadata = e.userMetadata; - } - announce.message = msgPayload.message; - announce.file = { - id: msgPayload.file.id, - name: msgPayload.file.name, - url: this.getFileUrl({ - id: msgPayload.file.id, - name: msgPayload.file.name, - channel: channel, - }), - }; - this.listenerManager.announceFile(announce); - this._announce('file', announce, announce.channel, announce.subscription); - } - else { - var announce = {}; - announce.channel = null; - announce.subscription = null; - announce.channel = channel; - announce.subscription = subscriptionMatch; - announce.timetoken = publishMetaData.publishTimetoken; - announce.publisher = e.issuingClientId; - if (e.userMetadata) { - announce.userMetadata = e.userMetadata; - } - if (this.modules.cryptoModule) { - var decryptedPayload = void 0; - try { - var decryptedData = this.modules.cryptoModule.decrypt(e.payload); - decryptedPayload = - decryptedData instanceof ArrayBuffer ? JSON.parse(this._decoder.decode(decryptedData)) : decryptedData; - } - catch (e) { - decryptedPayload = null; - announce.error = "Error while decrypting message content: ".concat(e.message); - } - if (decryptedPayload != null) { - announce.message = decryptedPayload; - } - else { - announce.message = e.payload; - } - } - else { - announce.message = e.payload; - } - // deprecated --> - announce.actualChannel = subscriptionMatch != null ? channel : null; - announce.subscribedChannel = subscriptionMatch != null ? subscriptionMatch : channel; - // <-- deprecated - this.listenerManager.announceMessage(announce); - this._announce('message', announce, announce.channel, announce.subscription); - } - }; - EventEmitter.prototype.addListener = function (l, channels, groups) { - var _this = this; - if (!(channels && groups)) { - this.listenerManager.addListener(l); - } - else { - channels === null || channels === void 0 ? void 0 : channels.forEach(function (c) { - if (_this._channelListenerMap[c]) { - if (!_this._channelListenerMap[c].includes(l)) - _this._channelListenerMap[c].push(l); - } - else { - _this._channelListenerMap[c] = [l]; + var handshake = createManagedEffect('HANDSHAKE', function (channels, groups) { return ({ + channels: channels, + groups: groups, + }); }); + var receiveMessages = createManagedEffect('RECEIVE_MESSAGES', function (channels, groups, cursor) { return ({ channels: channels, groups: groups, cursor: cursor }); }); + var emitMessages = createEffect('EMIT_MESSAGES', function (events) { return events; }); + // TODO: Find out actual `status` type. + /* eslint-disable @typescript-eslint/no-explicit-any */ + var emitStatus = createEffect('EMIT_STATUS', function (status) { return status; }); + var receiveReconnect = createManagedEffect('RECEIVE_RECONNECT', function (context) { return context; }); + var handshakeReconnect = createManagedEffect('HANDSHAKE_RECONNECT', function (context) { return context; }); + + var subscriptionChange = createEvent('SUBSCRIPTION_CHANGED', function (channels, groups) { return ({ + channels: channels, + groups: groups, + }); }); + var restore = createEvent('SUBSCRIPTION_RESTORED', function (channels, groups, timetoken, region) { return ({ + channels: channels, + groups: groups, + cursor: { + timetoken: timetoken, + region: region !== null && region !== void 0 ? region : 0, + }, + }); }); + var handshakeSuccess = createEvent('HANDSHAKE_SUCCESS', function (cursor) { return cursor; }); + var handshakeFailure = createEvent('HANDSHAKE_FAILURE', function (error) { return error; }); + var handshakeReconnectSuccess = createEvent('HANDSHAKE_RECONNECT_SUCCESS', function (cursor) { return ({ + cursor: cursor, + }); }); + var handshakeReconnectFailure = createEvent('HANDSHAKE_RECONNECT_FAILURE', function (error) { return error; }); + var handshakeReconnectGiveup = createEvent('HANDSHAKE_RECONNECT_GIVEUP', function (error) { return error; }); + var receiveSuccess = createEvent('RECEIVE_SUCCESS', function (cursor, events) { return ({ + cursor: cursor, + events: events, + }); }); + var receiveFailure = createEvent('RECEIVE_FAILURE', function (error) { return error; }); + var receiveReconnectSuccess = createEvent('RECEIVE_RECONNECT_SUCCESS', function (cursor, events) { return ({ + cursor: cursor, + events: events, + }); }); + var receiveReconnectFailure = createEvent('RECEIVE_RECONNECT_FAILURE', function (error) { return error; }); + var receiveReconnectGiveup = createEvent('RECEIVING_RECONNECT_GIVEUP', function (error) { return error; }); + var disconnect = createEvent('DISCONNECT', function () { return ({}); }); + var reconnect = createEvent('RECONNECT', function (timetoken, region) { return ({ + cursor: { + timetoken: timetoken !== null && timetoken !== void 0 ? timetoken : '', + region: region !== null && region !== void 0 ? region : 0, + }, + }); }); + var unsubscribeAll = createEvent('UNSUBSCRIBE_ALL', function () { return ({}); }); + + var EventEngineDispatcher = /** @class */ (function (_super) { + __extends(EventEngineDispatcher, _super); + function EventEngineDispatcher(engine, dependencies) { + var _this = _super.call(this, dependencies) || this; + _this.on(handshake.type, asyncHandler(function (payload_1, abortSignal_1, _a) { return __awaiter(_this, [payload_1, abortSignal_1, _a], void 0, function (payload, abortSignal, _b) { + var result, e_1; + var handshake = _b.handshake, presenceState = _b.presenceState, config = _b.config; + return __generator(this, function (_c) { + switch (_c.label) { + case 0: + abortSignal.throwIfAborted(); + _c.label = 1; + case 1: + _c.trys.push([1, 3, , 4]); + return [4 /*yield*/, handshake(__assign({ abortSignal: abortSignal, channels: payload.channels, channelGroups: payload.groups, filterExpression: config.filterExpression }, (config.maintainPresenceState && { state: presenceState })))]; + case 2: + result = _c.sent(); + return [2 /*return*/, engine.transition(handshakeSuccess(result))]; + case 3: + e_1 = _c.sent(); + if (e_1 instanceof Error && e_1.message === 'Aborted') { + return [2 /*return*/]; + } + if (e_1 instanceof PubNubError) { + return [2 /*return*/, engine.transition(handshakeFailure(e_1))]; + } + return [3 /*break*/, 4]; + case 4: return [2 /*return*/]; } }); - groups === null || groups === void 0 ? void 0 : groups.forEach(function (g) { - if (_this._groupListenerMap[g]) { - if (!_this._groupListenerMap[g].includes(l)) - _this._groupListenerMap[g].push(l); + }); })); + _this.on(receiveMessages.type, asyncHandler(function (payload_1, abortSignal_1, _a) { return __awaiter(_this, [payload_1, abortSignal_1, _a], void 0, function (payload, abortSignal, _b) { + var result, error_1; + var receiveMessages = _b.receiveMessages, config = _b.config; + return __generator(this, function (_c) { + switch (_c.label) { + case 0: + abortSignal.throwIfAborted(); + _c.label = 1; + case 1: + _c.trys.push([1, 3, , 4]); + return [4 /*yield*/, receiveMessages({ + abortSignal: abortSignal, + channels: payload.channels, + channelGroups: payload.groups, + timetoken: payload.cursor.timetoken, + region: payload.cursor.region, + filterExpression: config.filterExpression, + })]; + case 2: + result = _c.sent(); + engine.transition(receiveSuccess(result.cursor, result.messages)); + return [3 /*break*/, 4]; + case 3: + error_1 = _c.sent(); + if (error_1 instanceof Error && error_1.message === 'Aborted') { + return [2 /*return*/]; + } + if (error_1 instanceof PubNubError && !abortSignal.aborted) { + return [2 /*return*/, engine.transition(receiveFailure(error_1))]; + } + return [3 /*break*/, 4]; + case 4: return [2 /*return*/]; } - else { - _this._groupListenerMap[g] = [l]; + }); + }); })); + _this.on(emitMessages.type, asyncHandler(function (payload_1, _1, _a) { return __awaiter(_this, [payload_1, _1, _a], void 0, function (payload, _, _b) { + var emitMessages = _b.emitMessages; + return __generator(this, function (_c) { + if (payload.length > 0) { + emitMessages(payload); } + return [2 /*return*/]; }); - } - }; - EventEmitter.prototype.removeListener = function (listener, channels, groups) { - var _this = this; - if (!(channels && groups)) { - this.listenerManager.removeListener(listener); - } - else { - channels === null || channels === void 0 ? void 0 : channels.forEach(function (c) { - var _a; - _this._channelListenerMap[c] = (_a = _this._channelListenerMap[c]) === null || _a === void 0 ? void 0 : _a.filter(function (l) { return l !== listener; }); + }); })); + _this.on(emitStatus.type, asyncHandler(function (payload_1, _1, _a) { return __awaiter(_this, [payload_1, _1, _a], void 0, function (payload, _, _b) { + var emitStatus = _b.emitStatus; + return __generator(this, function (_c) { + emitStatus(payload); + return [2 /*return*/]; }); - groups === null || groups === void 0 ? void 0 : groups.forEach(function (g) { - var _a; - _this._groupListenerMap[g] = (_a = _this._groupListenerMap[g]) === null || _a === void 0 ? void 0 : _a.filter(function (l) { return l !== listener; }); + }); })); + _this.on(receiveReconnect.type, asyncHandler(function (payload_1, abortSignal_1, _a) { return __awaiter(_this, [payload_1, abortSignal_1, _a], void 0, function (payload, abortSignal, _b) { + var result, error_2; + var receiveMessages = _b.receiveMessages, delay = _b.delay, config = _b.config; + return __generator(this, function (_c) { + switch (_c.label) { + case 0: + if (!(config.retryConfiguration && config.retryConfiguration.shouldRetry(payload.reason, payload.attempts))) return [3 /*break*/, 6]; + abortSignal.throwIfAborted(); + return [4 /*yield*/, delay(config.retryConfiguration.getDelay(payload.attempts, payload.reason))]; + case 1: + _c.sent(); + abortSignal.throwIfAborted(); + _c.label = 2; + case 2: + _c.trys.push([2, 4, , 5]); + return [4 /*yield*/, receiveMessages({ + abortSignal: abortSignal, + channels: payload.channels, + channelGroups: payload.groups, + timetoken: payload.cursor.timetoken, + region: payload.cursor.region, + filterExpression: config.filterExpression, + })]; + case 3: + result = _c.sent(); + return [2 /*return*/, engine.transition(receiveReconnectSuccess(result.cursor, result.messages))]; + case 4: + error_2 = _c.sent(); + if (error_2 instanceof Error && error_2.message === 'Aborted') { + return [2 /*return*/]; + } + if (error_2 instanceof PubNubError) { + return [2 /*return*/, engine.transition(receiveReconnectFailure(error_2))]; + } + return [3 /*break*/, 5]; + case 5: return [3 /*break*/, 7]; + case 6: return [2 /*return*/, engine.transition(receiveReconnectGiveup(new PubNubError(config.retryConfiguration + ? config.retryConfiguration.getGiveupReason(payload.reason, payload.attempts) + : 'Unable to complete subscribe messages receive.')))]; + case 7: return [2 /*return*/]; + } }); - } - }; - EventEmitter.prototype.removeAllListeners = function () { - this.listenerManager.removeAllListeners(); - }; - EventEmitter.prototype._renameEvent = function (e) { - return e === 'set' ? 'updated' : 'removed'; - }; - EventEmitter.prototype._renameChannelField = function (announce) { - var channel = announce.channel, eventData = __rest(announce, ["channel"]); - eventData.spaceId = channel; - return eventData; - }; - EventEmitter.prototype._announce = function (type, event, channel, group) { - var _a, _b; - (_a = this._channelListenerMap[channel]) === null || _a === void 0 ? void 0 : _a.forEach(function (l) { return l[type] && l[type](event); }); - (_b = this._groupListenerMap[group]) === null || _b === void 0 ? void 0 : _b.forEach(function (l) { return l[type] && l[type](event); }); - }; - return EventEmitter; - }()); - - var SubscribeCapable = /** @class */ (function () { - function SubscribeCapable() { + }); })); + _this.on(handshakeReconnect.type, asyncHandler(function (payload_1, abortSignal_1, _a) { return __awaiter(_this, [payload_1, abortSignal_1, _a], void 0, function (payload, abortSignal, _b) { + var result, error_3; + var handshake = _b.handshake, delay = _b.delay, presenceState = _b.presenceState, config = _b.config; + return __generator(this, function (_c) { + switch (_c.label) { + case 0: + if (!(config.retryConfiguration && config.retryConfiguration.shouldRetry(payload.reason, payload.attempts))) return [3 /*break*/, 6]; + abortSignal.throwIfAborted(); + return [4 /*yield*/, delay(config.retryConfiguration.getDelay(payload.attempts, payload.reason))]; + case 1: + _c.sent(); + abortSignal.throwIfAborted(); + _c.label = 2; + case 2: + _c.trys.push([2, 4, , 5]); + return [4 /*yield*/, handshake(__assign({ abortSignal: abortSignal, channels: payload.channels, channelGroups: payload.groups, filterExpression: config.filterExpression }, (config.maintainPresenceState && { state: presenceState })))]; + case 3: + result = _c.sent(); + return [2 /*return*/, engine.transition(handshakeReconnectSuccess(result))]; + case 4: + error_3 = _c.sent(); + if (error_3 instanceof Error && error_3.message === 'Aborted') { + return [2 /*return*/]; + } + if (error_3 instanceof PubNubError) { + return [2 /*return*/, engine.transition(handshakeReconnectFailure(error_3))]; + } + return [3 /*break*/, 5]; + case 5: return [3 /*break*/, 7]; + case 6: return [2 /*return*/, engine.transition(handshakeReconnectGiveup(new PubNubError(config.retryConfiguration + ? config.retryConfiguration.getGiveupReason(payload.reason, payload.attempts) + : 'Unable to complete subscribe handshake')))]; + case 7: return [2 /*return*/]; + } + }); + }); })); + return _this; } - SubscribeCapable.prototype.subscribe = function () { - var _a, _b; - this.pubnub.subscribe(__assign({ channels: this.channelNames, channelGroups: this.groupNames }, (((_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.cursor) === null || _b === void 0 ? void 0 : _b.timetoken) && { timetoken: this.options.cursor.timetoken }))); - }; - SubscribeCapable.prototype.unsubscribe = function () { - this.pubnub.unsubscribe({ - channels: this.channelNames.filter(function (c) { return !c.endsWith('-pnpres'); }), - channelGroups: this.groupNames.filter(function (cg) { return !cg.endsWith('-pnpres'); }), - }); - }; - Object.defineProperty(SubscribeCapable.prototype, "onMessage", { - set: function (onMessagelistener) { - this.listener.message = onMessagelistener; - }, - enumerable: false, - configurable: true + return EventEngineDispatcher; + }(Dispatcher)); + + var HandshakeFailedState = new State('HANDSHAKE_FAILED'); + HandshakeFailedState.on(subscriptionChange.type, function (context, event) { + return HandshakingState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: context.cursor, }); - Object.defineProperty(SubscribeCapable.prototype, "onPresence", { - set: function (onPresencelistener) { - this.listener.presence = onPresencelistener; - }, - enumerable: false, - configurable: true + }); + HandshakeFailedState.on(reconnect.type, function (context, event) { + return HandshakingState.with({ + channels: context.channels, + groups: context.groups, + cursor: event.payload.cursor || context.cursor, }); - Object.defineProperty(SubscribeCapable.prototype, "onSignal", { - set: function (onSignalListener) { - this.listener.signal = onSignalListener; + }); + HandshakeFailedState.on(restore.type, function (context, event) { + var _a, _b; + return HandshakingState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: { + timetoken: event.payload.cursor.timetoken, + region: event.payload.cursor.region ? event.payload.cursor.region : (_b = (_a = context === null || context === void 0 ? void 0 : context.cursor) === null || _a === void 0 ? void 0 : _a.region) !== null && _b !== void 0 ? _b : 0, }, - enumerable: false, - configurable: true }); - Object.defineProperty(SubscribeCapable.prototype, "onObjects", { - set: function (onObjectsListener) { - this.listener.objects = onObjectsListener; + }); + HandshakeFailedState.on(unsubscribeAll.type, function (_) { return UnsubscribedState.with(); }); + + var HandshakeStoppedState = new State('HANDSHAKE_STOPPED'); + HandshakeStoppedState.on(subscriptionChange.type, function (context, event) { + return HandshakeStoppedState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: context.cursor, + }); + }); + HandshakeStoppedState.on(reconnect.type, function (context, event) { + return HandshakingState.with(__assign(__assign({}, context), { cursor: event.payload.cursor || context.cursor })); + }); + HandshakeStoppedState.on(restore.type, function (context, event) { + var _a; + return HandshakeStoppedState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: { + timetoken: event.payload.cursor.timetoken, + region: event.payload.cursor.region || ((_a = context === null || context === void 0 ? void 0 : context.cursor) === null || _a === void 0 ? void 0 : _a.region) || 0, }, - enumerable: false, - configurable: true }); - Object.defineProperty(SubscribeCapable.prototype, "onMessageAction", { - set: function (messageActionEventListener) { - this.listener.messageAction = messageActionEventListener; + }); + HandshakeStoppedState.on(unsubscribeAll.type, function (_) { return UnsubscribedState.with(); }); + + var ReceiveFailedState = new State('RECEIVE_FAILED'); + ReceiveFailedState.on(reconnect.type, function (context, event) { + var _a; + return HandshakingState.with({ + channels: context.channels, + groups: context.groups, + cursor: { + timetoken: !!event.payload.cursor.timetoken ? (_a = event.payload.cursor) === null || _a === void 0 ? void 0 : _a.timetoken : context.cursor.timetoken, + region: event.payload.cursor.region || context.cursor.region, }, - enumerable: false, - configurable: true }); - Object.defineProperty(SubscribeCapable.prototype, "onFile", { - set: function (fileEventListener) { - this.listener.file = fileEventListener; + }); + ReceiveFailedState.on(subscriptionChange.type, function (context, event) { + return HandshakingState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: context.cursor, + }); + }); + ReceiveFailedState.on(restore.type, function (context, event) { + return HandshakingState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: { + timetoken: event.payload.cursor.timetoken, + region: event.payload.cursor.region || context.cursor.region, }, - enumerable: false, - configurable: true }); - SubscribeCapable.prototype.addListener = function (listener) { - this.eventEmitter.addListener(listener, this.channelNames.filter(function (c) { return !c.endsWith('-pnpres'); }), this.groupNames.filter(function (cg) { return !cg.endsWith('-pnpres'); })); - }; - SubscribeCapable.prototype.removeListener = function (listener) { - this.eventEmitter.removeListener(listener, this.channelNames, this.groupNames); - }; - Object.defineProperty(SubscribeCapable.prototype, "channels", { - get: function () { - return this.channelNames.slice(0); + }); + ReceiveFailedState.on(unsubscribeAll.type, function (_) { return UnsubscribedState.with(undefined); }); + + var ReceiveStoppedState = new State('RECEIVE_STOPPED'); + ReceiveStoppedState.on(subscriptionChange.type, function (context, event) { + return ReceiveStoppedState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: context.cursor, + }); + }); + ReceiveStoppedState.on(restore.type, function (context, event) { + return ReceiveStoppedState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: { + timetoken: event.payload.cursor.timetoken, + region: event.payload.cursor.region || context.cursor.region, }, - enumerable: false, - configurable: true }); - Object.defineProperty(SubscribeCapable.prototype, "channelGroups", { - get: function () { - return this.groupNames.slice(0); + }); + ReceiveStoppedState.on(reconnect.type, function (context, event) { + var _a; + return HandshakingState.with({ + channels: context.channels, + groups: context.groups, + cursor: { + timetoken: !!event.payload.cursor.timetoken ? (_a = event.payload.cursor) === null || _a === void 0 ? void 0 : _a.timetoken : context.cursor.timetoken, + region: event.payload.cursor.region || context.cursor.region, }, - enumerable: false, - configurable: true }); - return SubscribeCapable; - }()); + }); + ReceiveStoppedState.on(unsubscribeAll.type, function () { return UnsubscribedState.with(undefined); }); - var SubscriptionSet = /** @class */ (function (_super) { - __extends(SubscriptionSet, _super); - function SubscriptionSet(_a) { - var _b = _a.channels, channels = _b === void 0 ? [] : _b, _c = _a.channelGroups, channelGroups = _c === void 0 ? [] : _c, subscriptionOptions = _a.subscriptionOptions, eventEmitter = _a.eventEmitter, pubnub = _a.pubnub; - var _this = _super.call(this) || this; - _this.channelNames = []; - _this.groupNames = []; - _this.subscriptionList = []; - _this.options = subscriptionOptions; - _this.eventEmitter = eventEmitter; - _this.pubnub = pubnub; - channels.forEach(function (c) { - var subscription = _this.pubnub.channel(c).subscription(_this.options); - _this.channelNames = __spreadArray$1(__spreadArray$1([], __read$1(_this.channelNames), false), __read$1(subscription.channels), false); - _this.subscriptionList.push(subscription); - }); - channelGroups.forEach(function (cg) { - var subscription = _this.pubnub.channelGroup(cg).subscription(_this.options); - _this.groupNames = __spreadArray$1(__spreadArray$1([], __read$1(_this.groupNames), false), __read$1(subscription.channelGroups), false); - _this.subscriptionList.push(subscription); - }); - _this.listener = {}; - eventEmitter.addListener(_this.listener, _this.channelNames.filter(function (c) { return !c.endsWith('-pnpres'); }), _this.groupNames.filter(function (cg) { return !cg.endsWith('-pnpres'); })); - return _this; - } - SubscriptionSet.prototype.addSubscription = function (subscription) { - this.subscriptionList.push(subscription); - this.channelNames = __spreadArray$1(__spreadArray$1([], __read$1(this.channelNames), false), __read$1(subscription.channels), false); - this.groupNames = __spreadArray$1(__spreadArray$1([], __read$1(this.groupNames), false), __read$1(subscription.channelGroups), false); - }; - SubscriptionSet.prototype.removeSubscription = function (subscription) { - var channelsToRemove = subscription.channels; - var groupsToRemove = subscription.channelGroups; - this.channelNames = this.channelNames.filter(function (c) { return !channelsToRemove.includes(c); }); - this.groupNames = this.groupNames.filter(function (cg) { return !groupsToRemove.includes(cg); }); - this.subscriptionList = this.subscriptionList.filter(function (s) { return s !== subscription; }); - }; - SubscriptionSet.prototype.addSubscriptionSet = function (subscriptionSet) { - this.subscriptionList = __spreadArray$1(__spreadArray$1([], __read$1(this.subscriptionList), false), __read$1(subscriptionSet.subscriptions), false); - this.channelNames = __spreadArray$1(__spreadArray$1([], __read$1(this.channelNames), false), __read$1(subscriptionSet.channels), false); - this.groupNames = __spreadArray$1(__spreadArray$1([], __read$1(this.groupNames), false), __read$1(subscriptionSet.channelGroups), false); - }; - SubscriptionSet.prototype.removeSubscriptionSet = function (subscriptionSet) { - var channelsToRemove = subscriptionSet.channels; - var groupsToRemove = subscriptionSet.channelGroups; - this.channelNames = this.channelNames.filter(function (c) { return !channelsToRemove.includes(c); }); - this.groupNames = this.groupNames.filter(function (cg) { return !groupsToRemove.includes(cg); }); - this.subscriptionList = this.subscriptionList.filter(function (s) { return !subscriptionSet.subscriptions.includes(s); }); - }; - Object.defineProperty(SubscriptionSet.prototype, "subscriptions", { - get: function () { - return this.subscriptionList.slice(0); + var ReceiveReconnectingState = new State('RECEIVE_RECONNECTING'); + ReceiveReconnectingState.onEnter(function (context) { return receiveReconnect(context); }); + ReceiveReconnectingState.onExit(function () { return receiveReconnect.cancel; }); + ReceiveReconnectingState.on(receiveReconnectSuccess.type, function (context, event) { + return ReceivingState.with({ + channels: context.channels, + groups: context.groups, + cursor: event.payload.cursor, + }, [emitMessages(event.payload.events)]); + }); + ReceiveReconnectingState.on(receiveReconnectFailure.type, function (context, event) { + return ReceiveReconnectingState.with(__assign(__assign({}, context), { attempts: context.attempts + 1, reason: event.payload })); + }); + ReceiveReconnectingState.on(receiveReconnectGiveup.type, function (context, event) { + var _a; + return ReceiveFailedState.with({ + groups: context.groups, + channels: context.channels, + cursor: context.cursor, + reason: event.payload, + }, [emitStatus({ category: StatusCategory$1.PNDisconnectedUnexpectedlyCategory, error: (_a = event.payload) === null || _a === void 0 ? void 0 : _a.message })]); + }); + ReceiveReconnectingState.on(disconnect.type, function (context) { + return ReceiveStoppedState.with({ + channels: context.channels, + groups: context.groups, + cursor: context.cursor, + }, [emitStatus({ category: StatusCategory$1.PNDisconnectedCategory })]); + }); + ReceiveReconnectingState.on(restore.type, function (context, event) { + return ReceivingState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: { + timetoken: event.payload.cursor.timetoken, + region: event.payload.cursor.region || context.cursor.region, }, - enumerable: false, - configurable: true }); - return SubscriptionSet; - }(SubscribeCapable)); - - var Subscription = /** @class */ (function (_super) { - __extends(Subscription, _super); - function Subscription(_a) { - var channels = _a.channels, channelGroups = _a.channelGroups, subscriptionOptions = _a.subscriptionOptions, eventEmitter = _a.eventEmitter, pubnub = _a.pubnub; - var _this = _super.call(this) || this; - _this.channelNames = []; - _this.groupNames = []; - _this.channelNames = channels; - _this.groupNames = channelGroups; - _this.options = subscriptionOptions; - _this.pubnub = pubnub; - _this.eventEmitter = eventEmitter; - _this.listener = {}; - eventEmitter.addListener(_this.listener, _this.channelNames.filter(function (c) { return !c.endsWith('-pnpres'); }), _this.groupNames.filter(function (cg) { return !cg.endsWith('-pnpres'); })); - return _this; - } - Subscription.prototype.addSubscription = function (subscription) { - return new SubscriptionSet({ - channels: __spreadArray$1(__spreadArray$1([], __read$1(this.channelNames), false), __read$1(subscription.channels), false), - channelGroups: __spreadArray$1(__spreadArray$1([], __read$1(this.groupNames), false), __read$1(subscription.channelGroups), false), - subscriptionOptions: __assign(__assign({}, this.options), subscription === null || subscription === void 0 ? void 0 : subscription.options), - eventEmitter: this.eventEmitter, - pubnub: this.pubnub, - }); - }; - return Subscription; - }(SubscribeCapable)); + }); + ReceiveReconnectingState.on(subscriptionChange.type, function (context, event) { + return ReceivingState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: context.cursor, + }); + }); + ReceiveReconnectingState.on(unsubscribeAll.type, function (_) { + return UnsubscribedState.with(undefined, [emitStatus({ category: StatusCategory$1.PNDisconnectedCategory })]); + }); - var Channel = /** @class */ (function () { - function Channel(channelName, eventEmitter, pubnub) { - this.name = channelName; - this.eventEmitter = eventEmitter; - this.pubnub = pubnub; + var ReceivingState = new State('RECEIVING'); + ReceivingState.onEnter(function (context) { return receiveMessages(context.channels, context.groups, context.cursor); }); + ReceivingState.onExit(function () { return receiveMessages.cancel; }); + ReceivingState.on(receiveSuccess.type, function (context, event) { + return ReceivingState.with({ channels: context.channels, groups: context.groups, cursor: event.payload.cursor }, [ + emitMessages(event.payload.events), + ]); + }); + ReceivingState.on(subscriptionChange.type, function (context, event) { + if (event.payload.channels.length === 0 && event.payload.groups.length === 0) { + return UnsubscribedState.with(undefined); } - Channel.prototype.subscription = function (subscriptionOptions) { - return new Subscription({ - channels: (subscriptionOptions === null || subscriptionOptions === void 0 ? void 0 : subscriptionOptions.receivePresenceEvents) ? [this.name, "".concat(this.name, "-pnpres")] : [this.name], - channelGroups: [], - subscriptionOptions: subscriptionOptions, - eventEmitter: this.eventEmitter, - pubnub: this.pubnub, - }); - }; - return Channel; - }()); - - var ChannelGroup = /** @class */ (function () { - function ChannelGroup(channelGroup, eventEmitter, pubnub) { - this.name = channelGroup; - this.eventEmitter = eventEmitter; - this.pubnub = pubnub; + return ReceivingState.with({ + cursor: context.cursor, + channels: event.payload.channels, + groups: event.payload.groups, + }); + }); + ReceivingState.on(restore.type, function (context, event) { + if (event.payload.channels.length === 0 && event.payload.groups.length === 0) { + return UnsubscribedState.with(undefined); } - ChannelGroup.prototype.subscription = function (subscriptionOptions) { - return new Subscription({ - channels: [], - channelGroups: (subscriptionOptions === null || subscriptionOptions === void 0 ? void 0 : subscriptionOptions.receivePresenceEvents) ? [this.name, "".concat(this.name, "-pnpres")] : [this.name], - subscriptionOptions: subscriptionOptions, - eventEmitter: this.eventEmitter, - pubnub: this.pubnub, - }); - }; - return ChannelGroup; - }()); + return ReceivingState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: { + timetoken: event.payload.cursor.timetoken, + region: event.payload.cursor.region || context.cursor.region, + }, + }); + }); + ReceivingState.on(receiveFailure.type, function (context, event) { + return ReceiveReconnectingState.with(__assign(__assign({}, context), { attempts: 0, reason: event.payload })); + }); + ReceivingState.on(disconnect.type, function (context) { + return ReceiveStoppedState.with({ + channels: context.channels, + groups: context.groups, + cursor: context.cursor, + }, [emitStatus({ category: StatusCategory$1.PNDisconnectedCategory })]); + }); + ReceivingState.on(unsubscribeAll.type, function (_) { + return UnsubscribedState.with(undefined, [emitStatus({ category: StatusCategory$1.PNDisconnectedCategory })]); + }); - var ChannelMetadata = /** @class */ (function () { - function ChannelMetadata(id, eventEmitter, pubnub) { - this.id = id; - this.eventEmitter = eventEmitter; - this.pubnub = pubnub; - } - ChannelMetadata.prototype.subscription = function (subscriptionOptions) { - return new Subscription({ - channels: [this.id], - channelGroups: [], - subscriptionOptions: subscriptionOptions, - eventEmitter: this.eventEmitter, - pubnub: this.pubnub, - }); + var HandshakeReconnectingState = new State('HANDSHAKE_RECONNECTING'); + HandshakeReconnectingState.onEnter(function (context) { return handshakeReconnect(context); }); + HandshakeReconnectingState.onExit(function () { return handshakeReconnect.cancel; }); + HandshakeReconnectingState.on(handshakeReconnectSuccess.type, function (context, event) { + var _a, _b; + var cursor = { + timetoken: !!((_a = context.cursor) === null || _a === void 0 ? void 0 : _a.timetoken) ? (_b = context.cursor) === null || _b === void 0 ? void 0 : _b.timetoken : event.payload.cursor.timetoken, + region: event.payload.cursor.region, }; - return ChannelMetadata; - }()); + return ReceivingState.with({ + channels: context.channels, + groups: context.groups, + cursor: cursor, + }, [emitStatus({ category: StatusCategory$1.PNConnectedCategory })]); + }); + HandshakeReconnectingState.on(handshakeReconnectFailure.type, function (context, event) { + return HandshakeReconnectingState.with(__assign(__assign({}, context), { attempts: context.attempts + 1, reason: event.payload })); + }); + HandshakeReconnectingState.on(handshakeReconnectGiveup.type, function (context, event) { + var _a; + return HandshakeFailedState.with({ + groups: context.groups, + channels: context.channels, + cursor: context.cursor, + reason: event.payload, + }, [emitStatus({ category: StatusCategory$1.PNConnectionErrorCategory, error: (_a = event.payload) === null || _a === void 0 ? void 0 : _a.message })]); + }); + HandshakeReconnectingState.on(disconnect.type, function (context) { + return HandshakeStoppedState.with({ + channels: context.channels, + groups: context.groups, + cursor: context.cursor, + }); + }); + HandshakeReconnectingState.on(subscriptionChange.type, function (context, event) { + return HandshakingState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: context.cursor, + }); + }); + HandshakeReconnectingState.on(restore.type, function (context, event) { + var _a, _b; + return HandshakingState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: { + timetoken: event.payload.cursor.timetoken, + region: ((_a = event.payload.cursor) === null || _a === void 0 ? void 0 : _a.region) || ((_b = context === null || context === void 0 ? void 0 : context.cursor) === null || _b === void 0 ? void 0 : _b.region) || 0, + }, + }); + }); + HandshakeReconnectingState.on(unsubscribeAll.type, function (_) { return UnsubscribedState.with(undefined); }); - var UserMetadata = /** @class */ (function () { - function UserMetadata(id, eventEmitter, pubnub) { - this.id = id; - this.eventEmitter = eventEmitter; - this.pubnub = pubnub; + var HandshakingState = new State('HANDSHAKING'); + HandshakingState.onEnter(function (context) { return handshake(context.channels, context.groups); }); + HandshakingState.onExit(function () { return handshake.cancel; }); + HandshakingState.on(subscriptionChange.type, function (context, event) { + if (event.payload.channels.length === 0 && event.payload.groups.length === 0) { + return UnsubscribedState.with(undefined); } - UserMetadata.prototype.subscription = function (subscriptionOptions) { - return new Subscription({ - channels: [this.id], - channelGroups: [], - subscriptionOptions: subscriptionOptions, - eventEmitter: this.eventEmitter, - pubnub: this.pubnub, - }); - }; - return UserMetadata; - }()); + return HandshakingState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: context.cursor, + }); + }); + HandshakingState.on(handshakeSuccess.type, function (context, event) { + var _a, _b; + return ReceivingState.with({ + channels: context.channels, + groups: context.groups, + cursor: { + timetoken: !!((_a = context === null || context === void 0 ? void 0 : context.cursor) === null || _a === void 0 ? void 0 : _a.timetoken) ? (_b = context === null || context === void 0 ? void 0 : context.cursor) === null || _b === void 0 ? void 0 : _b.timetoken : event.payload.timetoken, + region: event.payload.region, + }, + }, [ + emitStatus({ + category: StatusCategory$1.PNConnectedCategory, + }), + ]); + }); + HandshakingState.on(handshakeFailure.type, function (context, event) { + return HandshakeReconnectingState.with({ + channels: context.channels, + groups: context.groups, + cursor: context.cursor, + attempts: 0, + reason: event.payload, + }); + }); + HandshakingState.on(disconnect.type, function (context) { + return HandshakeStoppedState.with({ + channels: context.channels, + groups: context.groups, + cursor: context.cursor, + }); + }); + HandshakingState.on(restore.type, function (context, event) { + var _a; + return HandshakingState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: { + timetoken: event.payload.cursor.timetoken, + region: event.payload.cursor.region || ((_a = context === null || context === void 0 ? void 0 : context.cursor) === null || _a === void 0 ? void 0 : _a.region) || 0, + }, + }); + }); + HandshakingState.on(unsubscribeAll.type, function (_) { return UnsubscribedState.with(); }); - var default_1$3 = /** @class */ (function () { - function default_1(setup) { + var UnsubscribedState = new State('UNSUBSCRIBED'); + UnsubscribedState.on(subscriptionChange.type, function (_, event) { + return HandshakingState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + }); + }); + UnsubscribedState.on(restore.type, function (_, event) { + return HandshakingState.with({ + channels: event.payload.channels, + groups: event.payload.groups, + cursor: event.payload.cursor, + }); + }); + + var EventEngine = /** @class */ (function () { + function EventEngine(dependencies) { var _this = this; - var networking = setup.networking, cbor = setup.cbor; - var config = new default_1$b({ setup: setup }); - this._config = config; - var crypto = new default_1$a({ config: config }); // LEGACY - var cryptography = setup.cryptography; - networking.init(config); - var tokenManager = new default_1$4(config, cbor); - this._tokenManager = tokenManager; - var telemetryManager = new default_1$6({ - maximumSamplesCount: 60000, - }); - this._telemetryManager = telemetryManager; - var cryptoModule = this._config.cryptoModule; - var modules = { - config: config, - networking: networking, - crypto: crypto, - cryptography: cryptography, - tokenManager: tokenManager, - telemetryManager: telemetryManager, - PubNubFile: setup.PubNubFile, - cryptoModule: cryptoModule, - }; - this.File = setup.PubNubFile; - this.encryptFile = function (key, file) { - if (arguments.length == 1 && typeof key != 'string' && modules.cryptoModule) { - file = key; - return modules.cryptoModule.encryptFile(file, this.File); - } - return cryptography.encryptFile(key, file, this.File); - }; - this.decryptFile = function (key, file) { - if (arguments.length == 1 && typeof key != 'string' && modules.cryptoModule) { - file = key; - return modules.cryptoModule.decryptFile(file, this.File); - } - return cryptography.decryptFile(key, file, this.File); - }; - var timeEndpoint = endpointCreator.bind(this, modules, timeEndpointConfig); - var leaveEndpoint = endpointCreator.bind(this, modules, presenceLeaveEndpointConfig); - var heartbeatEndpoint = endpointCreator.bind(this, modules, presenceHeartbeatEndpointConfig); - var setStateEndpoint = endpointCreator.bind(this, modules, presenceSetStateConfig); - var subscribeEndpoint = endpointCreator.bind(this, modules, subscribeEndpointConfig); - // managers - var listenerManager = new default_1$5(); - this._listenerManager = listenerManager; - this.iAmHere = endpointCreator.bind(this, modules, presenceHeartbeatEndpointConfig); - this.iAmAway = endpointCreator.bind(this, modules, presenceLeaveEndpointConfig); - this.setPresenceState = endpointCreator.bind(this, modules, presenceSetStateConfig); - this.handshake = endpointCreator.bind(this, modules, endpoint$1); - this.receiveMessages = endpointCreator.bind(this, modules, endpoint); - this._eventEmitter = new EventEmitter({ - modules: modules, - listenerManager: this._listenerManager, - getFileUrl: function (params) { return getFileUrlFunction(modules, params); }, - }); - if (config.enableEventEngine === true) { - if (config.maintainPresenceState) { - this.presenceState = {}; - this.setState = function (args) { - var _a, _b; - (_a = args.channels) === null || _a === void 0 ? void 0 : _a.forEach(function (channel) { return (_this.presenceState[channel] = args.state); }); - (_b = args.channelGroups) === null || _b === void 0 ? void 0 : _b.forEach(function (group) { return (_this.presenceState[group] = args.state); }); - return _this.setPresenceState({ - channels: args.channels, - channelGroups: args.channelGroups, - state: _this.presenceState, - }); - }; - } - if (config.getHeartbeatInterval()) { - var presenceEventEngine = new PresenceEventEngine({ - heartbeat: this.iAmHere, - leave: this.iAmAway, - heartbeatDelay: function () { - return new Promise(function (resolve) { return setTimeout(resolve, modules.config.getHeartbeatInterval() * 1000); }); - }, - retryDelay: function (amount) { return new Promise(function (resolve) { return setTimeout(resolve, amount); }); }, - config: modules.config, - presenceState: this.presenceState, - emitStatus: function (status) { - listenerManager.announceStatus(status); - }, - }); - this.presenceEventEngine = presenceEventEngine; - this.join = this.presenceEventEngine.join.bind(presenceEventEngine); - this.leave = this.presenceEventEngine.leave.bind(presenceEventEngine); - this.leaveAll = this.presenceEventEngine.leaveAll.bind(presenceEventEngine); + this.engine = new Engine(); + this.channels = []; + this.groups = []; + this.dependencies = dependencies; + this.dispatcher = new EventEngineDispatcher(this.engine, dependencies); + this._unsubscribeEngine = this.engine.subscribe(function (change) { + if (change.type === 'invocationDispatched') { + _this.dispatcher.dispatch(change.invocation); } - var eventEngine = new EventEngine({ - handshake: this.handshake, - receiveMessages: this.receiveMessages, - delay: function (amount) { return new Promise(function (resolve) { return setTimeout(resolve, amount); }); }, - join: this.join, - leave: this.leave, - leaveAll: this.leaveAll, - presenceState: this.presenceState, - config: modules.config, - emitMessages: function (events) { - var e_1, _a; - try { - for (var events_1 = __values(events), events_1_1 = events_1.next(); !events_1_1.done; events_1_1 = events_1.next()) { - var event_1 = events_1_1.value; - _this._eventEmitter.emitEvent(event_1); - } - } - catch (e_1_1) { e_1 = { error: e_1_1 }; } - finally { - try { - if (events_1_1 && !events_1_1.done && (_a = events_1.return)) _a.call(events_1); - } - finally { if (e_1) throw e_1.error; } - } - }, - emitStatus: function (status) { - listenerManager.announceStatus(status); - }, - }); - this.subscribe = eventEngine.subscribe.bind(eventEngine); - this.unsubscribe = eventEngine.unsubscribe.bind(eventEngine); - this.unsubscribeAll = eventEngine.unsubscribeAll.bind(eventEngine); - this.reconnect = eventEngine.reconnect.bind(eventEngine); - this.disconnect = eventEngine.disconnect.bind(eventEngine); - this.destroy = eventEngine.dispose.bind(eventEngine); - this.getSubscribedChannels = eventEngine.getSubscribedChannels.bind(eventEngine); - this.getSubscribedChannelGroups = eventEngine.getSubscribedChannelGroups.bind(eventEngine); - this.eventEngine = eventEngine; + }); + this.engine.start(UnsubscribedState, undefined); + } + Object.defineProperty(EventEngine.prototype, "_engine", { + get: function () { + return this.engine; + }, + enumerable: false, + configurable: true + }); + EventEngine.prototype.subscribe = function (_a) { + var _this = this; + var channels = _a.channels, channelGroups = _a.channelGroups, timetoken = _a.timetoken, withPresence = _a.withPresence; + this.channels = __spreadArray(__spreadArray([], __read(this.channels), false), __read((channels !== null && channels !== void 0 ? channels : [])), false); + this.groups = __spreadArray(__spreadArray([], __read(this.groups), false), __read((channelGroups !== null && channelGroups !== void 0 ? channelGroups : [])), false); + if (withPresence) { + this.channels.map(function (c) { return _this.channels.push("".concat(c, "-pnpres")); }); + this.groups.map(function (g) { return _this.groups.push("".concat(g, "-pnpres")); }); + } + if (timetoken) { + this.engine.transition(restore(Array.from(new Set(__spreadArray(__spreadArray([], __read(this.channels), false), __read((channels !== null && channels !== void 0 ? channels : [])), false))), Array.from(new Set(__spreadArray(__spreadArray([], __read(this.groups), false), __read((channelGroups !== null && channelGroups !== void 0 ? channelGroups : [])), false))), timetoken)); } else { - var subscriptionManager_1 = new default_1$7({ - timeEndpoint: timeEndpoint, - leaveEndpoint: leaveEndpoint, - heartbeatEndpoint: heartbeatEndpoint, - setStateEndpoint: setStateEndpoint, - subscribeEndpoint: subscribeEndpoint, - crypto: modules.crypto, - config: modules.config, - listenerManager: listenerManager, - getFileUrl: function (params) { return getFileUrlFunction(modules, params); }, - cryptoModule: modules.cryptoModule, - eventEmitter: this._eventEmitter, - }); - this.subscribe = subscriptionManager_1.adaptSubscribeChange.bind(subscriptionManager_1); - this.unsubscribe = subscriptionManager_1.adaptUnsubscribeChange.bind(subscriptionManager_1); - this.disconnect = subscriptionManager_1.disconnect.bind(subscriptionManager_1); - this.reconnect = subscriptionManager_1.reconnect.bind(subscriptionManager_1); - this.unsubscribeAll = subscriptionManager_1.unsubscribeAll.bind(subscriptionManager_1); - this.getSubscribedChannels = subscriptionManager_1.getSubscribedChannels.bind(subscriptionManager_1); - this.getSubscribedChannelGroups = subscriptionManager_1.getSubscribedChannelGroups.bind(subscriptionManager_1); - this.setState = subscriptionManager_1.adaptStateChange.bind(subscriptionManager_1); - this.presence = subscriptionManager_1.adaptPresenceChange.bind(subscriptionManager_1); - this.destroy = function (isOffline) { - subscriptionManager_1.unsubscribeAll(isOffline); - subscriptionManager_1.disconnect(); - }; + this.engine.transition(subscriptionChange(Array.from(new Set(__spreadArray(__spreadArray([], __read(this.channels), false), __read((channels !== null && channels !== void 0 ? channels : [])), false))), Array.from(new Set(__spreadArray(__spreadArray([], __read(this.groups), false), __read((channelGroups !== null && channelGroups !== void 0 ? channelGroups : [])), false))))); } - this.addListener = this._eventEmitter.addListener.bind(this._eventEmitter); - this.removeListener = this._eventEmitter.removeListener.bind(this._eventEmitter); - this.removeAllListeners = this._eventEmitter.removeAllListeners.bind(this._eventEmitter); - this.parseToken = tokenManager.parseToken.bind(tokenManager); - this.setToken = tokenManager.setToken.bind(tokenManager); - this.getToken = tokenManager.getToken.bind(tokenManager); - /* channel groups */ - this.channelGroups = { - listGroups: endpointCreator.bind(this, modules, listChannelGroupsConfig), - listChannels: endpointCreator.bind(this, modules, listChannelsInChannelGroupConfig), - addChannels: endpointCreator.bind(this, modules, addChannelsChannelGroupConfig), - removeChannels: endpointCreator.bind(this, modules, removeChannelsChannelGroupConfig), - deleteGroup: endpointCreator.bind(this, modules, deleteChannelGroupConfig), - }; - /* push */ - this.push = { - addChannels: endpointCreator.bind(this, modules, addPushChannelsConfig), - removeChannels: endpointCreator.bind(this, modules, removePushChannelsConfig), - deleteDevice: endpointCreator.bind(this, modules, removeDevicePushConfig), - listChannels: endpointCreator.bind(this, modules, listPushChannelsConfig), - }; - /* presence */ - this.hereNow = endpointCreator.bind(this, modules, presenceHereNowConfig); - this.whereNow = endpointCreator.bind(this, modules, presenceWhereNowEndpointConfig); - this.getState = endpointCreator.bind(this, modules, presenceGetStateConfig); - /* PAM */ - this.grant = endpointCreator.bind(this, modules, grantEndpointConfig); - this.grantToken = endpointCreator.bind(this, modules, grantTokenEndpointConfig); - this.audit = endpointCreator.bind(this, modules, auditEndpointConfig); - this.revokeToken = endpointCreator.bind(this, modules, endpoint$2); - this.publish = endpointCreator.bind(this, modules, publishEndpointConfig); - this.fire = function (args, callback) { - args.replicate = false; - args.storeInHistory = false; - return _this.publish(args, callback); - }; - this.signal = endpointCreator.bind(this, modules, signalEndpointConfig); - this.history = endpointCreator.bind(this, modules, historyEndpointConfig); - this.deleteMessages = endpointCreator.bind(this, modules, deleteMessagesEndpointConfig); - this.messageCounts = endpointCreator.bind(this, modules, messageCountsEndpointConfig); - this.fetchMessages = endpointCreator.bind(this, modules, fetchMessagesEndpointConfig); - // Actions API - this.addMessageAction = endpointCreator.bind(this, modules, addMessageActionEndpointConfig); - this.removeMessageAction = endpointCreator.bind(this, modules, removeMessageActionEndpointConfig); - this.getMessageActions = endpointCreator.bind(this, modules, getMessageActionEndpointConfig); - // File Upload API v1 - this.listFiles = endpointCreator.bind(this, modules, endpoint$j); - var generateUploadUrl = endpointCreator.bind(this, modules, endpoint$i); - this.publishFile = endpointCreator.bind(this, modules, endpoint$h); - this.sendFile = sendFileFunction({ - generateUploadUrl: generateUploadUrl, - publishFile: this.publishFile, - modules: modules, - }); - this.getFileUrl = function (params) { return getFileUrlFunction(modules, params); }; - this.downloadFile = endpointCreator.bind(this, modules, endpoint$g); - this.deleteFile = endpointCreator.bind(this, modules, endpoint$f); - // entities - this.channel = function (name) { return new Channel(name, _this._eventEmitter, _this); }; - this.channelGroup = function (name) { return new ChannelGroup(name, _this._eventEmitter, _this); }; - this.channelMetadata = function (id) { return new ChannelMetadata(id, _this._eventEmitter, _this); }; - this.userMetadata = function (id) { return new UserMetadata(id, _this._eventEmitter, _this); }; - this.subscriptionSet = function (args) { - return new SubscriptionSet({ - channels: args.channels, - channelGroups: args.channelGroups, - subscriptionOptions: args.subscriptionOptions, - eventEmitter: _this._eventEmitter, - pubnub: _this, - }); - }; - // Objects API v2 - this.objects = { - getAllUUIDMetadata: endpointCreator.bind(this, modules, endpoint$e), - getUUIDMetadata: endpointCreator.bind(this, modules, endpoint$d), - setUUIDMetadata: endpointCreator.bind(this, modules, endpoint$c), - removeUUIDMetadata: endpointCreator.bind(this, modules, endpoint$b), - getAllChannelMetadata: endpointCreator.bind(this, modules, endpoint$a), - getChannelMetadata: endpointCreator.bind(this, modules, endpoint$9), - setChannelMetadata: endpointCreator.bind(this, modules, endpoint$8), - removeChannelMetadata: endpointCreator.bind(this, modules, endpoint$7), - getChannelMembers: endpointCreator.bind(this, modules, endpoint$6), - setChannelMembers: function (parameters) { - var rest = []; - for (var _i = 1; _i < arguments.length; _i++) { - rest[_i - 1] = arguments[_i]; - } - return endpointCreator.call.apply(endpointCreator, __spreadArray$1([_this, - modules, - endpoint$5, __assign({ type: 'set' }, parameters)], __read$1(rest), false)); - }, - removeChannelMembers: function (parameters) { - var rest = []; - for (var _i = 1; _i < arguments.length; _i++) { - rest[_i - 1] = arguments[_i]; - } - return endpointCreator.call.apply(endpointCreator, __spreadArray$1([_this, - modules, - endpoint$5, __assign({ type: 'delete' }, parameters)], __read$1(rest), false)); - }, - getMemberships: endpointCreator.bind(this, modules, endpoint$4), - setMemberships: function (parameters) { - var rest = []; - for (var _i = 1; _i < arguments.length; _i++) { - rest[_i - 1] = arguments[_i]; - } - return endpointCreator.call.apply(endpointCreator, __spreadArray$1([_this, - modules, - endpoint$3, __assign({ type: 'set' }, parameters)], __read$1(rest), false)); - }, - removeMemberships: function (parameters) { - var rest = []; - for (var _i = 1; _i < arguments.length; _i++) { - rest[_i - 1] = arguments[_i]; - } - return endpointCreator.call.apply(endpointCreator, __spreadArray$1([_this, - modules, - endpoint$3, __assign({ type: 'delete' }, parameters)], __read$1(rest), false)); - }, - }; - // User Apis - this.createUser = function (args) { - return _this.objects.setUUIDMetadata({ - uuid: args.userId, - data: args.data, - include: args.include, - }); - }; - this.updateUser = this.createUser; - this.removeUser = function (args) { - return _this.objects.removeUUIDMetadata({ - uuid: args === null || args === void 0 ? void 0 : args.userId, - }); - }; - this.fetchUser = function (args) { - return _this.objects.getUUIDMetadata({ - uuid: args === null || args === void 0 ? void 0 : args.userId, - include: args === null || args === void 0 ? void 0 : args.include, - }); - }; - this.fetchUsers = this.objects.getAllUUIDMetadata; - // Space apis - this.createSpace = function (args) { - return _this.objects.setChannelMetadata({ - channel: args.spaceId, - data: args.data, - include: args.include, - }); - }; - this.updateSpace = this.createSpace; - this.removeSpace = function (args) { - return _this.objects.removeChannelMetadata({ - channel: args.spaceId, - }); - }; - this.fetchSpace = function (args) { - return _this.objects.getChannelMetadata({ - channel: args.spaceId, - include: args.include, + if (this.dependencies.join) { + this.dependencies.join({ + channels: Array.from(new Set(this.channels.filter(function (c) { return !c.endsWith('-pnpres'); }))), + groups: Array.from(new Set(this.groups.filter(function (g) { return !g.endsWith('-pnpres'); }))), }); - }; - this.fetchSpaces = this.objects.getAllChannelMetadata; - // Membership apis - this.addMemberships = function (parameters) { - var _a, _b; - if (typeof parameters.spaceId === 'string') { - return _this.objects.setChannelMembers({ - channel: parameters.spaceId, - uuids: (_a = parameters.users) === null || _a === void 0 ? void 0 : _a.map(function (user) { - if (typeof user === 'string') { - return user; - } - return { - id: user.userId, - custom: user.custom, - status: user.status, - }; - }), - limit: 0, - }); - } - else { - return _this.objects.setMemberships({ - uuid: parameters.userId, - channels: (_b = parameters.spaces) === null || _b === void 0 ? void 0 : _b.map(function (space) { - if (typeof space === 'string') { - return space; - } - return { - id: space.spaceId, - custom: space.custom, - status: space.status, - }; - }), - limit: 0, - }); - } - }; - this.updateMemberships = this.addMemberships; - this.removeMemberships = function (parameters) { - if (typeof parameters.spaceId === 'string') { - return _this.objects.removeChannelMembers({ - channel: parameters.spaceId, - uuids: parameters.userIds, - limit: 0, - }); + } + }; + EventEngine.prototype.unsubscribe = function (_a) { + var _this = this; + var _b = _a.channels, channels = _b === void 0 ? [] : _b, _c = _a.channelGroups, channelGroups = _c === void 0 ? [] : _c; + var filteredChannels = removeSingleOccurance(this.channels, __spreadArray(__spreadArray([], __read(channels), false), __read(channels.map(function (c) { return "".concat(c, "-pnpres"); })), false)); + var filteredGroups = removeSingleOccurance(this.groups, __spreadArray(__spreadArray([], __read(channelGroups), false), __read(channelGroups.map(function (c) { return "".concat(c, "-pnpres"); })), false)); + if (new Set(this.channels).size !== new Set(filteredChannels).size || + new Set(this.groups).size !== new Set(filteredGroups).size) { + var channelsToLeave = findUniqueCommonElements(this.channels, channels); + var groupstoLeave = findUniqueCommonElements(this.groups, channelGroups); + if (this.dependencies.presenceState) { + channelsToLeave === null || channelsToLeave === void 0 ? void 0 : channelsToLeave.forEach(function (c) { return delete _this.dependencies.presenceState[c]; }); + groupstoLeave === null || groupstoLeave === void 0 ? void 0 : groupstoLeave.forEach(function (g) { return delete _this.dependencies.presenceState[g]; }); } - else { - return _this.objects.removeMemberships({ - uuid: parameters.userId, - channels: parameters.spaceIds, - limit: 0, + this.channels = filteredChannels; + this.groups = filteredGroups; + this.engine.transition(subscriptionChange(Array.from(new Set(this.channels.slice(0))), Array.from(new Set(this.groups.slice(0))))); + if (this.dependencies.leave) { + this.dependencies.leave({ + channels: channelsToLeave.slice(0), + groups: groupstoLeave.slice(0), }); } - }; - this.fetchMemberships = function (params) { - if (typeof params.spaceId === 'string') { - return _this.objects - .getChannelMembers({ - channel: params.spaceId, - filter: params.filter, - limit: params.limit, - page: params.page, - include: { - customFields: params.include.customFields, - UUIDFields: params.include.userFields, - customUUIDFields: params.include.customUserFields, - statusField: params.include.statusField, - UUIDStatusField: params.include.userStatusField, - UUIDTypeField: params.include.userTypeField, - totalCount: params.include.totalCount, - }, - sort: params.sort != null - ? Object.fromEntries(Object.entries(params.sort).map(function (_a) { - var _b = __read$1(_a, 2), k = _b[0], v = _b[1]; - return [k.replace('user', 'uuid'), v]; - })) - : null, - }) - .then(function (res) { - var _a; - res.data = (_a = res.data) === null || _a === void 0 ? void 0 : _a.map(function (m) { - return { - user: m.uuid, - custom: m.custom, - updated: m.updated, - eTag: m.eTag, - }; - }); - return res; - }); - } - else { - return _this.objects - .getMemberships({ - uuid: params.userId, - filter: params.filter, - limit: params.limit, - page: params.page, - include: { - customFields: params.include.customFields, - channelFields: params.include.spaceFields, - customChannelFields: params.include.customSpaceFields, - statusField: params.include.statusField, - channelStatusField: params.include.spaceStatusField, - channelTypeField: params.include.spaceTypeField, - totalCount: params.include.totalCount, - }, - sort: params.sort != null - ? Object.fromEntries(Object.entries(params.sort).map(function (_a) { - var _b = __read$1(_a, 2), k = _b[0], v = _b[1]; - return [k.replace('space', 'channel'), v]; - })) - : null, - }) - .then(function (res) { - var _a; - res.data = (_a = res.data) === null || _a === void 0 ? void 0 : _a.map(function (m) { - return { - space: m.channel, - custom: m.custom, - updated: m.updated, - eTag: m.eTag, - }; - }); - return res; - }); - } - }; - this.time = timeEndpoint; - // --- deprecated ------------------ - this.stop = this.destroy; // -------- - // --- deprecated ------------------ - // mount crypto - this.encrypt = function (data, key) { - if (typeof key === 'undefined' && modules.cryptoModule) { - var encrypted = modules.cryptoModule.encrypt(data); - return typeof encrypted === 'string' ? encrypted : encode$1(encrypted); - } - else { - return crypto.encrypt(data, key); - } - }; - this.decrypt = function (data, key) { - if (typeof key === 'undefined' && cryptoModule) { - var decrypted = modules.cryptoModule.decrypt(data); - return decrypted instanceof ArrayBuffer ? JSON.parse(new TextDecoder().decode(decrypted)) : decrypted; - } - else { - return crypto.decrypt(data, key); - } - }; - /* config */ - this.getAuthKey = modules.config.getAuthKey.bind(modules.config); - this.setAuthKey = modules.config.setAuthKey.bind(modules.config); - this.getUUID = modules.config.getUUID.bind(modules.config); - this.setUUID = modules.config.setUUID.bind(modules.config); - this.getUserId = modules.config.getUserId.bind(modules.config); - this.setUserId = modules.config.setUserId.bind(modules.config); - this.getFilterExpression = modules.config.getFilterExpression.bind(modules.config); - this.setFilterExpression = modules.config.setFilterExpression.bind(modules.config); - this.setCipherKey = function (key) { return modules.config.setCipherKey(key, setup, modules); }; - this.setHeartbeatInterval = modules.config.setHeartbeatInterval.bind(modules.config); - if (networking.hasModule('proxy')) { - this.setProxy = function (proxy) { - modules.config.setProxy(proxy); - _this.reconnect(); - }; } - } - default_1.prototype.getVersion = function () { - return this._config.getVersion(); - }; - default_1.prototype._addPnsdkSuffix = function (name, suffix) { - this._config._addPnsdkSuffix(name, suffix); }; - // network hooks to indicate network changes - default_1.prototype.networkDownDetected = function () { - this._listenerManager.announceNetworkDown(); - if (this._config.restore) { - this.disconnect(); + EventEngine.prototype.unsubscribeAll = function () { + this.channels = []; + this.groups = []; + if (this.dependencies.presenceState) { + this.dependencies.presenceState = {}; } - else { - this.destroy(true); + this.engine.transition(subscriptionChange(this.channels.slice(0), this.groups.slice(0))); + if (this.dependencies.leaveAll) { + this.dependencies.leaveAll(); } }; - default_1.prototype.networkUpDetected = function () { - this._listenerManager.announceNetworkUp(); - this.reconnect(); + EventEngine.prototype.reconnect = function (_a) { + var timetoken = _a.timetoken, region = _a.region; + this.engine.transition(reconnect(timetoken, region)); }; - default_1.notificationPayload = function (title, body) { - return new NotificationsPayload(title, body); + EventEngine.prototype.disconnect = function () { + this.engine.transition(disconnect()); + if (this.dependencies.leaveAll) { + this.dependencies.leaveAll(); + } }; - default_1.generateUUID = function () { - return uuidGenerator.createUUID(); + EventEngine.prototype.getSubscribedChannels = function () { + return Array.from(new Set(this.channels.slice(0))); }; - default_1.OPERATIONS = OPERATIONS; - default_1.CATEGORIES = categories; - default_1.LinearRetryPolicy = RetryPolicy.LinearRetryPolicy; - default_1.ExponentialRetryPolicy = RetryPolicy.ExponentialRetryPolicy; - return default_1; + EventEngine.prototype.getSubscribedChannelGroups = function () { + return Array.from(new Set(this.groups.slice(0))); + }; + EventEngine.prototype.dispose = function () { + this.disconnect(); + this._unsubscribeEngine(); + this.dispatcher.dispose(); + }; + return EventEngine; }()); - /* */ - var default_1$2 = /** @class */ (function () { - function default_1(modules) { - var _this = this; - this._modules = {}; - Object.keys(modules).forEach(function (key) { - _this._modules[key] = modules[key].bind(_this); - }); + /** + * Publish REST API module. + */ + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults + /** + * Whether published data should be stored in history or not. + */ + var STORE_IN_HISTORY$1 = true; + /** + * Whether data is published used `POST` body or not. + */ + var SEND_BY_POST = false; + /** + * Whether published data should be replicated across all data centers or not. + */ + var SHOULD_REPLICATE = true; + // endregion + /** + * Data publish request. + * + * Request will normalize and encrypt (if required) provided data and push it to the specified + * channel. + */ + var PublishRequest = /** @class */ (function (_super) { + __extends(PublishRequest, _super); + /** + * Construct data publish request. + * + * @param parameters - Request configuration. + */ + function PublishRequest(parameters) { + var _a, _b, _c; + var _d, _e, _f; + var _this = _super.call(this, { method: parameters.sendByPost ? TransportMethod.POST : TransportMethod.GET }) || this; + _this.parameters = parameters; + // Apply default request parameters. + (_a = (_d = _this.parameters).storeInHistory) !== null && _a !== void 0 ? _a : (_d.storeInHistory = STORE_IN_HISTORY$1); + (_b = (_e = _this.parameters).sendByPost) !== null && _b !== void 0 ? _b : (_e.sendByPost = SEND_BY_POST); + // Apply defaults to the deprecated parameter. + (_c = (_f = _this.parameters).replicate) !== null && _c !== void 0 ? _c : (_f.replicate = SHOULD_REPLICATE); + return _this; } - default_1.prototype.init = function (config) { - this._config = config; - if (Array.isArray(this._config.origin)) { - this._currentSubDomain = Math.floor(Math.random() * this._config.origin.length); - } - else { - this._currentSubDomain = 0; - } - this._coreParams = {}; - // create initial origins - this.shiftStandardOrigin(); - }; - default_1.prototype.nextOrigin = function () { - var protocol = this._config.secure ? 'https://' : 'http://'; - if (typeof this._config.origin === 'string') { - return "".concat(protocol).concat(this._config.origin); - } - this._currentSubDomain += 1; - if (this._currentSubDomain >= this._config.origin.length) { - this._currentSubDomain = 0; - } - var origin = this._config.origin[this._currentSubDomain]; - return "".concat(protocol).concat(origin); + PublishRequest.prototype.operation = function () { + return RequestOperation$1.PNPublishOperation; }; - default_1.prototype.hasModule = function (name) { - return name in this._modules; + PublishRequest.prototype.validate = function () { + var _a = this.parameters, message = _a.message, channel = _a.channel, publishKey = _a.keySet.publishKey; + if (!channel) + return "Missing 'channel''"; + if (!message) + return "Missing 'message'"; + if (!publishKey) + return "Missing 'publishKey'"; }; - // origin operations - default_1.prototype.shiftStandardOrigin = function () { - this._standardOrigin = this.nextOrigin(); - return this._standardOrigin; - }; - default_1.prototype.getStandardOrigin = function () { - return this._standardOrigin; - }; - default_1.prototype.POSTFILE = function (url, fields, file) { - return this._modules.postfile(url, fields, file); + PublishRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, { timetoken: serviceResponse[2] }]; + }); + }); }; - default_1.prototype.GETFILE = function (params, endpoint, callback) { - return this._modules.getfile(params, endpoint, callback); + Object.defineProperty(PublishRequest.prototype, "path", { + get: function () { + var _a = this.parameters, message = _a.message, channel = _a.channel, keySet = _a.keySet; + var stringifiedPayload = this.prepareMessagePayload(message); + return "/publish/".concat(keySet.publishKey, "/").concat(keySet.subscribeKey, "/0/").concat(encodeString(channel), "/0").concat(!this.parameters.sendByPost ? "/".concat(encodeString(stringifiedPayload)) : ''); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(PublishRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, meta = _a.meta, replicate = _a.replicate, storeInHistory = _a.storeInHistory, ttl = _a.ttl; + return __assign(__assign(__assign({ store: storeInHistory ? '1' : '0' }, (ttl !== undefined ? { ttl: ttl } : {})), (!replicate ? { norep: 'true' } : {})), (meta && typeof meta === 'object' ? { meta: JSON.stringify(meta) } : {})); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(PublishRequest.prototype, "body", { + get: function () { + return this.prepareMessagePayload(this.parameters.message); + }, + enumerable: false, + configurable: true + }); + /** + * Pre-process provided data. + * + * Data will be "normalized" and encrypted if `cryptoModule` has been provided. + * + * @param payload - User-provided data which should be pre-processed before use. + * + * @returns Payload which can be used as part of request URL or body. + * + * @throws {Error} in case if provided `payload` or results of `encryption` can't be stringified. + */ + PublishRequest.prototype.prepareMessagePayload = function (payload) { + var crypto = this.parameters.crypto; + if (!crypto) + return JSON.stringify(payload) || ''; + var encrypted = crypto.encrypt(JSON.stringify(payload)); + return JSON.stringify(typeof encrypted === 'string' ? encrypted : encode(encrypted)); }; - default_1.prototype.POST = function (params, body, endpoint, callback) { - return this._modules.post(params, body, endpoint, callback); + return PublishRequest; + }(AbstractRequest)); + + /** + * Signal REST API module. + */ + // endregion + var SignalRequest = /** @class */ (function (_super) { + __extends(SignalRequest, _super); + function SignalRequest(parameters) { + var _this = _super.call(this) || this; + _this.parameters = parameters; + return _this; + } + SignalRequest.prototype.operation = function () { + return RequestOperation$1.PNSignalOperation; }; - default_1.prototype.PATCH = function (params, body, endpoint, callback) { - return this._modules.patch(params, body, endpoint, callback); + SignalRequest.prototype.validate = function () { + var _a = this.parameters, message = _a.message, channel = _a.channel, publishKey = _a.keySet.publishKey; + if (!channel) + return "Missing 'channel''"; + if (!message) + return "Missing 'message'"; + if (!publishKey) + return "Missing 'publishKey'"; }; - default_1.prototype.GET = function (params, endpoint, callback) { - return this._modules.get(params, endpoint, callback); + SignalRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, { timetoken: serviceResponse[2] }]; + }); + }); }; - default_1.prototype.DELETE = function (params, endpoint, callback) { - return this._modules.del(params, endpoint, callback); + Object.defineProperty(SignalRequest.prototype, "path", { + get: function () { + var _a = this.parameters, _b = _a.keySet, publishKey = _b.publishKey, subscribeKey = _b.subscribeKey, channel = _a.channel, message = _a.message; + var stringifiedPayload = JSON.stringify(message); + return "/signal/".concat(publishKey, "/").concat(subscribeKey, "/0/").concat(encodeString(channel), "/0/").concat(encodeString(stringifiedPayload)); + }, + enumerable: false, + configurable: true + }); + return SignalRequest; + }(AbstractRequest)); + + /** + * Receive messages subscribe REST API module. + */ + /** + * Receive messages subscribe request. + */ + var ReceiveMessagesSubscribeRequest = /** @class */ (function (_super) { + __extends(ReceiveMessagesSubscribeRequest, _super); + function ReceiveMessagesSubscribeRequest() { + return _super !== null && _super.apply(this, arguments) || this; + } + ReceiveMessagesSubscribeRequest.prototype.operation = function () { + return RequestOperation$1.PNReceiveMessagesOperation; }; - default_1.prototype._detectErrorCategory = function (err) { - if (err.code === 'ENOTFOUND') { - return categories.PNNetworkIssuesCategory; - } - if (err.code === 'ECONNREFUSED') { - return categories.PNNetworkIssuesCategory; - } - if (err.code === 'ECONNRESET') { - return categories.PNNetworkIssuesCategory; - } - if (err.code === 'EAI_AGAIN') { - return categories.PNNetworkIssuesCategory; - } - if (err.status === 0 || (err.hasOwnProperty('status') && typeof err.status === 'undefined')) { - return categories.PNNetworkIssuesCategory; - } - if (err.timeout) - return categories.PNTimeoutCategory; - if (err.code === 'ETIMEDOUT') { - return categories.PNNetworkIssuesCategory; - } - if (err.response) { - if (err.response.badRequest) { - return categories.PNBadRequestCategory; - } - if (err.response.forbidden) { - return categories.PNAccessDeniedCategory; - } - } - return categories.PNUnknownCategory; + ReceiveMessagesSubscribeRequest.prototype.validate = function () { + var validationResult = _super.prototype.validate.call(this); + if (validationResult) + return validationResult; + if (!this.parameters.timetoken) + return 'timetoken can not be empty'; + if (!this.parameters.region) + return 'region can not be empty'; }; - return default_1; - }()); + Object.defineProperty(ReceiveMessagesSubscribeRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channels = _a.channels; + return "/v2/subscribe/".concat(subscribeKey, "/").concat(encodeString(channels.length > 0 ? channels.join(',') : ','), "/0"); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(ReceiveMessagesSubscribeRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, channelGroups = _a.channelGroups, filterExpression = _a.filterExpression, timetoken = _a.timetoken, region = _a.region; + var query = { ee: '' }; + if (channelGroups && channelGroups.length > 0) + query['channel-group'] = channelGroups.join(','); + if (filterExpression && filterExpression.length > 0) + query['filter-expr'] = filterExpression; + if (typeof timetoken === 'string') { + if (timetoken && timetoken.length > 0) + query['tt'] = timetoken; + } + else if (timetoken && timetoken > 0) + query['tt'] = timetoken; + if (region) + query['tr'] = region; + return query; + }, + enumerable: false, + configurable: true + }); + return ReceiveMessagesSubscribeRequest; + }(BaseSubscribeRequest)); - function stringifyBufferKeys(obj) { - var isObject = function (value) { return value && typeof value === 'object' && value.constructor === Object; }; - var isString = function (value) { return typeof value === 'string' || value instanceof String; }; - var isNumber = function (value) { return typeof value === 'number' && isFinite(value); }; - if (!isObject(obj)) { - return obj; + /** + * Handshake subscribe REST API module. + */ + /** + * Handshake subscribe request. + * + * Separate subscribe request required by Event Engine. + */ + var HandshakeSubscribeRequest = /** @class */ (function (_super) { + __extends(HandshakeSubscribeRequest, _super); + function HandshakeSubscribeRequest() { + return _super !== null && _super.apply(this, arguments) || this; } - var normalizedObject = {}; - Object.keys(obj).forEach(function (key) { - var keyIsString = isString(key); - var stringifiedKey = key; - var value = obj[key]; - if (Array.isArray(key) || (keyIsString && key.indexOf(',') >= 0)) { - var bytes = keyIsString ? key.split(',') : key; - stringifiedKey = bytes.reduce(function (string, byte) { - string += String.fromCharCode(byte); - return string; - }, ''); - } - else if (isNumber(key) || (keyIsString && !isNaN(key))) { - stringifiedKey = String.fromCharCode(keyIsString ? parseInt(key, 10) : 10); - } - normalizedObject[stringifiedKey] = isObject(value) ? stringifyBufferKeys(value) : value; + HandshakeSubscribeRequest.prototype.operation = function () { + return RequestOperation$1.PNHandshakeOperation; + }; + Object.defineProperty(HandshakeSubscribeRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channels = _a.channels; + return "/v2/subscribe/".concat(subscribeKey, "/").concat(encodeString(channels.length > 0 ? channels.join(',') : ','), "/0"); + }, + enumerable: false, + configurable: true }); - return normalizedObject; - } + Object.defineProperty(HandshakeSubscribeRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, channelGroups = _a.channelGroups, filterExpression = _a.filterExpression, state = _a.state; + var query = { tt: 0, ee: '' }; + if (channelGroups && channelGroups.length > 0) + query['channel-group'] = channelGroups.join(','); + if (filterExpression && filterExpression.length > 0) + query['filter-expr'] = filterExpression; + if (state && Object.keys(state).length > 0) + query['state'] = JSON.stringify(state); + return query; + }, + enumerable: false, + configurable: true + }); + return HandshakeSubscribeRequest; + }(BaseSubscribeRequest)); - var default_1$1 = /** @class */ (function () { - function default_1(decode, base64ToBinary) { - this._base64ToBinary = base64ToBinary; - this._decode = decode; + /** + * Get Presence State REST API module. + */ + // endregion + /** + * Get `uuid` presence state request. + */ + var GetPresenceStateRequest = /** @class */ (function (_super) { + __extends(GetPresenceStateRequest, _super); + function GetPresenceStateRequest(parameters) { + var _a, _b; + var _c, _d; + var _this = _super.call(this) || this; + _this.parameters = parameters; + // Apply defaults. + (_a = (_c = _this.parameters).channels) !== null && _a !== void 0 ? _a : (_c.channels = []); + (_b = (_d = _this.parameters).channelGroups) !== null && _b !== void 0 ? _b : (_d.channelGroups = []); + return _this; } - default_1.prototype.decodeToken = function (tokenString) { - var padding = ''; - if (tokenString.length % 4 === 3) { - padding = '='; - } - else if (tokenString.length % 4 === 2) { - padding = '=='; - } - var cleaned = tokenString.replace(/-/gi, '+').replace(/_/gi, '/') + padding; - var result = this._decode(this._base64ToBinary(cleaned)); - if (typeof result === 'object') { - return result; - } - return undefined; + GetPresenceStateRequest.prototype.operation = function () { + return RequestOperation$1.PNGetStateOperation; }; - return default_1; - }()); - - var client = {exports: {}}; - - var componentEmitter = {exports: {}}; + GetPresenceStateRequest.prototype.validate = function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channels = _a.channels, channelGroups = _a.channelGroups; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (channels && channels.length > 0 && channelGroups && channelGroups.length > 0) + return 'Only `channels` or `channelGroups` can be specified at once.'; + }; + GetPresenceStateRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse, _a, channels, channelGroups, state; + return __generator(this, function (_b) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + _a = this.parameters, channels = _a.channels, channelGroups = _a.channelGroups; + state = { channels: {} }; + if ((channels === null || channels === void 0 ? void 0 : channels.length) === 1 && (channelGroups === null || channelGroups === void 0 ? void 0 : channelGroups.length) === 0) + state.channels[channels[0]] = serviceResponse.payload; + else + state.channels = serviceResponse.payload; + return [2 /*return*/, state]; + }); + }); + }; + Object.defineProperty(GetPresenceStateRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, uuid = _a.uuid, channels = _a.channels; + var stringifiedChannels = channels && channels.length > 0 ? encodeString(channels.join(',')) : ','; + return "/v2/presence/sub-key/".concat(subscribeKey, "/channel/").concat(stringifiedChannels, "/uuid/").concat(uuid); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(GetPresenceStateRequest.prototype, "queryParameters", { + get: function () { + var channelGroups = this.parameters.channelGroups; + if (!channelGroups || channelGroups.length === 0) + return {}; + return { 'channel-group': channelGroups.join(',') }; + }, + enumerable: false, + configurable: true + }); + return GetPresenceStateRequest; + }(AbstractRequest)); - (function (module) { - /** - * Expose `Emitter`. - */ - - { - module.exports = Emitter; - } - - /** - * Initialize a new `Emitter`. - * - * @api public - */ - - function Emitter(obj) { - if (obj) return mixin(obj); - } - /** - * Mixin the emitter properties. - * - * @param {Object} obj - * @return {Object} - * @api private - */ - - function mixin(obj) { - for (var key in Emitter.prototype) { - obj[key] = Emitter.prototype[key]; - } - return obj; - } - - /** - * Listen on the given `event` with `fn`. - * - * @param {String} event - * @param {Function} fn - * @return {Emitter} - * @api public - */ - - Emitter.prototype.on = - Emitter.prototype.addEventListener = function(event, fn){ - this._callbacks = this._callbacks || {}; - (this._callbacks['$' + event] = this._callbacks['$' + event] || []) - .push(fn); - return this; - }; - - /** - * Adds an `event` listener that will be invoked a single - * time then automatically removed. - * - * @param {String} event - * @param {Function} fn - * @return {Emitter} - * @api public - */ - - Emitter.prototype.once = function(event, fn){ - function on() { - this.off(event, on); - fn.apply(this, arguments); - } - - on.fn = fn; - this.on(event, on); - return this; - }; - - /** - * Remove the given callback for `event` or all - * registered callbacks. - * - * @param {String} event - * @param {Function} fn - * @return {Emitter} - * @api public - */ - - Emitter.prototype.off = - Emitter.prototype.removeListener = - Emitter.prototype.removeAllListeners = - Emitter.prototype.removeEventListener = function(event, fn){ - this._callbacks = this._callbacks || {}; - - // all - if (0 == arguments.length) { - this._callbacks = {}; - return this; - } - - // specific event - var callbacks = this._callbacks['$' + event]; - if (!callbacks) return this; - - // remove all handlers - if (1 == arguments.length) { - delete this._callbacks['$' + event]; - return this; - } - - // remove specific handler - var cb; - for (var i = 0; i < callbacks.length; i++) { - cb = callbacks[i]; - if (cb === fn || cb.fn === fn) { - callbacks.splice(i, 1); - break; - } - } - - // Remove event specific arrays for event types that no - // one is subscribed for to avoid memory leak. - if (callbacks.length === 0) { - delete this._callbacks['$' + event]; - } - - return this; - }; - - /** - * Emit `event` with the given args. - * - * @param {String} event - * @param {Mixed} ... - * @return {Emitter} - */ - - Emitter.prototype.emit = function(event){ - this._callbacks = this._callbacks || {}; - - var args = new Array(arguments.length - 1) - , callbacks = this._callbacks['$' + event]; - - for (var i = 1; i < arguments.length; i++) { - args[i - 1] = arguments[i]; - } - - if (callbacks) { - callbacks = callbacks.slice(0); - for (var i = 0, len = callbacks.length; i < len; ++i) { - callbacks[i].apply(this, args); - } - } - - return this; - }; - - /** - * Return array of callbacks for `event`. - * - * @param {String} event - * @return {Array} - * @api public - */ - - Emitter.prototype.listeners = function(event){ - this._callbacks = this._callbacks || {}; - return this._callbacks['$' + event] || []; - }; - - /** - * Check if this emitter has `event` handlers. - * - * @param {String} event - * @return {Boolean} - * @api public - */ - - Emitter.prototype.hasListeners = function(event){ - return !! this.listeners(event).length; - }; - }(componentEmitter)); - - var fastSafeStringify = stringify$2; - stringify$2.default = stringify$2; - stringify$2.stable = deterministicStringify; - stringify$2.stableStringify = deterministicStringify; - - var LIMIT_REPLACE_NODE = '[...]'; - var CIRCULAR_REPLACE_NODE = '[Circular]'; - - var arr = []; - var replacerStack = []; - - function defaultOptions () { - return { - depthLimit: Number.MAX_SAFE_INTEGER, - edgesLimit: Number.MAX_SAFE_INTEGER - } - } - - // Regular stringify - function stringify$2 (obj, replacer, spacer, options) { - if (typeof options === 'undefined') { - options = defaultOptions(); - } - - decirc(obj, '', 0, [], undefined, 0, options); - var res; - try { - if (replacerStack.length === 0) { - res = JSON.stringify(obj, replacer, spacer); - } else { - res = JSON.stringify(obj, replaceGetterValues(replacer), spacer); - } - } catch (_) { - return JSON.stringify('[unable to serialize, circular reference is too complex to analyze]') - } finally { - while (arr.length !== 0) { - var part = arr.pop(); - if (part.length === 4) { - Object.defineProperty(part[0], part[1], part[3]); - } else { - part[0][part[1]] = part[2]; - } - } - } - return res - } - - function setReplace (replace, val, k, parent) { - var propertyDescriptor = Object.getOwnPropertyDescriptor(parent, k); - if (propertyDescriptor.get !== undefined) { - if (propertyDescriptor.configurable) { - Object.defineProperty(parent, k, { value: replace }); - arr.push([parent, k, val, propertyDescriptor]); - } else { - replacerStack.push([val, k, replace]); - } - } else { - parent[k] = replace; - arr.push([parent, k, val]); - } - } - - function decirc (val, k, edgeIndex, stack, parent, depth, options) { - depth += 1; - var i; - if (typeof val === 'object' && val !== null) { - for (i = 0; i < stack.length; i++) { - if (stack[i] === val) { - setReplace(CIRCULAR_REPLACE_NODE, val, k, parent); - return - } + /** + * Set Presence State REST API module. + */ + // endregion + /** + * Set `uuid` presence state request. + */ + var SetPresenceStateRequest = /** @class */ (function (_super) { + __extends(SetPresenceStateRequest, _super); + function SetPresenceStateRequest(parameters) { + var _this = _super.call(this) || this; + _this.parameters = parameters; + return _this; } + SetPresenceStateRequest.prototype.operation = function () { + return RequestOperation$1.PNSetStateOperation; + }; + SetPresenceStateRequest.prototype.validate = function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, state = _a.state, channels = _a.channels, channelGroups = _a.channelGroups; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!state) + return 'Missing State'; + if ((channels === null || channels === void 0 ? void 0 : channels.length) === 0 && (channelGroups === null || channelGroups === void 0 ? void 0 : channelGroups.length) === 0) + return 'Please provide a list of channels and/or channel-groups'; + }; + SetPresenceStateRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, { state: serviceResponse.payload }]; + }); + }); + }; + Object.defineProperty(SetPresenceStateRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, uuid = _a.uuid, channels = _a.channels; + var stringifiedChannels = channels && channels.length > 0 ? encodeString(channels.join(',')) : ','; + return "/v2/presence/sub-key/".concat(subscribeKey, "/channel/").concat(stringifiedChannels, "/uuid/").concat(uuid, "/data"); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(SetPresenceStateRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, channelGroups = _a.channelGroups, state = _a.state; + var query = { state: JSON.stringify(state) }; + if (channelGroups && channelGroups.length === 0) + query['channel-group'] = channelGroups.join(','); + return query; + }, + enumerable: false, + configurable: true + }); + return SetPresenceStateRequest; + }(AbstractRequest)); - if ( - typeof options.depthLimit !== 'undefined' && - depth > options.depthLimit - ) { - setReplace(LIMIT_REPLACE_NODE, val, k, parent); - return + /** + * Announce heartbeat REST API module. + */ + // endregion + var HeartbeatRequest = /** @class */ (function (_super) { + __extends(HeartbeatRequest, _super); + function HeartbeatRequest(parameters) { + var _this = _super.call(this) || this; + _this.parameters = parameters; + return _this; } + HeartbeatRequest.prototype.operation = function () { + return RequestOperation$1.PNHeartbeatOperation; + }; + HeartbeatRequest.prototype.validate = function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channels = _a.channels, channelGroups = _a.channelGroups; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if ((channels === null || channels === void 0 ? void 0 : channels.length) === 0 && (channelGroups === null || channelGroups === void 0 ? void 0 : channelGroups.length) === 0) + return 'Please provide a list of channels and/or channel-groups'; + }; + HeartbeatRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, {}]; + }); + }); + }; + Object.defineProperty(HeartbeatRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channels = _a.channels; + var stringifiedChannels = channels && channels.length > 0 ? encodeString(channels.join(',')) : ','; + return "/v2/presence/sub-key/".concat(subscribeKey, "/channel/").concat(stringifiedChannels, "/heartbeat"); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(HeartbeatRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, channelGroups = _a.channelGroups, state = _a.state, heartbeat = _a.heartbeat; + var query = { heartbeat: "".concat(heartbeat) }; + if (channelGroups && channelGroups.length === 0) + query['channel-group'] = channelGroups.join(','); + if (state) + query.state = JSON.stringify(state); + return query; + }, + enumerable: false, + configurable: true + }); + return HeartbeatRequest; + }(AbstractRequest)); - if ( - typeof options.edgesLimit !== 'undefined' && - edgeIndex + 1 > options.edgesLimit - ) { - setReplace(LIMIT_REPLACE_NODE, val, k, parent); - return - } - - stack.push(val); - // Optimize for Arrays. Big arrays could kill the performance otherwise! - if (Array.isArray(val)) { - for (i = 0; i < val.length; i++) { - decirc(val[i], i, i, stack, val, depth, options); - } - } else { - var keys = Object.keys(val); - for (i = 0; i < keys.length; i++) { - var key = keys[i]; - decirc(val[key], key, i, stack, val, depth, options); - } - } - stack.pop(); - } - } - - // Stable-stringify - function compareFunction (a, b) { - if (a < b) { - return -1 - } - if (a > b) { - return 1 - } - return 0 - } - - function deterministicStringify (obj, replacer, spacer, options) { - if (typeof options === 'undefined') { - options = defaultOptions(); - } - - var tmp = deterministicDecirc(obj, '', 0, [], undefined, 0, options) || obj; - var res; - try { - if (replacerStack.length === 0) { - res = JSON.stringify(tmp, replacer, spacer); - } else { - res = JSON.stringify(tmp, replaceGetterValues(replacer), spacer); - } - } catch (_) { - return JSON.stringify('[unable to serialize, circular reference is too complex to analyze]') - } finally { - // Ensure that we restore the object as it was. - while (arr.length !== 0) { - var part = arr.pop(); - if (part.length === 4) { - Object.defineProperty(part[0], part[1], part[3]); - } else { - part[0][part[1]] = part[2]; - } - } - } - return res - } - - function deterministicDecirc (val, k, edgeIndex, stack, parent, depth, options) { - depth += 1; - var i; - if (typeof val === 'object' && val !== null) { - for (i = 0; i < stack.length; i++) { - if (stack[i] === val) { - setReplace(CIRCULAR_REPLACE_NODE, val, k, parent); - return - } - } - try { - if (typeof val.toJSON === 'function') { - return - } - } catch (_) { - return + /** + * Announce leave REST API module. + */ + // endregion + var PresenceLeaveRequest = /** @class */ (function (_super) { + __extends(PresenceLeaveRequest, _super); + function PresenceLeaveRequest(parameters) { + var _this = _super.call(this) || this; + _this.parameters = parameters; + return _this; } + PresenceLeaveRequest.prototype.operation = function () { + return RequestOperation$1.PNUnsubscribeOperation; + }; + PresenceLeaveRequest.prototype.validate = function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channels = _a.channels, channelGroups = _a.channelGroups; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if ((channels === null || channels === void 0 ? void 0 : channels.length) === 0 && (channelGroups === null || channelGroups === void 0 ? void 0 : channelGroups.length) === 0) + return 'At least one `channel` or `channel group` should be provided.'; + }; + PresenceLeaveRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, {}]; + }); + }); + }; + Object.defineProperty(PresenceLeaveRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channels = _a.channels; + var stringifiedChannels = channels && channels.length > 0 ? encodeString(channels.join(',')) : ','; + return "/v2/presence/sub-key/".concat(subscribeKey, "/channel/").concat(stringifiedChannels, "/leave"); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(PresenceLeaveRequest.prototype, "queryParameters", { + get: function () { + var channelGroups = this.parameters.channelGroups; + if (!channelGroups || channelGroups.length === 0) + return {}; + return { 'channel-group': channelGroups.join(',') }; + }, + enumerable: false, + configurable: true + }); + return PresenceLeaveRequest; + }(AbstractRequest)); - if ( - typeof options.depthLimit !== 'undefined' && - depth > options.depthLimit - ) { - setReplace(LIMIT_REPLACE_NODE, val, k, parent); - return + /** + * `uuid` presence REST API module. + */ + // endregion + var WhereNowRequest = /** @class */ (function (_super) { + __extends(WhereNowRequest, _super); + function WhereNowRequest(parameters) { + var _this = _super.call(this) || this; + _this.parameters = parameters; + return _this; } + WhereNowRequest.prototype.operation = function () { + return RequestOperation$1.PNWhereNowOperation; + }; + WhereNowRequest.prototype.validate = function () { + if (!this.parameters.keySet.subscribeKey) + return 'Missing Subscribe Key'; + }; + WhereNowRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + if (!serviceResponse.payload) + return [2 /*return*/, { channels: [] }]; + return [2 /*return*/, { channels: serviceResponse.payload.channels }]; + }); + }); + }; + Object.defineProperty(WhereNowRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, uuid = _a.uuid; + return "/v2/presence/sub-key/".concat(subscribeKey, "/uuid/").concat(encodeString(uuid)); + }, + enumerable: false, + configurable: true + }); + return WhereNowRequest; + }(AbstractRequest)); - if ( - typeof options.edgesLimit !== 'undefined' && - edgeIndex + 1 > options.edgesLimit - ) { - setReplace(LIMIT_REPLACE_NODE, val, k, parent); - return - } - - stack.push(val); - // Optimize for Arrays. Big arrays could kill the performance otherwise! - if (Array.isArray(val)) { - for (i = 0; i < val.length; i++) { - deterministicDecirc(val[i], i, i, stack, val, depth, options); - } - } else { - // Create a temporary object in the required way - var tmp = {}; - var keys = Object.keys(val).sort(compareFunction); - for (i = 0; i < keys.length; i++) { - var key = keys[i]; - deterministicDecirc(val[key], key, i, stack, val, depth, options); - tmp[key] = val[key]; - } - if (typeof parent !== 'undefined') { - arr.push([parent, k, val]); - parent[k] = tmp; - } else { - return tmp - } - } - stack.pop(); - } - } - - // wraps replacer function to handle values we couldn't replace - // and mark them as replaced value - function replaceGetterValues (replacer) { - replacer = - typeof replacer !== 'undefined' - ? replacer - : function (k, v) { - return v - }; - return function (key, val) { - if (replacerStack.length > 0) { - for (var i = 0; i < replacerStack.length; i++) { - var part = replacerStack[i]; - if (part[1] === key && part[0] === val) { - val = part[2]; - replacerStack.splice(i, 1); - break - } - } + /** + * Channels / channel groups presence REST API module. + */ + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults + /** + * Whether `uuid` should be included in response or not. + */ + var INCLUDE_UUID$1 = true; + /** + * Whether state associated with `uuid` should be included in response or not. + */ + var INCLUDE_STATE = false; + // endregion + var HereNowRequest = /** @class */ (function (_super) { + __extends(HereNowRequest, _super); + function HereNowRequest(parameters) { + var _a, _b, _c; + var _d, _e, _f; + var _this = _super.call(this) || this; + _this.parameters = parameters; + // Apply defaults. + (_a = (_d = _this.parameters).queryParameters) !== null && _a !== void 0 ? _a : (_d.queryParameters = {}); + (_b = (_e = _this.parameters).includeUUIDs) !== null && _b !== void 0 ? _b : (_e.includeUUIDs = INCLUDE_UUID$1); + (_c = (_f = _this.parameters).includeState) !== null && _c !== void 0 ? _c : (_f.includeState = INCLUDE_STATE); + return _this; } - return replacer.call(this, key, val) - } - } - - /* eslint complexity: [2, 18], max-statements: [2, 33] */ - var shams = function hasSymbols() { - if (typeof Symbol !== 'function' || typeof Object.getOwnPropertySymbols !== 'function') { return false; } - if (typeof Symbol.iterator === 'symbol') { return true; } - - var obj = {}; - var sym = Symbol('test'); - var symObj = Object(sym); - if (typeof sym === 'string') { return false; } - - if (Object.prototype.toString.call(sym) !== '[object Symbol]') { return false; } - if (Object.prototype.toString.call(symObj) !== '[object Symbol]') { return false; } - - // temp disabled per https://github.com/ljharb/object.assign/issues/17 - // if (sym instanceof Symbol) { return false; } - // temp disabled per https://github.com/WebReflection/get-own-property-symbols/issues/4 - // if (!(symObj instanceof Symbol)) { return false; } - - // if (typeof Symbol.prototype.toString !== 'function') { return false; } - // if (String(sym) !== Symbol.prototype.toString.call(sym)) { return false; } - - var symVal = 42; - obj[sym] = symVal; - for (sym in obj) { return false; } // eslint-disable-line no-restricted-syntax, no-unreachable-loop - if (typeof Object.keys === 'function' && Object.keys(obj).length !== 0) { return false; } - - if (typeof Object.getOwnPropertyNames === 'function' && Object.getOwnPropertyNames(obj).length !== 0) { return false; } - - var syms = Object.getOwnPropertySymbols(obj); - if (syms.length !== 1 || syms[0] !== sym) { return false; } - - if (!Object.prototype.propertyIsEnumerable.call(obj, sym)) { return false; } - - if (typeof Object.getOwnPropertyDescriptor === 'function') { - var descriptor = Object.getOwnPropertyDescriptor(obj, sym); - if (descriptor.value !== symVal || descriptor.enumerable !== true) { return false; } - } - - return true; - }; - - var origSymbol = typeof Symbol !== 'undefined' && Symbol; - var hasSymbolSham = shams; - - var hasSymbols$1 = function hasNativeSymbols() { - if (typeof origSymbol !== 'function') { return false; } - if (typeof Symbol !== 'function') { return false; } - if (typeof origSymbol('foo') !== 'symbol') { return false; } - if (typeof Symbol('bar') !== 'symbol') { return false; } - - return hasSymbolSham(); - }; - - /* eslint no-invalid-this: 1 */ - - var ERROR_MESSAGE = 'Function.prototype.bind called on incompatible '; - var slice = Array.prototype.slice; - var toStr$1 = Object.prototype.toString; - var funcType = '[object Function]'; - - var implementation$1 = function bind(that) { - var target = this; - if (typeof target !== 'function' || toStr$1.call(target) !== funcType) { - throw new TypeError(ERROR_MESSAGE + target); - } - var args = slice.call(arguments, 1); - - var bound; - var binder = function () { - if (this instanceof bound) { - var result = target.apply( - this, - args.concat(slice.call(arguments)) - ); - if (Object(result) === result) { - return result; - } - return this; - } else { - return target.apply( - that, - args.concat(slice.call(arguments)) - ); - } + HereNowRequest.prototype.operation = function () { + return RequestOperation$1.PNHereNowOperation; + }; + HereNowRequest.prototype.validate = function () { + if (!this.parameters.keySet.subscribeKey) + return 'Missing Subscribe Key'; + }; + HereNowRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse, totalChannels, totalOccupancy, channelsPresence, channels, channel; + var _a, _b; + return __generator(this, function (_c) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + totalChannels = 'occupancy' in serviceResponse ? 1 : serviceResponse.payload.total_channels; + totalOccupancy = 'occupancy' in serviceResponse ? serviceResponse.occupancy : serviceResponse.payload.total_channels; + channelsPresence = {}; + channels = {}; + // Remap single channel presence to multiple channels presence response. + if ('occupancy' in serviceResponse) { + channel = this.parameters.channels[0]; + channels[channel] = { uuids: (_a = serviceResponse.uuids) !== null && _a !== void 0 ? _a : [], occupancy: totalOccupancy }; + } + else + channels = (_b = serviceResponse.payload.channels) !== null && _b !== void 0 ? _b : {}; + Object.keys(channels).forEach(function (channel) { + var channelEntry = channels[channel]; + channelsPresence[channel] = { + occupants: channelEntry.uuids.map(function (uuid) { + if (typeof uuid === 'string') + return { uuid: uuid, state: null }; + return uuid; + }), + name: channel, + occupancy: channelEntry.occupancy, + }; + }); + return [2 /*return*/, { + totalChannels: totalChannels, + totalOccupancy: totalOccupancy, + channels: channelsPresence, + }]; + }); + }); }; + Object.defineProperty(HereNowRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channels = _a.channels, channelGroups = _a.channelGroups; + var path = "/v2/presence/sub-key/".concat(subscribeKey); + if ((channels && channels.length > 0) || (channelGroups && channelGroups.length > 0)) { + var stringifiedChannels = channels && channels.length > 0 ? encodeString(channels.join(',')) : ','; + path += "/channel/".concat(stringifiedChannels); + } + return path; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(HereNowRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, channelGroups = _a.channelGroups, includeUUIDs = _a.includeUUIDs, includeState = _a.includeState, queryParameters = _a.queryParameters; + return __assign(__assign(__assign(__assign({}, (!includeUUIDs ? { disable_uuids: '1' } : {})), ((includeState !== null && includeState !== void 0 ? includeState : false) ? { state: '1' } : {})), (channelGroups && channelGroups.length > 0 ? { 'channel-group': channelGroups.join(',') } : {})), queryParameters); + }, + enumerable: false, + configurable: true + }); + return HereNowRequest; + }(AbstractRequest)); - var boundLength = Math.max(0, target.length - args.length); - var boundArgs = []; - for (var i = 0; i < boundLength; i++) { - boundArgs.push('$' + i); + /** + * Delete messages REST API module. + */ + // endregion + /** + * Delete messages from channel history. + */ + var DeleteMessageRequest = /** @class */ (function (_super) { + __extends(DeleteMessageRequest, _super); + function DeleteMessageRequest(parameters) { + var _this = _super.call(this, { method: TransportMethod.DELETE }) || this; + _this.parameters = parameters; + return _this; } + DeleteMessageRequest.prototype.operation = function () { + return RequestOperation$1.PNDeleteMessagesOperation; + }; + DeleteMessageRequest.prototype.validate = function () { + if (!this.parameters.keySet.subscribeKey) + return 'Missing Subscribe Key'; + if (!this.parameters.channel) + return 'Missing channel'; + }; + DeleteMessageRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, {}]; + }); + }); + }; + Object.defineProperty(DeleteMessageRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channel = _a.channel; + return "/v3/history/sub-key/".concat(subscribeKey, "/channel/").concat(encodeString(channel)); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(DeleteMessageRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, start = _a.start, end = _a.end; + return __assign(__assign({}, (start ? { start: start } : {})), (end ? { end: end } : {})); + }, + enumerable: false, + configurable: true + }); + return DeleteMessageRequest; + }(AbstractRequest)); - bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this,arguments); }')(binder); - - if (target.prototype) { - var Empty = function Empty() {}; - Empty.prototype = target.prototype; - bound.prototype = new Empty(); - Empty.prototype = null; + /** + * Messages count REST API module. + */ + // endregion + var MessageCountRequest = /** @class */ (function (_super) { + __extends(MessageCountRequest, _super); + function MessageCountRequest(parameters) { + var _this = _super.call(this) || this; + _this.parameters = parameters; + return _this; } + MessageCountRequest.prototype.operation = function () { + return RequestOperation$1.PNMessageCounts; + }; + MessageCountRequest.prototype.validate = function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channels = _a.channels, timetoken = _a.timetoken, channelTimetokens = _a.channelTimetokens; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!channels) + return 'Missing channels'; + if (timetoken && channelTimetokens) + return '`timetoken` and `channelTimetokens` are incompatible together'; + if (!timetoken && !channelTimetokens) + return '`timetoken` or `channelTimetokens` need to be set'; + if (channelTimetokens && channelTimetokens.length && channelTimetokens.length !== channels.length) + return 'Length of `channelTimetokens` and `channels` do not match'; + }; + MessageCountRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, { channels: serviceResponse.channels }]; + }); + }); + }; + Object.defineProperty(MessageCountRequest.prototype, "path", { + get: function () { + return "/v3/history/sub-key/".concat(this.parameters.keySet.subscribeKey, "/message-counts/").concat(encodeString(this.parameters.channels.join(','))); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(MessageCountRequest.prototype, "queryParameters", { + get: function () { + var channelTimetokens = this.parameters.channelTimetokens; + if (this.parameters.timetoken) + channelTimetokens = [this.parameters.timetoken]; + return __assign(__assign({}, (channelTimetokens.length === 1 ? { timetoken: channelTimetokens[0] } : {})), (channelTimetokens.length > 1 ? { channelsTimetoken: channelTimetokens.join(',') } : {})); + }, + enumerable: false, + configurable: true + }); + return MessageCountRequest; + }(AbstractRequest)); - return bound; - }; - - var implementation = implementation$1; - - var functionBind = Function.prototype.bind || implementation; - - var bind$1 = functionBind; - - var src = bind$1.call(Function.call, Object.prototype.hasOwnProperty); - - var undefined$1; - - var $SyntaxError = SyntaxError; - var $Function = Function; - var $TypeError$1 = TypeError; - - // eslint-disable-next-line consistent-return - var getEvalledConstructor = function (expressionSyntax) { - try { - return $Function('"use strict"; return (' + expressionSyntax + ').constructor;')(); - } catch (e) {} - }; - - var $gOPD = Object.getOwnPropertyDescriptor; - if ($gOPD) { - try { - $gOPD({}, ''); - } catch (e) { - $gOPD = null; // this is IE 8, which has a broken gOPD - } - } - - var throwTypeError = function () { - throw new $TypeError$1(); - }; - var ThrowTypeError = $gOPD - ? (function () { - try { - // eslint-disable-next-line no-unused-expressions, no-caller, no-restricted-properties - arguments.callee; // IE 8 does not throw here - return throwTypeError; - } catch (calleeThrows) { - try { - // IE 8 throws on Object.getOwnPropertyDescriptor(arguments, '') - return $gOPD(arguments, 'callee').get; - } catch (gOPDthrows) { - return throwTypeError; - } - } - }()) - : throwTypeError; - - var hasSymbols = hasSymbols$1(); - - var getProto = Object.getPrototypeOf || function (x) { return x.__proto__; }; // eslint-disable-line no-proto - - var needsEval = {}; - - var TypedArray = typeof Uint8Array === 'undefined' ? undefined$1 : getProto(Uint8Array); - - var INTRINSICS = { - '%AggregateError%': typeof AggregateError === 'undefined' ? undefined$1 : AggregateError, - '%Array%': Array, - '%ArrayBuffer%': typeof ArrayBuffer === 'undefined' ? undefined$1 : ArrayBuffer, - '%ArrayIteratorPrototype%': hasSymbols ? getProto([][Symbol.iterator]()) : undefined$1, - '%AsyncFromSyncIteratorPrototype%': undefined$1, - '%AsyncFunction%': needsEval, - '%AsyncGenerator%': needsEval, - '%AsyncGeneratorFunction%': needsEval, - '%AsyncIteratorPrototype%': needsEval, - '%Atomics%': typeof Atomics === 'undefined' ? undefined$1 : Atomics, - '%BigInt%': typeof BigInt === 'undefined' ? undefined$1 : BigInt, - '%Boolean%': Boolean, - '%DataView%': typeof DataView === 'undefined' ? undefined$1 : DataView, - '%Date%': Date, - '%decodeURI%': decodeURI, - '%decodeURIComponent%': decodeURIComponent, - '%encodeURI%': encodeURI, - '%encodeURIComponent%': encodeURIComponent, - '%Error%': Error, - '%eval%': eval, // eslint-disable-line no-eval - '%EvalError%': EvalError, - '%Float32Array%': typeof Float32Array === 'undefined' ? undefined$1 : Float32Array, - '%Float64Array%': typeof Float64Array === 'undefined' ? undefined$1 : Float64Array, - '%FinalizationRegistry%': typeof FinalizationRegistry === 'undefined' ? undefined$1 : FinalizationRegistry, - '%Function%': $Function, - '%GeneratorFunction%': needsEval, - '%Int8Array%': typeof Int8Array === 'undefined' ? undefined$1 : Int8Array, - '%Int16Array%': typeof Int16Array === 'undefined' ? undefined$1 : Int16Array, - '%Int32Array%': typeof Int32Array === 'undefined' ? undefined$1 : Int32Array, - '%isFinite%': isFinite, - '%isNaN%': isNaN, - '%IteratorPrototype%': hasSymbols ? getProto(getProto([][Symbol.iterator]())) : undefined$1, - '%JSON%': typeof JSON === 'object' ? JSON : undefined$1, - '%Map%': typeof Map === 'undefined' ? undefined$1 : Map, - '%MapIteratorPrototype%': typeof Map === 'undefined' || !hasSymbols ? undefined$1 : getProto(new Map()[Symbol.iterator]()), - '%Math%': Math, - '%Number%': Number, - '%Object%': Object, - '%parseFloat%': parseFloat, - '%parseInt%': parseInt, - '%Promise%': typeof Promise === 'undefined' ? undefined$1 : Promise, - '%Proxy%': typeof Proxy === 'undefined' ? undefined$1 : Proxy, - '%RangeError%': RangeError, - '%ReferenceError%': ReferenceError, - '%Reflect%': typeof Reflect === 'undefined' ? undefined$1 : Reflect, - '%RegExp%': RegExp, - '%Set%': typeof Set === 'undefined' ? undefined$1 : Set, - '%SetIteratorPrototype%': typeof Set === 'undefined' || !hasSymbols ? undefined$1 : getProto(new Set()[Symbol.iterator]()), - '%SharedArrayBuffer%': typeof SharedArrayBuffer === 'undefined' ? undefined$1 : SharedArrayBuffer, - '%String%': String, - '%StringIteratorPrototype%': hasSymbols ? getProto(''[Symbol.iterator]()) : undefined$1, - '%Symbol%': hasSymbols ? Symbol : undefined$1, - '%SyntaxError%': $SyntaxError, - '%ThrowTypeError%': ThrowTypeError, - '%TypedArray%': TypedArray, - '%TypeError%': $TypeError$1, - '%Uint8Array%': typeof Uint8Array === 'undefined' ? undefined$1 : Uint8Array, - '%Uint8ClampedArray%': typeof Uint8ClampedArray === 'undefined' ? undefined$1 : Uint8ClampedArray, - '%Uint16Array%': typeof Uint16Array === 'undefined' ? undefined$1 : Uint16Array, - '%Uint32Array%': typeof Uint32Array === 'undefined' ? undefined$1 : Uint32Array, - '%URIError%': URIError, - '%WeakMap%': typeof WeakMap === 'undefined' ? undefined$1 : WeakMap, - '%WeakRef%': typeof WeakRef === 'undefined' ? undefined$1 : WeakRef, - '%WeakSet%': typeof WeakSet === 'undefined' ? undefined$1 : WeakSet - }; - - var doEval = function doEval(name) { - var value; - if (name === '%AsyncFunction%') { - value = getEvalledConstructor('async function () {}'); - } else if (name === '%GeneratorFunction%') { - value = getEvalledConstructor('function* () {}'); - } else if (name === '%AsyncGeneratorFunction%') { - value = getEvalledConstructor('async function* () {}'); - } else if (name === '%AsyncGenerator%') { - var fn = doEval('%AsyncGeneratorFunction%'); - if (fn) { - value = fn.prototype; - } - } else if (name === '%AsyncIteratorPrototype%') { - var gen = doEval('%AsyncGenerator%'); - if (gen) { - value = getProto(gen.prototype); - } - } - - INTRINSICS[name] = value; - - return value; - }; - - var LEGACY_ALIASES = { - '%ArrayBufferPrototype%': ['ArrayBuffer', 'prototype'], - '%ArrayPrototype%': ['Array', 'prototype'], - '%ArrayProto_entries%': ['Array', 'prototype', 'entries'], - '%ArrayProto_forEach%': ['Array', 'prototype', 'forEach'], - '%ArrayProto_keys%': ['Array', 'prototype', 'keys'], - '%ArrayProto_values%': ['Array', 'prototype', 'values'], - '%AsyncFunctionPrototype%': ['AsyncFunction', 'prototype'], - '%AsyncGenerator%': ['AsyncGeneratorFunction', 'prototype'], - '%AsyncGeneratorPrototype%': ['AsyncGeneratorFunction', 'prototype', 'prototype'], - '%BooleanPrototype%': ['Boolean', 'prototype'], - '%DataViewPrototype%': ['DataView', 'prototype'], - '%DatePrototype%': ['Date', 'prototype'], - '%ErrorPrototype%': ['Error', 'prototype'], - '%EvalErrorPrototype%': ['EvalError', 'prototype'], - '%Float32ArrayPrototype%': ['Float32Array', 'prototype'], - '%Float64ArrayPrototype%': ['Float64Array', 'prototype'], - '%FunctionPrototype%': ['Function', 'prototype'], - '%Generator%': ['GeneratorFunction', 'prototype'], - '%GeneratorPrototype%': ['GeneratorFunction', 'prototype', 'prototype'], - '%Int8ArrayPrototype%': ['Int8Array', 'prototype'], - '%Int16ArrayPrototype%': ['Int16Array', 'prototype'], - '%Int32ArrayPrototype%': ['Int32Array', 'prototype'], - '%JSONParse%': ['JSON', 'parse'], - '%JSONStringify%': ['JSON', 'stringify'], - '%MapPrototype%': ['Map', 'prototype'], - '%NumberPrototype%': ['Number', 'prototype'], - '%ObjectPrototype%': ['Object', 'prototype'], - '%ObjProto_toString%': ['Object', 'prototype', 'toString'], - '%ObjProto_valueOf%': ['Object', 'prototype', 'valueOf'], - '%PromisePrototype%': ['Promise', 'prototype'], - '%PromiseProto_then%': ['Promise', 'prototype', 'then'], - '%Promise_all%': ['Promise', 'all'], - '%Promise_reject%': ['Promise', 'reject'], - '%Promise_resolve%': ['Promise', 'resolve'], - '%RangeErrorPrototype%': ['RangeError', 'prototype'], - '%ReferenceErrorPrototype%': ['ReferenceError', 'prototype'], - '%RegExpPrototype%': ['RegExp', 'prototype'], - '%SetPrototype%': ['Set', 'prototype'], - '%SharedArrayBufferPrototype%': ['SharedArrayBuffer', 'prototype'], - '%StringPrototype%': ['String', 'prototype'], - '%SymbolPrototype%': ['Symbol', 'prototype'], - '%SyntaxErrorPrototype%': ['SyntaxError', 'prototype'], - '%TypedArrayPrototype%': ['TypedArray', 'prototype'], - '%TypeErrorPrototype%': ['TypeError', 'prototype'], - '%Uint8ArrayPrototype%': ['Uint8Array', 'prototype'], - '%Uint8ClampedArrayPrototype%': ['Uint8ClampedArray', 'prototype'], - '%Uint16ArrayPrototype%': ['Uint16Array', 'prototype'], - '%Uint32ArrayPrototype%': ['Uint32Array', 'prototype'], - '%URIErrorPrototype%': ['URIError', 'prototype'], - '%WeakMapPrototype%': ['WeakMap', 'prototype'], - '%WeakSetPrototype%': ['WeakSet', 'prototype'] - }; - - var bind = functionBind; - var hasOwn$2 = src; - var $concat$1 = bind.call(Function.call, Array.prototype.concat); - var $spliceApply = bind.call(Function.apply, Array.prototype.splice); - var $replace$1 = bind.call(Function.call, String.prototype.replace); - var $strSlice = bind.call(Function.call, String.prototype.slice); - - /* adapted from https://github.com/lodash/lodash/blob/4.17.15/dist/lodash.js#L6735-L6744 */ - var rePropName = /[^%.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|%$))/g; - var reEscapeChar = /\\(\\)?/g; /** Used to match backslashes in property paths. */ - var stringToPath = function stringToPath(string) { - var first = $strSlice(string, 0, 1); - var last = $strSlice(string, -1); - if (first === '%' && last !== '%') { - throw new $SyntaxError('invalid intrinsic syntax, expected closing `%`'); - } else if (last === '%' && first !== '%') { - throw new $SyntaxError('invalid intrinsic syntax, expected opening `%`'); - } - var result = []; - $replace$1(string, rePropName, function (match, number, quote, subString) { - result[result.length] = quote ? $replace$1(subString, reEscapeChar, '$1') : number || match; - }); - return result; - }; - /* end adaptation */ - - var getBaseIntrinsic = function getBaseIntrinsic(name, allowMissing) { - var intrinsicName = name; - var alias; - if (hasOwn$2(LEGACY_ALIASES, intrinsicName)) { - alias = LEGACY_ALIASES[intrinsicName]; - intrinsicName = '%' + alias[0] + '%'; - } - - if (hasOwn$2(INTRINSICS, intrinsicName)) { - var value = INTRINSICS[intrinsicName]; - if (value === needsEval) { - value = doEval(intrinsicName); - } - if (typeof value === 'undefined' && !allowMissing) { - throw new $TypeError$1('intrinsic ' + name + ' exists, but is not available. Please file an issue!'); - } - - return { - alias: alias, - name: intrinsicName, - value: value - }; - } - - throw new $SyntaxError('intrinsic ' + name + ' does not exist!'); - }; - - var getIntrinsic = function GetIntrinsic(name, allowMissing) { - if (typeof name !== 'string' || name.length === 0) { - throw new $TypeError$1('intrinsic name must be a non-empty string'); - } - if (arguments.length > 1 && typeof allowMissing !== 'boolean') { - throw new $TypeError$1('"allowMissing" argument must be a boolean'); - } - - var parts = stringToPath(name); - var intrinsicBaseName = parts.length > 0 ? parts[0] : ''; - - var intrinsic = getBaseIntrinsic('%' + intrinsicBaseName + '%', allowMissing); - var intrinsicRealName = intrinsic.name; - var value = intrinsic.value; - var skipFurtherCaching = false; - - var alias = intrinsic.alias; - if (alias) { - intrinsicBaseName = alias[0]; - $spliceApply(parts, $concat$1([0, 1], alias)); - } - - for (var i = 1, isOwn = true; i < parts.length; i += 1) { - var part = parts[i]; - var first = $strSlice(part, 0, 1); - var last = $strSlice(part, -1); - if ( - ( - (first === '"' || first === "'" || first === '`') - || (last === '"' || last === "'" || last === '`') - ) - && first !== last - ) { - throw new $SyntaxError('property names with quotes must have matching quotes'); - } - if (part === 'constructor' || !isOwn) { - skipFurtherCaching = true; - } - - intrinsicBaseName += '.' + part; - intrinsicRealName = '%' + intrinsicBaseName + '%'; - - if (hasOwn$2(INTRINSICS, intrinsicRealName)) { - value = INTRINSICS[intrinsicRealName]; - } else if (value != null) { - if (!(part in value)) { - if (!allowMissing) { - throw new $TypeError$1('base intrinsic for ' + name + ' exists, but the property is not available.'); - } - return void undefined$1; - } - if ($gOPD && (i + 1) >= parts.length) { - var desc = $gOPD(value, part); - isOwn = !!desc; - - // By convention, when a data property is converted to an accessor - // property to emulate a data property that does not suffer from - // the override mistake, that accessor's getter is marked with - // an `originalValue` property. Here, when we detect this, we - // uphold the illusion by pretending to see that original data - // property, i.e., returning the value rather than the getter - // itself. - if (isOwn && 'get' in desc && !('originalValue' in desc.get)) { - value = desc.get; - } else { - value = value[part]; - } - } else { - isOwn = hasOwn$2(value, part); - value = value[part]; - } - - if (isOwn && !skipFurtherCaching) { - INTRINSICS[intrinsicRealName] = value; - } - } - } - return value; - }; - - var callBind$1 = {exports: {}}; - - (function (module) { - - var bind = functionBind; - var GetIntrinsic = getIntrinsic; - - var $apply = GetIntrinsic('%Function.prototype.apply%'); - var $call = GetIntrinsic('%Function.prototype.call%'); - var $reflectApply = GetIntrinsic('%Reflect.apply%', true) || bind.call($call, $apply); - - var $gOPD = GetIntrinsic('%Object.getOwnPropertyDescriptor%', true); - var $defineProperty = GetIntrinsic('%Object.defineProperty%', true); - var $max = GetIntrinsic('%Math.max%'); - - if ($defineProperty) { - try { - $defineProperty({}, 'a', { value: 1 }); - } catch (e) { - // IE 8 has a broken defineProperty - $defineProperty = null; - } - } - - module.exports = function callBind(originalFunction) { - var func = $reflectApply(bind, $call, arguments); - if ($gOPD && $defineProperty) { - var desc = $gOPD(func, 'length'); - if (desc.configurable) { - // original length, plus the receiver, minus any additional arguments (after the receiver) - $defineProperty( - func, - 'length', - { value: 1 + $max(0, originalFunction.length - (arguments.length - 1)) } - ); - } - } - return func; - }; - - var applyBind = function applyBind() { - return $reflectApply(bind, $apply, arguments); - }; - - if ($defineProperty) { - $defineProperty(module.exports, 'apply', { value: applyBind }); - } else { - module.exports.apply = applyBind; - } - }(callBind$1)); - - var GetIntrinsic$1 = getIntrinsic; - - var callBind = callBind$1.exports; - - var $indexOf = callBind(GetIntrinsic$1('String.prototype.indexOf')); - - var callBound$1 = function callBoundIntrinsic(name, allowMissing) { - var intrinsic = GetIntrinsic$1(name, !!allowMissing); - if (typeof intrinsic === 'function' && $indexOf(name, '.prototype.') > -1) { - return callBind(intrinsic); - } - return intrinsic; - }; - - var _nodeResolve_empty = {}; - - var _nodeResolve_empty$1 = /*#__PURE__*/Object.freeze({ - __proto__: null, - 'default': _nodeResolve_empty - }); - - var require$$0 = /*@__PURE__*/getAugmentedNamespace(_nodeResolve_empty$1); - - var hasMap = typeof Map === 'function' && Map.prototype; - var mapSizeDescriptor = Object.getOwnPropertyDescriptor && hasMap ? Object.getOwnPropertyDescriptor(Map.prototype, 'size') : null; - var mapSize = hasMap && mapSizeDescriptor && typeof mapSizeDescriptor.get === 'function' ? mapSizeDescriptor.get : null; - var mapForEach = hasMap && Map.prototype.forEach; - var hasSet = typeof Set === 'function' && Set.prototype; - var setSizeDescriptor = Object.getOwnPropertyDescriptor && hasSet ? Object.getOwnPropertyDescriptor(Set.prototype, 'size') : null; - var setSize = hasSet && setSizeDescriptor && typeof setSizeDescriptor.get === 'function' ? setSizeDescriptor.get : null; - var setForEach = hasSet && Set.prototype.forEach; - var hasWeakMap = typeof WeakMap === 'function' && WeakMap.prototype; - var weakMapHas = hasWeakMap ? WeakMap.prototype.has : null; - var hasWeakSet = typeof WeakSet === 'function' && WeakSet.prototype; - var weakSetHas = hasWeakSet ? WeakSet.prototype.has : null; - var hasWeakRef = typeof WeakRef === 'function' && WeakRef.prototype; - var weakRefDeref = hasWeakRef ? WeakRef.prototype.deref : null; - var booleanValueOf = Boolean.prototype.valueOf; - var objectToString = Object.prototype.toString; - var functionToString = Function.prototype.toString; - var $match = String.prototype.match; - var $slice = String.prototype.slice; - var $replace = String.prototype.replace; - var $toUpperCase = String.prototype.toUpperCase; - var $toLowerCase = String.prototype.toLowerCase; - var $test = RegExp.prototype.test; - var $concat = Array.prototype.concat; - var $join = Array.prototype.join; - var $arrSlice = Array.prototype.slice; - var $floor = Math.floor; - var bigIntValueOf = typeof BigInt === 'function' ? BigInt.prototype.valueOf : null; - var gOPS = Object.getOwnPropertySymbols; - var symToString = typeof Symbol === 'function' && typeof Symbol.iterator === 'symbol' ? Symbol.prototype.toString : null; - var hasShammedSymbols = typeof Symbol === 'function' && typeof Symbol.iterator === 'object'; - // ie, `has-tostringtag/shams - var toStringTag = typeof Symbol === 'function' && Symbol.toStringTag && (typeof Symbol.toStringTag === hasShammedSymbols ? 'object' : 'symbol') - ? Symbol.toStringTag - : null; - var isEnumerable = Object.prototype.propertyIsEnumerable; - - var gPO = (typeof Reflect === 'function' ? Reflect.getPrototypeOf : Object.getPrototypeOf) || ( - [].__proto__ === Array.prototype // eslint-disable-line no-proto - ? function (O) { - return O.__proto__; // eslint-disable-line no-proto - } - : null - ); - - function addNumericSeparator(num, str) { - if ( - num === Infinity - || num === -Infinity - || num !== num - || (num && num > -1000 && num < 1000) - || $test.call(/e/, str) - ) { - return str; - } - var sepRegex = /[0-9](?=(?:[0-9]{3})+(?![0-9]))/g; - if (typeof num === 'number') { - var int = num < 0 ? -$floor(-num) : $floor(num); // trunc(num) - if (int !== num) { - var intStr = String(int); - var dec = $slice.call(str, intStr.length + 1); - return $replace.call(intStr, sepRegex, '$&_') + '.' + $replace.call($replace.call(dec, /([0-9]{3})/g, '$&_'), /_$/, ''); - } - } - return $replace.call(str, sepRegex, '$&_'); - } - - var utilInspect = require$$0; - var inspectCustom = utilInspect.custom; - var inspectSymbol = isSymbol(inspectCustom) ? inspectCustom : null; - - var objectInspect = function inspect_(obj, options, depth, seen) { - var opts = options || {}; - - if (has$3(opts, 'quoteStyle') && (opts.quoteStyle !== 'single' && opts.quoteStyle !== 'double')) { - throw new TypeError('option "quoteStyle" must be "single" or "double"'); - } - if ( - has$3(opts, 'maxStringLength') && (typeof opts.maxStringLength === 'number' - ? opts.maxStringLength < 0 && opts.maxStringLength !== Infinity - : opts.maxStringLength !== null - ) - ) { - throw new TypeError('option "maxStringLength", if provided, must be a positive integer, Infinity, or `null`'); - } - var customInspect = has$3(opts, 'customInspect') ? opts.customInspect : true; - if (typeof customInspect !== 'boolean' && customInspect !== 'symbol') { - throw new TypeError('option "customInspect", if provided, must be `true`, `false`, or `\'symbol\'`'); - } - - if ( - has$3(opts, 'indent') - && opts.indent !== null - && opts.indent !== '\t' - && !(parseInt(opts.indent, 10) === opts.indent && opts.indent > 0) - ) { - throw new TypeError('option "indent" must be "\\t", an integer > 0, or `null`'); - } - if (has$3(opts, 'numericSeparator') && typeof opts.numericSeparator !== 'boolean') { - throw new TypeError('option "numericSeparator", if provided, must be `true` or `false`'); - } - var numericSeparator = opts.numericSeparator; - - if (typeof obj === 'undefined') { - return 'undefined'; - } - if (obj === null) { - return 'null'; - } - if (typeof obj === 'boolean') { - return obj ? 'true' : 'false'; - } - - if (typeof obj === 'string') { - return inspectString(obj, opts); + /** + * Get history REST API module. + */ + // -------------------------------------------------------- + // ---------------------- Defaults ------------------------ + // -------------------------------------------------------- + // region Defaults + /** + * Whether verbose logging enabled or not. + */ + var LOG_VERBOSITY$1 = false; + /** + * Whether associated message metadata should be returned or not. + */ + var INCLUDE_METADATA$1 = false; + /** + * Whether timetokens should be returned as strings by default or not. + */ + var STRINGIFY_TIMETOKENS$1 = false; + /** + * Default and maximum number of messages which should be returned. + */ + var MESSAGES_COUNT = 100; + // endregion + /** + * Get single channel messages request. + */ + var GetHistoryRequest = /** @class */ (function (_super) { + __extends(GetHistoryRequest, _super); + function GetHistoryRequest(parameters) { + var _a, _b, _c; + var _this = _super.call(this) || this; + _this.parameters = parameters; + // Apply defaults. + if (parameters.count) + parameters.count = Math.min(parameters.count, MESSAGES_COUNT); + else + parameters.count = MESSAGES_COUNT; + (_a = parameters.stringifiedTimeToken) !== null && _a !== void 0 ? _a : (parameters.stringifiedTimeToken = STRINGIFY_TIMETOKENS$1); + (_b = parameters.includeMeta) !== null && _b !== void 0 ? _b : (parameters.includeMeta = INCLUDE_METADATA$1); + (_c = parameters.logVerbosity) !== null && _c !== void 0 ? _c : (parameters.logVerbosity = LOG_VERBOSITY$1); + return _this; } - if (typeof obj === 'number') { - if (obj === 0) { - return Infinity / obj > 0 ? '0' : '-0'; + GetHistoryRequest.prototype.operation = function () { + return RequestOperation$1.PNHistoryOperation; + }; + GetHistoryRequest.prototype.validate = function () { + if (!this.parameters.keySet.subscribeKey) + return 'Missing Subscribe Key'; + if (!this.parameters.channel) + return 'Missing channel'; + }; + GetHistoryRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse, messages, startTimeToken, endTimeToken; + var _this = this; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + messages = serviceResponse[0]; + startTimeToken = serviceResponse[1]; + endTimeToken = serviceResponse[2]; + // Handle malformed get history response. + if (!Array.isArray(messages)) + return [2 /*return*/, { messages: [], startTimeToken: startTimeToken, endTimeToken: endTimeToken }]; + return [2 /*return*/, { + messages: messages.map(function (payload) { + var processedPayload = _this.processPayload(payload.message); + var item = { + entry: processedPayload.payload, + timetoken: payload.timetoken, + }; + if (processedPayload.error) + item.error = processedPayload.error; + if (payload.meta) + item.meta = payload.meta; + return item; + }), + startTimeToken: startTimeToken, + endTimeToken: endTimeToken, + }]; + }); + }); + }; + Object.defineProperty(GetHistoryRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channel = _a.channel; + return "/v2/history/sub-key/".concat(subscribeKey, "/channel/").concat(encodeString(channel)); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(GetHistoryRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, start = _a.start, end = _a.end, reverse = _a.reverse, count = _a.count, stringifiedTimeToken = _a.stringifiedTimeToken, includeMeta = _a.includeMeta; + return __assign(__assign(__assign(__assign(__assign({ count: count, include_token: 'true' }, (start ? { start: start } : {})), (end ? { end: end } : {})), (stringifiedTimeToken ? { string_message_token: 'true' } : {})), (reverse !== undefined && reverse !== null ? { reverse: reverse.toString() } : {})), (includeMeta ? { include_meta: 'true' } : {})); + }, + enumerable: false, + configurable: true + }); + GetHistoryRequest.prototype.processPayload = function (payload) { + var _a = this.parameters, crypto = _a.crypto, logVerbosity = _a.logVerbosity; + if (!crypto || typeof payload !== 'string') + return { payload: payload }; + var decryptedPayload; + var error; + try { + var decryptedData = crypto.decrypt(payload); + decryptedPayload = + decryptedData instanceof ArrayBuffer + ? JSON.parse(GetHistoryRequest.decoder.decode(decryptedData)) + : decryptedData; + } + catch (err) { + if (logVerbosity) + console.log("decryption error", err.message); + decryptedPayload = payload; + error = "Error while decrypting message content: ".concat(err.message); } - var str = String(obj); - return numericSeparator ? addNumericSeparator(obj, str) : str; - } - if (typeof obj === 'bigint') { - var bigIntStr = String(obj) + 'n'; - return numericSeparator ? addNumericSeparator(obj, bigIntStr) : bigIntStr; - } - - var maxDepth = typeof opts.depth === 'undefined' ? 5 : opts.depth; - if (typeof depth === 'undefined') { depth = 0; } - if (depth >= maxDepth && maxDepth > 0 && typeof obj === 'object') { - return isArray$3(obj) ? '[Array]' : '[Object]'; - } + return { + payload: decryptedPayload, + error: error, + }; + }; + return GetHistoryRequest; + }(AbstractRequest)); - var indent = getIndent(opts, depth); + // endregion + // -------------------------------------------------------- + // -------------------- Fetch Messages -------------------- + // -------------------------------------------------------- + // region Fetch Messages + /** + * PubNub-defined message type. + * + * Types of messages which can be retrieved with fetch messages REST API. + */ + var PubNubMessageType; + (function (PubNubMessageType) { + /** + * Regular message. + */ + PubNubMessageType[PubNubMessageType["Message"] = -1] = "Message"; + /** + * File message. + */ + PubNubMessageType[PubNubMessageType["Files"] = 4] = "Files"; + })(PubNubMessageType || (PubNubMessageType = {})); + // endregion - if (typeof seen === 'undefined') { - seen = []; - } else if (indexOf(seen, obj) >= 0) { - return '[Circular]'; + /** + * Fetch messages REST API module. + */ + // -------------------------------------------------------- + // ---------------------- Defaults ------------------------ + // -------------------------------------------------------- + // region Defaults + /** + * Whether verbose logging enabled or not. + */ + var LOG_VERBOSITY = false; + /** + * Whether associated message metadata should be returned or not. + */ + var INCLUDE_METADATA = true; + /** + * Whether message type should be returned or not. + */ + var INCLUDE_MESSAGE_TYPE = true; + /** + * Whether timetokens should be returned as strings by default or not. + */ + var STRINGIFY_TIMETOKENS = false; + /** + * Whether message publisher `uuid` should be returned or not. + */ + var INCLUDE_UUID = true; + /** + * Default number of messages which can be returned for single channel, and it is maximum as well. + */ + var SINGLE_CHANNEL_MESSAGES_COUNT = 100; + /** + * Default number of messages which can be returned for multiple channels or when fetched + * message actions. + */ + var MULTIPLE_CHANNELS_MESSAGES_COUNT = 25; + // endregion + /** + * Fetch messages from channels request. + */ + var FetchMessagesRequest = /** @class */ (function (_super) { + __extends(FetchMessagesRequest, _super); + function FetchMessagesRequest(parameters) { + var _a, _b, _c, _d, _e, _f; + var _this = _super.call(this) || this; + _this.parameters = parameters; + // Apply defaults. + var includeMessageActions = (_a = parameters.includeMessageActions) !== null && _a !== void 0 ? _a : false; + var defaultCount = parameters.channels.length === 1 && includeMessageActions + ? SINGLE_CHANNEL_MESSAGES_COUNT + : MULTIPLE_CHANNELS_MESSAGES_COUNT; + if (!parameters.count) + parameters.count = defaultCount; + else + parameters.count = Math.min(parameters.count, defaultCount); + if (parameters.includeUuid) + parameters.includeUUID = parameters.includeUuid; + else + (_b = parameters.includeUUID) !== null && _b !== void 0 ? _b : (parameters.includeUUID = INCLUDE_UUID); + (_c = parameters.stringifiedTimeToken) !== null && _c !== void 0 ? _c : (parameters.stringifiedTimeToken = STRINGIFY_TIMETOKENS); + (_d = parameters.includeMessageType) !== null && _d !== void 0 ? _d : (parameters.includeMessageType = INCLUDE_MESSAGE_TYPE); + (_e = parameters.includeMeta) !== null && _e !== void 0 ? _e : (parameters.includeMeta = INCLUDE_METADATA); + (_f = parameters.logVerbosity) !== null && _f !== void 0 ? _f : (parameters.logVerbosity = LOG_VERBOSITY); + return _this; } - - function inspect(value, from, noIndent) { - if (from) { - seen = $arrSlice.call(seen); - seen.push(from); - } - if (noIndent) { - var newOpts = { - depth: opts.depth + FetchMessagesRequest.prototype.operation = function () { + return RequestOperation$1.PNFetchMessagesOperation; + }; + FetchMessagesRequest.prototype.validate = function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channels = _a.channels, includeMessageActions = _a.includeMessageActions; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!channels) + return 'Missing channels'; + if (includeMessageActions && channels.length > 1) + return ('History can return actions data for a single channel only. Either pass a single channel ' + + 'or disable the includeMessageActions flag.'); + }; + FetchMessagesRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse, responseChannels, channels; + var _this = this; + var _a; + return __generator(this, function (_b) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + responseChannels = (_a = serviceResponse.channels) !== null && _a !== void 0 ? _a : {}; + channels = {}; + Object.keys(responseChannels).forEach(function (channel) { + // Map service response to expected data object type structure. + channels[channel] = responseChannels[channel].map(function (payload) { + // `null` message type means regular message. + if (payload.message_type === null) + payload.message_type = PubNubMessageType.Message; + var processedPayload = _this.processPayload(channel, payload); + var item = { + channel: channel, + timetoken: payload.timetoken, + message: processedPayload.payload, + messageType: payload.message_type, + uuid: payload.uuid, + }; + if (payload.actions) { + var itemWithActions = item; + itemWithActions.actions = payload.actions; + // Backward compatibility for existing users. + // TODO: Remove in next release. + itemWithActions.data = payload.actions; + } + if (payload.meta) + item.meta = payload.meta; + if (processedPayload.error) + item.error = processedPayload.error; + return item; + }); + }); + if (serviceResponse.more) + return [2 /*return*/, { channels: responseChannels, more: serviceResponse.more }]; + return [2 /*return*/, { channels: responseChannels }]; + }); + }); + }; + Object.defineProperty(FetchMessagesRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channels = _a.channels, includeMessageActions = _a.includeMessageActions; + var endpoint = !includeMessageActions ? 'history' : 'history-with-actions'; + return "/v3/".concat(endpoint, "/sub-key/").concat(subscribeKey, "/channel/").concat(encodeString(channels.join(','))); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(FetchMessagesRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, start = _a.start, end = _a.end, count = _a.count, includeMessageType = _a.includeMessageType, includeMeta = _a.includeMeta, includeUUID = _a.includeUUID, stringifiedTimeToken = _a.stringifiedTimeToken; + return __assign(__assign(__assign(__assign(__assign(__assign({ max: count }, (start ? { start: start } : {})), (end ? { end: end } : {})), (stringifiedTimeToken ? { string_message_token: 'true' } : {})), (includeMeta ? { include_meta: 'true' } : {})), (includeUUID ? { include_uuid: 'true' } : {})), (includeMessageType ? { include_message_type: 'true' } : {})); + }, + enumerable: false, + configurable: true + }); + /** + * Parse single channel data entry. + * + * @param channel - Channel for which {@link payload} should be processed. + * @param payload - Source payload which should be processed and parsed to expected type. + * + * @returns + */ + FetchMessagesRequest.prototype.processPayload = function (channel, payload) { + var _a = this.parameters, crypto = _a.crypto, logVerbosity = _a.logVerbosity; + if (!crypto || typeof payload.message !== 'string') + return { payload: payload.message }; + var decryptedPayload; + var error; + try { + var decryptedData = crypto.decrypt(payload.message); + decryptedPayload = + decryptedData instanceof ArrayBuffer + ? JSON.parse(FetchMessagesRequest.decoder.decode(decryptedData)) + : decryptedData; + } + catch (err) { + if (logVerbosity) + console.log("decryption error", err.message); + decryptedPayload = payload.message; + error = "Error while decrypting message content: ".concat(err.message); + } + if (!error && + decryptedPayload && + payload.message_type == PubNubMessageType.Files && + typeof decryptedPayload === 'object' && + this.isFileMessage(decryptedPayload)) { + var fileMessage = decryptedPayload; + return { + payload: { + message: fileMessage.message, + file: __assign(__assign({}, fileMessage.file), { url: this.parameters.getFileUrl({ channel: channel, id: fileMessage.file.id, name: fileMessage.file.name }) }), + }, + error: error, }; - if (has$3(opts, 'quoteStyle')) { - newOpts.quoteStyle = opts.quoteStyle; - } - return inspect_(value, newOpts, depth + 1, seen); } - return inspect_(value, opts, depth + 1, seen); - } + return { payload: decryptedPayload, error: error }; + }; + /** + * Check whether `payload` potentially represents file message. + * + * @param payload - Fetched message payload. + * + * @returns `true` if payload can be {@link History#FileMessage|FileMessage}. + */ + FetchMessagesRequest.prototype.isFileMessage = function (payload) { + return payload.file !== undefined; + }; + return FetchMessagesRequest; + }(AbstractRequest)); - if (typeof obj === 'function' && !isRegExp$1(obj)) { // in older engines, regexes are callable - var name = nameOf(obj); - var keys = arrObjKeys(obj, inspect); - return '[Function' + (name ? ': ' + name : ' (anonymous)') + ']' + (keys.length > 0 ? ' { ' + $join.call(keys, ', ') + ' }' : ''); - } - if (isSymbol(obj)) { - var symString = hasShammedSymbols ? $replace.call(String(obj), /^(Symbol\(.*\))_[^)]*$/, '$1') : symToString.call(obj); - return typeof obj === 'object' && !hasShammedSymbols ? markBoxed(symString) : symString; - } - if (isElement(obj)) { - var s = '<' + $toLowerCase.call(String(obj.nodeName)); - var attrs = obj.attributes || []; - for (var i = 0; i < attrs.length; i++) { - s += ' ' + attrs[i].name + '=' + wrapQuotes(quote(attrs[i].value), 'double', opts); - } - s += '>'; - if (obj.childNodes && obj.childNodes.length) { s += '...'; } - s += ''; - return s; - } - if (isArray$3(obj)) { - if (obj.length === 0) { return '[]'; } - var xs = arrObjKeys(obj, inspect); - if (indent && !singleLineValues(xs)) { - return '[' + indentedJoin(xs, indent) + ']'; - } - return '[ ' + $join.call(xs, ', ') + ' ]'; - } - if (isError(obj)) { - var parts = arrObjKeys(obj, inspect); - if (!('cause' in Error.prototype) && 'cause' in obj && !isEnumerable.call(obj, 'cause')) { - return '{ [' + String(obj) + '] ' + $join.call($concat.call('[cause]: ' + inspect(obj.cause), parts), ', ') + ' }'; - } - if (parts.length === 0) { return '[' + String(obj) + ']'; } - return '{ [' + String(obj) + '] ' + $join.call(parts, ', ') + ' }'; - } - if (typeof obj === 'object' && customInspect) { - if (inspectSymbol && typeof obj[inspectSymbol] === 'function' && utilInspect) { - return utilInspect(obj, { depth: maxDepth - depth }); - } else if (customInspect !== 'symbol' && typeof obj.inspect === 'function') { - return obj.inspect(); - } - } - if (isMap(obj)) { - var mapParts = []; - if (mapForEach) { - mapForEach.call(obj, function (value, key) { - mapParts.push(inspect(key, obj, true) + ' => ' + inspect(value, obj)); - }); - } - return collectionOf('Map', mapSize.call(obj), mapParts, indent); + /** + * Get Message Actions REST API module. + */ + // endregion + /** + * Fetch channel message actions request. + */ + var GetMessageActionsRequest = /** @class */ (function (_super) { + __extends(GetMessageActionsRequest, _super); + function GetMessageActionsRequest(parameters) { + var _this = _super.call(this) || this; + _this.parameters = parameters; + return _this; } - if (isSet(obj)) { - var setParts = []; - if (setForEach) { - setForEach.call(obj, function (value) { - setParts.push(inspect(value, obj)); + GetMessageActionsRequest.prototype.operation = function () { + return RequestOperation$1.PNGetMessageActionsOperation; + }; + GetMessageActionsRequest.prototype.validate = function () { + if (!this.parameters.keySet.subscribeKey) + return 'Missing Subscribe Key'; + if (!this.parameters.channel) + return 'Missing message channel'; + }; + GetMessageActionsRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse, start, end; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + start = null; + end = null; + if (serviceResponse.data.length > 0) { + start = serviceResponse.data[0].actionTimetoken; + end = serviceResponse.data[serviceResponse.data.length - 1].actionTimetoken; + } + return [2 /*return*/, { + data: serviceResponse.data, + more: serviceResponse.more, + start: start, + end: end, + }]; }); - } - return collectionOf('Set', setSize.call(obj), setParts, indent); - } - if (isWeakMap(obj)) { - return weakCollectionOf('WeakMap'); - } - if (isWeakSet(obj)) { - return weakCollectionOf('WeakSet'); - } - if (isWeakRef(obj)) { - return weakCollectionOf('WeakRef'); - } - if (isNumber(obj)) { - return markBoxed(inspect(Number(obj))); - } - if (isBigInt(obj)) { - return markBoxed(inspect(bigIntValueOf.call(obj))); - } - if (isBoolean(obj)) { - return markBoxed(booleanValueOf.call(obj)); - } - if (isString(obj)) { - return markBoxed(inspect(String(obj))); - } - // note: in IE 8, sometimes `global !== window` but both are the prototypes of each other - /* eslint-env browser */ - if (typeof window !== 'undefined' && obj === window) { - return '{ [object Window] }'; - } - if (obj === commonjsGlobal) { - return '{ [object globalThis] }'; - } - if (!isDate(obj) && !isRegExp$1(obj)) { - var ys = arrObjKeys(obj, inspect); - var isPlainObject = gPO ? gPO(obj) === Object.prototype : obj instanceof Object || obj.constructor === Object; - var protoTag = obj instanceof Object ? '' : 'null prototype'; - var stringTag = !isPlainObject && toStringTag && Object(obj) === obj && toStringTag in obj ? $slice.call(toStr(obj), 8, -1) : protoTag ? 'Object' : ''; - var constructorTag = isPlainObject || typeof obj.constructor !== 'function' ? '' : obj.constructor.name ? obj.constructor.name + ' ' : ''; - var tag = constructorTag + (stringTag || protoTag ? '[' + $join.call($concat.call([], stringTag || [], protoTag || []), ': ') + '] ' : ''); - if (ys.length === 0) { return tag + '{}'; } - if (indent) { - return tag + '{' + indentedJoin(ys, indent) + '}'; - } - return tag + '{ ' + $join.call(ys, ', ') + ' }'; - } - return String(obj); - }; - - function wrapQuotes(s, defaultStyle, opts) { - var quoteChar = (opts.quoteStyle || defaultStyle) === 'double' ? '"' : "'"; - return quoteChar + s + quoteChar; - } - - function quote(s) { - return $replace.call(String(s), /"/g, '"'); - } - - function isArray$3(obj) { return toStr(obj) === '[object Array]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); } - function isDate(obj) { return toStr(obj) === '[object Date]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); } - function isRegExp$1(obj) { return toStr(obj) === '[object RegExp]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); } - function isError(obj) { return toStr(obj) === '[object Error]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); } - function isString(obj) { return toStr(obj) === '[object String]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); } - function isNumber(obj) { return toStr(obj) === '[object Number]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); } - function isBoolean(obj) { return toStr(obj) === '[object Boolean]' && (!toStringTag || !(typeof obj === 'object' && toStringTag in obj)); } + }); + }; + Object.defineProperty(GetMessageActionsRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channel = _a.channel; + return "/v1/message-actions/".concat(subscribeKey, "/channel/").concat(encodeString(channel)); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(GetMessageActionsRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, limit = _a.limit, start = _a.start, end = _a.end; + return __assign(__assign(__assign({}, (start ? { start: start } : {})), (end ? { end: end } : {})), (limit ? { limit: limit } : {})); + }, + enumerable: false, + configurable: true + }); + return GetMessageActionsRequest; + }(AbstractRequest)); - // Symbol and BigInt do have Symbol.toStringTag by spec, so that can't be used to eliminate false positives - function isSymbol(obj) { - if (hasShammedSymbols) { - return obj && typeof obj === 'object' && obj instanceof Symbol; - } - if (typeof obj === 'symbol') { - return true; - } - if (!obj || typeof obj !== 'object' || !symToString) { - return false; + /** + * Add Message Action REST API module. + */ + // endregion + /** + * Add Message Reaction request. + */ + var AddMessageActionRequest = /** @class */ (function (_super) { + __extends(AddMessageActionRequest, _super); + function AddMessageActionRequest(parameters) { + var _this = _super.call(this, { method: TransportMethod.POST }) || this; + _this.parameters = parameters; + return _this; } - try { - symToString.call(obj); - return true; - } catch (e) {} - return false; - } + AddMessageActionRequest.prototype.operation = function () { + return RequestOperation$1.PNAddMessageActionOperation; + }; + AddMessageActionRequest.prototype.validate = function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, action = _a.action, channel = _a.channel, messageTimetoken = _a.messageTimetoken; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!channel) + return 'Missing message channel'; + if (!messageTimetoken) + return 'Missing message timetoken'; + if (!action) + return 'Missing Action.value'; + if (!action.value) + return 'Missing Action.value'; + if (!action.type) + return 'Missing Action.type'; + if (action.type.length > 15) + return 'Action.type value exceed maximum length of 15'; + }; + AddMessageActionRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, { data: serviceResponse.data }]; + }); + }); + }; + Object.defineProperty(AddMessageActionRequest.prototype, "headers", { + get: function () { + return { 'Content-Type': 'application/json' }; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(AddMessageActionRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channel = _a.channel, messageTimetoken = _a.messageTimetoken; + return "/v1/message-actions/".concat(subscribeKey, "/channel/").concat(encodeString(channel), "/message/").concat(messageTimetoken); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(AddMessageActionRequest.prototype, "body", { + get: function () { + return JSON.stringify(this.parameters.action); + }, + enumerable: false, + configurable: true + }); + return AddMessageActionRequest; + }(AbstractRequest)); - function isBigInt(obj) { - if (!obj || typeof obj !== 'object' || !bigIntValueOf) { - return false; + /** + * Remove Message Action REST API module. + */ + // endregion + /** + * Remove specific message action request. + */ + var RemoveMessageAction = /** @class */ (function (_super) { + __extends(RemoveMessageAction, _super); + function RemoveMessageAction(parameters) { + var _this = _super.call(this, { method: TransportMethod.DELETE }) || this; + _this.parameters = parameters; + return _this; } - try { - bigIntValueOf.call(obj); - return true; - } catch (e) {} - return false; - } - - var hasOwn$1 = Object.prototype.hasOwnProperty || function (key) { return key in this; }; - function has$3(obj, key) { - return hasOwn$1.call(obj, key); - } - - function toStr(obj) { - return objectToString.call(obj); - } - - function nameOf(f) { - if (f.name) { return f.name; } - var m = $match.call(functionToString.call(f), /^function\s*([\w$]+)/); - if (m) { return m[1]; } - return null; - } + RemoveMessageAction.prototype.operation = function () { + return RequestOperation$1.PNRemoveMessageActionOperation; + }; + RemoveMessageAction.prototype.validate = function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channel = _a.channel, messageTimetoken = _a.messageTimetoken, actionTimetoken = _a.actionTimetoken; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!channel) + return 'Missing message action channel'; + if (!messageTimetoken) + return 'Missing message timetoken'; + if (!actionTimetoken) + return 'Missing action timetoken'; + }; + RemoveMessageAction.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, { data: serviceResponse.data }]; + }); + }); + }; + Object.defineProperty(RemoveMessageAction.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channel = _a.channel, actionTimetoken = _a.actionTimetoken, messageTimetoken = _a.messageTimetoken; + return "/v1/message-actions/".concat(subscribeKey, "/channel/").concat(encodeString(channel), "/message/").concat(messageTimetoken, "/action/").concat(actionTimetoken); + }, + enumerable: false, + configurable: true + }); + return RemoveMessageAction; + }(AbstractRequest)); - function indexOf(xs, x) { - if (xs.indexOf) { return xs.indexOf(x); } - for (var i = 0, l = xs.length; i < l; i++) { - if (xs[i] === x) { return i; } + /** + * Publish File Message REST API module. + */ + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults + /** + * Whether published file messages should be stored in the channel's history. + */ + var STORE_IN_HISTORY = true; + // endregion + var PublishFileMessageRequest = /** @class */ (function (_super) { + __extends(PublishFileMessageRequest, _super); + function PublishFileMessageRequest(parameters) { + var _a; + var _b; + var _this = _super.call(this) || this; + _this.parameters = parameters; + // Apply default request parameters. + (_a = (_b = _this.parameters).storeInHistory) !== null && _a !== void 0 ? _a : (_b.storeInHistory = STORE_IN_HISTORY); + return _this; } - return -1; - } + PublishFileMessageRequest.prototype.operation = function () { + return RequestOperation$1.PNPublishFileMessageOperation; + }; + PublishFileMessageRequest.prototype.validate = function () { + var _a = this.parameters, channel = _a.channel, fileId = _a.fileId, fileName = _a.fileName; + if (!channel) + return "channel can't be empty"; + if (!fileId) + return "file id can't be empty"; + if (!fileName) + return "file name can't be empty"; + }; + PublishFileMessageRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, { timetoken: serviceResponse[2] }]; + }); + }); + }; + Object.defineProperty(PublishFileMessageRequest.prototype, "path", { + get: function () { + var _a = this.parameters, message = _a.message, channel = _a.channel, _b = _a.keySet, publishKey = _b.publishKey, subscribeKey = _b.subscribeKey, fileId = _a.fileId, fileName = _a.fileName; + var fileMessage = __assign({ file: { + name: fileName, + id: fileId, + } }, (message ? { message: message } : {})); + return "/v1/files/publish-file/".concat(publishKey, "/").concat(subscribeKey, "/0/").concat(encodeString(channel), "/0/").concat(encodeString(this.prepareMessagePayload(fileMessage))); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(PublishFileMessageRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, storeInHistory = _a.storeInHistory, ttl = _a.ttl, meta = _a.meta; + return __assign(__assign({ store: storeInHistory ? '1' : '0' }, (ttl ? { ttl: ttl } : {})), (meta && typeof meta === 'object' ? { meta: JSON.stringify(meta) } : {})); + }, + enumerable: false, + configurable: true + }); + /** + * Pre-process provided data. + * + * Data will be "normalized" and encrypted if `cryptoModule` has been provided. + * + * @param payload - User-provided data which should be pre-processed before use. + * + * @returns Payload which can be used as part of request URL or body. + * + * @throws {Error} in case if provided `payload` or results of `encryption` can't be stringified. + */ + PublishFileMessageRequest.prototype.prepareMessagePayload = function (payload) { + var crypto = this.parameters.crypto; + if (!crypto) + return JSON.stringify(payload) || ''; + var encrypted = crypto.encrypt(JSON.stringify(payload)); + return JSON.stringify(typeof encrypted === 'string' ? encrypted : encode(encrypted)); + }; + return PublishFileMessageRequest; + }(AbstractRequest)); - function isMap(x) { - if (!mapSize || !x || typeof x !== 'object') { - return false; + /** + * File sharing REST API module. + */ + // endregion + /** + * File download Url generation request. + * + * Local request which generates Url to download shared file from the specific channel. + */ + var GetFileDownloadUrlRequest = /** @class */ (function (_super) { + __extends(GetFileDownloadUrlRequest, _super); + /** + * Construct file download Url generation request. + * + * @param parameters - Request configuration. + */ + function GetFileDownloadUrlRequest(parameters) { + var _this = _super.call(this, { method: TransportMethod.LOCAL }) || this; + _this.parameters = parameters; + return _this; } - try { - mapSize.call(x); - try { - setSize.call(x); - } catch (s) { - return true; - } - return x instanceof Map; // core-js workaround, pre-v2.5.0 - } catch (e) {} - return false; - } + GetFileDownloadUrlRequest.prototype.operation = function () { + return RequestOperation$1.PNGetFileUrlOperation; + }; + GetFileDownloadUrlRequest.prototype.validate = function () { + var _a = this.parameters, channel = _a.channel, id = _a.id, name = _a.name; + if (!channel) + return "channel can't be empty"; + if (!id) + return "file id can't be empty"; + if (!name) + return "file name can't be empty"; + }; + GetFileDownloadUrlRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, response.url]; + }); + }); + }; + Object.defineProperty(GetFileDownloadUrlRequest.prototype, "path", { + get: function () { + var _a = this.parameters, channel = _a.channel, id = _a.id, name = _a.name, subscribeKey = _a.keySet.subscribeKey; + return "/v1/files/".concat(subscribeKey, "/channels/").concat(encodeString(channel), "/files/").concat(id, "/").concat(name); + }, + enumerable: false, + configurable: true + }); + return GetFileDownloadUrlRequest; + }(AbstractRequest)); - function isWeakMap(x) { - if (!weakMapHas || !x || typeof x !== 'object') { - return false; + /** + * Delete file REST API module. + */ + // endregion + /** + * Delete File request. + */ + var DeleteFileRequest = /** @class */ (function (_super) { + __extends(DeleteFileRequest, _super); + function DeleteFileRequest(parameters) { + var _this = _super.call(this, { method: TransportMethod.DELETE }) || this; + _this.parameters = parameters; + return _this; } - try { - weakMapHas.call(x, weakMapHas); - try { - weakSetHas.call(x, weakSetHas); - } catch (s) { - return true; - } - return x instanceof WeakMap; // core-js workaround, pre-v2.5.0 - } catch (e) {} - return false; - } + DeleteFileRequest.prototype.operation = function () { + return RequestOperation$1.PNDeleteFileOperation; + }; + DeleteFileRequest.prototype.validate = function () { + var _a = this.parameters, channel = _a.channel, id = _a.id, name = _a.name; + if (!channel) + return "channel can't be empty"; + if (!id) + return "file id can't be empty"; + if (!name) + return "file name can't be empty"; + }; + DeleteFileRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, serviceResponse]; + }); + }); + }; + Object.defineProperty(DeleteFileRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, id = _a.id, channel = _a.channel, name = _a.name; + return "/v1/files/".concat(subscribeKey, "/channels/").concat(encodeString(channel), "/files/").concat(id, "/").concat(name); + }, + enumerable: false, + configurable: true + }); + return DeleteFileRequest; + }(AbstractRequest)); - function isWeakRef(x) { - if (!weakRefDeref || !x || typeof x !== 'object') { - return false; + /** + * List Files REST API module. + */ + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults + /** + * Number of files to return in response. + */ + var LIMIT$6 = 100; + // endregion + /** + * Files List request. + */ + var FilesListRequest = /** @class */ (function (_super) { + __extends(FilesListRequest, _super); + function FilesListRequest(parameters) { + var _a; + var _b; + var _this = _super.call(this) || this; + _this.parameters = parameters; + // Apply default request parameters. + (_a = (_b = _this.parameters).limit) !== null && _a !== void 0 ? _a : (_b.limit = LIMIT$6); + return _this; } - try { - weakRefDeref.call(x); - return true; - } catch (e) {} - return false; - } + FilesListRequest.prototype.operation = function () { + return RequestOperation$1.PNListFilesOperation; + }; + FilesListRequest.prototype.validate = function () { + if (!this.parameters.channel) + return "channel can't be empty"; + }; + FilesListRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, serviceResponse]; + }); + }); + }; + Object.defineProperty(FilesListRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channel = _a.channel; + return "/v1/files/".concat(subscribeKey, "/channels/").concat(encodeString(channel), "/files"); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(FilesListRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, limit = _a.limit, next = _a.next; + return __assign({ limit: limit }, (next ? { next: next } : {})); + }, + enumerable: false, + configurable: true + }); + return FilesListRequest; + }(AbstractRequest)); - function isSet(x) { - if (!setSize || !x || typeof x !== 'object') { - return false; + /** + * Generate file upload URL REST API request. + */ + // endregion + /** + * Generate File Upload Url request. + */ + var GenerateFileUploadUrlRequest = /** @class */ (function (_super) { + __extends(GenerateFileUploadUrlRequest, _super); + function GenerateFileUploadUrlRequest(parameters) { + var _this = _super.call(this, { method: TransportMethod.POST }) || this; + _this.parameters = parameters; + return _this; } - try { - setSize.call(x); - try { - mapSize.call(x); - } catch (m) { - return true; - } - return x instanceof Set; // core-js workaround, pre-v2.5.0 - } catch (e) {} - return false; - } + GenerateFileUploadUrlRequest.prototype.operation = function () { + return RequestOperation$1.PNGenerateUploadUrlOperation; + }; + GenerateFileUploadUrlRequest.prototype.validate = function () { + if (!this.parameters.channel) + return "channel can't be empty"; + if (!this.parameters.name) + return "'name' can't be empty"; + }; + GenerateFileUploadUrlRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, { + id: serviceResponse.data.id, + name: serviceResponse.data.name, + url: serviceResponse.file_upload_request.url, + formFields: serviceResponse.file_upload_request.form_fields, + }]; + }); + }); + }; + Object.defineProperty(GenerateFileUploadUrlRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channel = _a.channel; + return "/v1/files/".concat(subscribeKey, "/channels/").concat(encodeString(channel), "/generate-upload-url"); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(GenerateFileUploadUrlRequest.prototype, "body", { + get: function () { + return JSON.stringify({ name: this.parameters.name }); + }, + enumerable: false, + configurable: true + }); + return GenerateFileUploadUrlRequest; + }(AbstractRequest)); - function isWeakSet(x) { - if (!weakSetHas || !x || typeof x !== 'object') { - return false; - } - try { - weakSetHas.call(x, weakSetHas); - try { - weakMapHas.call(x, weakMapHas); - } catch (s) { - return true; + /** + * Upload file REST API request. + */ + /** + * File Upload request. + */ + var UploadFileRequest = /** @class */ (function (_super) { + __extends(UploadFileRequest, _super); + function UploadFileRequest(parameters) { + var _this = _super.call(this) || this; + _this.parameters = parameters; + // Use file's actual mime type if available. + var mimeType = parameters.file.mimeType; + if (mimeType) { + parameters.formFields = parameters.formFields.map(function (entry) { + if (entry.name === 'Content-Type') + return { name: entry.name, value: mimeType }; + return entry; + }); } - return x instanceof WeakSet; // core-js workaround, pre-v2.5.0 - } catch (e) {} - return false; - } - - function isElement(x) { - if (!x || typeof x !== 'object') { return false; } - if (typeof HTMLElement !== 'undefined' && x instanceof HTMLElement) { - return true; - } - return typeof x.nodeName === 'string' && typeof x.getAttribute === 'function'; - } - - function inspectString(str, opts) { - if (str.length > opts.maxStringLength) { - var remaining = str.length - opts.maxStringLength; - var trailer = '... ' + remaining + ' more character' + (remaining > 1 ? 's' : ''); - return inspectString($slice.call(str, 0, opts.maxStringLength), opts) + trailer; + return _this; } - // eslint-disable-next-line no-control-regex - var s = $replace.call($replace.call(str, /(['\\])/g, '\\$1'), /[\x00-\x1f]/g, lowbyte); - return wrapQuotes(s, 'single', opts); - } - - function lowbyte(c) { - var n = c.charCodeAt(0); - var x = { - 8: 'b', - 9: 't', - 10: 'n', - 12: 'f', - 13: 'r' - }[n]; - if (x) { return '\\' + x; } - return '\\x' + (n < 0x10 ? '0' : '') + $toUpperCase.call(n.toString(16)); - } - - function markBoxed(str) { - return 'Object(' + str + ')'; - } - - function weakCollectionOf(type) { - return type + ' { ? }'; - } - - function collectionOf(type, size, entries, indent) { - var joinedEntries = indent ? indentedJoin(entries, indent) : $join.call(entries, ', '); - return type + ' (' + size + ') {' + joinedEntries + '}'; - } + UploadFileRequest.prototype.operation = function () { + return RequestOperation$1.PNPublishFileOperation; + }; + UploadFileRequest.prototype.validate = function () { + var _a = this.parameters, fileId = _a.fileId, fileName = _a.fileName, file = _a.file, uploadUrl = _a.uploadUrl; + if (!fileId) + return "Validation failed: file 'id' can't be empty"; + if (!fileName) + return "Validation failed: file 'name' can't be empty"; + if (!file) + return "Validation failed: 'file' can't be empty"; + if (!uploadUrl) + return "Validation failed: file upload 'url' can't be empty"; + }; + UploadFileRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, { + status: response.status, + message: response.body ? UploadFileRequest.decoder.decode(response.body) : 'OK', + }]; + }); + }); + }; + UploadFileRequest.prototype.request = function () { + return __assign(__assign({}, _super.prototype.request.call(this)), { origin: new URL(this.parameters.uploadUrl).origin }); + }; + Object.defineProperty(UploadFileRequest.prototype, "path", { + get: function () { + var _a = new URL(this.parameters.uploadUrl), pathname = _a.pathname, search = _a.search; + return "".concat(pathname).concat(search); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(UploadFileRequest.prototype, "body", { + get: function () { + return this.parameters.file; + }, + enumerable: false, + configurable: true + }); + return UploadFileRequest; + }(AbstractRequest)); - function singleLineValues(xs) { - for (var i = 0; i < xs.length; i++) { - if (indexOf(xs[i], '\n') >= 0) { - return false; - } + // endregion + /** + * Send file composed request. + */ + var SendFileRequest = /** @class */ (function () { + function SendFileRequest(parameters) { + var _a; + this.parameters = parameters; + this.file = (_a = this.parameters.PubNubFile) === null || _a === void 0 ? void 0 : _a.create(parameters.file); + if (!this.file) + throw new Error('File upload error: unable to create File object.'); } - return true; - } + /** + * Process user-input and upload file. + * + * @returns File upload request response. + */ + SendFileRequest.prototype.process = function () { + return __awaiter(this, void 0, void 0, function () { + var fileName, fileId; + var _this = this; + return __generator(this, function (_a) { + return [2 /*return*/, this.generateFileUploadUrl() + .then(function (result) { + fileName = result.name; + fileId = result.id; + return _this.uploadFile(result); + }) + .then(function () { return _this.publishFileMessage(fileId, fileName); }) + .catch(function (error) { + var errorStatus = PubNubAPIError.create(error).toStatus(RequestOperation$1.PNPublishFileOperation); + throw new PubNubError('File upload error.', errorStatus); + })]; + }); + }); + }; + /** + * Generate pre-signed file upload Url. + * + * @returns File upload credentials. + */ + SendFileRequest.prototype.generateFileUploadUrl = function () { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new GenerateFileUploadUrlRequest(__assign(__assign({}, this.parameters), { name: this.file.name, keySet: this.parameters.keySet })); + return [2 /*return*/, this.parameters.sendRequest(request)]; + }); + }); + }; + /** + * Prepare and upload {@link PubNub} File object to remote storage. + * + * @param uploadParameters - File upload request parameters. + * + * @returns + */ + SendFileRequest.prototype.uploadFile = function (uploadParameters) { + return __awaiter(this, void 0, void 0, function () { + var _a, cipherKey, PubNubFile, crypto, cryptography, id, name, url, formFields, _b, _c; + return __generator(this, function (_d) { + switch (_d.label) { + case 0: + _a = this.parameters, cipherKey = _a.cipherKey, PubNubFile = _a.PubNubFile, crypto = _a.crypto, cryptography = _a.cryptography; + id = uploadParameters.id, name = uploadParameters.name, url = uploadParameters.url, formFields = uploadParameters.formFields; + if (!this.parameters.PubNubFile.supportsEncryptFile) return [3 /*break*/, 4]; + if (!(!cipherKey && crypto)) return [3 /*break*/, 2]; + _b = this; + return [4 /*yield*/, crypto.encryptFile(this.file, PubNubFile)]; + case 1: + _b.file = (_d.sent()); + return [3 /*break*/, 4]; + case 2: + if (!(cipherKey && cryptography)) return [3 /*break*/, 4]; + _c = this; + return [4 /*yield*/, cryptography.encryptFile(cipherKey, this.file, PubNubFile)]; + case 3: + _c.file = (_d.sent()); + _d.label = 4; + case 4: return [2 /*return*/, this.parameters.sendRequest(new UploadFileRequest({ + fileId: id, + fileName: name, + file: this.file, + uploadUrl: url, + formFields: formFields, + }))]; + } + }); + }); + }; + SendFileRequest.prototype.publishFileMessage = function (fileId, fileName) { + return __awaiter(this, void 0, void 0, function () { + var result, retries, wasSuccessful; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + result = { timetoken: '0' }; + retries = this.parameters.fileUploadPublishRetryLimit; + wasSuccessful = false; + _a.label = 1; + case 1: + _a.trys.push([1, 3, , 4]); + return [4 /*yield*/, this.parameters.publishFile(__assign(__assign({}, this.parameters), { fileId: fileId, fileName: fileName }))]; + case 2: + result = _a.sent(); + wasSuccessful = true; + return [3 /*break*/, 4]; + case 3: + _a.sent(); + retries -= 1; + return [3 /*break*/, 4]; + case 4: + if (!wasSuccessful && retries > 0) return [3 /*break*/, 1]; + _a.label = 5; + case 5: + if (!wasSuccessful) { + throw new PubNubError('Publish failed. You may want to execute that operation manually using pubnub.publishFile', { error: true, channel: this.parameters.channel, id: fileId, name: fileName }); + } + else + return [2 /*return*/, { status: 200, timetoken: result.timetoken, id: fileId, name: fileName }]; + } + }); + }); + }; + return SendFileRequest; + }()); - function getIndent(opts, depth) { - var baseIndent; - if (opts.indent === '\t') { - baseIndent = '\t'; - } else if (typeof opts.indent === 'number' && opts.indent > 0) { - baseIndent = $join.call(Array(opts.indent + 1), ' '); - } else { - return null; + /** + * PAM Revoke Token REST API module. + */ + // endregion + /** + * Access token revoke request. + * + * Invalidate token and permissions which has been granted for it. + */ + var RevokeTokenRequest = /** @class */ (function (_super) { + __extends(RevokeTokenRequest, _super); + function RevokeTokenRequest(parameters) { + var _this = _super.call(this, { method: TransportMethod.DELETE }) || this; + _this.parameters = parameters; + return _this; } - return { - base: baseIndent, - prev: $join.call(Array(depth + 1), baseIndent) + RevokeTokenRequest.prototype.operation = function () { + return RequestOperation$1.PNAccessManagerRevokeToken; }; - } - - function indentedJoin(xs, indent) { - if (xs.length === 0) { return ''; } - var lineJoiner = '\n' + indent.prev + indent.base; - return lineJoiner + $join.call(xs, ',' + lineJoiner) + '\n' + indent.prev; - } + RevokeTokenRequest.prototype.validate = function () { + if (!this.parameters.keySet.secretKey) + return 'Missing Secret Key'; + if (!this.parameters.token) + return "token can't be empty"; + }; + RevokeTokenRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, {}]; + }); + }); + }; + Object.defineProperty(RevokeTokenRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, token = _a.token; + return "/v3/pam/".concat(subscribeKey, "/grant/").concat(encodeString(token)); + }, + enumerable: false, + configurable: true + }); + return RevokeTokenRequest; + }(AbstractRequest)); - function arrObjKeys(obj, inspect) { - var isArr = isArray$3(obj); - var xs = []; - if (isArr) { - xs.length = obj.length; - for (var i = 0; i < obj.length; i++) { - xs[i] = has$3(obj, i) ? inspect(obj[i], obj) : ''; - } - } - var syms = typeof gOPS === 'function' ? gOPS(obj) : []; - var symMap; - if (hasShammedSymbols) { - symMap = {}; - for (var k = 0; k < syms.length; k++) { - symMap['$' + syms[k]] = syms[k]; - } - } - - for (var key in obj) { // eslint-disable-line no-restricted-syntax - if (!has$3(obj, key)) { continue; } // eslint-disable-line no-restricted-syntax, no-continue - if (isArr && String(Number(key)) === key && key < obj.length) { continue; } // eslint-disable-line no-restricted-syntax, no-continue - if (hasShammedSymbols && symMap['$' + key] instanceof Symbol) { - // this is to prevent shammed Symbols, which are stored as strings, from being included in the string key section - continue; // eslint-disable-line no-restricted-syntax, no-continue - } else if ($test.call(/[^\w$]/, key)) { - xs.push(inspect(key, obj) + ': ' + inspect(obj[key], obj)); - } else { - xs.push(key + ': ' + inspect(obj[key], obj)); - } - } - if (typeof gOPS === 'function') { - for (var j = 0; j < syms.length; j++) { - if (isEnumerable.call(obj, syms[j])) { - xs.push('[' + inspect(syms[j]) + ']: ' + inspect(obj[syms[j]], obj)); - } - } + /** + * PAM Grant Token REST API module. + */ + // endregion + /** + * Grant token permissions request. + */ + var GrantTokenRequest = /** @class */ (function (_super) { + __extends(GrantTokenRequest, _super); + function GrantTokenRequest(parameters) { + var _a, _b; + var _c, _d; + var _this = _super.call(this, { method: TransportMethod.POST }) || this; + _this.parameters = parameters; + // Apply defaults. + (_a = (_c = _this.parameters).resources) !== null && _a !== void 0 ? _a : (_c.resources = {}); + (_b = (_d = _this.parameters).patterns) !== null && _b !== void 0 ? _b : (_d.patterns = {}); + return _this; } - return xs; - } - - var GetIntrinsic = getIntrinsic; - var callBound = callBound$1; - var inspect = objectInspect; - - var $TypeError = GetIntrinsic('%TypeError%'); - var $WeakMap = GetIntrinsic('%WeakMap%', true); - var $Map = GetIntrinsic('%Map%', true); - - var $weakMapGet = callBound('WeakMap.prototype.get', true); - var $weakMapSet = callBound('WeakMap.prototype.set', true); - var $weakMapHas = callBound('WeakMap.prototype.has', true); - var $mapGet = callBound('Map.prototype.get', true); - var $mapSet = callBound('Map.prototype.set', true); - var $mapHas = callBound('Map.prototype.has', true); - - /* - * This function traverses the list returning the node corresponding to the - * given key. - * - * That node is also moved to the head of the list, so that if it's accessed - * again we don't need to traverse the whole list. By doing so, all the recently - * used nodes can be accessed relatively quickly. - */ - var listGetNode = function (list, key) { // eslint-disable-line consistent-return - for (var prev = list, curr; (curr = prev.next) !== null; prev = curr) { - if (curr.key === key) { - prev.next = curr.next; - curr.next = list.next; - list.next = curr; // eslint-disable-line no-param-reassign - return curr; - } - } - }; - - var listGet = function (objects, key) { - var node = listGetNode(objects, key); - return node && node.value; - }; - var listSet = function (objects, key, value) { - var node = listGetNode(objects, key); - if (node) { - node.value = value; - } else { - // Prepend the new node to the beginning of the list - objects.next = { // eslint-disable-line no-param-reassign - key: key, - next: objects.next, - value: value - }; - } - }; - var listHas = function (objects, key) { - return !!listGetNode(objects, key); - }; - - var sideChannel = function getSideChannel() { - var $wm; - var $m; - var $o; - var channel = { - assert: function (key) { - if (!channel.has(key)) { - throw new $TypeError('Side channel does not contain ' + inspect(key)); - } - }, - get: function (key) { // eslint-disable-line consistent-return - if ($WeakMap && key && (typeof key === 'object' || typeof key === 'function')) { - if ($wm) { - return $weakMapGet($wm, key); - } - } else if ($Map) { - if ($m) { - return $mapGet($m, key); - } - } else { - if ($o) { // eslint-disable-line no-lonely-if - return listGet($o, key); - } - } - }, - has: function (key) { - if ($WeakMap && key && (typeof key === 'object' || typeof key === 'function')) { - if ($wm) { - return $weakMapHas($wm, key); - } - } else if ($Map) { - if ($m) { - return $mapHas($m, key); - } - } else { - if ($o) { // eslint-disable-line no-lonely-if - return listHas($o, key); - } - } - return false; - }, - set: function (key, value) { - if ($WeakMap && key && (typeof key === 'object' || typeof key === 'function')) { - if (!$wm) { - $wm = new $WeakMap(); - } - $weakMapSet($wm, key, value); - } else if ($Map) { - if (!$m) { - $m = new $Map(); - } - $mapSet($m, key, value); - } else { - if (!$o) { - /* - * Initialize the linked list as an empty node, so that we don't have - * to special-case handling of the first node: we can always refer to - * it as (previous node).next, instead of something like (list).head - */ - $o = { key: {}, next: null }; - } - listSet($o, key, value); - } - } - }; - return channel; - }; - - var replace = String.prototype.replace; - var percentTwenties = /%20/g; - - var Format = { - RFC1738: 'RFC1738', - RFC3986: 'RFC3986' - }; - - var formats$3 = { - 'default': Format.RFC3986, - formatters: { - RFC1738: function (value) { - return replace.call(value, percentTwenties, '+'); + GrantTokenRequest.prototype.operation = function () { + return RequestOperation$1.PNAccessManagerGrantToken; + }; + GrantTokenRequest.prototype.validate = function () { + var _a, _b, _c, _d, _e, _f; + var _g = this.parameters, _h = _g.keySet, subscribeKey = _h.subscribeKey, publishKey = _h.publishKey, secretKey = _h.secretKey, resources = _g.resources, patterns = _g.patterns; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!publishKey) + return 'Missing Publish Key'; + if (!secretKey) + return 'Missing Secret Key'; + if (!resources && !patterns) + return 'Missing either Resources or Patterns'; + if (this.isVspPermissions(this.parameters) && + ('channels' in ((_a = this.parameters.resources) !== null && _a !== void 0 ? _a : {}) || + 'uuids' in ((_b = this.parameters.resources) !== null && _b !== void 0 ? _b : {}) || + 'groups' in ((_c = this.parameters.resources) !== null && _c !== void 0 ? _c : {}) || + 'channels' in ((_d = this.parameters.patterns) !== null && _d !== void 0 ? _d : {}) || + 'uuids' in ((_e = this.parameters.patterns) !== null && _e !== void 0 ? _e : {}) || + 'groups' in ((_f = this.parameters.patterns) !== null && _f !== void 0 ? _f : {}))) + return ('Cannot mix `users`, `spaces` and `authorizedUserId` with `uuids`, `channels`,' + + ' `groups` and `authorized_uuid`'); + var permissionsEmpty = true; + [this.parameters.resources, this.parameters.patterns].forEach(function (refPerm) { + Object.keys(refPerm !== null && refPerm !== void 0 ? refPerm : {}).forEach(function (scope) { + var _a; + // @ts-expect-error Permissions with backward compatibility. + if (refPerm && permissionsEmpty && Object.keys((_a = refPerm[scope]) !== null && _a !== void 0 ? _a : {}).length > 0) { + permissionsEmpty = false; + } + }); + }); + if (permissionsEmpty) + return 'Missing values for either Resources or Patterns'; + }; + GrantTokenRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, serviceResponse.data.token]; + }); + }); + }; + Object.defineProperty(GrantTokenRequest.prototype, "path", { + get: function () { + return "/v3/pam/".concat(this.parameters.keySet.subscribeKey, "/grant"); }, - RFC3986: function (value) { - return String(value); - } - }, - RFC1738: Format.RFC1738, - RFC3986: Format.RFC3986 - }; - - var formats$2 = formats$3; - - var has$2 = Object.prototype.hasOwnProperty; - var isArray$2 = Array.isArray; - - var hexTable = (function () { - var array = []; - for (var i = 0; i < 256; ++i) { - array.push('%' + ((i < 16 ? '0' : '') + i.toString(16)).toUpperCase()); - } - - return array; - }()); - - var compactQueue = function compactQueue(queue) { - while (queue.length > 1) { - var item = queue.pop(); - var obj = item.obj[item.prop]; - - if (isArray$2(obj)) { - var compacted = []; - - for (var j = 0; j < obj.length; ++j) { - if (typeof obj[j] !== 'undefined') { - compacted.push(obj[j]); + enumerable: false, + configurable: true + }); + Object.defineProperty(GrantTokenRequest.prototype, "body", { + get: function () { + var _this = this; + var _a = this.parameters, ttl = _a.ttl, meta = _a.meta; + var body = __assign({}, (ttl || ttl === 0 ? { ttl: ttl } : {})); + var uuid = this.isVspPermissions(this.parameters) + ? this.parameters.authorizedUserId + : this.parameters.authorized_uuid; + var permissions = {}; + var resourcePermissions = {}; + var patternPermissions = {}; + var mapPermissions = function (name, permissionBit, type, permissions) { + if (!permissions[type]) + permissions[type] = {}; + permissions[type][name] = permissionBit; + }; + var _b = this.parameters, resources = _b.resources, patterns = _b.patterns; + [resources, patterns].forEach(function (refPerm, idx) { + var _a, _b, _c, _d, _e; + var target = idx === 0 ? resourcePermissions : patternPermissions; + var channelsPermissions = {}; + var channelGroupsPermissions = {}; + var uuidsPermissions = {}; + if (refPerm) { + // Check whether working with legacy Objects permissions. + if ('spaces' in refPerm || 'users' in refPerm) { + channelsPermissions = (_a = refPerm.spaces) !== null && _a !== void 0 ? _a : {}; + uuidsPermissions = (_b = refPerm.users) !== null && _b !== void 0 ? _b : {}; + } + else if ('channels' in refPerm || 'uuids' in refPerm || 'groups' in refPerm) { + channelsPermissions = (_c = refPerm.channels) !== null && _c !== void 0 ? _c : {}; + channelGroupsPermissions = (_d = refPerm.groups) !== null && _d !== void 0 ? _d : {}; + uuidsPermissions = (_e = refPerm.uuids) !== null && _e !== void 0 ? _e : {}; + } } - } - - item.obj[item.prop] = compacted; - } - } - }; - - var arrayToObject = function arrayToObject(source, options) { - var obj = options && options.plainObjects ? Object.create(null) : {}; - for (var i = 0; i < source.length; ++i) { - if (typeof source[i] !== 'undefined') { - obj[i] = source[i]; - } - } - - return obj; - }; - - var merge = function merge(target, source, options) { - /* eslint no-param-reassign: 0 */ - if (!source) { - return target; - } - - if (typeof source !== 'object') { - if (isArray$2(target)) { - target.push(source); - } else if (target && typeof target === 'object') { - if ((options && (options.plainObjects || options.allowPrototypes)) || !has$2.call(Object.prototype, source)) { - target[source] = true; - } - } else { - return [target, source]; - } - - return target; - } - - if (!target || typeof target !== 'object') { - return [target].concat(source); - } + Object.keys(channelsPermissions).forEach(function (channel) { + return mapPermissions(channel, _this.extractPermissions(channelsPermissions[channel]), 'channels', target); + }); + Object.keys(channelGroupsPermissions).forEach(function (groups) { + return mapPermissions(groups, _this.extractPermissions(channelGroupsPermissions[groups]), 'groups', target); + }); + Object.keys(uuidsPermissions).forEach(function (uuids) { + return mapPermissions(uuids, _this.extractPermissions(uuidsPermissions[uuids]), 'uuids', target); + }); + }); + if (uuid) + permissions.uuid = "".concat(uuid); + if (meta) + permissions.meta = meta; + body.permissions = permissions; + return JSON.stringify(body); + }, + enumerable: false, + configurable: true + }); + /** + * Extract permissions bit from permission configuration object. + * + * @param permissions - User provided scope-based permissions. + * + * @returns Permissions bit. + */ + GrantTokenRequest.prototype.extractPermissions = function (permissions) { + var permissionsResult = 0; + if ('join' in permissions && permissions.join) + permissionsResult |= 128; + if ('update' in permissions && permissions.update) + permissionsResult |= 64; + if ('get' in permissions && permissions.get) + permissionsResult |= 32; + if ('delete' in permissions && permissions.delete) + permissionsResult |= 8; + if ('manage' in permissions && permissions.manage) + permissionsResult |= 4; + if ('write' in permissions && permissions.write) + permissionsResult |= 2; + if ('read' in permissions && permissions.read) + permissionsResult |= 1; + return permissionsResult; + }; + /** + * Check whether provided parameters is part of legacy VSP access token configuration. + * + * @param parameters - Parameters which should be checked. + * + * @returns VSP request parameters if it is legacy configuration. + */ + GrantTokenRequest.prototype.isVspPermissions = function (parameters) { + var _a, _b, _c, _d; + return ('authorizedUserId' in parameters || + 'spaces' in ((_a = parameters.resources) !== null && _a !== void 0 ? _a : {}) || + 'users' in ((_b = parameters.resources) !== null && _b !== void 0 ? _b : {}) || + 'spaces' in ((_c = parameters.patterns) !== null && _c !== void 0 ? _c : {}) || + 'users' in ((_d = parameters.patterns) !== null && _d !== void 0 ? _d : {})); + }; + return GrantTokenRequest; + }(AbstractRequest)); - var mergeTarget = target; - if (isArray$2(target) && !isArray$2(source)) { - mergeTarget = arrayToObject(target, options); + /** + * PAM Grant REST API module. + */ + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults + /** + * Resources `read` permission. + */ + var READ_PERMISSION = false; + /** + * Resources `write` permission. + */ + var WRITE_PERMISSION = false; + /** + * Resources `delete` permission. + */ + var DELETE_PERMISSION = false; + /** + * Resources `get` permission. + */ + var GET_PERMISSION = false; + /** + * Resources `update` permission. + */ + var UPDATE_PERMISSION = false; + /** + * Resources `manage` permission. + */ + var MANAGE_PERMISSION = false; + /** + * Resources `join` permission. + */ + var JOIN_PERMISSION = false; + // endregion + /** + * Grant permissions request. + */ + var GrantRequest = /** @class */ (function (_super) { + __extends(GrantRequest, _super); + function GrantRequest(parameters) { + var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k; + var _l, _m, _o, _p, _q, _r, _s, _t, _u, _v; + var _this = _super.call(this) || this; + _this.parameters = parameters; + // Apply defaults. + (_a = (_l = _this.parameters).channels) !== null && _a !== void 0 ? _a : (_l.channels = []); + (_b = (_m = _this.parameters).channelGroups) !== null && _b !== void 0 ? _b : (_m.channelGroups = []); + (_c = (_o = _this.parameters).uuids) !== null && _c !== void 0 ? _c : (_o.uuids = []); + (_d = (_p = _this.parameters).read) !== null && _d !== void 0 ? _d : (_p.read = READ_PERMISSION); + (_e = (_q = _this.parameters).write) !== null && _e !== void 0 ? _e : (_q.write = WRITE_PERMISSION); + (_f = (_r = _this.parameters).delete) !== null && _f !== void 0 ? _f : (_r.delete = DELETE_PERMISSION); + (_g = (_s = _this.parameters).get) !== null && _g !== void 0 ? _g : (_s.get = GET_PERMISSION); + (_h = (_t = _this.parameters).update) !== null && _h !== void 0 ? _h : (_t.update = UPDATE_PERMISSION); + (_j = (_u = _this.parameters).manage) !== null && _j !== void 0 ? _j : (_u.manage = MANAGE_PERMISSION); + (_k = (_v = _this.parameters).join) !== null && _k !== void 0 ? _k : (_v.join = JOIN_PERMISSION); + return _this; } - - if (isArray$2(target) && isArray$2(source)) { - source.forEach(function (item, i) { - if (has$2.call(target, i)) { - var targetItem = target[i]; - if (targetItem && typeof targetItem === 'object' && item && typeof item === 'object') { - target[i] = merge(targetItem, item, options); - } else { - target.push(item); - } - } else { - target[i] = item; - } + GrantRequest.prototype.operation = function () { + return RequestOperation$1.PNAccessManagerGrant; + }; + GrantRequest.prototype.validate = function () { + var _a; + var _b = this.parameters, _c = _b.keySet, subscribeKey = _c.subscribeKey, publishKey = _c.publishKey, secretKey = _c.secretKey, uuids = _b.uuids, channels = _b.channels, channelGroups = _b.channelGroups; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!publishKey) + return 'Missing Publish Key'; + if (!secretKey) + return 'Missing Secret Key'; + if ((uuids === null || uuids === void 0 ? void 0 : uuids.length) !== 0 && ((_a = this.parameters.authKeys) === null || _a === void 0 ? void 0 : _a.length) === 0) + return 'authKeys are required for grant request on uuids'; + if ((uuids === null || uuids === void 0 ? void 0 : uuids.length) && ((channels === null || channels === void 0 ? void 0 : channels.length) !== 0 || (channelGroups === null || channelGroups === void 0 ? void 0 : channelGroups.length) !== 0)) + return 'Both channel/channel group and uuid cannot be used in the same request'; + }; + GrantRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, serviceResponse.payload]; + }); }); - return target; - } - - return Object.keys(source).reduce(function (acc, key) { - var value = source[key]; - - if (has$2.call(acc, key)) { - acc[key] = merge(acc[key], value, options); - } else { - acc[key] = value; - } - return acc; - }, mergeTarget); - }; - - var assign = function assignSingleSource(target, source) { - return Object.keys(source).reduce(function (acc, key) { - acc[key] = source[key]; - return acc; - }, target); - }; - - var decode = function (str, decoder, charset) { - var strWithoutPlus = str.replace(/\+/g, ' '); - if (charset === 'iso-8859-1') { - // unescape never throws, no try...catch needed: - return strWithoutPlus.replace(/%[0-9a-f]{2}/gi, unescape); - } - // utf-8 - try { - return decodeURIComponent(strWithoutPlus); - } catch (e) { - return strWithoutPlus; - } - }; - - var encode = function encode(str, defaultEncoder, charset, kind, format) { - // This code was originally written by Brian White (mscdex) for the io.js core querystring library. - // It has been adapted here for stricter adherence to RFC 3986 - if (str.length === 0) { - return str; - } + }; + Object.defineProperty(GrantRequest.prototype, "path", { + get: function () { + return "/v2/auth/grant/sub-key/".concat(this.parameters.keySet.subscribeKey); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(GrantRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, channels = _a.channels, channelGroups = _a.channelGroups, authKeys = _a.authKeys, uuids = _a.uuids, read = _a.read, write = _a.write, manage = _a.manage, del = _a.delete, get = _a.get, join = _a.join, update = _a.update, ttl = _a.ttl; + return __assign(__assign(__assign(__assign(__assign(__assign({}, (channels && (channels === null || channels === void 0 ? void 0 : channels.length) > 0 ? { channel: channels.join(',') } : {})), (channelGroups && (channelGroups === null || channelGroups === void 0 ? void 0 : channelGroups.length) > 0 ? { 'channel-group': channelGroups.join(',') } : {})), (authKeys && (authKeys === null || authKeys === void 0 ? void 0 : authKeys.length) > 0 ? { auth: authKeys.join(',') } : {})), (uuids && (uuids === null || uuids === void 0 ? void 0 : uuids.length) > 0 ? { 'target-uuid': uuids.join(',') } : {})), { r: read ? '1' : '0', w: write ? '1' : '0', m: manage ? '1' : '0', d: del ? '1' : '0', g: get ? '1' : '0', j: join ? '1' : '0', u: update ? '1' : '0' }), (ttl || ttl === 0 ? { ttl: ttl } : {})); + }, + enumerable: false, + configurable: true + }); + return GrantRequest; + }(AbstractRequest)); - var string = str; - if (typeof str === 'symbol') { - string = Symbol.prototype.toString.call(str); - } else if (typeof str !== 'string') { - string = String(str); + /** + * PAM Audit REST API module. + */ + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults + /** + * Auth keys for which permissions should be audited. + */ + var AUTH_KEYS = []; + // endregion + /** + * Permissions audit request. + */ + var AuditRequest = /** @class */ (function (_super) { + __extends(AuditRequest, _super); + function AuditRequest(parameters) { + var _a; + var _b; + var _this = _super.call(this) || this; + _this.parameters = parameters; + // Apply default request parameters. + (_a = (_b = _this.parameters).authKeys) !== null && _a !== void 0 ? _a : (_b.authKeys = AUTH_KEYS); + return _this; } - - if (charset === 'iso-8859-1') { - return escape(string).replace(/%u[0-9a-f]{4}/gi, function ($0) { - return '%26%23' + parseInt($0.slice(2), 16) + '%3B'; + AuditRequest.prototype.operation = function () { + return RequestOperation$1.PNAccessManagerAudit; + }; + AuditRequest.prototype.validate = function () { + if (!this.parameters.keySet.subscribeKey) + return 'Missing Subscribe Key'; + }; + AuditRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, serviceResponse.payload]; + }); }); - } - - var out = ''; - for (var i = 0; i < string.length; ++i) { - var c = string.charCodeAt(i); - - if ( - c === 0x2D // - - || c === 0x2E // . - || c === 0x5F // _ - || c === 0x7E // ~ - || (c >= 0x30 && c <= 0x39) // 0-9 - || (c >= 0x41 && c <= 0x5A) // a-z - || (c >= 0x61 && c <= 0x7A) // A-Z - || (format === formats$2.RFC1738 && (c === 0x28 || c === 0x29)) // ( ) - ) { - out += string.charAt(i); - continue; - } - - if (c < 0x80) { - out = out + hexTable[c]; - continue; - } - - if (c < 0x800) { - out = out + (hexTable[0xC0 | (c >> 6)] + hexTable[0x80 | (c & 0x3F)]); - continue; - } - - if (c < 0xD800 || c >= 0xE000) { - out = out + (hexTable[0xE0 | (c >> 12)] + hexTable[0x80 | ((c >> 6) & 0x3F)] + hexTable[0x80 | (c & 0x3F)]); - continue; - } - - i += 1; - c = 0x10000 + (((c & 0x3FF) << 10) | (string.charCodeAt(i) & 0x3FF)); - /* eslint operator-linebreak: [2, "before"] */ - out += hexTable[0xF0 | (c >> 18)] - + hexTable[0x80 | ((c >> 12) & 0x3F)] - + hexTable[0x80 | ((c >> 6) & 0x3F)] - + hexTable[0x80 | (c & 0x3F)]; - } - - return out; - }; - - var compact = function compact(value) { - var queue = [{ obj: { o: value }, prop: 'o' }]; - var refs = []; - - for (var i = 0; i < queue.length; ++i) { - var item = queue[i]; - var obj = item.obj[item.prop]; - - var keys = Object.keys(obj); - for (var j = 0; j < keys.length; ++j) { - var key = keys[j]; - var val = obj[key]; - if (typeof val === 'object' && val !== null && refs.indexOf(val) === -1) { - queue.push({ obj: obj, prop: key }); - refs.push(val); - } - } - } - - compactQueue(queue); - - return value; - }; - - var isRegExp = function isRegExp(obj) { - return Object.prototype.toString.call(obj) === '[object RegExp]'; - }; - - var isBuffer = function isBuffer(obj) { - if (!obj || typeof obj !== 'object') { - return false; - } - - return !!(obj.constructor && obj.constructor.isBuffer && obj.constructor.isBuffer(obj)); - }; - - var combine = function combine(a, b) { - return [].concat(a, b); - }; - - var maybeMap = function maybeMap(val, fn) { - if (isArray$2(val)) { - var mapped = []; - for (var i = 0; i < val.length; i += 1) { - mapped.push(fn(val[i])); - } - return mapped; - } - return fn(val); - }; - - var utils$4 = { - arrayToObject: arrayToObject, - assign: assign, - combine: combine, - compact: compact, - decode: decode, - encode: encode, - isBuffer: isBuffer, - isRegExp: isRegExp, - maybeMap: maybeMap, - merge: merge - }; - - var getSideChannel = sideChannel; - var utils$3 = utils$4; - var formats$1 = formats$3; - var has$1 = Object.prototype.hasOwnProperty; - - var arrayPrefixGenerators = { - brackets: function brackets(prefix) { - return prefix + '[]'; - }, - comma: 'comma', - indices: function indices(prefix, key) { - return prefix + '[' + key + ']'; - }, - repeat: function repeat(prefix) { - return prefix; - } - }; - - var isArray$1 = Array.isArray; - var push = Array.prototype.push; - var pushToArray = function (arr, valueOrArray) { - push.apply(arr, isArray$1(valueOrArray) ? valueOrArray : [valueOrArray]); - }; - - var toISO = Date.prototype.toISOString; - - var defaultFormat = formats$1['default']; - var defaults$1 = { - addQueryPrefix: false, - allowDots: false, - charset: 'utf-8', - charsetSentinel: false, - delimiter: '&', - encode: true, - encoder: utils$3.encode, - encodeValuesOnly: false, - format: defaultFormat, - formatter: formats$1.formatters[defaultFormat], - // deprecated - indices: false, - serializeDate: function serializeDate(date) { - return toISO.call(date); - }, - skipNulls: false, - strictNullHandling: false - }; - - var isNonNullishPrimitive = function isNonNullishPrimitive(v) { - return typeof v === 'string' - || typeof v === 'number' - || typeof v === 'boolean' - || typeof v === 'symbol' - || typeof v === 'bigint'; - }; + }; + Object.defineProperty(AuditRequest.prototype, "path", { + get: function () { + return "/v2/auth/audit/sub-key/".concat(this.parameters.keySet.subscribeKey); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(AuditRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, channel = _a.channel, channelGroup = _a.channelGroup, authKeys = _a.authKeys; + return __assign(__assign(__assign({}, (channel ? { channel: channel } : {})), (channelGroup ? { 'channel-group': channelGroup } : {})), (authKeys && authKeys.length ? { auth: authKeys.join(',') } : {})); + }, + enumerable: false, + configurable: true + }); + return AuditRequest; + }(AbstractRequest)); - var sentinel = {}; - - var stringify$1 = function stringify( - object, - prefix, - generateArrayPrefix, - commaRoundTrip, - strictNullHandling, - skipNulls, - encoder, - filter, - sort, - allowDots, - serializeDate, - format, - formatter, - encodeValuesOnly, - charset, - sideChannel - ) { - var obj = object; - - var tmpSc = sideChannel; - var step = 0; - var findFlag = false; - while ((tmpSc = tmpSc.get(sentinel)) !== void undefined && !findFlag) { - // Where object last appeared in the ref tree - var pos = tmpSc.get(object); - step += 1; - if (typeof pos !== 'undefined') { - if (pos === step) { - throw new RangeError('Cyclic object value'); - } else { - findFlag = true; // Break while - } - } - if (typeof tmpSc.get(sentinel) === 'undefined') { - step = 0; - } + var SubscribeCapable = /** @class */ (function () { + function SubscribeCapable() { } - - if (typeof filter === 'function') { - obj = filter(prefix, obj); - } else if (obj instanceof Date) { - obj = serializeDate(obj); - } else if (generateArrayPrefix === 'comma' && isArray$1(obj)) { - obj = utils$3.maybeMap(obj, function (value) { - if (value instanceof Date) { - return serializeDate(value); - } - return value; + SubscribeCapable.prototype.subscribe = function () { + var _a, _b; + this.pubnub.subscribe(__assign({ channels: this.channelNames, channelGroups: this.groupNames }, (((_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.cursor) === null || _b === void 0 ? void 0 : _b.timetoken) && { timetoken: this.options.cursor.timetoken }))); + }; + SubscribeCapable.prototype.unsubscribe = function () { + this.pubnub.unsubscribe({ + channels: this.channelNames.filter(function (c) { return !c.endsWith('-pnpres'); }), + channelGroups: this.groupNames.filter(function (cg) { return !cg.endsWith('-pnpres'); }), }); - } - - if (obj === null) { - if (strictNullHandling) { - return encoder && !encodeValuesOnly ? encoder(prefix, defaults$1.encoder, charset, 'key', format) : prefix; - } - - obj = ''; - } - - if (isNonNullishPrimitive(obj) || utils$3.isBuffer(obj)) { - if (encoder) { - var keyValue = encodeValuesOnly ? prefix : encoder(prefix, defaults$1.encoder, charset, 'key', format); - return [formatter(keyValue) + '=' + formatter(encoder(obj, defaults$1.encoder, charset, 'value', format))]; - } - return [formatter(prefix) + '=' + formatter(String(obj))]; - } - - var values = []; - - if (typeof obj === 'undefined') { - return values; - } - - var objKeys; - if (generateArrayPrefix === 'comma' && isArray$1(obj)) { - // we need to join elements in - if (encodeValuesOnly && encoder) { - obj = utils$3.maybeMap(obj, encoder); - } - objKeys = [{ value: obj.length > 0 ? obj.join(',') || null : void undefined }]; - } else if (isArray$1(filter)) { - objKeys = filter; - } else { - var keys = Object.keys(obj); - objKeys = sort ? keys.sort(sort) : keys; - } - - var adjustedPrefix = commaRoundTrip && isArray$1(obj) && obj.length === 1 ? prefix + '[]' : prefix; - - for (var j = 0; j < objKeys.length; ++j) { - var key = objKeys[j]; - var value = typeof key === 'object' && typeof key.value !== 'undefined' ? key.value : obj[key]; - - if (skipNulls && value === null) { - continue; - } - - var keyPrefix = isArray$1(obj) - ? typeof generateArrayPrefix === 'function' ? generateArrayPrefix(adjustedPrefix, key) : adjustedPrefix - : adjustedPrefix + (allowDots ? '.' + key : '[' + key + ']'); - - sideChannel.set(object, step); - var valueSideChannel = getSideChannel(); - valueSideChannel.set(sentinel, sideChannel); - pushToArray(values, stringify( - value, - keyPrefix, - generateArrayPrefix, - commaRoundTrip, - strictNullHandling, - skipNulls, - generateArrayPrefix === 'comma' && encodeValuesOnly && isArray$1(obj) ? null : encoder, - filter, - sort, - allowDots, - serializeDate, - format, - formatter, - encodeValuesOnly, - charset, - valueSideChannel - )); - } - - return values; - }; - - var normalizeStringifyOptions = function normalizeStringifyOptions(opts) { - if (!opts) { - return defaults$1; - } - - if (opts.encoder !== null && typeof opts.encoder !== 'undefined' && typeof opts.encoder !== 'function') { - throw new TypeError('Encoder has to be a function.'); - } - - var charset = opts.charset || defaults$1.charset; - if (typeof opts.charset !== 'undefined' && opts.charset !== 'utf-8' && opts.charset !== 'iso-8859-1') { - throw new TypeError('The charset option must be either utf-8, iso-8859-1, or undefined'); - } - - var format = formats$1['default']; - if (typeof opts.format !== 'undefined') { - if (!has$1.call(formats$1.formatters, opts.format)) { - throw new TypeError('Unknown format option provided.'); - } - format = opts.format; - } - var formatter = formats$1.formatters[format]; - - var filter = defaults$1.filter; - if (typeof opts.filter === 'function' || isArray$1(opts.filter)) { - filter = opts.filter; - } - - return { - addQueryPrefix: typeof opts.addQueryPrefix === 'boolean' ? opts.addQueryPrefix : defaults$1.addQueryPrefix, - allowDots: typeof opts.allowDots === 'undefined' ? defaults$1.allowDots : !!opts.allowDots, - charset: charset, - charsetSentinel: typeof opts.charsetSentinel === 'boolean' ? opts.charsetSentinel : defaults$1.charsetSentinel, - delimiter: typeof opts.delimiter === 'undefined' ? defaults$1.delimiter : opts.delimiter, - encode: typeof opts.encode === 'boolean' ? opts.encode : defaults$1.encode, - encoder: typeof opts.encoder === 'function' ? opts.encoder : defaults$1.encoder, - encodeValuesOnly: typeof opts.encodeValuesOnly === 'boolean' ? opts.encodeValuesOnly : defaults$1.encodeValuesOnly, - filter: filter, - format: format, - formatter: formatter, - serializeDate: typeof opts.serializeDate === 'function' ? opts.serializeDate : defaults$1.serializeDate, - skipNulls: typeof opts.skipNulls === 'boolean' ? opts.skipNulls : defaults$1.skipNulls, - sort: typeof opts.sort === 'function' ? opts.sort : null, - strictNullHandling: typeof opts.strictNullHandling === 'boolean' ? opts.strictNullHandling : defaults$1.strictNullHandling }; - }; - - var stringify_1 = function (object, opts) { - var obj = object; - var options = normalizeStringifyOptions(opts); - - var objKeys; - var filter; + Object.defineProperty(SubscribeCapable.prototype, "onMessage", { + set: function (onMessageListener) { + this.listener.message = onMessageListener; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(SubscribeCapable.prototype, "onPresence", { + set: function (onPresenceListener) { + this.listener.presence = onPresenceListener; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(SubscribeCapable.prototype, "onSignal", { + set: function (onSignalListener) { + this.listener.signal = onSignalListener; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(SubscribeCapable.prototype, "onObjects", { + set: function (onObjectsListener) { + this.listener.objects = onObjectsListener; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(SubscribeCapable.prototype, "onMessageAction", { + set: function (messageActionEventListener) { + this.listener.messageAction = messageActionEventListener; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(SubscribeCapable.prototype, "onFile", { + set: function (fileEventListener) { + this.listener.file = fileEventListener; + }, + enumerable: false, + configurable: true + }); + SubscribeCapable.prototype.addListener = function (listener) { + this.eventEmitter.addListener(listener, this.channelNames.filter(function (c) { return !c.endsWith('-pnpres'); }), this.groupNames.filter(function (cg) { return !cg.endsWith('-pnpres'); })); + }; + SubscribeCapable.prototype.removeListener = function (listener) { + this.eventEmitter.removeListener(listener, this.channelNames, this.groupNames); + }; + Object.defineProperty(SubscribeCapable.prototype, "channels", { + get: function () { + return this.channelNames.slice(0); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(SubscribeCapable.prototype, "channelGroups", { + get: function () { + return this.groupNames.slice(0); + }, + enumerable: false, + configurable: true + }); + return SubscribeCapable; + }()); - if (typeof options.filter === 'function') { - filter = options.filter; - obj = filter('', obj); - } else if (isArray$1(options.filter)) { - filter = options.filter; - objKeys = filter; + var SubscriptionSet = /** @class */ (function (_super) { + __extends(SubscriptionSet, _super); + function SubscriptionSet(_a) { + var _b = _a.channels, channels = _b === void 0 ? [] : _b, _c = _a.channelGroups, channelGroups = _c === void 0 ? [] : _c, subscriptionOptions = _a.subscriptionOptions, eventEmitter = _a.eventEmitter, pubnub = _a.pubnub; + var _this = _super.call(this) || this; + _this.channelNames = []; + _this.groupNames = []; + _this.subscriptionList = []; + _this.options = subscriptionOptions; + _this.eventEmitter = eventEmitter; + _this.pubnub = pubnub; + channels.forEach(function (c) { + var subscription = _this.pubnub.channel(c).subscription(_this.options); + _this.channelNames = __spreadArray(__spreadArray([], __read(_this.channelNames), false), __read(subscription.channels), false); + _this.subscriptionList.push(subscription); + }); + channelGroups.forEach(function (cg) { + var subscription = _this.pubnub.channelGroup(cg).subscription(_this.options); + _this.groupNames = __spreadArray(__spreadArray([], __read(_this.groupNames), false), __read(subscription.channelGroups), false); + _this.subscriptionList.push(subscription); + }); + _this.listener = {}; + eventEmitter.addListener(_this.listener, _this.channelNames.filter(function (c) { return !c.endsWith('-pnpres'); }), _this.groupNames.filter(function (cg) { return !cg.endsWith('-pnpres'); })); + return _this; } + SubscriptionSet.prototype.addSubscription = function (subscription) { + this.subscriptionList.push(subscription); + this.channelNames = __spreadArray(__spreadArray([], __read(this.channelNames), false), __read(subscription.channels), false); + this.groupNames = __spreadArray(__spreadArray([], __read(this.groupNames), false), __read(subscription.channelGroups), false); + }; + SubscriptionSet.prototype.removeSubscription = function (subscription) { + var channelsToRemove = subscription.channels; + var groupsToRemove = subscription.channelGroups; + this.channelNames = this.channelNames.filter(function (c) { return !channelsToRemove.includes(c); }); + this.groupNames = this.groupNames.filter(function (cg) { return !groupsToRemove.includes(cg); }); + this.subscriptionList = this.subscriptionList.filter(function (s) { return s !== subscription; }); + }; + SubscriptionSet.prototype.addSubscriptionSet = function (subscriptionSet) { + this.subscriptionList = __spreadArray(__spreadArray([], __read(this.subscriptionList), false), __read(subscriptionSet.subscriptions), false); + this.channelNames = __spreadArray(__spreadArray([], __read(this.channelNames), false), __read(subscriptionSet.channels), false); + this.groupNames = __spreadArray(__spreadArray([], __read(this.groupNames), false), __read(subscriptionSet.channelGroups), false); + }; + SubscriptionSet.prototype.removeSubscriptionSet = function (subscriptionSet) { + var channelsToRemove = subscriptionSet.channels; + var groupsToRemove = subscriptionSet.channelGroups; + this.channelNames = this.channelNames.filter(function (c) { return !channelsToRemove.includes(c); }); + this.groupNames = this.groupNames.filter(function (cg) { return !groupsToRemove.includes(cg); }); + this.subscriptionList = this.subscriptionList.filter(function (s) { return !subscriptionSet.subscriptions.includes(s); }); + }; + Object.defineProperty(SubscriptionSet.prototype, "subscriptions", { + get: function () { + return this.subscriptionList.slice(0); + }, + enumerable: false, + configurable: true + }); + return SubscriptionSet; + }(SubscribeCapable)); - var keys = []; - - if (typeof obj !== 'object' || obj === null) { - return ''; + var Subscription = /** @class */ (function (_super) { + __extends(Subscription, _super); + function Subscription(_a) { + var channels = _a.channels, channelGroups = _a.channelGroups, subscriptionOptions = _a.subscriptionOptions, eventEmitter = _a.eventEmitter, pubnub = _a.pubnub; + var _this = _super.call(this) || this; + _this.channelNames = []; + _this.groupNames = []; + _this.channelNames = channels; + _this.groupNames = channelGroups; + _this.options = subscriptionOptions; + _this.pubnub = pubnub; + _this.eventEmitter = eventEmitter; + _this.listener = {}; + eventEmitter.addListener(_this.listener, _this.channelNames.filter(function (c) { return !c.endsWith('-pnpres'); }), _this.groupNames.filter(function (cg) { return !cg.endsWith('-pnpres'); })); + return _this; } + Subscription.prototype.addSubscription = function (subscription) { + return new SubscriptionSet({ + channels: __spreadArray(__spreadArray([], __read(this.channelNames), false), __read(subscription.channels), false), + channelGroups: __spreadArray(__spreadArray([], __read(this.groupNames), false), __read(subscription.channelGroups), false), + subscriptionOptions: __assign(__assign({}, this.options), subscription === null || subscription === void 0 ? void 0 : subscription.options), + eventEmitter: this.eventEmitter, + pubnub: this.pubnub, + }); + }; + return Subscription; + }(SubscribeCapable)); - var arrayFormat; - if (opts && opts.arrayFormat in arrayPrefixGenerators) { - arrayFormat = opts.arrayFormat; - } else if (opts && 'indices' in opts) { - arrayFormat = opts.indices ? 'indices' : 'repeat'; - } else { - arrayFormat = 'indices'; + var ChannelMetadata = /** @class */ (function () { + function ChannelMetadata(id, eventEmitter, pubnub) { + this.id = id; + this.eventEmitter = eventEmitter; + this.pubnub = pubnub; } + ChannelMetadata.prototype.subscription = function (subscriptionOptions) { + return new Subscription({ + channels: [this.id], + channelGroups: [], + subscriptionOptions: subscriptionOptions, + eventEmitter: this.eventEmitter, + pubnub: this.pubnub, + }); + }; + return ChannelMetadata; + }()); - var generateArrayPrefix = arrayPrefixGenerators[arrayFormat]; - if (opts && 'commaRoundTrip' in opts && typeof opts.commaRoundTrip !== 'boolean') { - throw new TypeError('`commaRoundTrip` must be a boolean, or absent'); + var ChannelGroup = /** @class */ (function () { + function ChannelGroup(channelGroup, eventEmitter, pubnub) { + this.eventEmitter = eventEmitter; + this.pubnub = pubnub; + this.name = channelGroup; } - var commaRoundTrip = generateArrayPrefix === 'comma' && opts && opts.commaRoundTrip; + ChannelGroup.prototype.subscription = function (subscriptionOptions) { + return new Subscription({ + channels: [], + channelGroups: (subscriptionOptions === null || subscriptionOptions === void 0 ? void 0 : subscriptionOptions.receivePresenceEvents) ? [this.name, "".concat(this.name, "-pnpres")] : [this.name], + subscriptionOptions: subscriptionOptions, + eventEmitter: this.eventEmitter, + pubnub: this.pubnub, + }); + }; + return ChannelGroup; + }()); - if (!objKeys) { - objKeys = Object.keys(obj); + var UserMetadata = /** @class */ (function () { + function UserMetadata(id, eventEmitter, pubnub) { + this.id = id; + this.eventEmitter = eventEmitter; + this.pubnub = pubnub; } + UserMetadata.prototype.subscription = function (subscriptionOptions) { + return new Subscription({ + channels: [this.id], + channelGroups: [], + subscriptionOptions: subscriptionOptions, + eventEmitter: this.eventEmitter, + pubnub: this.pubnub, + }); + }; + return UserMetadata; + }()); - if (options.sort) { - objKeys.sort(options.sort); + var Channel = /** @class */ (function () { + function Channel(channelName, eventEmitter, pubnub) { + this.eventEmitter = eventEmitter; + this.pubnub = pubnub; + this.name = channelName; } + Channel.prototype.subscription = function (subscriptionOptions) { + return new Subscription({ + channels: (subscriptionOptions === null || subscriptionOptions === void 0 ? void 0 : subscriptionOptions.receivePresenceEvents) ? [this.name, "".concat(this.name, "-pnpres")] : [this.name], + channelGroups: [], + subscriptionOptions: subscriptionOptions, + eventEmitter: this.eventEmitter, + pubnub: this.pubnub, + }); + }; + return Channel; + }()); - var sideChannel = getSideChannel(); - for (var i = 0; i < objKeys.length; ++i) { - var key = objKeys[i]; - - if (options.skipNulls && obj[key] === null) { - continue; - } - pushToArray(keys, stringify$1( - obj[key], - key, - generateArrayPrefix, - commaRoundTrip, - options.strictNullHandling, - options.skipNulls, - options.encode ? options.encoder : null, - options.filter, - options.sort, - options.allowDots, - options.serializeDate, - options.format, - options.formatter, - options.encodeValuesOnly, - options.charset, - sideChannel - )); - } - - var joined = keys.join(options.delimiter); - var prefix = options.addQueryPrefix === true ? '?' : ''; - - if (options.charsetSentinel) { - if (options.charset === 'iso-8859-1') { - // encodeURIComponent('✓'), the "numeric entity" representation of a checkmark - prefix += 'utf8=%26%2310003%3B&'; - } else { - // encodeURIComponent('✓') - prefix += 'utf8=%E2%9C%93&'; - } + /** + * Remove channel group channels REST API module. + */ + // endregion + /** + * Remove channel group channels request. + */ + // prettier-ignore + var RemoveChannelGroupChannelsRequest = /** @class */ (function (_super) { + __extends(RemoveChannelGroupChannelsRequest, _super); + function RemoveChannelGroupChannelsRequest(parameters) { + var _this = _super.call(this) || this; + _this.parameters = parameters; + return _this; } - - return joined.length > 0 ? prefix + joined : ''; - }; - - var utils$2 = utils$4; - - var has = Object.prototype.hasOwnProperty; - var isArray = Array.isArray; - - var defaults = { - allowDots: false, - allowPrototypes: false, - allowSparse: false, - arrayLimit: 20, - charset: 'utf-8', - charsetSentinel: false, - comma: false, - decoder: utils$2.decode, - delimiter: '&', - depth: 5, - ignoreQueryPrefix: false, - interpretNumericEntities: false, - parameterLimit: 1000, - parseArrays: true, - plainObjects: false, - strictNullHandling: false - }; - - var interpretNumericEntities = function (str) { - return str.replace(/&#(\d+);/g, function ($0, numberStr) { - return String.fromCharCode(parseInt(numberStr, 10)); + RemoveChannelGroupChannelsRequest.prototype.operation = function () { + return RequestOperation$1.PNRemoveChannelsFromGroupOperation; + }; + RemoveChannelGroupChannelsRequest.prototype.validate = function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channels = _a.channels, channelGroup = _a.channelGroup; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!channelGroup) + return 'Missing Channel Group'; + if (!channels) + return 'Missing channels'; + }; + RemoveChannelGroupChannelsRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, {}]; + }); + }); + }; + Object.defineProperty(RemoveChannelGroupChannelsRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channelGroup = _a.channelGroup; + return "/v1/channel-registration/sub-key/".concat(subscribeKey, "/channel-group/").concat(encodeString(channelGroup)); + }, + enumerable: false, + configurable: true }); - }; + Object.defineProperty(RemoveChannelGroupChannelsRequest.prototype, "queryParameters", { + get: function () { + return { remove: this.parameters.channels.join(',') }; + }, + enumerable: false, + configurable: true + }); + return RemoveChannelGroupChannelsRequest; + }(AbstractRequest)); - var parseArrayValue = function (val, options) { - if (val && typeof val === 'string' && options.comma && val.indexOf(',') > -1) { - return val.split(','); + /** + * Add channel group channels REST API module. + */ + // endregion + /** + * Add channel group channels request. + */ + var AddChannelGroupChannelsRequest = /** @class */ (function (_super) { + __extends(AddChannelGroupChannelsRequest, _super); + function AddChannelGroupChannelsRequest(parameters) { + var _this = _super.call(this) || this; + _this.parameters = parameters; + return _this; } - - return val; - }; - - // This is what browsers will submit when the ✓ character occurs in an - // application/x-www-form-urlencoded body and the encoding of the page containing - // the form is iso-8859-1, or when the submitted form has an accept-charset - // attribute of iso-8859-1. Presumably also with other charsets that do not contain - // the ✓ character, such as us-ascii. - var isoSentinel = 'utf8=%26%2310003%3B'; // encodeURIComponent('✓') - - // These are the percent-encoded utf-8 octets representing a checkmark, indicating that the request actually is utf-8 encoded. - var charsetSentinel = 'utf8=%E2%9C%93'; // encodeURIComponent('✓') - - var parseValues = function parseQueryStringValues(str, options) { - var obj = { __proto__: null }; - - var cleanStr = options.ignoreQueryPrefix ? str.replace(/^\?/, '') : str; - var limit = options.parameterLimit === Infinity ? undefined : options.parameterLimit; - var parts = cleanStr.split(options.delimiter, limit); - var skipIndex = -1; // Keep track of where the utf8 sentinel was found - var i; - - var charset = options.charset; - if (options.charsetSentinel) { - for (i = 0; i < parts.length; ++i) { - if (parts[i].indexOf('utf8=') === 0) { - if (parts[i] === charsetSentinel) { - charset = 'utf-8'; - } else if (parts[i] === isoSentinel) { - charset = 'iso-8859-1'; - } - skipIndex = i; - i = parts.length; // The eslint settings do not allow break; - } - } - } - - for (i = 0; i < parts.length; ++i) { - if (i === skipIndex) { - continue; - } - var part = parts[i]; - - var bracketEqualsPos = part.indexOf(']='); - var pos = bracketEqualsPos === -1 ? part.indexOf('=') : bracketEqualsPos + 1; - - var key, val; - if (pos === -1) { - key = options.decoder(part, defaults.decoder, charset, 'key'); - val = options.strictNullHandling ? null : ''; - } else { - key = options.decoder(part.slice(0, pos), defaults.decoder, charset, 'key'); - val = utils$2.maybeMap( - parseArrayValue(part.slice(pos + 1), options), - function (encodedVal) { - return options.decoder(encodedVal, defaults.decoder, charset, 'value'); - } - ); - } - - if (val && options.interpretNumericEntities && charset === 'iso-8859-1') { - val = interpretNumericEntities(val); - } - - if (part.indexOf('[]=') > -1) { - val = isArray(val) ? [val] : val; - } - - if (has.call(obj, key)) { - obj[key] = utils$2.combine(obj[key], val); - } else { - obj[key] = val; - } - } - - return obj; - }; - - var parseObject = function (chain, val, options, valuesParsed) { - var leaf = valuesParsed ? val : parseArrayValue(val, options); - - for (var i = chain.length - 1; i >= 0; --i) { - var obj; - var root = chain[i]; - - if (root === '[]' && options.parseArrays) { - obj = [].concat(leaf); - } else { - obj = options.plainObjects ? Object.create(null) : {}; - var cleanRoot = root.charAt(0) === '[' && root.charAt(root.length - 1) === ']' ? root.slice(1, -1) : root; - var index = parseInt(cleanRoot, 10); - if (!options.parseArrays && cleanRoot === '') { - obj = { 0: leaf }; - } else if ( - !isNaN(index) - && root !== cleanRoot - && String(index) === cleanRoot - && index >= 0 - && (options.parseArrays && index <= options.arrayLimit) - ) { - obj = []; - obj[index] = leaf; - } else if (cleanRoot !== '__proto__') { - obj[cleanRoot] = leaf; - } - } - - leaf = obj; - } - - return leaf; - }; - - var parseKeys = function parseQueryStringKeys(givenKey, val, options, valuesParsed) { - if (!givenKey) { - return; - } - - // Transform dot notation to bracket notation - var key = options.allowDots ? givenKey.replace(/\.([^.[]+)/g, '[$1]') : givenKey; - - // The regex chunks - - var brackets = /(\[[^[\]]*])/; - var child = /(\[[^[\]]*])/g; - - // Get the parent - - var segment = options.depth > 0 && brackets.exec(key); - var parent = segment ? key.slice(0, segment.index) : key; - - // Stash the parent if it exists - - var keys = []; - if (parent) { - // If we aren't using plain objects, optionally prefix keys that would overwrite object prototype properties - if (!options.plainObjects && has.call(Object.prototype, parent)) { - if (!options.allowPrototypes) { - return; - } - } - - keys.push(parent); - } - - // Loop through children appending to the array until we hit depth - - var i = 0; - while (options.depth > 0 && (segment = child.exec(key)) !== null && i < options.depth) { - i += 1; - if (!options.plainObjects && has.call(Object.prototype, segment[1].slice(1, -1))) { - if (!options.allowPrototypes) { - return; - } - } - keys.push(segment[1]); - } - - // If there's a remainder, just add whatever is left - - if (segment) { - keys.push('[' + key.slice(segment.index) + ']'); - } - - return parseObject(keys, val, options, valuesParsed); - }; - - var normalizeParseOptions = function normalizeParseOptions(opts) { - if (!opts) { - return defaults; - } - - if (opts.decoder !== null && opts.decoder !== undefined && typeof opts.decoder !== 'function') { - throw new TypeError('Decoder has to be a function.'); - } - - if (typeof opts.charset !== 'undefined' && opts.charset !== 'utf-8' && opts.charset !== 'iso-8859-1') { - throw new TypeError('The charset option must be either utf-8, iso-8859-1, or undefined'); - } - var charset = typeof opts.charset === 'undefined' ? defaults.charset : opts.charset; - - return { - allowDots: typeof opts.allowDots === 'undefined' ? defaults.allowDots : !!opts.allowDots, - allowPrototypes: typeof opts.allowPrototypes === 'boolean' ? opts.allowPrototypes : defaults.allowPrototypes, - allowSparse: typeof opts.allowSparse === 'boolean' ? opts.allowSparse : defaults.allowSparse, - arrayLimit: typeof opts.arrayLimit === 'number' ? opts.arrayLimit : defaults.arrayLimit, - charset: charset, - charsetSentinel: typeof opts.charsetSentinel === 'boolean' ? opts.charsetSentinel : defaults.charsetSentinel, - comma: typeof opts.comma === 'boolean' ? opts.comma : defaults.comma, - decoder: typeof opts.decoder === 'function' ? opts.decoder : defaults.decoder, - delimiter: typeof opts.delimiter === 'string' || utils$2.isRegExp(opts.delimiter) ? opts.delimiter : defaults.delimiter, - // eslint-disable-next-line no-implicit-coercion, no-extra-parens - depth: (typeof opts.depth === 'number' || opts.depth === false) ? +opts.depth : defaults.depth, - ignoreQueryPrefix: opts.ignoreQueryPrefix === true, - interpretNumericEntities: typeof opts.interpretNumericEntities === 'boolean' ? opts.interpretNumericEntities : defaults.interpretNumericEntities, - parameterLimit: typeof opts.parameterLimit === 'number' ? opts.parameterLimit : defaults.parameterLimit, - parseArrays: opts.parseArrays !== false, - plainObjects: typeof opts.plainObjects === 'boolean' ? opts.plainObjects : defaults.plainObjects, - strictNullHandling: typeof opts.strictNullHandling === 'boolean' ? opts.strictNullHandling : defaults.strictNullHandling + AddChannelGroupChannelsRequest.prototype.operation = function () { + return RequestOperation$1.PNAddChannelsToGroupOperation; }; - }; - - var parse$1 = function (str, opts) { - var options = normalizeParseOptions(opts); - - if (str === '' || str === null || typeof str === 'undefined') { - return options.plainObjects ? Object.create(null) : {}; - } - - var tempObj = typeof str === 'string' ? parseValues(str, options) : str; - var obj = options.plainObjects ? Object.create(null) : {}; - - // Iterate over the keys and setup the new object - - var keys = Object.keys(tempObj); - for (var i = 0; i < keys.length; ++i) { - var key = keys[i]; - var newObj = parseKeys(key, tempObj[key], options, typeof str === 'string'); - obj = utils$2.merge(obj, newObj, options); - } - - if (options.allowSparse === true) { - return obj; - } - - return utils$2.compact(obj); - }; - - var stringify = stringify_1; - var parse = parse$1; - var formats = formats$3; - - var lib = { - formats: formats, - parse: parse, - stringify: stringify - }; - - var utils$1 = {}; - - (function (exports) { + AddChannelGroupChannelsRequest.prototype.validate = function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channels = _a.channels, channelGroup = _a.channelGroup; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!channelGroup) + return 'Missing Channel Group'; + if (!channels) + return 'Missing channels'; + }; + AddChannelGroupChannelsRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, {}]; + }); + }); + }; + Object.defineProperty(AddChannelGroupChannelsRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channelGroup = _a.channelGroup; + return "/v1/channel-registration/sub-key/".concat(subscribeKey, "/channel-group/").concat(encodeString(channelGroup)); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(AddChannelGroupChannelsRequest.prototype, "queryParameters", { + get: function () { + return { add: this.parameters.channels.join(',') }; + }, + enumerable: false, + configurable: true + }); + return AddChannelGroupChannelsRequest; + }(AbstractRequest)); - function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } - function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } - function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } /** - * Return the mime type for the given `str`. - * - * @param {String} str - * @return {String} - * @api private + * List channel group channels REST API module. */ - - exports.type = string_ => string_.split(/ *; */).shift(); - + // endregion /** - * Return header field parameters. - * - * @param {String} str - * @return {Object} - * @api private - */ - - exports.params = value => { - const object = {}; - var _iterator = _createForOfIteratorHelper(value.split(/ *; */)), - _step; - try { - for (_iterator.s(); !(_step = _iterator.n()).done;) { - const string_ = _step.value; - const parts = string_.split(/ *= */); - const key = parts.shift(); - const value = parts.shift(); - if (key && value) object[key] = value; - } - } catch (err) { - _iterator.e(err); - } finally { - _iterator.f(); - } - return object; - }; + * List Channel Group Channels request. + */ + var ListChannelGroupChannels = /** @class */ (function (_super) { + __extends(ListChannelGroupChannels, _super); + function ListChannelGroupChannels(parameters) { + var _this = _super.call(this) || this; + _this.parameters = parameters; + return _this; + } + ListChannelGroupChannels.prototype.operation = function () { + return RequestOperation$1.PNChannelsForGroupOperation; + }; + ListChannelGroupChannels.prototype.validate = function () { + if (!this.parameters.keySet.subscribeKey) + return 'Missing Subscribe Key'; + if (!this.parameters.channelGroup) + return 'Missing Channel Group'; + }; + ListChannelGroupChannels.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, { channels: serviceResponse.payload.channels }]; + }); + }); + }; + Object.defineProperty(ListChannelGroupChannels.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channelGroup = _a.channelGroup; + return "/v1/channel-registration/sub-key/".concat(subscribeKey, "/channel-group/").concat(encodeString(channelGroup)); + }, + enumerable: false, + configurable: true + }); + return ListChannelGroupChannels; + }(AbstractRequest)); /** - * Parse Link header fields. - * - * @param {String} str - * @return {Object} - * @api private - */ - - exports.parseLinks = value => { - const object = {}; - var _iterator2 = _createForOfIteratorHelper(value.split(/ *, */)), - _step2; - try { - for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { - const string_ = _step2.value; - const parts = string_.split(/ *; */); - const url = parts[0].slice(1, -1); - const rel = parts[1].split(/ *= */)[1].slice(1, -1); - object[rel] = url; - } - } catch (err) { - _iterator2.e(err); - } finally { - _iterator2.f(); - } - return object; - }; - + * Delete channel group REST API module. + */ + // endregion /** - * Strip content related fields from `header`. - * - * @param {Object} header - * @return {Object} header - * @api private - */ - - exports.cleanHeader = (header, changesOrigin) => { - delete header['content-type']; - delete header['content-length']; - delete header['transfer-encoding']; - delete header.host; - // secuirty - if (changesOrigin) { - delete header.authorization; - delete header.cookie; - } - return header; - }; + * Channel group delete request. + */ + var DeleteChannelGroupRequest = /** @class */ (function (_super) { + __extends(DeleteChannelGroupRequest, _super); + function DeleteChannelGroupRequest(parameters) { + var _this = _super.call(this) || this; + _this.parameters = parameters; + return _this; + } + DeleteChannelGroupRequest.prototype.operation = function () { + return RequestOperation$1.PNRemoveGroupOperation; + }; + DeleteChannelGroupRequest.prototype.validate = function () { + if (!this.parameters.keySet.subscribeKey) + return 'Missing Subscribe Key'; + if (!this.parameters.channelGroup) + return 'Missing Channel Group'; + }; + DeleteChannelGroupRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, {}]; + }); + }); + }; + Object.defineProperty(DeleteChannelGroupRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channelGroup = _a.channelGroup; + return "/v1/channel-registration/sub-key/".concat(subscribeKey, "/channel-group/").concat(encodeString(channelGroup), "/remove"); + }, + enumerable: false, + configurable: true + }); + return DeleteChannelGroupRequest; + }(AbstractRequest)); /** - * Check if `obj` is an object. - * - * @param {Object} object - * @return {Boolean} - * @api private + * List All Channel Groups REST API module. */ - exports.isObject = object => { - return object !== null && typeof object === 'object'; - }; - + // endregion /** - * Object.hasOwn fallback/polyfill. - * - * @type {(object: object, property: string) => boolean} object - * @api private - */ - exports.hasOwn = Object.hasOwn || function (object, property) { - if (object == null) { - throw new TypeError('Cannot convert undefined or null to object'); - } - return Object.prototype.hasOwnProperty.call(new Object(object), property); - }; - exports.mixin = (target, source) => { - for (const key in source) { - if (exports.hasOwn(source, key)) { - target[key] = source[key]; + * List all channel groups request. + */ + var ListChannelGroupsRequest = /** @class */ (function (_super) { + __extends(ListChannelGroupsRequest, _super); + function ListChannelGroupsRequest(parameters) { + var _this = _super.call(this) || this; + _this.parameters = parameters; + return _this; } - } - }; - - }(utils$1)); - - const semver = require$$0; + ListChannelGroupsRequest.prototype.operation = function () { + return RequestOperation$1.PNChannelGroupsOperation; + }; + ListChannelGroupsRequest.prototype.validate = function () { + if (!this.parameters.keySet.subscribeKey) + return 'Missing Subscribe Key'; + }; + ListChannelGroupsRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, { groups: serviceResponse.payload.groups }]; + }); + }); + }; + Object.defineProperty(ListChannelGroupsRequest.prototype, "path", { + get: function () { + return "/v1/channel-registration/sub-key/".concat(this.parameters.keySet.subscribeKey, "/channel-group"); + }, + enumerable: false, + configurable: true + }); + return ListChannelGroupsRequest; + }(AbstractRequest)); /** - * Module of mixed-in functions shared between node and client code + * PubNub Channel Groups API module. */ - const _require = utils$1, - isObject = _require.isObject, - hasOwn = _require.hasOwn; + var PubnubChannelGroups = /** @class */ (function () { + function PubnubChannelGroups(keySet, + /* eslint-disable @typescript-eslint/no-explicit-any */ + sendRequest) { + this.keySet = keySet; + this.sendRequest = sendRequest; + } + /** + * Fetch channel group channels. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get channel group channels response or `void` in case if `callback` + * provided. + */ + PubnubChannelGroups.prototype.listChannels = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new ListChannelGroupChannels(__assign(__assign({}, parameters), { keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Fetch all channel groups. + * + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get all channel groups response or `void` in case if `callback` provided. + * + * @deprecated + */ + PubnubChannelGroups.prototype.listGroups = function (callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new ListChannelGroupsRequest({ keySet: this.keySet }); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Add channels to the channel group. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous add channels to the channel group response or `void` in case if + * `callback` provided. + */ + PubnubChannelGroups.prototype.addChannels = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new AddChannelGroupChannelsRequest(__assign(__assign({}, parameters), { keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Remove channels from the channel group. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous remove channels from the channel group response or `void` in + * case if `callback` provided. + */ + PubnubChannelGroups.prototype.removeChannels = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new RemoveChannelGroupChannelsRequest(__assign(__assign({}, parameters), { keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Remove channel group. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous remove channel group response or `void` in case if `callback` provided. + */ + PubnubChannelGroups.prototype.deleteGroup = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new DeleteChannelGroupRequest(__assign(__assign({}, parameters), { keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + return PubnubChannelGroups; + }()); /** - * Expose `RequestBase`. + * Manage channels enabled for device push REST API module. */ - - var requestBase = RequestBase; - + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults /** - * Initialize a new `RequestBase`. - * - * @api public + * Environment for which APNS2 notifications */ - - function RequestBase() {} - + var ENVIRONMENT = 'development'; /** - * Clear previous timeout. - * - * @return {Request} for chaining - * @api public - */ - - RequestBase.prototype.clearTimeout = function () { - clearTimeout(this._timer); - clearTimeout(this._responseTimeoutTimer); - clearTimeout(this._uploadTimeoutTimer); - delete this._timer; - delete this._responseTimeoutTimer; - delete this._uploadTimeoutTimer; - return this; - }; - + * Maximum number of channels in `list` response. + */ + var MAX_COUNT = 1000; + // endregion /** - * Override default response body parser - * - * This function will be called to convert incoming data into request.body - * - * @param {Function} - * @api public + * Base push notification request. */ - - RequestBase.prototype.parse = function (fn) { - this._parser = fn; - return this; - }; + var BasePushNotificationChannelsRequest = /** @class */ (function (_super) { + __extends(BasePushNotificationChannelsRequest, _super); + function BasePushNotificationChannelsRequest(parameters) { + var _a; + var _b; + var _this = _super.call(this) || this; + _this.parameters = parameters; + // Apply request defaults + if (_this.parameters.pushGateway === 'apns2') + (_a = (_b = _this.parameters).environment) !== null && _a !== void 0 ? _a : (_b.environment = ENVIRONMENT); + if (_this.parameters.count && _this.parameters.count > MAX_COUNT) + _this.parameters.count = MAX_COUNT; + return _this; + } + BasePushNotificationChannelsRequest.prototype.operation = function () { + throw Error('Should be implemented in subclass.'); + }; + BasePushNotificationChannelsRequest.prototype.validate = function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, action = _a.action, device = _a.device, pushGateway = _a.pushGateway; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!device) + return 'Missing Device ID (device)'; + if ((action === 'add' || action === 'remove') && + (!('channels' in this.parameters) || this.parameters.channels.length === 0)) + return 'Missing Channels'; + if (!pushGateway) + return 'Missing GW Type (pushGateway: gcm or apns2)'; + if (this.parameters.pushGateway === 'apns2' && !this.parameters.topic) + return 'Missing APNS2 topic'; + }; + BasePushNotificationChannelsRequest.prototype.parse = function (_response) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + throw Error('Should be implemented in subclass.'); + }); + }); + }; + Object.defineProperty(BasePushNotificationChannelsRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, action = _a.action, device = _a.device, pushGateway = _a.pushGateway; + var path = pushGateway === 'apns2' + ? "/v2/push/sub-key/".concat(subscribeKey, "/devices-apns2/").concat(device) + : "/v1/push/sub-key/".concat(subscribeKey, "/devices/").concat(device); + if (action === 'remove-device') + path = "".concat(path, "/remove"); + return path; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(BasePushNotificationChannelsRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, start = _a.start, count = _a.count; + var query = __assign(__assign({ type: this.parameters.pushGateway }, (start ? { start: start } : {})), (count && count > 0 ? { count: count } : {})); + if ('channels' in this.parameters) + query[this.parameters.action] = this.parameters.channels.join(','); + if (this.parameters.pushGateway === 'apns2') { + var _b = this.parameters, environment = _b.environment, topic = _b.topic; + query = __assign(__assign({}, query), { environment: environment, topic: topic }); + } + return query; + }, + enumerable: false, + configurable: true + }); + return BasePushNotificationChannelsRequest; + }(AbstractRequest)); /** - * Set format of binary response body. - * In browser valid formats are 'blob' and 'arraybuffer', - * which return Blob and ArrayBuffer, respectively. - * - * In Node all values result in Buffer. - * - * Examples: - * - * req.get('/') - * .responseType('blob') - * .end(callback); - * - * @param {String} val - * @return {Request} for chaining - * @api public + * Unregister Channels from Device push REST API module. */ - - RequestBase.prototype.responseType = function (value) { - this._responseType = value; - return this; - }; - + // endregion /** - * Override default request body serializer - * - * This function will be called to convert data set via .send or .attach into payload to send - * - * @param {Function} - * @api public + * Unregister channels from device push request. */ - - RequestBase.prototype.serialize = function (fn) { - this._serializer = fn; - return this; - }; - - /** - * Set timeouts. - * - * - response timeout is time between sending request and receiving the first byte of the response. Includes DNS and connection time. - * - deadline is the time from start of the request to receiving response body in full. If the deadline is too short large files may not load at all on slow connections. - * - upload is the time since last bit of data was sent or received. This timeout works only if deadline timeout is off - * - * Value of 0 or false means no timeout. - * - * @param {Number|Object} ms or {response, deadline} - * @return {Request} for chaining - * @api public - */ - - RequestBase.prototype.timeout = function (options) { - if (!options || typeof options !== 'object') { - this._timeout = options; - this._responseTimeout = 0; - this._uploadTimeout = 0; - return this; - } - for (const option in options) { - if (hasOwn(options, option)) { - switch (option) { - case 'deadline': - this._timeout = options.deadline; - break; - case 'response': - this._responseTimeout = options.response; - break; - case 'upload': - this._uploadTimeout = options.upload; - break; - default: - console.warn('Unknown timeout option', option); - } - } - } - return this; - }; - - /** - * Set number of retry attempts on error. - * - * Failed requests will be retried 'count' times if timeout or err.code >= 500. - * - * @param {Number} count - * @param {Function} [fn] - * @return {Request} for chaining - * @api public - */ - - RequestBase.prototype.retry = function (count, fn) { - // Default to 1 if no count passed or true - if (arguments.length === 0 || count === true) count = 1; - if (count <= 0) count = 0; - this._maxRetries = count; - this._retries = 0; - this._retryCallback = fn; - return this; - }; - - // - // NOTE: we do not include ESOCKETTIMEDOUT because that is from `request` package - // - // - // NOTE: we do not include EADDRINFO because it was removed from libuv in 2014 - // - // - // - // - // TODO: expose these as configurable defaults - // - const ERROR_CODES = new Set(['ETIMEDOUT', 'ECONNRESET', 'EADDRINUSE', 'ECONNREFUSED', 'EPIPE', 'ENOTFOUND', 'ENETUNREACH', 'EAI_AGAIN']); - const STATUS_CODES = new Set([408, 413, 429, 500, 502, 503, 504, 521, 522, 524]); - - // TODO: we would need to make this easily configurable before adding it in (e.g. some might want to add POST) - // const METHODS = new Set(['GET', 'PUT', 'HEAD', 'DELETE', 'OPTIONS', 'TRACE']); - - /** - * Determine if a request should be retried. - * (Inspired by https://github.com/sindresorhus/got#retry) - * - * @param {Error} err an error - * @param {Response} [res] response - * @returns {Boolean} if segment should be retried - */ - RequestBase.prototype._shouldRetry = function (error, res) { - if (!this._maxRetries || this._retries++ >= this._maxRetries) { - return false; - } - if (this._retryCallback) { - try { - const override = this._retryCallback(error, res); - if (override === true) return true; - if (override === false) return false; - // undefined falls back to defaults - } catch (err) { - console.error(err); - } - } - - // TODO: we would need to make this easily configurable before adding it in (e.g. some might want to add POST) - /* - if ( - this.req && - this.req.method && - !METHODS.has(this.req.method.toUpperCase()) - ) - return false; - */ - if (res && res.status && STATUS_CODES.has(res.status)) return true; - if (error) { - if (error.code && ERROR_CODES.has(error.code)) return true; - // Superagent timeout - if (error.timeout && error.code === 'ECONNABORTED') return true; - if (error.crossDomain) return true; - } - return false; - }; + // prettier-ignore + var RemoveDevicePushNotificationChannelsRequest = /** @class */ (function (_super) { + __extends(RemoveDevicePushNotificationChannelsRequest, _super); + function RemoveDevicePushNotificationChannelsRequest(parameters) { + return _super.call(this, __assign(__assign({}, parameters), { action: 'remove' })) || this; + } + RemoveDevicePushNotificationChannelsRequest.prototype.operation = function () { + return RequestOperation$1.PNRemovePushNotificationEnabledChannelsOperation; + }; + RemoveDevicePushNotificationChannelsRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, {}]; + }); + }); + }; + return RemoveDevicePushNotificationChannelsRequest; + }(BasePushNotificationChannelsRequest)); /** - * Retry request - * - * @return {Request} for chaining - * @api private - */ - - RequestBase.prototype._retry = function () { - this.clearTimeout(); - - // node - if (this.req) { - this.req = null; - this.req = this.request(); - } - this._aborted = false; - this.timedout = false; - this.timedoutError = null; - return this._end(); - }; - + * List Device push enabled channels REST API module. + */ + // endregion /** - * Promise support - * - * @param {Function} resolve - * @param {Function} [reject] - * @return {Request} + * List device push enabled channels request. */ - - RequestBase.prototype.then = function (resolve, reject) { - if (!this._fullfilledPromise) { - const self = this; - if (this._endCalled) { - console.warn('Warning: superagent request was sent twice, because both .end() and .then() were called. Never call .end() if you use promises'); + // prettier-ignore + var ListDevicePushNotificationChannelsRequest = /** @class */ (function (_super) { + __extends(ListDevicePushNotificationChannelsRequest, _super); + function ListDevicePushNotificationChannelsRequest(parameters) { + return _super.call(this, __assign(__assign({}, parameters), { action: 'list' })) || this; } - this._fullfilledPromise = new Promise((resolve, reject) => { - self.on('abort', () => { - if (this._maxRetries && this._maxRetries > this._retries) { - return; - } - if (this.timedout && this.timedoutError) { - reject(this.timedoutError); - return; - } - const error = new Error('Aborted'); - error.code = 'ABORTED'; - error.status = this.status; - error.method = this.method; - error.url = this.url; - reject(error); - }); - self.end((error, res) => { - if (error) reject(error);else resolve(res); - }); - }); - } - return this._fullfilledPromise.then(resolve, reject); - }; - RequestBase.prototype.catch = function (callback) { - return this.then(undefined, callback); - }; + ListDevicePushNotificationChannelsRequest.prototype.operation = function () { + return RequestOperation$1.PNPushNotificationEnabledChannelsOperation; + }; + ListDevicePushNotificationChannelsRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, { channels: serviceResponse }]; + }); + }); + }; + return ListDevicePushNotificationChannelsRequest; + }(BasePushNotificationChannelsRequest)); /** - * Allow for extension + * Register Channels with Device push REST API module. */ - - RequestBase.prototype.use = function (fn) { - fn(this); - return this; - }; - RequestBase.prototype.ok = function (callback) { - if (typeof callback !== 'function') throw new Error('Callback required'); - this._okCallback = callback; - return this; - }; - RequestBase.prototype._isResponseOK = function (res) { - if (!res) { - return false; - } - if (this._okCallback) { - return this._okCallback(res); - } - return res.status >= 200 && res.status < 300; - }; - + // endregion /** - * Get request header `field`. - * Case-insensitive. - * - * @param {String} field - * @return {String} - * @api public + * Register channels with device push request. */ - - RequestBase.prototype.get = function (field) { - return this._header[field.toLowerCase()]; - }; + // prettier-ignore + var AddDevicePushNotificationChannelsRequest = /** @class */ (function (_super) { + __extends(AddDevicePushNotificationChannelsRequest, _super); + function AddDevicePushNotificationChannelsRequest(parameters) { + return _super.call(this, __assign(__assign({}, parameters), { action: 'add' })) || this; + } + AddDevicePushNotificationChannelsRequest.prototype.operation = function () { + return RequestOperation$1.PNAddPushNotificationEnabledChannelsOperation; + }; + AddDevicePushNotificationChannelsRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, {}]; + }); + }); + }; + return AddDevicePushNotificationChannelsRequest; + }(BasePushNotificationChannelsRequest)); /** - * Get case-insensitive header `field` value. - * This is a deprecated internal API. Use `.get(field)` instead. - * - * (getHeader is no longer used internally by the superagent code base) - * - * @param {String} field - * @return {String} - * @api private - * @deprecated + * Unregister Device push REST API module. */ - - RequestBase.prototype.getHeader = RequestBase.prototype.get; - - /** - * Set header `field` to `val`, or multiple fields with one object. - * Case-insensitive. - * - * Examples: - * - * req.get('/') - * .set('Accept', 'application/json') - * .set('X-API-Key', 'foobar') - * .end(callback); - * - * req.get('/') - * .set({ Accept: 'application/json', 'X-API-Key': 'foobar' }) - * .end(callback); - * - * @param {String|Object} field - * @param {String} val - * @return {Request} for chaining - * @api public - */ - - RequestBase.prototype.set = function (field, value) { - if (isObject(field)) { - for (const key in field) { - if (hasOwn(field, key)) this.set(key, field[key]); - } - return this; - } - this._header[field.toLowerCase()] = value; - this.header[field] = value; - return this; - }; - + // endregion /** - * Remove header `field`. - * Case-insensitive. - * - * Example: - * - * req.get('/') - * .unset('User-Agent') - * .end(callback); - * - * @param {String} field field name + * Unregister device push notifications request. */ - RequestBase.prototype.unset = function (field) { - delete this._header[field.toLowerCase()]; - delete this.header[field]; - return this; - }; - - /** - * Write the field `name` and `val`, or multiple fields with one object - * for "multipart/form-data" request bodies. - * - * ``` js - * request.post('/upload') - * .field('foo', 'bar') - * .end(callback); - * - * request.post('/upload') - * .field({ foo: 'bar', baz: 'qux' }) - * .end(callback); - * ``` - * - * @param {String|Object} name name of field - * @param {String|Blob|File|Buffer|fs.ReadStream} val value of field - * @param {String} options extra options, e.g. 'blob' - * @return {Request} for chaining - * @api public - */ - RequestBase.prototype.field = function (name, value, options) { - // name should be either a string or an object. - if (name === null || undefined === name) { - throw new Error('.field(name, val) name can not be empty'); - } - if (this._data) { - throw new Error(".field() can't be used if .send() is used. Please use only .send() or only .field() & .attach()"); - } - if (isObject(name)) { - for (const key in name) { - if (hasOwn(name, key)) this.field(key, name[key]); - } - return this; - } - if (Array.isArray(value)) { - for (const i in value) { - if (hasOwn(value, i)) this.field(name, value[i]); - } - return this; - } - - // val should be defined now - if (value === null || undefined === value) { - throw new Error('.field(name, val) val can not be empty'); - } - if (typeof value === 'boolean') { - value = String(value); - } - - // fix https://github.com/ladjs/superagent/issues/1680 - if (options) this._getFormData().append(name, value, options);else this._getFormData().append(name, value); - return this; - }; - - /** - * Abort the request, and clear potential timeout. - * - * @return {Request} request - * @api public - */ - RequestBase.prototype.abort = function () { - if (this._aborted) { - return this; - } - this._aborted = true; - if (this.xhr) this.xhr.abort(); // browser - if (this.req) { - // Node v13 has major differences in `abort()` - // https://github.com/nodejs/node/blob/v12.x/lib/internal/streams/end-of-stream.js - // https://github.com/nodejs/node/blob/v13.x/lib/internal/streams/end-of-stream.js - // https://github.com/nodejs/node/blob/v14.x/lib/internal/streams/end-of-stream.js - // (if you run a diff across these you will see the differences) - // - // References: - // - // - // - // Thanks to @shadowgate15 and @niftylettuce - if (semver.gte(process.version, 'v13.0.0') && semver.lt(process.version, 'v14.0.0')) { - // Note that the reason this doesn't work is because in v13 as compared to v14 - // there is no `callback = nop` set in end-of-stream.js above - throw new Error('Superagent does not work in v13 properly with abort() due to Node.js core changes'); - } - this.req.abort(); // node - } - - this.clearTimeout(); - this.emit('abort'); - return this; - }; - RequestBase.prototype._auth = function (user, pass, options, base64Encoder) { - switch (options.type) { - case 'basic': - this.set('Authorization', `Basic ${base64Encoder(`${user}:${pass}`)}`); - break; - case 'auto': - this.username = user; - this.password = pass; - break; - case 'bearer': - // usage would be .auth(accessToken, { type: 'bearer' }) - this.set('Authorization', `Bearer ${user}`); - break; - } - return this; - }; - - /** - * Enable transmission of cookies with x-domain requests. - * - * Note that for this to work the origin must not be - * using "Access-Control-Allow-Origin" with a wildcard, - * and also must set "Access-Control-Allow-Credentials" - * to "true". - * @param {Boolean} [on=true] - Set 'withCredentials' state - * @return {Request} for chaining - * @api public - */ - - RequestBase.prototype.withCredentials = function (on) { - // This is browser-only functionality. Node side is no-op. - if (on === undefined) on = true; - this._withCredentials = on; - return this; - }; + // prettier-ignore + var RemoveDevicePushNotificationRequest = /** @class */ (function (_super) { + __extends(RemoveDevicePushNotificationRequest, _super); + function RemoveDevicePushNotificationRequest(parameters) { + return _super.call(this, __assign(__assign({}, parameters), { action: 'remove-device' })) || this; + } + RemoveDevicePushNotificationRequest.prototype.operation = function () { + return RequestOperation$1.PNRemoveAllPushNotificationsOperation; + }; + RemoveDevicePushNotificationRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, {}]; + }); + }); + }; + return RemoveDevicePushNotificationRequest; + }(BasePushNotificationChannelsRequest)); /** - * Set the max redirects to `n`. Does nothing in browser XHR implementation. - * - * @param {Number} n - * @return {Request} for chaining - * @api public + * PubNub Push Notifications API module. */ - - RequestBase.prototype.redirects = function (n) { - this._maxRedirects = n; - return this; - }; - - /** - * Maximum size of buffered response body, in bytes. Counts uncompressed size. - * Default 200MB. - * - * @param {Number} n number of bytes - * @return {Request} for chaining - */ - RequestBase.prototype.maxResponseSize = function (n) { - if (typeof n !== 'number') { - throw new TypeError('Invalid argument'); - } - this._maxResponseSize = n; - return this; - }; + var PubNubPushNotifications = /** @class */ (function () { + function PubNubPushNotifications(keySet, + /* eslint-disable @typescript-eslint/no-explicit-any */ + sendRequest) { + this.keySet = keySet; + this.sendRequest = sendRequest; + } + /** + * Fetch device's push notification enabled channels. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get device channels response or `void` in case if `callback` provided. + */ + PubNubPushNotifications.prototype.listChannels = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new ListDevicePushNotificationChannelsRequest(__assign(__assign({}, parameters), { keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Enable push notifications on channels for device. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + */ + PubNubPushNotifications.prototype.addChannels = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new AddDevicePushNotificationChannelsRequest(__assign(__assign({}, parameters), { keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Disable push notifications on channels for device. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + */ + PubNubPushNotifications.prototype.removeChannels = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new RemoveDevicePushNotificationChannelsRequest(__assign(__assign({}, parameters), { keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Disable push notifications for device. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + */ + PubNubPushNotifications.prototype.deleteDevice = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new RemoveDevicePushNotificationRequest(__assign(__assign({}, parameters), { keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + return PubNubPushNotifications; + }()); /** - * Convert to a plain javascript object (not JSON string) of scalar properties. - * Note as this method is designed to return a useful non-this value, - * it cannot be chained. - * - * @return {Object} describing method, url, and data of this request - * @api public + * Get All Channel Metadata REST API module. */ - - RequestBase.prototype.toJSON = function () { - return { - method: this.method, - url: this.url, - data: this._data, - headers: this._header - }; - }; - - /** - * Send `data` as the request body, defaulting the `.type()` to "json" when - * an object is given. - * - * Examples: - * - * // manual json - * request.post('/user') - * .type('json') - * .send('{"name":"tj"}') - * .end(callback) - * - * // auto json - * request.post('/user') - * .send({ name: 'tj' }) - * .end(callback) - * - * // manual x-www-form-urlencoded - * request.post('/user') - * .type('form') - * .send('name=tj') - * .end(callback) - * - * // auto x-www-form-urlencoded - * request.post('/user') - * .type('form') - * .send({ name: 'tj' }) - * .end(callback) - * - * // defaults to x-www-form-urlencoded - * request.post('/user') - * .send('name=tobi') - * .send('species=ferret') - * .end(callback) - * - * @param {String|Object} data - * @return {Request} for chaining - * @api public - */ - - // eslint-disable-next-line complexity - RequestBase.prototype.send = function (data) { - const isObject_ = isObject(data); - let type = this._header['content-type']; - if (this._formData) { - throw new Error(".send() can't be used if .attach() or .field() is used. Please use only .send() or only .field() & .attach()"); - } - if (isObject_ && !this._data) { - if (Array.isArray(data)) { - this._data = []; - } else if (!this._isHost(data)) { - this._data = {}; - } - } else if (data && this._data && this._isHost(this._data)) { - throw new Error("Can't merge these send calls"); - } - - // merge - if (isObject_ && isObject(this._data)) { - for (const key in data) { - if (typeof data[key] == 'bigint' && !data[key].toJSON) throw new Error('Cannot serialize BigInt value to json'); - if (hasOwn(data, key)) this._data[key] = data[key]; - } - } else if (typeof data === 'bigint') throw new Error("Cannot send value of type BigInt");else if (typeof data === 'string') { - // default to x-www-form-urlencoded - if (!type) this.type('form'); - type = this._header['content-type']; - if (type) type = type.toLowerCase().trim(); - if (type === 'application/x-www-form-urlencoded') { - this._data = this._data ? `${this._data}&${data}` : data; - } else { - this._data = (this._data || '') + data; - } - } else { - this._data = data; - } - if (!isObject_ || this._isHost(data)) { - return this; - } - - // default to json - if (!type) this.type('json'); - return this; - }; - + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults /** - * Sort `querystring` by the sort function - * - * - * Examples: - * - * // default order - * request.get('/user') - * .query('name=Nick') - * .query('search=Manny') - * .sortQuery() - * .end(callback) - * - * // customized sort function - * request.get('/user') - * .query('name=Nick') - * .query('search=Manny') - * .sortQuery(function(a, b){ - * return a.length - b.length; - * }) - * .end(callback) - * - * - * @param {Function} sort - * @return {Request} for chaining - * @api public + * Whether `Channel` custom fields should be included in response or not. */ - - RequestBase.prototype.sortQuery = function (sort) { - // _sort default to true but otherwise can be a function or boolean - this._sort = typeof sort === 'undefined' ? true : sort; - return this; - }; - - /** - * Compose querystring to append to req.url - * - * @api private - */ - RequestBase.prototype._finalizeQueryString = function () { - const query = this._query.join('&'); - if (query) { - this.url += (this.url.includes('?') ? '&' : '?') + query; - } - this._query.length = 0; // Makes the call idempotent - - if (this._sort) { - const index = this.url.indexOf('?'); - if (index >= 0) { - const queryArray = this.url.slice(index + 1).split('&'); - if (typeof this._sort === 'function') { - queryArray.sort(this._sort); - } else { - queryArray.sort(); - } - this.url = this.url.slice(0, index) + '?' + queryArray.join('&'); - } - } - }; - - // For backwards compat only - RequestBase.prototype._appendQueryString = () => { - console.warn('Unsupported'); - }; - - /** - * Invoke callback with timeout error. - * - * @api private - */ - - RequestBase.prototype._timeoutError = function (reason, timeout, errno) { - if (this._aborted) { - return; - } - const error = new Error(`${reason + timeout}ms exceeded`); - error.timeout = timeout; - error.code = 'ECONNABORTED'; - error.errno = errno; - this.timedout = true; - this.timedoutError = error; - this.abort(); - this.callback(error); - }; - RequestBase.prototype._setTimeouts = function () { - const self = this; - - // deadline - if (this._timeout && !this._timer) { - this._timer = setTimeout(() => { - self._timeoutError('Timeout of ', self._timeout, 'ETIME'); - }, this._timeout); - } - - // response timeout - if (this._responseTimeout && !this._responseTimeoutTimer) { - this._responseTimeoutTimer = setTimeout(() => { - self._timeoutError('Response timeout of ', self._responseTimeout, 'ETIMEDOUT'); - }, this._responseTimeout); - } - }; - + var INCLUDE_CUSTOM_FIELDS$8 = false; /** - * Module dependencies. + * Whether total number of channels should be included in response or not. */ - - const utils = utils$1; - + var INCLUDE_TOTAL_COUNT$5 = false; /** - * Expose `ResponseBase`. + * Number of objects to return in response. */ - - var responseBase = ResponseBase; - + var LIMIT$5 = 100; + // endregion /** - * Initialize a new `ResponseBase`. - * - * @api public + * Get All Channels Metadata request. */ - - function ResponseBase() {} + var GetAllChannelsMetadataRequest = /** @class */ (function (_super) { + __extends(GetAllChannelsMetadataRequest, _super); + function GetAllChannelsMetadataRequest(parameters) { + var _a, _b, _c, _d; + var _e, _f; + var _this = _super.call(this) || this; + _this.parameters = parameters; + // Apply default request parameters. + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_e = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_e.customFields = INCLUDE_CUSTOM_FIELDS$8); + (_c = (_f = parameters.include).totalCount) !== null && _c !== void 0 ? _c : (_f.totalCount = INCLUDE_TOTAL_COUNT$5); + (_d = parameters.limit) !== null && _d !== void 0 ? _d : (parameters.limit = LIMIT$5); + return _this; + } + GetAllChannelsMetadataRequest.prototype.operation = function () { + return RequestOperation$1.PNGetAllChannelMetadataOperation; + }; + GetAllChannelsMetadataRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, serviceResponse]; + }); + }); + }; + Object.defineProperty(GetAllChannelsMetadataRequest.prototype, "path", { + get: function () { + return "/v2/objects/".concat(this.parameters.keySet.subscribeKey, "/channels"); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(GetAllChannelsMetadataRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, include = _a.include, page = _a.page, filter = _a.filter, sort = _a.sort, limit = _a.limit; + var sorting = Object.entries(sort !== null && sort !== void 0 ? sort : {}).map(function (_a) { + var _b = __read(_a, 2), option = _b[0], order = _b[1]; + return order !== null ? "".concat(option, ":").concat(order) : option; + }); + return __assign(__assign(__assign(__assign(__assign({ include: __spreadArray(['status', 'type'], __read((include.customFields ? ['custom'] : [])), false).join(','), count: "".concat(include.totalCount) }, (filter ? { filter: filter } : {})), ((page === null || page === void 0 ? void 0 : page.next) ? { start: page.next } : {})), ((page === null || page === void 0 ? void 0 : page.prev) ? { end: page.prev } : {})), (limit ? { limit: limit } : {})), (sorting.length ? { sort: sorting } : {})); + }, + enumerable: false, + configurable: true + }); + return GetAllChannelsMetadataRequest; + }(AbstractRequest)); /** - * Get case-insensitive `field` value. - * - * @param {String} field - * @return {String} - * @api public + * Remove Channel Metadata REST API module. */ - - ResponseBase.prototype.get = function (field) { - return this.header[field.toLowerCase()]; - }; - + // endregion /** - * Set header related properties: - * - * - `.type` the content type without params - * - * A response of "Content-Type: text/plain; charset=utf-8" - * will provide you with a `.type` of "text/plain". - * - * @param {Object} header - * @api private + * Remove Channel Metadata request. */ - - ResponseBase.prototype._setHeaderProperties = function (header) { - // TODO: moar! - // TODO: make this a util - - // content-type - const ct = header['content-type'] || ''; - this.type = utils.type(ct); - - // params - const parameters = utils.params(ct); - for (const key in parameters) { - if (Object.prototype.hasOwnProperty.call(parameters, key)) this[key] = parameters[key]; - } - this.links = {}; - - // links - try { - if (header.link) { - this.links = utils.parseLinks(header.link); + var RemoveChannelMetadataRequest = /** @class */ (function (_super) { + __extends(RemoveChannelMetadataRequest, _super); + function RemoveChannelMetadataRequest(parameters) { + var _this = _super.call(this, { method: TransportMethod.DELETE }) || this; + _this.parameters = parameters; + return _this; } - } catch (err) { - // ignore - } - }; + RemoveChannelMetadataRequest.prototype.operation = function () { + return RequestOperation$1.PNRemoveChannelMetadataOperation; + }; + RemoveChannelMetadataRequest.prototype.validate = function () { + if (!this.parameters.channel) + return 'Channel cannot be empty'; + }; + RemoveChannelMetadataRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, serviceResponse]; + }); + }); + }; + Object.defineProperty(RemoveChannelMetadataRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channel = _a.channel; + return "/v2/objects/".concat(subscribeKey, "/channels/").concat(encodeString(channel)); + }, + enumerable: false, + configurable: true + }); + return RemoveChannelMetadataRequest; + }(AbstractRequest)); /** - * Set flags such as `.ok` based on `status`. - * - * For example a 2xx response will give you a `.ok` of __true__ - * whereas 5xx will be __false__ and `.error` will be __true__. The - * `.clientError` and `.serverError` are also available to be more - * specific, and `.statusType` is the class of error ranging from 1..5 - * sometimes useful for mapping respond colors etc. - * - * "sugar" properties are also defined for common cases. Currently providing: - * - * - .noContent - * - .badRequest - * - .unauthorized - * - .notAcceptable - * - .notFound - * - * @param {Number} status - * @api private - */ - - ResponseBase.prototype._setStatusProperties = function (status) { - const type = Math.trunc(status / 100); - - // status / class - this.statusCode = status; - this.status = this.statusCode; - this.statusType = type; - - // basics - this.info = type === 1; - this.ok = type === 2; - this.redirect = type === 3; - this.clientError = type === 4; - this.serverError = type === 5; - this.error = type === 4 || type === 5 ? this.toError() : false; - - // sugar - this.created = status === 201; - this.accepted = status === 202; - this.noContent = status === 204; - this.badRequest = status === 400; - this.unauthorized = status === 401; - this.notAcceptable = status === 406; - this.forbidden = status === 403; - this.notFound = status === 404; - this.unprocessableEntity = status === 422; - }; - - function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } - function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } - function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } - function Agent() { - this._defaults = []; - } - for (var _i = 0, _arr = ['use', 'on', 'once', 'set', 'query', 'type', 'accept', 'auth', 'withCredentials', 'sortQuery', 'retry', 'ok', 'redirects', 'timeout', 'buffer', 'serialize', 'parse', 'ca', 'key', 'pfx', 'cert', 'disableTLSCerts']; _i < _arr.length; _i++) { - const fn = _arr[_i]; - // Default setting for all requests from this agent - Agent.prototype[fn] = function () { - for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = arguments[_key]; - } - this._defaults.push({ - fn, - args - }); - return this; - }; - } - Agent.prototype._setDefaults = function (request) { - var _iterator = _createForOfIteratorHelper(this._defaults), - _step; - try { - for (_iterator.s(); !(_step = _iterator.n()).done;) { - const def = _step.value; - request[def.fn](...def.args); - } - } catch (err) { - _iterator.e(err); - } finally { - _iterator.f(); - } - }; - var agentBase = Agent; - - (function (module, exports) { - - function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } - function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } - function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } + * Get UUID Memberships REST API module. + */ + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults /** - * Root reference for iframes. + * Whether `Membership` custom field should be included in response or not. */ - - let root; - if (typeof window !== 'undefined') { - // Browser window - root = window; - } else if (typeof self === 'undefined') { - // Other environments - console.warn('Using browser-only version of superagent in non-browser environment'); - root = void 0; - } else { - // Web Worker - root = self; - } - const Emitter = componentEmitter.exports; - const safeStringify = fastSafeStringify; - const qs = lib; - const RequestBase = requestBase; - const _require = utils$1, - isObject = _require.isObject, - mixin = _require.mixin, - hasOwn = _require.hasOwn; - const ResponseBase = responseBase; - const Agent = agentBase; - + var INCLUDE_CUSTOM_FIELDS$7 = false; /** - * Noop. + * Whether membership's status field should be included in response or not. */ - - function noop() {} - + var INCLUDE_STATUS$1 = false; /** - * Expose `request`. + * Whether total number of memberships should be included in response or not. */ - - module.exports = function (method, url) { - // callback - if (typeof url === 'function') { - return new exports.Request('GET', method).end(url); - } - - // url first - if (arguments.length === 1) { - return new exports.Request('GET', method); - } - return new exports.Request(method, url); - }; - exports = module.exports; - const request = exports; - exports.Request = Request; - + var INCLUDE_TOTAL_COUNT$4 = false; /** - * Determine XHR. + * Whether `Channel` fields should be included in response or not. */ - - request.getXHR = () => { - if (root.XMLHttpRequest) { - return new root.XMLHttpRequest(); - } - throw new Error('Browser-only version of superagent could not find XHR'); - }; - + var INCLUDE_CHANNEL_FIELDS$1 = false; /** - * Removes leading and trailing whitespace, added to support IE. - * - * @param {String} s - * @return {String} - * @api private + * Whether `Channel` status field should be included in response or not. */ - - const trim = ''.trim ? s => s.trim() : s => s.replace(/(^\s*|\s*$)/g, ''); - + var INCLUDE_CHANNEL_STATUS_FIELD = false; /** - * Serialize the given `obj`. - * - * @param {Object} obj - * @return {String} - * @api private - */ - - function serialize(object) { - if (!isObject(object)) return object; - const pairs = []; - for (const key in object) { - if (hasOwn(object, key)) pushEncodedKeyValuePair(pairs, key, object[key]); - } - return pairs.join('&'); - } - + * Whether `Channel` type field should be included in response or not. + */ + var INCLUDE_CHANNEL_TYPE_FIELD = false; /** - * Helps 'serialize' with serializing arrays. - * Mutates the pairs array. - * - * @param {Array} pairs - * @param {String} key - * @param {Mixed} val - */ - - function pushEncodedKeyValuePair(pairs, key, value) { - if (value === undefined) return; - if (value === null) { - pairs.push(encodeURI(key)); - return; - } - if (Array.isArray(value)) { - var _iterator = _createForOfIteratorHelper(value), - _step; - try { - for (_iterator.s(); !(_step = _iterator.n()).done;) { - const v = _step.value; - pushEncodedKeyValuePair(pairs, key, v); - } - } catch (err) { - _iterator.e(err); - } finally { - _iterator.f(); - } - } else if (isObject(value)) { - for (const subkey in value) { - if (hasOwn(value, subkey)) pushEncodedKeyValuePair(pairs, `${key}[${subkey}]`, value[subkey]); - } - } else { - pairs.push(encodeURI(key) + '=' + encodeURIComponent(value)); - } - } - + * Whether `Channel` custom field should be included in response or not. + */ + var INCLUDE_CHANNEL_CUSTOM_FIELDS$1 = false; /** - * Expose serialization method. + * Number of objects to return in response. */ - - request.serializeObject = serialize; - + var LIMIT$4 = 100; + // endregion /** - * Parse the given x-www-form-urlencoded `str`. - * - * @param {String} str - * @return {Object} - * @api private - */ - - function parseString(string_) { - const object = {}; - const pairs = string_.split('&'); - let pair; - let pos; - for (let i = 0, length_ = pairs.length; i < length_; ++i) { - pair = pairs[i]; - pos = pair.indexOf('='); - if (pos === -1) { - object[decodeURIComponent(pair)] = ''; - } else { - object[decodeURIComponent(pair.slice(0, pos))] = decodeURIComponent(pair.slice(pos + 1)); - } - } - return object; - } + * Get UUID Memberships request. + */ + var GetUUIDMembershipsRequest = /** @class */ (function (_super) { + __extends(GetUUIDMembershipsRequest, _super); + function GetUUIDMembershipsRequest(parameters) { + var _a, _b, _c, _d, _e, _f, _g, _h, _j; + var _k, _l, _m, _o, _p, _q, _r; + var _this = _super.call(this) || this; + _this.parameters = parameters; + // Apply default request parameters. + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_k = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_k.customFields = INCLUDE_CUSTOM_FIELDS$7); + (_c = (_l = parameters.include).totalCount) !== null && _c !== void 0 ? _c : (_l.totalCount = INCLUDE_TOTAL_COUNT$4); + (_d = (_m = parameters.include).statusField) !== null && _d !== void 0 ? _d : (_m.statusField = INCLUDE_STATUS$1); + (_e = (_o = parameters.include).channelFields) !== null && _e !== void 0 ? _e : (_o.channelFields = INCLUDE_CHANNEL_FIELDS$1); + (_f = (_p = parameters.include).customChannelFields) !== null && _f !== void 0 ? _f : (_p.customChannelFields = INCLUDE_CHANNEL_CUSTOM_FIELDS$1); + (_g = (_q = parameters.include).channelStatusField) !== null && _g !== void 0 ? _g : (_q.channelStatusField = INCLUDE_CHANNEL_STATUS_FIELD); + (_h = (_r = parameters.include).channelTypeField) !== null && _h !== void 0 ? _h : (_r.channelTypeField = INCLUDE_CHANNEL_TYPE_FIELD); + (_j = parameters.limit) !== null && _j !== void 0 ? _j : (parameters.limit = LIMIT$4); + // Remap for backward compatibility. + if (_this.parameters.userId) + _this.parameters.uuid = _this.parameters.userId; + return _this; + } + GetUUIDMembershipsRequest.prototype.operation = function () { + return RequestOperation$1.PNGetMembershipsOperation; + }; + GetUUIDMembershipsRequest.prototype.validate = function () { + if (!this.parameters.uuid) + return "'uuid' cannot be empty"; + }; + GetUUIDMembershipsRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, serviceResponse]; + }); + }); + }; + Object.defineProperty(GetUUIDMembershipsRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, uuid = _a.uuid; + return "/v2/objects/".concat(subscribeKey, "/uuids/").concat(encodeString(uuid), "/channels"); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(GetUUIDMembershipsRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, include = _a.include, page = _a.page, filter = _a.filter, sort = _a.sort, limit = _a.limit; + var sorting = Object.entries(sort !== null && sort !== void 0 ? sort : {}).map(function (_a) { + var _b = __read(_a, 2), option = _b[0], order = _b[1]; + return order !== null ? "".concat(option, ":").concat(order) : option; + }); + var includeFlags = []; + if (include.statusField) + includeFlags.push('status'); + if (include.customFields) + includeFlags.push('custom'); + if (include.channelFields) + includeFlags.push('channel'); + if (include.channelStatusField) + includeFlags.push('channel.status'); + if (include.channelTypeField) + includeFlags.push('channel.type'); + if (include.customChannelFields) + includeFlags.push('channel.custom'); + return __assign(__assign(__assign(__assign(__assign(__assign({ count: "".concat(include.totalCount) }, (includeFlags.length > 0 ? { include: includeFlags.join(',') } : {})), (filter ? { filter: filter } : {})), ((page === null || page === void 0 ? void 0 : page.next) ? { start: page.next } : {})), ((page === null || page === void 0 ? void 0 : page.prev) ? { end: page.prev } : {})), (limit ? { limit: limit } : {})), (sorting.length ? { sort: sorting } : {})); + }, + enumerable: false, + configurable: true + }); + return GetUUIDMembershipsRequest; + }(AbstractRequest)); /** - * Expose parser. + * Set UUID Memberships REST API module. */ - - request.parseString = parseString; - + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults /** - * Default MIME type map. - * - * superagent.types.xml = 'application/xml'; - * + * Whether `Membership` custom field should be included in response or not. */ - - request.types = { - html: 'text/html', - json: 'application/json', - xml: 'text/xml', - urlencoded: 'application/x-www-form-urlencoded', - form: 'application/x-www-form-urlencoded', - 'form-data': 'application/x-www-form-urlencoded' - }; - + var INCLUDE_CUSTOM_FIELDS$6 = false; /** - * Default serialization map. - * - * superagent.serialize['application/xml'] = function(obj){ - * return 'generated xml here'; - * }; - * + * Whether total number of memberships should be included in response or not. */ - - request.serialize = { - 'application/x-www-form-urlencoded': qs.stringify, - 'application/json': safeStringify - }; - + var INCLUDE_TOTAL_COUNT$3 = false; /** - * Default parsers. - * - * superagent.parse['application/xml'] = function(str){ - * return { object parsed from str }; - * }; - * + * Whether `Channel` fields should be included in response or not. */ - - request.parse = { - 'application/x-www-form-urlencoded': parseString, - 'application/json': JSON.parse - }; - + var INCLUDE_CHANNEL_FIELDS = false; /** - * Parse the given header `str` into - * an object containing the mapped fields. - * - * @param {String} str - * @return {Object} - * @api private - */ - - function parseHeader(string_) { - const lines = string_.split(/\r?\n/); - const fields = {}; - let index; - let line; - let field; - let value; - for (let i = 0, length_ = lines.length; i < length_; ++i) { - line = lines[i]; - index = line.indexOf(':'); - if (index === -1) { - // could be empty line, just skip it - continue; - } - field = line.slice(0, index).toLowerCase(); - value = trim(line.slice(index + 1)); - fields[field] = value; - } - return fields; - } - + * Whether `Channel` custom field should be included in response or not. + */ + var INCLUDE_CHANNEL_CUSTOM_FIELDS = false; /** - * Check if `mime` is json or has +json structured syntax suffix. - * - * @param {String} mime - * @return {Boolean} - * @api private + * Number of objects to return in response. */ - - function isJSON(mime) { - // should match /json or +json - // but not /json-seq - return /[/+]json($|[^-\w])/i.test(mime); - } - + var LIMIT$3 = 100; + // endregion /** - * Initialize a new `Response` with the given `xhr`. - * - * - set flags (.ok, .error, etc) - * - parse header - * - * Examples: - * - * Aliasing `superagent` as `request` is nice: - * - * request = superagent; - * - * We can use the promise-like API, or pass callbacks: - * - * request.get('/').end(function(res){}); - * request.get('/', function(res){}); - * - * Sending data can be chained: - * - * request - * .post('/user') - * .send({ name: 'tj' }) - * .end(function(res){}); - * - * Or passed to `.send()`: - * - * request - * .post('/user') - * .send({ name: 'tj' }, function(res){}); - * - * Or passed to `.post()`: - * - * request - * .post('/user', { name: 'tj' }) - * .end(function(res){}); - * - * Or further reduced to a single call for simple cases: - * - * request - * .post('/user', { name: 'tj' }, function(res){}); - * - * @param {XMLHTTPRequest} xhr - * @param {Object} options - * @api private - */ - - function Response(request_) { - this.req = request_; - this.xhr = this.req.xhr; - // responseText is accessible only if responseType is '' or 'text' and on older browsers - this.text = this.req.method !== 'HEAD' && (this.xhr.responseType === '' || this.xhr.responseType === 'text') || typeof this.xhr.responseType === 'undefined' ? this.xhr.responseText : null; - this.statusText = this.req.xhr.statusText; - let status = this.xhr.status; - // handle IE9 bug: http://stackoverflow.com/questions/10046972/msie-returns-status-code-of-1223-for-ajax-request - if (status === 1223) { - status = 204; - } - this._setStatusProperties(status); - this.headers = parseHeader(this.xhr.getAllResponseHeaders()); - this.header = this.headers; - // getAllResponseHeaders sometimes falsely returns "" for CORS requests, but - // getResponseHeader still works. so we get content-type even if getting - // other headers fails. - this.header['content-type'] = this.xhr.getResponseHeader('content-type'); - this._setHeaderProperties(this.header); - if (this.text === null && request_._responseType) { - this.body = this.xhr.response; - } else { - this.body = this.req.method === 'HEAD' ? null : this._parseBody(this.text ? this.text : this.xhr.response); - } - } - mixin(Response.prototype, ResponseBase.prototype); + * Set UUID Memberships request. + */ + var SetUUIDMembershipsRequest = /** @class */ (function (_super) { + __extends(SetUUIDMembershipsRequest, _super); + function SetUUIDMembershipsRequest(parameters) { + var _a, _b, _c, _d, _e, _f; + var _g, _h, _j, _k; + var _this = _super.call(this, { method: TransportMethod.PATCH }) || this; + _this.parameters = parameters; + // Apply default request parameters. + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_g = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_g.customFields = INCLUDE_CUSTOM_FIELDS$6); + (_c = (_h = parameters.include).totalCount) !== null && _c !== void 0 ? _c : (_h.totalCount = INCLUDE_TOTAL_COUNT$3); + (_d = (_j = parameters.include).channelFields) !== null && _d !== void 0 ? _d : (_j.channelFields = INCLUDE_CHANNEL_FIELDS); + (_e = (_k = parameters.include).customChannelFields) !== null && _e !== void 0 ? _e : (_k.customChannelFields = INCLUDE_CHANNEL_CUSTOM_FIELDS); + (_f = parameters.limit) !== null && _f !== void 0 ? _f : (parameters.limit = LIMIT$3); + // Remap for backward compatibility. + if (_this.parameters.userId) + _this.parameters.uuid = _this.parameters.userId; + return _this; + } + SetUUIDMembershipsRequest.prototype.operation = function () { + return RequestOperation$1.PNSetMembershipsOperation; + }; + SetUUIDMembershipsRequest.prototype.validate = function () { + var _a = this.parameters, uuid = _a.uuid, channels = _a.channels; + if (!uuid) + return "'uuid' cannot be empty"; + if (!channels || channels.length === 0) + return 'Channels cannot be empty'; + }; + SetUUIDMembershipsRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, serviceResponse]; + }); + }); + }; + Object.defineProperty(SetUUIDMembershipsRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, uuid = _a.uuid; + return "/v2/objects/".concat(subscribeKey, "/uuids/").concat(encodeString(uuid), "/channels"); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(SetUUIDMembershipsRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, include = _a.include, page = _a.page, filter = _a.filter, sort = _a.sort, limit = _a.limit; + var sorting = Object.entries(sort !== null && sort !== void 0 ? sort : {}).map(function (_a) { + var _b = __read(_a, 2), option = _b[0], order = _b[1]; + return order !== null ? "".concat(option, ":").concat(order) : option; + }); + var includeFlags = ['channel.status', 'channel.type', 'status']; + if (include.customFields) + includeFlags.push('custom'); + if (include.channelFields) + includeFlags.push('channel'); + if (include.customChannelFields) + includeFlags.push('channel.custom'); + return __assign(__assign(__assign(__assign(__assign(__assign({ count: "".concat(include.totalCount) }, (includeFlags.length > 0 ? { include: includeFlags.join(',') } : {})), (filter ? { filter: filter } : {})), ((page === null || page === void 0 ? void 0 : page.next) ? { start: page.next } : {})), ((page === null || page === void 0 ? void 0 : page.prev) ? { end: page.prev } : {})), (limit ? { limit: limit } : {})), (sorting.length ? { sort: sorting } : {})); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(SetUUIDMembershipsRequest.prototype, "body", { + get: function () { + var _a; + var _b = this.parameters, channels = _b.channels, type = _b.type; + return JSON.stringify((_a = {}, + _a["".concat(type)] = channels.map(function (channel) { + if (typeof channel === 'string') { + return { channel: { id: channel } }; + } + else { + return { channel: { id: channel.id }, status: channel.status, custom: channel.custom }; + } + }), + _a)); + }, + enumerable: false, + configurable: true + }); + return SetUUIDMembershipsRequest; + }(AbstractRequest)); /** - * Parse the given body `str`. - * - * Used for auto-parsing of bodies. Parsers - * are defined on the `superagent.parse` object. - * - * @param {String} str - * @return {Mixed} - * @api private - */ - - Response.prototype._parseBody = function (string_) { - let parse = request.parse[this.type]; - if (this.req._parser) { - return this.req._parser(this, string_); - } - if (!parse && isJSON(this.type)) { - parse = request.parse['application/json']; - } - return parse && string_ && (string_.length > 0 || string_ instanceof Object) ? parse(string_) : null; - }; - + * Get All UUID Metadata REST API module. + */ + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults /** - * Return an `Error` representative of this response. - * - * @return {Error} - * @api public - */ - - Response.prototype.toError = function () { - const req = this.req; - const method = req.method; - const url = req.url; - const message = `cannot ${method} ${url} (${this.status})`; - const error = new Error(message); - error.status = this.status; - error.method = method; - error.url = url; - return error; - }; - + * Whether `Channel` custom field should be included by default or not. + */ + var INCLUDE_CUSTOM_FIELDS$5 = false; /** - * Expose `Response`. + * Whether to fetch total count or not. */ - - request.Response = Response; - + var INCLUDE_TOTAL_COUNT$2 = false; /** - * Initialize a new `Request` with the given `method` and `url`. - * - * @param {String} method - * @param {String} url - * @api public - */ - - function Request(method, url) { - const self = this; - this._query = this._query || []; - this.method = method; - this.url = url; - this.header = {}; // preserves header name case - this._header = {}; // coerces header names to lowercase - this.on('end', () => { - let error = null; - let res = null; - try { - res = new Response(self); - } catch (err) { - error = new Error('Parser is unable to parse the response'); - error.parse = true; - error.original = err; - // issue #675: return the raw response if the response parsing fails - if (self.xhr) { - // ie9 doesn't have 'response' property - error.rawResponse = typeof self.xhr.responseType === 'undefined' ? self.xhr.responseText : self.xhr.response; - // issue #876: return the http status code if the response parsing fails - error.status = self.xhr.status ? self.xhr.status : null; - error.statusCode = error.status; // backwards-compat only - } else { - error.rawResponse = null; - error.status = null; - } - return self.callback(error); - } - self.emit('response', res); - let new_error; - try { - if (!self._isResponseOK(res)) { - new_error = new Error(res.statusText || res.text || 'Unsuccessful HTTP response'); - } - } catch (err) { - new_error = err; // ok() callback can throw - } - - // #1000 don't catch errors from the callback to avoid double calling it - if (new_error) { - new_error.original = error; - new_error.response = res; - new_error.status = new_error.status || res.status; - self.callback(new_error, res); - } else { - self.callback(null, res); - } - }); - } + * Number of objects to return in response. + */ + var LIMIT$2 = 100; + // endregion + var GetAllUUIDMetadataRequest = /** @class */ (function (_super) { + __extends(GetAllUUIDMetadataRequest, _super); + function GetAllUUIDMetadataRequest(parameters) { + var _a, _b, _c, _d; + var _e, _f; + var _this = _super.call(this) || this; + _this.parameters = parameters; + // Apply default request parameters. + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_e = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_e.customFields = INCLUDE_CUSTOM_FIELDS$5); + (_c = (_f = parameters.include).totalCount) !== null && _c !== void 0 ? _c : (_f.totalCount = INCLUDE_TOTAL_COUNT$2); + (_d = parameters.limit) !== null && _d !== void 0 ? _d : (parameters.limit = LIMIT$2); + return _this; + } + GetAllUUIDMetadataRequest.prototype.operation = function () { + return RequestOperation$1.PNGetAllUUIDMetadataOperation; + }; + GetAllUUIDMetadataRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, serviceResponse]; + }); + }); + }; + Object.defineProperty(GetAllUUIDMetadataRequest.prototype, "path", { + get: function () { + return "/v2/objects/".concat(this.parameters.keySet.subscribeKey, "/uuids"); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(GetAllUUIDMetadataRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, include = _a.include, page = _a.page, filter = _a.filter, sort = _a.sort, limit = _a.limit; + var sorting = Object.entries(sort !== null && sort !== void 0 ? sort : {}).map(function (_a) { + var _b = __read(_a, 2), option = _b[0], order = _b[1]; + return order !== null ? "".concat(option, ":").concat(order) : option; + }); + return __assign(__assign(__assign(__assign(__assign({ include: __spreadArray(['status', 'type'], __read((include.customFields ? ['custom'] : [])), false).join(','), count: "".concat(include.totalCount) }, (filter ? { filter: filter } : {})), ((page === null || page === void 0 ? void 0 : page.next) ? { start: page.next } : {})), ((page === null || page === void 0 ? void 0 : page.prev) ? { end: page.prev } : {})), (limit ? { limit: limit } : {})), (sorting.length ? { sort: sorting } : {})); + }, + enumerable: false, + configurable: true + }); + return GetAllUUIDMetadataRequest; + }(AbstractRequest)); /** - * Mixin `Emitter` and `RequestBase`. + * Get Channel Metadata REST API module. */ - - // eslint-disable-next-line new-cap - Emitter(Request.prototype); - mixin(Request.prototype, RequestBase.prototype); - + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults /** - * Set Content-Type to `type`, mapping values from `request.types`. - * - * Examples: - * - * superagent.types.xml = 'application/xml'; - * - * request.post('/') - * .type('xml') - * .send(xmlstring) - * .end(callback); - * - * request.post('/') - * .type('application/xml') - * .send(xmlstring) - * .end(callback); - * - * @param {String} type - * @return {Request} for chaining - * @api public + * Whether `Channel` custom field should be included by default or not. */ - - Request.prototype.type = function (type) { - this.set('Content-Type', request.types[type] || type); - return this; - }; - + var INCLUDE_CUSTOM_FIELDS$4 = true; + // endregion /** - * Set Accept to `type`, mapping values from `request.types`. - * - * Examples: - * - * superagent.types.json = 'application/json'; - * - * request.get('/agent') - * .accept('json') - * .end(callback); - * - * request.get('/agent') - * .accept('application/json') - * .end(callback); - * - * @param {String} accept - * @return {Request} for chaining - * @api public + * Get Channel Metadata request. */ - - Request.prototype.accept = function (type) { - this.set('Accept', request.types[type] || type); - return this; - }; + var GetChannelMetadataRequest = /** @class */ (function (_super) { + __extends(GetChannelMetadataRequest, _super); + function GetChannelMetadataRequest(parameters) { + var _a, _b; + var _c; + var _this = _super.call(this) || this; + _this.parameters = parameters; + // Apply default request parameters. + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_c = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_c.customFields = INCLUDE_CUSTOM_FIELDS$4); + return _this; + } + GetChannelMetadataRequest.prototype.operation = function () { + return RequestOperation$1.PNGetChannelMetadataOperation; + }; + GetChannelMetadataRequest.prototype.validate = function () { + if (!this.parameters.channel) + return 'Channel cannot be empty'; + }; + GetChannelMetadataRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, serviceResponse]; + }); + }); + }; + Object.defineProperty(GetChannelMetadataRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channel = _a.channel; + return "/v2/objects/".concat(subscribeKey, "/channels/").concat(encodeString(channel)); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(GetChannelMetadataRequest.prototype, "queryParameters", { + get: function () { + return { + include: __spreadArray(['status', 'type'], __read((this.parameters.include.customFields ? ['custom'] : [])), false).join(','), + }; + }, + enumerable: false, + configurable: true + }); + return GetChannelMetadataRequest; + }(AbstractRequest)); /** - * Set Authorization field value with `user` and `pass`. - * - * @param {String} user - * @param {String} [pass] optional in case of using 'bearer' as type - * @param {Object} options with 'type' property 'auto', 'basic' or 'bearer' (default 'basic') - * @return {Request} for chaining - * @api public - */ - - Request.prototype.auth = function (user, pass, options) { - if (arguments.length === 1) pass = ''; - if (typeof pass === 'object' && pass !== null) { - // pass is optional and can be replaced with options - options = pass; - pass = ''; - } - if (!options) { - options = { - type: typeof btoa === 'function' ? 'basic' : 'auto' - }; - } - const encoder = options.encoder ? options.encoder : string => { - if (typeof btoa === 'function') { - return btoa(string); - } - throw new Error('Cannot use basic auth, btoa is not a function'); - }; - return this._auth(user, pass, options, encoder); - }; - + * Set Channel Metadata REST API module. + */ + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults /** - * Add query-string `val`. - * - * Examples: - * - * request.get('/shoes') - * .query('size=10') - * .query({ color: 'blue' }) - * - * @param {Object|String} val - * @return {Request} for chaining - * @api public + * Whether `Channel` custom field should be included by default or not. */ - - Request.prototype.query = function (value) { - if (typeof value !== 'string') value = serialize(value); - if (value) this._query.push(value); - return this; - }; - + var INCLUDE_CUSTOM_FIELDS$3 = true; + // endregion /** - * Queue the given `file` as an attachment to the specified `field`, - * with optional `options` (or filename). - * - * ``` js - * request.post('/upload') - * .attach('content', new Blob(['hey!'], { type: "text/html"})) - * .end(callback); - * ``` - * - * @param {String} field - * @param {Blob|File} file - * @param {String|Object} options - * @return {Request} for chaining - * @api public + * Set Channel Metadata request. */ - - Request.prototype.attach = function (field, file, options) { - if (file) { - if (this._data) { - throw new Error("superagent can't mix .send() and .attach()"); + var SetChannelMetadataRequest = /** @class */ (function (_super) { + __extends(SetChannelMetadataRequest, _super); + function SetChannelMetadataRequest(parameters) { + var _a, _b; + var _c; + var _this = _super.call(this, { method: TransportMethod.PATCH }) || this; + _this.parameters = parameters; + // Apply default request parameters. + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_c = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_c.customFields = INCLUDE_CUSTOM_FIELDS$3); + return _this; } - this._getFormData().append(field, file, options || file.name); - } - return this; - }; - Request.prototype._getFormData = function () { - if (!this._formData) { - this._formData = new root.FormData(); - } - return this._formData; - }; + SetChannelMetadataRequest.prototype.operation = function () { + return RequestOperation$1.PNSetChannelMetadataOperation; + }; + SetChannelMetadataRequest.prototype.validate = function () { + if (!this.parameters.channel) + return 'Channel cannot be empty'; + if (!this.parameters.data) + return 'Data cannot be empty'; + }; + SetChannelMetadataRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, serviceResponse]; + }); + }); + }; + Object.defineProperty(SetChannelMetadataRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channel = _a.channel; + return "/v2/objects/".concat(subscribeKey, "/channels/").concat(encodeString(channel)); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(SetChannelMetadataRequest.prototype, "queryParameters", { + get: function () { + return { + include: __spreadArray(['status', 'type'], __read((this.parameters.include.customFields ? ['custom'] : [])), false).join(','), + }; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(SetChannelMetadataRequest.prototype, "body", { + get: function () { + return JSON.stringify(this.parameters.data); + }, + enumerable: false, + configurable: true + }); + return SetChannelMetadataRequest; + }(AbstractRequest)); /** - * Invoke the callback with `err` and `res` - * and handle arity check. - * - * @param {Error} err - * @param {Response} res - * @api private - */ - - Request.prototype.callback = function (error, res) { - if (this._shouldRetry(error, res)) { - return this._retry(); - } - const fn = this._callback; - this.clearTimeout(); - if (error) { - if (this._maxRetries) error.retries = this._retries - 1; - this.emit('error', error); - } - fn(error, res); - }; - + * Remove UUID Metadata REST API module. + */ + // endregion /** - * Invoke callback with x-domain error. - * - * @api private + * Remove UUID Metadata request. */ - - Request.prototype.crossDomainError = function () { - const error = new Error('Request has been terminated\nPossible causes: the network is offline, Origin is not allowed by Access-Control-Allow-Origin, the page is being unloaded, etc.'); - error.crossDomain = true; - error.status = this.status; - error.method = this.method; - error.url = this.url; - this.callback(error); - }; - - // This only warns, because the request is still likely to work - Request.prototype.agent = function () { - console.warn('This is not supported in browser version of superagent'); - return this; - }; - Request.prototype.ca = Request.prototype.agent; - Request.prototype.buffer = Request.prototype.ca; - - // This throws, because it can't send/receive data as expected - Request.prototype.write = () => { - throw new Error('Streaming is not supported in browser version of superagent'); - }; - Request.prototype.pipe = Request.prototype.write; + var RemoveUUIDMetadataRequest = /** @class */ (function (_super) { + __extends(RemoveUUIDMetadataRequest, _super); + function RemoveUUIDMetadataRequest(parameters) { + var _this = _super.call(this, { method: TransportMethod.DELETE }) || this; + _this.parameters = parameters; + // Remap for backward compatibility. + if (_this.parameters.userId) + _this.parameters.uuid = _this.parameters.userId; + return _this; + } + RemoveUUIDMetadataRequest.prototype.operation = function () { + return RequestOperation$1.PNRemoveUUIDMetadataOperation; + }; + RemoveUUIDMetadataRequest.prototype.validate = function () { + if (!this.parameters.uuid) + return "'uuid' cannot be empty"; + }; + RemoveUUIDMetadataRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, serviceResponse]; + }); + }); + }; + Object.defineProperty(RemoveUUIDMetadataRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, uuid = _a.uuid; + return "/v2/objects/".concat(subscribeKey, "/uuids/").concat(encodeString(uuid)); + }, + enumerable: false, + configurable: true + }); + return RemoveUUIDMetadataRequest; + }(AbstractRequest)); /** - * Check if `obj` is a host object, - * we don't want to serialize these :) - * - * @param {Object} obj host object - * @return {Boolean} is a host object - * @api private + * Get Channel Members REST API module. */ - Request.prototype._isHost = function (object) { - // Native objects stringify to [object File], [object Blob], [object FormData], etc. - return object && typeof object === 'object' && !Array.isArray(object) && Object.prototype.toString.call(object) !== '[object Object]'; - }; - + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults /** - * Initiate request, invoking callback `fn(res)` - * with an instanceof `Response`. - * - * @param {Function} fn - * @return {Request} for chaining - * @api public + * Whether `Member` custom field should be included in response or not. */ - - Request.prototype.end = function (fn) { - if (this._endCalled) { - console.warn('Warning: .end() was called twice. This is not supported in superagent'); - } - this._endCalled = true; - - // store callback - this._callback = fn || noop; - - // querystring - this._finalizeQueryString(); - this._end(); - }; - Request.prototype._setUploadTimeout = function () { - const self = this; - - // upload timeout it's wokrs only if deadline timeout is off - if (this._uploadTimeout && !this._uploadTimeoutTimer) { - this._uploadTimeoutTimer = setTimeout(() => { - self._timeoutError('Upload timeout of ', self._uploadTimeout, 'ETIMEDOUT'); - }, this._uploadTimeout); - } - }; - - // eslint-disable-next-line complexity - Request.prototype._end = function () { - if (this._aborted) return this.callback(new Error('The request has been aborted even before .end() was called')); - const self = this; - this.xhr = request.getXHR(); - const xhr = this.xhr; - let data = this._formData || this._data; - this._setTimeouts(); - - // state change - xhr.addEventListener('readystatechange', () => { - const readyState = xhr.readyState; - if (readyState >= 2 && self._responseTimeoutTimer) { - clearTimeout(self._responseTimeoutTimer); - } - if (readyState !== 4) { - return; - } - - // In IE9, reads to any property (e.g. status) off of an aborted XHR will - // result in the error "Could not complete the operation due to error c00c023f" - let status; - try { - status = xhr.status; - } catch (err) { - status = 0; - } - if (!status) { - if (self.timedout || self._aborted) return; - return self.crossDomainError(); - } - self.emit('end'); - }); - - // progress - const handleProgress = (direction, e) => { - if (e.total > 0) { - e.percent = e.loaded / e.total * 100; - if (e.percent === 100) { - clearTimeout(self._uploadTimeoutTimer); - } - } - e.direction = direction; - self.emit('progress', e); - }; - if (this.hasListeners('progress')) { - try { - xhr.addEventListener('progress', handleProgress.bind(null, 'download')); - if (xhr.upload) { - xhr.upload.addEventListener('progress', handleProgress.bind(null, 'upload')); - } - } catch (err) { - // Accessing xhr.upload fails in IE from a web worker, so just pretend it doesn't exist. - // Reported here: - // https://connect.microsoft.com/IE/feedback/details/837245/xmlhttprequest-upload-throws-invalid-argument-when-used-from-web-worker-context - } - } - if (xhr.upload) { - this._setUploadTimeout(); - } - - // initiate request - try { - if (this.username && this.password) { - xhr.open(this.method, this.url, true, this.username, this.password); - } else { - xhr.open(this.method, this.url, true); - } - } catch (err) { - // see #1149 - return this.callback(err); - } - - // CORS - if (this._withCredentials) xhr.withCredentials = true; - - // body - if (!this._formData && this.method !== 'GET' && this.method !== 'HEAD' && typeof data !== 'string' && !this._isHost(data)) { - // serialize stuff - const contentType = this._header['content-type']; - let serialize = this._serializer || request.serialize[contentType ? contentType.split(';')[0] : '']; - if (!serialize && isJSON(contentType)) { - serialize = request.serialize['application/json']; - } - if (serialize) data = serialize(data); - } - - // set header fields - for (const field in this.header) { - if (this.header[field] === null) continue; - if (hasOwn(this.header, field)) xhr.setRequestHeader(field, this.header[field]); - } - if (this._responseType) { - xhr.responseType = this._responseType; - } - - // send stuff - this.emit('request', this); - - // IE11 xhr.send(undefined) sends 'undefined' string as POST payload (instead of nothing) - // We need null here if data is undefined - xhr.send(typeof data === 'undefined' ? null : data); - }; - request.agent = () => new Agent(); - for (var _i = 0, _arr = ['GET', 'POST', 'OPTIONS', 'PATCH', 'PUT', 'DELETE']; _i < _arr.length; _i++) { - const method = _arr[_i]; - Agent.prototype[method.toLowerCase()] = function (url, fn) { - const request_ = new request.Request(method, url); - this._setDefaults(request_); - if (fn) { - request_.end(fn); - } - return request_; - }; - } - Agent.prototype.del = Agent.prototype.delete; - + var INCLUDE_CUSTOM_FIELDS$2 = false; /** - * GET `url` with optional callback `fn(res)`. - * - * @param {String} url - * @param {Mixed|Function} [data] or fn - * @param {Function} [fn] - * @return {Request} - * @api public - */ - - request.get = (url, data, fn) => { - const request_ = request('GET', url); - if (typeof data === 'function') { - fn = data; - data = null; - } - if (data) request_.query(data); - if (fn) request_.end(fn); - return request_; - }; - + * Whether member's status field should be included in response or not. + */ + var INCLUDE_STATUS = false; /** - * HEAD `url` with optional callback `fn(res)`. - * - * @param {String} url - * @param {Mixed|Function} [data] or fn - * @param {Function} [fn] - * @return {Request} - * @api public - */ - - request.head = (url, data, fn) => { - const request_ = request('HEAD', url); - if (typeof data === 'function') { - fn = data; - data = null; - } - if (data) request_.query(data); - if (fn) request_.end(fn); - return request_; - }; - + * Whether total number of members should be included in response or not. + */ + var INCLUDE_TOTAL_COUNT$1 = false; /** - * OPTIONS query to `url` with optional callback `fn(res)`. - * - * @param {String} url - * @param {Mixed|Function} [data] or fn - * @param {Function} [fn] - * @return {Request} - * @api public - */ - - request.options = (url, data, fn) => { - const request_ = request('OPTIONS', url); - if (typeof data === 'function') { - fn = data; - data = null; - } - if (data) request_.send(data); - if (fn) request_.end(fn); - return request_; - }; - + * Whether `UUID` fields should be included in response or not. + */ + var INCLUDE_UUID_FIELDS$1 = false; /** - * DELETE `url` with optional `data` and callback `fn(res)`. - * - * @param {String} url - * @param {Mixed} [data] - * @param {Function} [fn] - * @return {Request} - * @api public - */ - - function del(url, data, fn) { - const request_ = request('DELETE', url); - if (typeof data === 'function') { - fn = data; - data = null; - } - if (data) request_.send(data); - if (fn) request_.end(fn); - return request_; - } - request.del = del; - request.delete = del; - + * Whether `UUID` status field should be included in response or not. + */ + var INCLUDE_UUID_STATUS_FIELD = false; /** - * PATCH `url` with optional `data` and callback `fn(res)`. - * - * @param {String} url - * @param {Mixed} [data] - * @param {Function} [fn] - * @return {Request} - * @api public - */ - - request.patch = (url, data, fn) => { - const request_ = request('PATCH', url); - if (typeof data === 'function') { - fn = data; - data = null; - } - if (data) request_.send(data); - if (fn) request_.end(fn); - return request_; - }; - + * Whether `UUID` type field should be included in response or not. + */ + var INCLUDE_UUID_TYPE_FIELD = false; /** - * POST `url` with optional `data` and callback `fn(res)`. - * - * @param {String} url - * @param {Mixed} [data] - * @param {Function} [fn] - * @return {Request} - * @api public - */ - - request.post = (url, data, fn) => { - const request_ = request('POST', url); - if (typeof data === 'function') { - fn = data; - data = null; - } - if (data) request_.send(data); - if (fn) request_.end(fn); - return request_; - }; - + * Whether `UUID` custom field should be included in response or not. + */ + var INCLUDE_UUID_CUSTOM_FIELDS$1 = false; /** - * PUT `url` with optional `data` and callback `fn(res)`. - * - * @param {String} url - * @param {Mixed|Function} [data] or fn - * @param {Function} [fn] - * @return {Request} - * @api public - */ - - request.put = (url, data, fn) => { - const request_ = request('PUT', url); - if (typeof data === 'function') { - fn = data; - data = null; - } - if (data) request_.send(data); - if (fn) request_.end(fn); - return request_; - }; - - }(client, client.exports)); - - var superagent = client.exports; - - /* */ - function log(req) { - var _pickLogger = function () { - if (console && console.log) - return console; // eslint-disable-line no-console - if (window && window.console && window.console.log) - return window.console; - return console; - }; - var start = new Date().getTime(); - var timestamp = new Date().toISOString(); - var logger = _pickLogger(); - logger.log('<<<<<'); - logger.log("[".concat(timestamp, "]"), '\n', req.url, '\n', req.qs); - logger.log('-----'); - req.on('response', function (res) { - var now = new Date().getTime(); - var elapsed = now - start; - var timestampDone = new Date().toISOString(); - logger.log('>>>>>>'); - logger.log("[".concat(timestampDone, " / ").concat(elapsed, "]"), '\n', req.url, '\n', req.qs, '\n', res.text); - logger.log('-----'); + * Number of objects to return in response. + */ + var LIMIT$1 = 100; + // endregion + /** + * Get Channel Members request. + */ + var GetChannelMembersRequest = /** @class */ (function (_super) { + __extends(GetChannelMembersRequest, _super); + function GetChannelMembersRequest(parameters) { + var _a, _b, _c, _d, _e, _f, _g, _h, _j; + var _k, _l, _m, _o, _p, _q, _r; + var _this = _super.call(this) || this; + _this.parameters = parameters; + // Apply default request parameters. + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_k = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_k.customFields = INCLUDE_CUSTOM_FIELDS$2); + (_c = (_l = parameters.include).totalCount) !== null && _c !== void 0 ? _c : (_l.totalCount = INCLUDE_TOTAL_COUNT$1); + (_d = (_m = parameters.include).statusField) !== null && _d !== void 0 ? _d : (_m.statusField = INCLUDE_STATUS); + (_e = (_o = parameters.include).UUIDFields) !== null && _e !== void 0 ? _e : (_o.UUIDFields = INCLUDE_UUID_FIELDS$1); + (_f = (_p = parameters.include).customUUIDFields) !== null && _f !== void 0 ? _f : (_p.customUUIDFields = INCLUDE_UUID_CUSTOM_FIELDS$1); + (_g = (_q = parameters.include).UUIDStatusField) !== null && _g !== void 0 ? _g : (_q.UUIDStatusField = INCLUDE_UUID_STATUS_FIELD); + (_h = (_r = parameters.include).UUIDTypeField) !== null && _h !== void 0 ? _h : (_r.UUIDTypeField = INCLUDE_UUID_TYPE_FIELD); + (_j = parameters.limit) !== null && _j !== void 0 ? _j : (parameters.limit = LIMIT$1); + return _this; + } + GetChannelMembersRequest.prototype.operation = function () { + return RequestOperation$1.PNSetMembersOperation; + }; + GetChannelMembersRequest.prototype.validate = function () { + if (!this.parameters.channel) + return 'Channel cannot be empty'; + }; + GetChannelMembersRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, serviceResponse]; + }); + }); + }; + Object.defineProperty(GetChannelMembersRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channel = _a.channel; + return "/v2/objects/".concat(subscribeKey, "/channels/").concat(encodeString(channel), "/uuids"); + }, + enumerable: false, + configurable: true }); - } - function xdr(superagentConstruct, endpoint, callback) { - var _this = this; - if (this._config.logVerbosity) { - superagentConstruct = superagentConstruct.use(log); + Object.defineProperty(GetChannelMembersRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, include = _a.include, page = _a.page, filter = _a.filter, sort = _a.sort, limit = _a.limit; + var sorting = Object.entries(sort !== null && sort !== void 0 ? sort : {}).map(function (_a) { + var _b = __read(_a, 2), option = _b[0], order = _b[1]; + return order !== null ? "".concat(option, ":").concat(order) : option; + }); + var includeFlags = []; + if (include.statusField) + includeFlags.push('status'); + if (include.customFields) + includeFlags.push('custom'); + if (include.UUIDFields) + includeFlags.push('uuid'); + if (include.UUIDStatusField) + includeFlags.push('uuid.status'); + if (include.UUIDTypeField) + includeFlags.push('uuid.type'); + if (include.customUUIDFields) + includeFlags.push('uuid.custom'); + return __assign(__assign(__assign(__assign(__assign(__assign({ count: "".concat(include.totalCount) }, (includeFlags.length > 0 ? { include: includeFlags.join(',') } : {})), (filter ? { filter: filter } : {})), ((page === null || page === void 0 ? void 0 : page.next) ? { start: page.next } : {})), ((page === null || page === void 0 ? void 0 : page.prev) ? { end: page.prev } : {})), (limit ? { limit: limit } : {})), (sorting.length ? { sort: sorting } : {})); + }, + enumerable: false, + configurable: true + }); + return GetChannelMembersRequest; + }(AbstractRequest)); + + /** + * Set Channel Members REST API module. + */ + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults + /** + * Whether `Member` custom field should be included in response or not. + */ + var INCLUDE_CUSTOM_FIELDS$1 = false; + /** + * Whether total number of members should be included in response or not. + */ + var INCLUDE_TOTAL_COUNT = false; + /** + * Whether `UUID` fields should be included in response or not. + */ + var INCLUDE_UUID_FIELDS = false; + /** + * Whether `UUID` custom field should be included in response or not. + */ + var INCLUDE_UUID_CUSTOM_FIELDS = false; + /** + * Number of objects to return in response. + */ + var LIMIT = 100; + // endregion + /** + * Set Channel Members request. + */ + var SetChannelMembersRequest = /** @class */ (function (_super) { + __extends(SetChannelMembersRequest, _super); + function SetChannelMembersRequest(parameters) { + var _a, _b, _c, _d, _e, _f; + var _g, _h, _j, _k; + var _this = _super.call(this, { method: TransportMethod.PATCH }) || this; + _this.parameters = parameters; + // Apply default request parameters. + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_g = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_g.customFields = INCLUDE_CUSTOM_FIELDS$1); + (_c = (_h = parameters.include).totalCount) !== null && _c !== void 0 ? _c : (_h.totalCount = INCLUDE_TOTAL_COUNT); + (_d = (_j = parameters.include).UUIDFields) !== null && _d !== void 0 ? _d : (_j.UUIDFields = INCLUDE_UUID_FIELDS); + (_e = (_k = parameters.include).customUUIDFields) !== null && _e !== void 0 ? _e : (_k.customUUIDFields = INCLUDE_UUID_CUSTOM_FIELDS); + (_f = parameters.limit) !== null && _f !== void 0 ? _f : (parameters.limit = LIMIT); + return _this; } - if (this._config.proxy && this._modules.proxy) { - superagentConstruct = this._modules.proxy.call(this, superagentConstruct); + SetChannelMembersRequest.prototype.operation = function () { + return RequestOperation$1.PNSetMembersOperation; + }; + SetChannelMembersRequest.prototype.validate = function () { + var _a = this.parameters, channel = _a.channel, uuids = _a.uuids; + if (!channel) + return 'Channel cannot be empty'; + if (!uuids || uuids.length === 0) + return 'UUIDs cannot be empty'; + }; + SetChannelMembersRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, serviceResponse]; + }); + }); + }; + Object.defineProperty(SetChannelMembersRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channel = _a.channel; + return "/v2/objects/".concat(subscribeKey, "/channels/").concat(encodeString(channel), "/uuids"); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(SetChannelMembersRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, include = _a.include, page = _a.page, filter = _a.filter, sort = _a.sort, limit = _a.limit; + var sorting = Object.entries(sort !== null && sort !== void 0 ? sort : {}).map(function (_a) { + var _b = __read(_a, 2), option = _b[0], order = _b[1]; + return order !== null ? "".concat(option, ":").concat(order) : option; + }); + var includeFlags = ['uuid.status', 'uuid.type', 'type']; + if (include.customFields) + includeFlags.push('custom'); + if (include.UUIDFields) + includeFlags.push('uuid'); + if (include.customUUIDFields) + includeFlags.push('uuid.custom'); + return __assign(__assign(__assign(__assign(__assign(__assign({ count: "".concat(include.totalCount) }, (includeFlags.length > 0 ? { include: includeFlags.join(',') } : {})), (filter ? { filter: filter } : {})), ((page === null || page === void 0 ? void 0 : page.next) ? { start: page.next } : {})), ((page === null || page === void 0 ? void 0 : page.prev) ? { end: page.prev } : {})), (limit ? { limit: limit } : {})), (sorting.length ? { sort: sorting } : {})); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(SetChannelMembersRequest.prototype, "body", { + get: function () { + var _a; + var _b = this.parameters, uuids = _b.uuids, type = _b.type; + return JSON.stringify((_a = {}, + _a["".concat(type)] = uuids.map(function (uuid) { + if (typeof uuid === 'string') { + return { uuid: { id: uuid } }; + } + else { + return { uuid: { id: uuid.id }, status: uuid.status, custom: uuid.custom }; + } + }), + _a)); + }, + enumerable: false, + configurable: true + }); + return SetChannelMembersRequest; + }(AbstractRequest)); + + /** + * Get UUID Metadata REST API module. + */ + // -------------------------------------------------------- + // ----------------------- Defaults ----------------------- + // -------------------------------------------------------- + // region Defaults + /** + * Whether UUID custom field should be included by default or not. + */ + var INCLUDE_CUSTOM_FIELDS = true; + // endregion + /** + * Get UUID Metadata request. + */ + var GetUUIDMetadataRequest = /** @class */ (function (_super) { + __extends(GetUUIDMetadataRequest, _super); + function GetUUIDMetadataRequest(parameters) { + var _a, _b; + var _c; + var _this = _super.call(this) || this; + _this.parameters = parameters; + // Apply default request parameters. + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_c = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_c.customFields = INCLUDE_CUSTOM_FIELDS); + // Remap for backward compatibility. + if (_this.parameters.userId) + _this.parameters.uuid = _this.parameters.userId; + return _this; } - if (this._config.keepAlive && this._modules.keepAlive) { - superagentConstruct = this._modules.keepAlive(superagentConstruct); + GetUUIDMetadataRequest.prototype.operation = function () { + return RequestOperation$1.PNGetUUIDMetadataOperation; + }; + GetUUIDMetadataRequest.prototype.validate = function () { + if (!this.parameters.uuid) + return "'uuid' cannot be empty"; + }; + GetUUIDMetadataRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, serviceResponse]; + }); + }); + }; + Object.defineProperty(GetUUIDMetadataRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, uuid = _a.uuid; + return "/v2/objects/".concat(subscribeKey, "/uuids/").concat(encodeString(uuid)); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(GetUUIDMetadataRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, uuid = _a.uuid; _a.include; + return { + uuid: uuid, + include: __spreadArray(['status', 'type'], __read((this.parameters.include.customFields ? ['custom'] : [])), false).join(','), + }; + }, + enumerable: false, + configurable: true + }); + return GetUUIDMetadataRequest; + }(AbstractRequest)); + + /** + * PubNub Objects API module. + */ + var PubNubObjects = /** @class */ (function () { + function PubNubObjects(configuration, + /* eslint-disable @typescript-eslint/no-explicit-any */ + sendRequest) { + this.configuration = configuration; + this.sendRequest = sendRequest; + this.keySet = configuration.keySet; } - var sc = superagentConstruct; - if (endpoint.abortSignal) { - var unsubscribe_1 = endpoint.abortSignal.subscribe(function () { - sc.abort(); - unsubscribe_1(); + /** + * Fetch a paginated list of UUID Metadata objects. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get all UUID metadata response or `void` in case if `callback` provided. + */ + PubNubObjects.prototype.getAllUUIDMetadata = function (parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this._getAllUUIDMetadata(parametersOrCallback, callback)]; + }); + }); + }; + /** + * Fetch a paginated list of UUID Metadata objects. + * + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get all UUID metadata response or `void` in case if `callback` provided. + */ + PubNubObjects.prototype._getAllUUIDMetadata = function (parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function () { + var parameters, request; + return __generator(this, function (_a) { + parameters = parametersOrCallback && typeof parametersOrCallback !== 'function' ? parametersOrCallback : {}; + callback !== null && callback !== void 0 ? callback : (callback = typeof parametersOrCallback === 'function' ? parametersOrCallback : undefined); + request = new GetAllUUIDMetadataRequest(__assign(__assign({}, parameters), { keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Fetch a specific UUID Metadata object. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get UUID metadata response or `void` in case if `callback` provided. + */ + PubNubObjects.prototype.getUUIDMetadata = function (parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this._getUUIDMetadata(parametersOrCallback, callback)]; + }); + }); + }; + /** + * Fetch a specific UUID Metadata object. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get UUID metadata response or `void` in case if `callback` provided. + */ + PubNubObjects.prototype._getUUIDMetadata = function (parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function () { + var parameters, request; + var _a; + return __generator(this, function (_b) { + parameters = parametersOrCallback && typeof parametersOrCallback !== 'function' ? parametersOrCallback : {}; + callback !== null && callback !== void 0 ? callback : (callback = typeof parametersOrCallback === 'function' ? parametersOrCallback : undefined); + if (parameters.userId) + parameters.uuid = parameters.userId; + (_a = parameters.uuid) !== null && _a !== void 0 ? _a : (parameters.uuid = this.configuration.userId); + request = new GetUUIDMetadataRequest(__assign(__assign({}, parameters), { keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Update specific UUID Metadata object. + * + * @param parameters - Request configuration parameters. Will set UUID metadata for currently + * configured PubNub client `uuid` if not set. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous set UUID metadata response or `void` in case if `callback` provided. + */ + PubNubObjects.prototype.setUUIDMetadata = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this._setUUIDMetadata(parameters, callback)]; + }); + }); + }; + /** + * Update specific UUID Metadata object. + * + * @param parameters - Request configuration parameters. Will set UUID metadata for currently + * configured PubNub client `uuid` if not set. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous set UUID metadata response or `void` in case if `callback` provided. + */ + PubNubObjects.prototype._setUUIDMetadata = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + var _a; + return __generator(this, function (_b) { + if (parameters.userId) + parameters.uuid = parameters.userId; + (_a = parameters.uuid) !== null && _a !== void 0 ? _a : (parameters.uuid = this.configuration.userId); + request = new GetUUIDMetadataRequest(__assign(__assign({}, parameters), { keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Remove a specific UUID Metadata object. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous UUID metadata remove response or `void` in case if `callback` provided. + */ + PubNubObjects.prototype.removeUUIDMetadata = function (parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this._removeUUIDMetadata(parametersOrCallback, callback)]; + }); + }); + }; + /** + * Remove a specific UUID Metadata object. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous UUID metadata remove response or `void` in case if `callback` provided. + */ + PubNubObjects.prototype._removeUUIDMetadata = function (parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function () { + var parameters, request; + var _a; + return __generator(this, function (_b) { + parameters = parametersOrCallback && typeof parametersOrCallback !== 'function' ? parametersOrCallback : {}; + callback !== null && callback !== void 0 ? callback : (callback = typeof parametersOrCallback === 'function' ? parametersOrCallback : undefined); + if (parameters.userId) + parameters.uuid = parameters.userId; + (_a = parameters.uuid) !== null && _a !== void 0 ? _a : (parameters.uuid = this.configuration.userId); + request = new RemoveUUIDMetadataRequest(__assign(__assign({}, parameters), { keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Fetch a paginated list of Channel Metadata objects. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get all Channel metadata response or `void` in case if `callback` + * provided. + */ + PubNubObjects.prototype.getAllChannelMetadata = function (parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this._getAllChannelMetadata(parametersOrCallback, callback)]; + }); + }); + }; + /** + * Fetch a paginated list of Channel Metadata objects. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get all Channel metadata response or `void` in case if `callback` + * provided. + */ + PubNubObjects.prototype._getAllChannelMetadata = function (parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function () { + var parameters, request; + return __generator(this, function (_a) { + parameters = parametersOrCallback && typeof parametersOrCallback !== 'function' ? parametersOrCallback : {}; + callback !== null && callback !== void 0 ? callback : (callback = typeof parametersOrCallback === 'function' ? parametersOrCallback : undefined); + request = new GetAllChannelsMetadataRequest(__assign(__assign({}, parameters), { keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Fetch Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get Channel metadata response or `void` in case if `callback` provided. + */ + PubNubObjects.prototype.getChannelMetadata = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this._getChannelMetadata(parameters, callback)]; + }); + }); + }; + /** + * Fetch Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get Channel metadata response or `void` in case if `callback` provided. + */ + PubNubObjects.prototype._getChannelMetadata = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new GetChannelMetadataRequest(__assign(__assign({}, parameters), { keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Update specific Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous set Channel metadata response or `void` in case if `callback` provided. + */ + PubNubObjects.prototype.setChannelMetadata = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this._setChannelMetadata(parameters, callback)]; + }); + }); + }; + /** + * Update specific Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous set Channel metadata response or `void` in case if `callback` provided. + */ + PubNubObjects.prototype._setChannelMetadata = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new SetChannelMetadataRequest(__assign(__assign({}, parameters), { keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Remove a specific Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous Channel metadata remove response or `void` in case if `callback` + * provided. + */ + PubNubObjects.prototype.removeChannelMetadata = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this._removeChannelMetadata(parameters, callback)]; + }); + }); + }; + /** + * Remove a specific Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous Channel metadata remove response or `void` in case if `callback` + * provided. + */ + PubNubObjects.prototype._removeChannelMetadata = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new RemoveChannelMetadataRequest(__assign(__assign({}, parameters), { keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Fetch a paginated list of Channel Member objects. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get Channel Members response or `void` in case if `callback` provided. + */ + PubNubObjects.prototype.getChannelMembers = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new GetChannelMembersRequest(__assign(__assign({}, parameters), { keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Update specific Channel Members list. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous update Channel members list response or `void` in case if `callback` + * provided. + */ + PubNubObjects.prototype.setChannelMembers = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new SetChannelMembersRequest(__assign(__assign({}, parameters), { type: 'set', keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Remove Members from the Channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous Channel Members remove response or `void` in case if `callback` provided. + */ + PubNubObjects.prototype.removeChannelMembers = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new SetChannelMembersRequest(__assign(__assign({}, parameters), { type: 'delete', keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Fetch a specific UUID Memberships list. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get UUID Memberships response or `void` in case if `callback` provided. + */ + PubNubObjects.prototype.getMemberships = function (parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function () { + var parameters, request; + var _a; + return __generator(this, function (_b) { + parameters = parametersOrCallback && typeof parametersOrCallback !== 'function' ? parametersOrCallback : {}; + callback !== null && callback !== void 0 ? callback : (callback = typeof parametersOrCallback === 'function' ? parametersOrCallback : undefined); + if (parameters.userId) + parameters.uuid = parameters.userId; + (_a = parameters.uuid) !== null && _a !== void 0 ? _a : (parameters.uuid = this.configuration.userId); + request = new GetUUIDMembershipsRequest(__assign(__assign({}, parameters), { keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Update specific UUID Memberships list. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous update UUID Memberships list response or `void` in case if `callback` + * provided. + */ + PubNubObjects.prototype.setMemberships = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + var _a; + return __generator(this, function (_b) { + if (parameters.userId) + parameters.uuid = parameters.userId; + (_a = parameters.uuid) !== null && _a !== void 0 ? _a : (parameters.uuid = this.configuration.userId); + request = new SetUUIDMembershipsRequest(__assign(__assign({}, parameters), { type: 'set', keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Remove a specific UUID Memberships. + * + * @param parameters - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous UUID Memberships remove response or `void` in case if `callback` + * provided. + */ + PubNubObjects.prototype.removeMemberships = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + var _a; + return __generator(this, function (_b) { + if (parameters.userId) + parameters.uuid = parameters.userId; + (_a = parameters.uuid) !== null && _a !== void 0 ? _a : (parameters.uuid = this.configuration.userId); + request = new SetUUIDMembershipsRequest(__assign(__assign({}, parameters), { type: 'delete', keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + // endregion + // endregion + // -------------------------------------------------------- + // --------------------- Deprecated API ------------------- + // -------------------------------------------------------- + // region Deprecated + /** + * Fetch paginated list of specific Space members or specific User memberships. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get specific Space members or specific User memberships response. + * + * @deprecated Use {@link PubNubObjects#getChannelMembers} or {@link PubNubObjects#getMemberships} methods instead. + */ + PubNubObjects.prototype.fetchMemberships = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var spaceParameters, mappedParameters_1, mapMembers_1, userParameters, mappedParameters, mapMemberships; + var _a, _b; + return __generator(this, function (_c) { + if ('spaceId' in parameters) { + spaceParameters = parameters; + mappedParameters_1 = { + channel: (_a = spaceParameters.spaceId) !== null && _a !== void 0 ? _a : spaceParameters.channel, + filter: spaceParameters.filter, + limit: spaceParameters.limit, + page: spaceParameters.page, + include: __assign({}, spaceParameters.include), + sort: spaceParameters.sort + ? Object.fromEntries(Object.entries(spaceParameters.sort).map(function (_a) { + var _b = __read(_a, 2), key = _b[0], value = _b[1]; + return [key.replace('user', 'uuid'), value]; + })) + : undefined, + }; + mapMembers_1 = function (response) { + return ({ + status: response.status, + data: response.data.map(function (members) { return ({ + user: members.uuid, + custom: members.custom, + updated: members.updated, + eTag: members.eTag, + }); }), + totalCount: response.totalCount, + next: response.next, + prev: response.prev, + }); + }; + if (callback) + return [2 /*return*/, this.getChannelMembers(mappedParameters_1, function (status, result) { + callback(status, result ? mapMembers_1(result) : result); + })]; + return [2 /*return*/, this.getChannelMembers(mappedParameters_1).then(mapMembers_1)]; + } + userParameters = parameters; + mappedParameters = { + uuid: (_b = userParameters.userId) !== null && _b !== void 0 ? _b : userParameters.uuid, + filter: userParameters.filter, + limit: userParameters.limit, + page: userParameters.page, + include: __assign({}, userParameters.include), + sort: userParameters.sort + ? Object.fromEntries(Object.entries(userParameters.sort).map(function (_a) { + var _b = __read(_a, 2), key = _b[0], value = _b[1]; + return [key.replace('space', 'channel'), value]; + })) + : undefined, + }; + mapMemberships = function (response) { + return ({ + status: response.status, + data: response.data.map(function (membership) { return ({ + space: membership.channel, + custom: membership.custom, + updated: membership.updated, + eTag: membership.eTag, + }); }), + totalCount: response.totalCount, + next: response.next, + prev: response.prev, + }); + }; + if (callback) + return [2 /*return*/, this.getMemberships(mappedParameters, function (status, result) { + callback(status, result ? mapMemberships(result) : result); + })]; + return [2 /*return*/, this.getMemberships(mappedParameters).then(mapMemberships)]; + }); + }); + }; + /** + * Add members to specific Space or memberships specific User. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous add members to specific Space or memberships specific User response or + * `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubObjects#setChannelMembers} or {@link PubNubObjects#setMemberships} methods instead. + */ + PubNubObjects.prototype.addMemberships = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var spaceParameters, mappedParameters_2, userParameters, mappedParameters; + var _a, _b, _c, _d, _e, _f; + return __generator(this, function (_g) { + if ('spaceId' in parameters) { + spaceParameters = parameters; + mappedParameters_2 = { + channel: (_a = spaceParameters.spaceId) !== null && _a !== void 0 ? _a : spaceParameters.channel, + uuids: (_c = (_b = spaceParameters.users) === null || _b === void 0 ? void 0 : _b.map(function (user) { + if (typeof user === 'string') + return user; + user.userId; + return { id: user.userId, custom: user.custom }; + })) !== null && _c !== void 0 ? _c : spaceParameters.uuids, + limit: 0, + }; + if (callback) + return [2 /*return*/, this.setChannelMembers(mappedParameters_2, callback)]; + return [2 /*return*/, this.setChannelMembers(mappedParameters_2)]; + } + userParameters = parameters; + mappedParameters = { + uuid: (_d = userParameters.userId) !== null && _d !== void 0 ? _d : userParameters.uuid, + channels: (_f = (_e = userParameters.spaces) === null || _e === void 0 ? void 0 : _e.map(function (space) { + if (typeof space === 'string') + return space; + return { + id: space.spaceId, + custom: space.custom, + }; + })) !== null && _f !== void 0 ? _f : userParameters.channels, + limit: 0, + }; + if (callback) + return [2 /*return*/, this.setMemberships(mappedParameters, callback)]; + return [2 /*return*/, this.setMemberships(mappedParameters)]; + }); + }); + }; + return PubNubObjects; + }()); + + /** + * Time REST API module. + */ + // endregion + var TimeRequest = /** @class */ (function (_super) { + __extends(TimeRequest, _super); + function TimeRequest() { + return _super.call(this) || this; + } + TimeRequest.prototype.operation = function () { + return RequestOperation$1.PNTimeOperation; + }; + TimeRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError('Service response error, check status for details', createValidationError('Unable to deserialize service response')); + return [2 /*return*/, { timetoken: serviceResponse[0] }]; + }); + }); + }; + Object.defineProperty(TimeRequest.prototype, "path", { + get: function () { + return '/time/0'; + }, + enumerable: false, + configurable: true + }); + return TimeRequest; + }(AbstractRequest)); + + /** + * Download File REST API module. + */ + // endregion + /** + * Download File request. + */ + var DownloadFileRequest = /** @class */ (function (_super) { + __extends(DownloadFileRequest, _super); + function DownloadFileRequest(parameters) { + var _this = _super.call(this) || this; + _this.parameters = parameters; + return _this; + } + DownloadFileRequest.prototype.operation = function () { + return RequestOperation$1.PNDownloadFileOperation; + }; + DownloadFileRequest.prototype.validate = function () { + var _a = this.parameters, channel = _a.channel, id = _a.id, name = _a.name; + if (!channel) + return "channel can't be empty"; + if (!id) + return "file id can't be empty"; + if (!name) + return "file name can't be empty"; + }; + DownloadFileRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var _a, cipherKey, crypto, cryptography, name, PubNubFile, mimeType, decryptedFile, body; + return __generator(this, function (_b) { + switch (_b.label) { + case 0: + _a = this.parameters, cipherKey = _a.cipherKey, crypto = _a.crypto, cryptography = _a.cryptography, name = _a.name, PubNubFile = _a.PubNubFile; + mimeType = response.headers['content-type']; + body = response.body; + if (!(PubNubFile.supportsEncryptFile && (cipherKey || crypto))) return [3 /*break*/, 4]; + if (!(cipherKey && cryptography)) return [3 /*break*/, 2]; + return [4 /*yield*/, cryptography.decrypt(cipherKey, body)]; + case 1: + body = _b.sent(); + return [3 /*break*/, 4]; + case 2: + if (!(!cipherKey && crypto)) return [3 /*break*/, 4]; + return [4 /*yield*/, crypto.decryptFile(PubNubFile.create({ data: body, name: name, mimeType: mimeType }), PubNubFile)]; + case 3: + decryptedFile = _b.sent(); + _b.label = 4; + case 4: return [2 /*return*/, (decryptedFile + ? decryptedFile + : PubNubFile.create({ + data: body, + name: name, + mimeType: mimeType, + }))]; + } + }); + }); + }; + Object.defineProperty(DownloadFileRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channel = _a.channel, id = _a.id, name = _a.name; + return "/v1/files/".concat(subscribeKey, "/channels/").concat(encodeString(channel), "/files/").concat(id, "/").concat(name); + }, + enumerable: false, + configurable: true + }); + return DownloadFileRequest; + }(AbstractRequest)); + + // endregion + /** + * Platform-agnostic PubNub client core. + */ + var PubNubCore = /** @class */ (function () { + // endregion + function PubNubCore(configuration) { + var _this = this; + var _a, _b, _c; + this._configuration = configuration.configuration; + this.cryptography = configuration.cryptography; + this.tokenManager = configuration.tokenManager; + this.transport = configuration.transport; + this.crypto = configuration.crypto; + // API group entry points initialization. + this._objects = new PubNubObjects(this._configuration, this.sendRequest); + this._channelGroups = new PubnubChannelGroups(this._configuration.keySet, this.sendRequest); + this._push = new PubNubPushNotifications(this._configuration.keySet, this.sendRequest); + // Prepare for real-time events announcement. + this.listenerManager = new ListenerManager(); + this.eventEmitter = new EventEmitter(this.listenerManager); + if (this._configuration.enableEventEngine) { + var heartbeatInterval_1 = this._configuration.getHeartbeatInterval(); + this.presenceState = {}; + if (heartbeatInterval_1) { + this.presenceEventEngine = new PresenceEventEngine({ + heartbeat: this.heartbeat, + leave: this.unsubscribe, + heartbeatDelay: function () { + return new Promise(function (resolve, reject) { + heartbeatInterval_1 = _this._configuration.getHeartbeatInterval(); + if (!heartbeatInterval_1) + reject(new PubNubError('Heartbeat interval has been reset.')); + else + setTimeout(resolve, heartbeatInterval_1 * 1000); + }); + }, + retryDelay: function (amount) { return new Promise(function (resolve) { return setTimeout(resolve, amount); }); }, + emitStatus: function (status) { return _this.listenerManager.announceStatus(status); }, + config: this._configuration, + presenceState: this.presenceState, + }); + } + this.eventEngine = new EventEngine({ + handshake: this.subscribeHandshake, + receiveMessages: this.subscribeReceiveMessages, + delay: function (amount) { return new Promise(function (resolve) { return setTimeout(resolve, amount); }); }, + join: (_a = this.presenceEventEngine) === null || _a === void 0 ? void 0 : _a.join, + leave: (_b = this.presenceEventEngine) === null || _b === void 0 ? void 0 : _b.leave, + leaveAll: (_c = this.presenceEventEngine) === null || _c === void 0 ? void 0 : _c.leaveAll, + presenceState: this.presenceState, + config: this._configuration, + emitMessages: function (events) { return events.forEach(function (event) { return _this.eventEmitter.emitEvent(event); }); }, + emitStatus: function (status) { return _this.listenerManager.announceStatus(status); }, + }); + } + else { + this.subscriptionManager = new SubscriptionManager(this._configuration, this.listenerManager, this.eventEmitter, this.makeSubscribe, this.heartbeat, this.makeUnsubscribe, this.time); + } + } + /** + * Construct notification payload which will trigger push notification. + * + * @param title - Title which will be shown on notification. + * @param body - Payload which will be sent as part of notification. + * + * @returns Pre-formatted message payload which will trigger push notification. + */ + PubNubCore.notificationPayload = function (title, body) { + return new NotificationsPayload(title, body); + }; + /** + * Generate unique identifier. + * + * @returns Unique identifier. + */ + PubNubCore.generateUUID = function () { + return uuidGenerator.createUUID(); + }; + Object.defineProperty(PubNubCore.prototype, "configuration", { + // -------------------------------------------------------- + // -------------------- Configuration ---------------------- + // -------------------------------------------------------- + // region Configuration + /** + * PubNub client configuration. + * + * @returns Currently user PubNub client configuration. + */ + get: function () { + return this._configuration; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(PubNubCore.prototype, "_config", { + /** + * Current PubNub client configuration. + * + * @returns Currently user PubNub client configuration. + * + * @deprecated Use {@link configuration} getter instead. + */ + get: function () { + return this.configuration; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(PubNubCore.prototype, "authKey", { + /** + * REST API endpoint access authorization key. + * + * It is required to have `authorization key` with required permissions to access REST API + * endpoints when `PAM` enabled for user key set. + */ + get: function () { + var _a; + return (_a = this._configuration.authKey) !== null && _a !== void 0 ? _a : undefined; + }, + enumerable: false, + configurable: true + }); + /** + * REST API endpoint access authorization key. + * + * It is required to have `authorization key` with required permissions to access REST API + * endpoints when `PAM` enabled for user key set. + */ + PubNubCore.prototype.getAuthKey = function () { + return this.authKey; + }; + /** + * Change REST API endpoint access authorization key. + * + * @param authKey - New authorization key which should be used with new requests. + */ + PubNubCore.prototype.setAuthKey = function (authKey) { + this._configuration.setAuthKey(authKey); + }; + Object.defineProperty(PubNubCore.prototype, "userId", { + /** + * Get a PubNub client user identifier. + * + * @returns Current PubNub client user identifier. + */ + get: function () { + return this._configuration.userId; + }, + /** + * Change the current PubNub client user identifier. + * + * **Important:** Change won't affect ongoing REST API calls. + * + * @param value - New PubNub client user identifier. + * + * @throws Error empty user identifier has been provided. + */ + set: function (value) { + this._configuration.userId = value; + }, + enumerable: false, + configurable: true + }); + /** + * Get a PubNub client user identifier. + * + * @returns Current PubNub client user identifier. + */ + PubNubCore.prototype.getUserId = function () { + return this._configuration.userId; + }; + /** + * Change the current PubNub client user identifier. + * + * **Important:** Change won't affect ongoing REST API calls. + * + * @param value - New PubNub client user identifier. + * + * @throws Error empty user identifier has been provided. + */ + PubNubCore.prototype.setUserId = function (value) { + this._configuration.userId = value; + }; + Object.defineProperty(PubNubCore.prototype, "filterExpression", { + /** + * Real-time updates filtering expression. + * + * @returns Filtering expression. + */ + get: function () { + var _a; + return (_a = this._configuration.getFilterExpression()) !== null && _a !== void 0 ? _a : undefined; + }, + /** + * Update real-time updates filtering expression. + * + * @param expression - New expression which should be used or `undefined` to disable filtering. + */ + set: function (expression) { + this._configuration.setFilterExpression(expression); + }, + enumerable: false, + configurable: true + }); + /** + * Real-time updates filtering expression. + * + * @returns Filtering expression. + */ + PubNubCore.prototype.getFilterExpression = function () { + return this.filterExpression; + }; + /** + * Update real-time updates filtering expression. + * + * @param expression - New expression which should be used or `undefined` to disable filtering. + */ + PubNubCore.prototype.setFilterExpression = function (expression) { + this.filterExpression = expression; + }; + Object.defineProperty(PubNubCore.prototype, "cipherKey", { + /** + * Dta encryption / decryption key. + * + * @returns Currently used key for data encryption / decryption. + */ + get: function () { + return this._configuration.cipherKey; + }, + /** + * Change data encryption / decryption key. + * + * @param key - New key which should be used for data encryption / decryption. + */ + set: function (key) { + this._configuration.setCipherKey(key); + }, + enumerable: false, + configurable: true + }); + /** + * Change data encryption / decryption key. + * + * @param key - New key which should be used for data encryption / decryption. + */ + PubNubCore.prototype.setCipherKey = function (key) { + this.cipherKey = key; + }; + Object.defineProperty(PubNubCore.prototype, "heartbeatInterval", { + /** + * Change heartbeat requests interval. + * + * @param interval - New presence request heartbeat intervals. + */ + set: function (interval) { + this._configuration.setHeartbeatInterval(interval); + }, + enumerable: false, + configurable: true + }); + /** + * Change heartbeat requests interval. + * + * @param interval - New presence request heartbeat intervals. + */ + PubNubCore.prototype.setHeartbeatInterval = function (interval) { + this.heartbeatInterval = interval; + }; + /** + * Get PubNub SDK version. + * + * @returns Current SDK version. + */ + PubNubCore.prototype.getVersion = function () { + return this._configuration.version; + }; + /** + * Add framework's prefix. + * + * @param name - Name of the framework which would want to add own data into `pnsdk` suffix. + * @param suffix - Suffix with information about framework. + */ + PubNubCore.prototype._addPnsdkSuffix = function (name, suffix) { + this._configuration._addPnsdkSuffix(name, suffix); + }; + // -------------------------------------------------------- + // ---------------------- Deprecated ---------------------- + // -------------------------------------------------------- + // region Deprecated + /** + * Get a PubNub client user identifier. + * + * @returns Current PubNub client user identifier. + * + * @deprecated Use the {@link getUserId} or {@link userId} getter instead. + */ + PubNubCore.prototype.getUUID = function () { + return this.userId; + }; + /** + * Change the current PubNub client user identifier. + * + * **Important:** Change won't affect ongoing REST API calls. + * + * @param value - New PubNub client user identifier. + * + * @throws Error empty user identifier has been provided. + * + * @deprecated Use the {@link PubNubCore#setUserId} or {@link PubNubCore#userId} setter instead. + */ + PubNubCore.prototype.setUUID = function (value) { + this.userId = value; + }; + Object.defineProperty(PubNubCore.prototype, "customEncrypt", { + /** + * Custom data encryption method. + * + * @deprecated Instead use {@link cryptoModule} for data encryption. + */ + get: function () { + return this._configuration.customEncrypt; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(PubNubCore.prototype, "customDecrypt", { + /** + * Custom data decryption method. + * + * @deprecated Instead use {@link cryptoModule} for data decryption. + */ + get: function () { + return this._configuration.customDecrypt; + }, + enumerable: false, + configurable: true + }); + // endregion + // endregion + // -------------------------------------------------------- + // ---------------------- Entities ------------------------ + // -------------------------------------------------------- + // region Entities + /** + * Create a `Channel` entity. + * + * Entity can be used for the interaction with the following API: + * - `subscribe` + * + * @param name - Unique channel name. + * @returns `Channel` entity. + */ + PubNubCore.prototype.channel = function (name) { + return new Channel(name, this.eventEmitter, this); + }; + /** + * Create a `ChannelGroup` entity. + * + * Entity can be used for the interaction with the following API: + * - `subscribe` + * + * @param name - Unique channel group name. + * @returns `ChannelGroup` entity. + */ + PubNubCore.prototype.channelGroup = function (name) { + return new ChannelGroup(name, this.eventEmitter, this); + }; + /** + * Create a `ChannelMetadata` entity. + * + * Entity can be used for the interaction with the following API: + * - `subscribe` + * + * @param id - Unique channel metadata object identifier. + * @returns `ChannelMetadata` entity. + */ + PubNubCore.prototype.channelMetadata = function (id) { + return new ChannelMetadata(id, this.eventEmitter, this); + }; + /** + * Create a `UserMetadata` entity. + * + * Entity can be used for the interaction with the following API: + * - `subscribe` + * + * @param id - Unique user metadata object identifier. + * @returns `UserMetadata` entity. + */ + PubNubCore.prototype.userMetadata = function (id) { + return new UserMetadata(id, this.eventEmitter, this); + }; + /** + * Create subscriptions set object. + * + * @param parameters - Subscriptions set configuration parameters. + */ + PubNubCore.prototype.subscriptionSet = function (parameters) { + return new SubscriptionSet(__assign(__assign({}, parameters), { eventEmitter: this.eventEmitter, pubnub: this })); + }; + /** + * Schedule request execution. + * + * @param request - REST API request. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous request execution and response parsing result or `void` in case if + * `callback` provided. + * + * @throws PubNubError in case of request processing error. + */ + PubNubCore.prototype.sendRequest = function (request, callback) { + return __awaiter(this, void 0, void 0, function () { + var validationResult, transportRequest, status, _a, sendableRequest, cancellationController; + return __generator(this, function (_b) { + validationResult = request.validate(); + if (validationResult) { + if (callback) + return [2 /*return*/, callback(createValidationError(validationResult), null)]; + throw new PubNubError('Validation failed, check status for details', createValidationError(validationResult)); + } + transportRequest = request.request(); + if (transportRequest.body && + typeof transportRequest.body === 'object' && + 'toArrayBuffer' in transportRequest.body) { + // Set 300 seconds file upload request delay. + transportRequest.timeout = 300; + } + else { + if (request.operation() === RequestOperation$1.PNSubscribeOperation) + transportRequest.timeout = this._configuration.getSubscribeTimeout(); + else + transportRequest.timeout = this._configuration.getTransactionTimeout(); + } + status = { + error: false, + operation: request.operation(), + statusCode: 0, + }; + _a = __read(this.transport.makeSendable(transportRequest), 2), sendableRequest = _a[0], cancellationController = _a[1]; + /** + * **Important:** Because of multiple environments where JS SDK can be used control over + * cancellation had to be inverted to let transport provider solve request cancellation task + * more efficiently. As result, cancellation controller can be retrieved and used only after + * request will be scheduled by transport provider. + */ + request.cancellationController = cancellationController ? cancellationController : null; + return [2 /*return*/, sendableRequest + .then(function (response) { + status.statusCode = response.status; + return request.parse(response); + }) + .then(function (parsed) { + // Notify callback (if possible). + if (callback) + return callback(status, parsed); + return parsed; + }) + .catch(function (error) { + console.log("~~~~~~~> WHAT HERE?:", error); + if (error instanceof PubNubError) { + console.log("~~~~~~> OH, WE ARE REGULAR PUBNUB ERROR"); + // @ts-expect-error I allow this for debug + console.log("~~~~~~~~> WHAT IN STATUS?: ", error['status']); + } + // const errorStatus = error.toStatus(request.operation()); + var errorStatus = { error: true }; + // Notify callback (if possible). + if (callback) + callback(errorStatus, null); + throw new PubNubError('REST API request processing error, check status for details', errorStatus); + })]; + }); + }); + }; + /** + * Unsubscribe from all channels and groups. + * + * @param isOffline - Whether `offline` presence should be notified or not. + */ + PubNubCore.prototype.destroy = function (isOffline) { + if (this.subscriptionManager) { + this.subscriptionManager.unsubscribeAll(isOffline); + this.subscriptionManager.disconnect(); + } + else if (this.eventEngine) + this.eventEngine.dispose(); + }; + // endregion + // -------------------------------------------------------- + // ----------------------- Listener ----------------------- + // -------------------------------------------------------- + // region Listener + /** + * Register real-time events listener. + * + * @param listener - Listener with event callbacks to handle different types of events. + */ + PubNubCore.prototype.addListener = function (listener) { + this.listenerManager.addListener(listener); + }; + /** + * Remove real-time event listener. + * + * @param listener - Event listeners which should be removed. + */ + PubNubCore.prototype.removeListener = function (listener) { + this.listenerManager.removeListener(listener); + }; + /** + * Clear all real-time event listeners. + */ + PubNubCore.prototype.removeAllListeners = function () { + this.listenerManager.removeAllListeners(); + }; + /** + * Publish data to a specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous publish data response or `void` in case if `callback` provided. + */ + PubNubCore.prototype.publish = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new PublishRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet, crypto: this._configuration.cryptoModule })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Signal data to a specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous signal data response or `void` in case if `callback` provided. + */ + PubNubCore.prototype.signal = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new SignalRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * `Fire` a data to a specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous signal data response or `void` in case if `callback` provided. + * + * @deprecated Use {@link publish} method instead. + */ + PubNubCore.prototype.fire = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + callback !== null && callback !== void 0 ? callback : (callback = function () { }); + return [2 /*return*/, this.publish(__assign(__assign({}, parameters), { replicate: false, storeInHistory: false }), callback)]; + }); + }); + }; + // endregion + // -------------------------------------------------------- + // -------------------- Subscribe API --------------------- + // -------------------------------------------------------- + // region Subscribe API + /** + * Get list of channels on which PubNub client currently subscribed. + * + * @returns List of active channels. + */ + PubNubCore.prototype.getSubscribedChannels = function () { + if (this.subscriptionManager) + return this.subscriptionManager.subscribedChannels; + else if (this.eventEngine) + return this.eventEngine.getSubscribedChannels(); + return []; + }; + /** + * Get list of channel groups on which PubNub client currently subscribed. + * + * @returns List of active channel groups. + */ + PubNubCore.prototype.getSubscribedChannelGroups = function () { + if (this.subscriptionManager) + return this.subscriptionManager.subscribedChannelGroups; + else if (this.eventEngine) + return this.eventEngine.getSubscribedChannelGroups(); + return []; + }; + /** + * Subscribe to specified channels and groups real-time events. + * + * @param parameters - Request configuration parameters. + */ + PubNubCore.prototype.subscribe = function (parameters) { + if (this.subscriptionManager) + this.subscriptionManager.subscribe(parameters); + else if (this.eventEngine) + this.eventEngine.subscribe(parameters); + }; + /** + * Perform subscribe request. + * + * **Note:** Method passed into managers to let them use it when required. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + PubNubCore.prototype.makeSubscribe = function (parameters, callback) { + var _this = this; + var request = new SubscribeRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet, getFileUrl: this.getFileUrl })); + this.sendRequest(request, function (status, result) { + if (_this.subscriptionManager && _this.subscriptionManager.abort === request.abort) + _this.subscriptionManager.abort = null; + callback(status, result); + }); + /** + * Allow subscription cancellation. + * + * **Note:** Had to be done after scheduling because transport provider return cancellation + * controller only when schedule new request. + */ + if (this.subscriptionManager) + this.subscriptionManager.abort = request.abort; + }; + /** + * Unsubscribe from specified channels and groups real-time events. + * + * @param parameters - Request configuration parameters. + */ + PubNubCore.prototype.unsubscribe = function (parameters) { + if (this.subscriptionManager) + this.subscriptionManager.unsubscribe(parameters); + else if (this.eventEngine) + this.eventEngine.unsubscribe(parameters); + }; + /** + * Perform unsubscribe request. + * + * **Note:** Method passed into managers to let them use it when required. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + PubNubCore.prototype.makeUnsubscribe = function (parameters, callback) { + this.sendRequest(new PresenceLeaveRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet })), callback); + }; + /** + * Unsubscribe from all channels and groups. + */ + PubNubCore.prototype.unsubscribeAll = function () { + if (this.subscriptionManager) + this.subscriptionManager.unsubscribeAll(); + else if (this.eventEngine) + this.eventEngine.unsubscribeAll(); + }; + /** + * Temporarily disconnect from real-time events stream. + */ + PubNubCore.prototype.disconnect = function () { + if (this.subscriptionManager) + this.subscriptionManager.disconnect(); + else if (this.eventEngine) + this.eventEngine.disconnect(); + }; + /** + * Restore connection to the real-time events stream. + * + * @param parameters - Reconnection catch up configuration. **Note:** available only with + * enabled event engine. + */ + PubNubCore.prototype.reconnect = function (parameters) { + if (this.subscriptionManager) + this.subscriptionManager.reconnect(); + else if (this.eventEngine) + this.eventEngine.reconnect(parameters !== null && parameters !== void 0 ? parameters : {}); + }; + /** + * Event engine handshake subscribe. + * + * @param parameters - Request configuration parameters. + */ + PubNubCore.prototype.subscribeHandshake = function (parameters) { + return __awaiter(this, void 0, void 0, function () { + var request, abortUnsubscribe, handshakeResponse; + return __generator(this, function (_a) { + request = new HandshakeSubscribeRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet, crypto: this._configuration.cryptoModule, getFileUrl: this.getFileUrl })); + abortUnsubscribe = parameters.abortSignal.subscribe(request.abort); + handshakeResponse = this.sendRequest(request); + return [2 /*return*/, handshakeResponse.then(function (response) { + abortUnsubscribe(); + return response.cursor; + })]; + }); + }); + }; + /** + * Event engine receive messages subscribe. + * + * @param parameters - Request configuration parameters. + */ + PubNubCore.prototype.subscribeReceiveMessages = function (parameters) { + return __awaiter(this, void 0, void 0, function () { + var request, abortUnsubscribe, handshakeResponse; + return __generator(this, function (_a) { + request = new ReceiveMessagesSubscribeRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet, crypto: this._configuration.cryptoModule, getFileUrl: this.getFileUrl })); + abortUnsubscribe = parameters.abortSignal.subscribe(request.abort); + handshakeResponse = this.sendRequest(request); + return [2 /*return*/, handshakeResponse.then(function (response) { + abortUnsubscribe(); + return response; + })]; + }); + }); + }; + /** + * Get reactions to a specific message. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get reactions response or `void` in case if `callback` provided. + */ + PubNubCore.prototype.getMessageActions = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new GetMessageActionsRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Add a reaction to a specific message. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous add a reaction response or `void` in case if `callback` provided. + */ + PubNubCore.prototype.addMessageAction = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new AddMessageActionRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Remove a reaction from a specific message. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous remove a reaction response or `void` in case if `callback` provided. + */ + PubNubCore.prototype.removeMessageAction = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new RemoveMessageAction(__assign(__assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Fetch messages history for channels. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous fetch messages response or `void` in case if `callback` provided. + * + * @deprecated + */ + PubNubCore.prototype.fetchMessages = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new FetchMessagesRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet, crypto: this._configuration.cryptoModule, getFileUrl: this.getFileUrl })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Delete messages from the channel history. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous delete messages response or `void` in case if `callback` provided. + * + * @deprecated + */ + PubNubCore.prototype.deleteMessages = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new DeleteMessageRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Count messages from the channels' history. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous count messages response or `void` in case if `callback` provided. + * + * @deprecated + */ + PubNubCore.prototype.messageCounts = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new MessageCountRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Fetch single channel history. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous fetch channel history response or `void` in case if `callback` provided. + * + * @deprecated + */ + PubNubCore.prototype.history = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new GetHistoryRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet, crypto: this._configuration.cryptoModule })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Get channel's presence information. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get channel's presence response or `void` in case if `callback` provided. + */ + PubNubCore.prototype.hereNow = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new HereNowRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Get user's presence information. + * + * Get list of channels to which `uuid` currently subscribed. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get user's presence response or `void` in case if `callback` provided. + */ + PubNubCore.prototype.whereNow = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + var _a; + return __generator(this, function (_b) { + request = new WhereNowRequest({ + uuid: (_a = parameters.uuid) !== null && _a !== void 0 ? _a : this._configuration.userId, + keySet: this._configuration.keySet, + }); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Get associated user's data for channels and groups. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get user's data response or `void` in case if `callback` provided. + */ + PubNubCore.prototype.getState = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + var _a; + return __generator(this, function (_b) { + request = new GetPresenceStateRequest(__assign(__assign({}, parameters), { uuid: (_a = parameters.uuid) !== null && _a !== void 0 ? _a : this._configuration.userId, keySet: this._configuration.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Set associated user's data for channels and groups. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous set user's data response or `void` in case if `callback` provided. + */ + PubNubCore.prototype.setState = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var _a, keySet, uuid, heartbeat, request, presenceState_1; + var _b, _c; + return __generator(this, function (_d) { + _a = this._configuration, keySet = _a.keySet, uuid = _a.userId; + heartbeat = this._configuration.getPresenceTimeout(); + // Maintain presence information (if required). + if (this._configuration.enableEventEngine && this.presenceState) { + presenceState_1 = this.presenceState; + (_b = parameters.channels) === null || _b === void 0 ? void 0 : _b.forEach(function (channel) { return (presenceState_1[channel] = parameters.state); }); + if ('channelGroups' in parameters) { + (_c = parameters.channelGroups) === null || _c === void 0 ? void 0 : _c.forEach(function (group) { return (presenceState_1[group] = parameters.state); }); + } + } + // Check whether state should be set with heartbeat or not. + if ('withHeartbeat' in parameters) { + request = new HeartbeatRequest(__assign(__assign({}, parameters), { keySet: keySet, heartbeat: heartbeat })); + } + else { + request = new SetPresenceStateRequest(__assign(__assign({}, parameters), { keySet: keySet, uuid: uuid })); + } + // Update state used by subscription manager. + if (this.subscriptionManager) + this.subscriptionManager.setState(parameters); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + // endregion + // region Change presence state + /** + * Manual presence management. + * + * @param parameters - Desired presence state for provided list of channels and groups. + */ + PubNubCore.prototype.presence = function (parameters) { + var _a; + (_a = this.subscriptionManager) === null || _a === void 0 ? void 0 : _a.changePresence(parameters); + }; + // endregion + // region Heartbeat + /** + * Announce user presence + * + * @param parameters - Desired presence state for provided list of channels and groups. + */ + PubNubCore.prototype.heartbeat = function (parameters) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + // Manual presence management possible only with subscription manager. + if (!this.subscriptionManager) + return [2 /*return*/]; + request = new HeartbeatRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet })); + return [2 /*return*/, this.sendRequest(request)]; + }); }); - } - if (endpoint.forceBuffered === true) { - if (typeof Blob === 'undefined') { - sc = sc.buffer().responseType('arraybuffer'); - } - else { - sc = sc.responseType('arraybuffer'); - } - } - else if (endpoint.forceBuffered === false) { - sc = sc.buffer(false); - } - sc = sc.timeout(endpoint.timeout); - sc.on('abort', function () { - return callback({ - category: categories.PNUnknownCategory, - error: true, - operation: endpoint.operation, - errorData: new Error('Aborted'), - }, null); - }); - sc.end(function (err, resp) { - var parsedResponse; - var status = {}; - status.error = err !== null; - status.operation = endpoint.operation; - if (resp && resp.status) { - status.statusCode = resp.status; - } - if (err) { - if (err.response && err.response.text && !_this._config.logVerbosity) { - try { - status.errorData = JSON.parse(err.response.text); - } - catch (e) { - status.errorData = err; - } - } - else { - status.errorData = err; - } - status.category = _this._detectErrorCategory(err); - return callback(status, null); - } - if (endpoint.ignoreBody) { - parsedResponse = { - headers: resp.headers, - redirects: resp.redirects, - response: resp, - }; - } - else { - try { - parsedResponse = JSON.parse(resp.text); - } - catch (e) { - status.errorData = resp; - status.error = true; - return callback(status, null); - } - } - if (parsedResponse.error && - parsedResponse.error === 1 && - parsedResponse.status && - parsedResponse.message && - parsedResponse.service) { - status.errorData = parsedResponse; - status.statusCode = parsedResponse.status; - status.error = true; - status.category = _this._detectErrorCategory(status); - return callback(status, null); - } - if (parsedResponse.error && parsedResponse.error.message) { - status.errorData = parsedResponse.error; - } - return callback(status, parsedResponse); - }); - return sc; - } - function postfile(url, fields, fileInput) { - return __awaiter(this, void 0, void 0, function () { - var agent, result; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - agent = superagent.post(url); - fields.forEach(function (_a) { - var key = _a.key, value = _a.value; - agent = agent.field(key, value); - }); - agent.attach('file', fileInput, { contentType: 'application/octet-stream' }); - return [4 /*yield*/, agent]; - case 1: - result = _a.sent(); - return [2 /*return*/, result]; - } + }; + /** + * Grant token permission. + * + * Generate access token with requested permissions. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous grant token response or `void` in case if `callback` provided. + */ + PubNubCore.prototype.grantToken = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new GrantTokenRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Revoke token permission. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous revoke token response or `void` in case if `callback` provided. + */ + PubNubCore.prototype.revokeToken = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new RevokeTokenRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); }); + }; + Object.defineProperty(PubNubCore.prototype, "token", { + // endregion + // region Token Manipulation + /** + * Get current access token. + * + * @returns Previously configured access token using {@link setToken} method. + */ + get: function () { + return this.tokenManager.getToken(); + }, + /** + * Set current access token. + * + * @param token - New access token which should be used with next REST API endpoint calls. + */ + set: function (token) { + this.tokenManager.setToken(token); + }, + enumerable: false, + configurable: true }); - } - function getfile(params, endpoint, callback) { - var superagentConstruct = superagent - .get(this.getStandardOrigin() + endpoint.url) - .set(endpoint.headers) - .query(params); - return xdr.call(this, superagentConstruct, endpoint, callback); - } - function get(params, endpoint, callback) { - var superagentConstruct = superagent - .get(this.getStandardOrigin() + endpoint.url) - .set(endpoint.headers) - .query(params); - return xdr.call(this, superagentConstruct, endpoint, callback); - } - function post(params, body, endpoint, callback) { - var superagentConstruct = superagent - .post(this.getStandardOrigin() + endpoint.url) - .query(params) - .set(endpoint.headers) - .send(body); - return xdr.call(this, superagentConstruct, endpoint, callback); - } - function patch(params, body, endpoint, callback) { - var superagentConstruct = superagent - .patch(this.getStandardOrigin() + endpoint.url) - .query(params) - .set(endpoint.headers) - .send(body); - return xdr.call(this, superagentConstruct, endpoint, callback); - } - function del(params, endpoint, callback) { - var superagentConstruct = superagent - .delete(this.getStandardOrigin() + endpoint.url) - .set(endpoint.headers) - .query(params); - return xdr.call(this, superagentConstruct, endpoint, callback); - } - - /* global crypto */ - function concatArrayBuffer(ab1, ab2) { - var tmp = new Uint8Array(ab1.byteLength + ab2.byteLength); - tmp.set(new Uint8Array(ab1), 0); - tmp.set(new Uint8Array(ab2), ab1.byteLength); - return tmp.buffer; - } - var WebCryptography = /** @class */ (function () { - function WebCryptography() { - } - Object.defineProperty(WebCryptography.prototype, "algo", { + /** + * Get current access token. + * + * @returns Previously configured access token using {@link setToken} method. + */ + PubNubCore.prototype.getToken = function () { + return this.token; + }; + /** + * Set current access token. + * + * @param token - New access token which should be used with next REST API endpoint calls. + */ + PubNubCore.prototype.setToken = function (token) { + this.token = token; + }; + /** + * Parse access token. + * + * Parse token to see what permissions token owner has. + * + * @param token - Token which should be parsed. + * + * @returns Token's permissions information for the resources. + */ + PubNubCore.prototype.parseToken = function (token) { + return this.tokenManager.parseToken(token); + }; + /** + * Grant auth key(s) permission. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous grant auth key(s) permissions or `void` in case if `callback` provided. + * + * @deprecated Use {@link grantToken} and {@link setToken} methods instead. + */ + PubNubCore.prototype.grant = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new GrantRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Audit auth key(s) permission. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @deprecated + * + * @deprecated Use {@link grantToken} and {@link setToken} methods instead. + */ + PubNubCore.prototype.audit = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new AuditRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + Object.defineProperty(PubNubCore.prototype, "objects", { + // endregion + // endregion + // endregion + // -------------------------------------------------------- + // ------------------- App Context API -------------------- + // -------------------------------------------------------- + // region App Context API + /** + * PubNub App Context API group. + */ get: function () { - return 'aes-256-cbc'; + return this._objects; }, enumerable: false, configurable: true }); - WebCryptography.prototype.encrypt = function (key, input) { + /** + Fetch a paginated list of User objects. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get all User objects response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.getAllUUIDMetadata} method instead. + */ + PubNubCore.prototype.fetchUsers = function (parametersOrCallback, callback) { return __awaiter(this, void 0, void 0, function () { - var cKey; return __generator(this, function (_a) { - switch (_a.label) { - case 0: return [4 /*yield*/, this.getKey(key)]; - case 1: - cKey = _a.sent(); - if (input instanceof ArrayBuffer) { - return [2 /*return*/, this.encryptArrayBuffer(cKey, input)]; - } - if (typeof input === 'string') { - return [2 /*return*/, this.encryptString(cKey, input)]; - } - throw new Error('Cannot encrypt this file. In browsers file encryption supports only string or ArrayBuffer'); - } + return [2 /*return*/, this.objects._getAllUUIDMetadata(parametersOrCallback, callback)]; }); }); }; - WebCryptography.prototype.decrypt = function (key, input) { + /** + * Fetch User object for currently configured PubNub client `uuid`. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get User object response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.getUUIDMetadata} method instead. + */ + PubNubCore.prototype.fetchUser = function (parametersOrCallback, callback) { return __awaiter(this, void 0, void 0, function () { - var cKey; return __generator(this, function (_a) { - switch (_a.label) { - case 0: return [4 /*yield*/, this.getKey(key)]; - case 1: - cKey = _a.sent(); - if (input instanceof ArrayBuffer) { - return [2 /*return*/, this.decryptArrayBuffer(cKey, input)]; - } - if (typeof input === 'string') { - return [2 /*return*/, this.decryptString(cKey, input)]; - } - throw new Error('Cannot decrypt this file. In browsers file decryption supports only string or ArrayBuffer'); - } + return [2 /*return*/, this.objects._getUUIDMetadata(parametersOrCallback, callback)]; }); }); }; - WebCryptography.prototype.encryptFile = function (key, file, File) { + /** + * Create User object. + * + * @param parameters - Request configuration parameters. Will create User object for currently + * configured PubNub client `uuid` if not set. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous create User object response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.setUUIDMetadata} method instead. + */ + PubNubCore.prototype.createUser = function (parameters, callback) { return __awaiter(this, void 0, void 0, function () { - var bKey, abPlaindata, abCipherdata; return __generator(this, function (_a) { - switch (_a.label) { - case 0: - if (file.data.byteLength <= 0) - throw new Error('encryption error. empty content'); - return [4 /*yield*/, this.getKey(key)]; - case 1: - bKey = _a.sent(); - return [4 /*yield*/, file.data.arrayBuffer()]; - case 2: - abPlaindata = _a.sent(); - return [4 /*yield*/, this.encryptArrayBuffer(bKey, abPlaindata)]; - case 3: - abCipherdata = _a.sent(); - return [2 /*return*/, File.create({ - name: file.name, - mimeType: 'application/octet-stream', - data: abCipherdata, - })]; - } + return [2 /*return*/, this.objects._setUUIDMetadata(parameters, callback)]; }); }); }; - WebCryptography.prototype.decryptFile = function (key, file, File) { + /** + * Update User object. + * + * @param parameters - Request configuration parameters. Will update User object for currently + * configured PubNub client `uuid` if not set. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous update User object response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.setUUIDMetadata} method instead. + */ + PubNubCore.prototype.updateUser = function (parameters, callback) { return __awaiter(this, void 0, void 0, function () { - var bKey, abCipherdata, abPlaindata; return __generator(this, function (_a) { - switch (_a.label) { - case 0: return [4 /*yield*/, this.getKey(key)]; - case 1: - bKey = _a.sent(); - return [4 /*yield*/, file.data.arrayBuffer()]; - case 2: - abCipherdata = _a.sent(); - return [4 /*yield*/, this.decryptArrayBuffer(bKey, abCipherdata)]; - case 3: - abPlaindata = _a.sent(); - return [2 /*return*/, File.create({ - name: file.name, - data: abPlaindata, - })]; - } + return [2 /*return*/, this.objects._setUUIDMetadata(parameters, callback)]; }); }); }; - WebCryptography.prototype.getKey = function (key) { + /** + * Remove a specific User object. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous User object remove response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.removeUUIDMetadata} method instead. + */ + PubNubCore.prototype.removeUser = function (parametersOrCallback, callback) { return __awaiter(this, void 0, void 0, function () { - var digest, hashHex, abKey; return __generator(this, function (_a) { - switch (_a.label) { - case 0: return [4 /*yield*/, crypto.subtle.digest('SHA-256', WebCryptography.encoder.encode(key))]; - case 1: - digest = _a.sent(); - hashHex = Array.from(new Uint8Array(digest)) - .map(function (b) { return b.toString(16).padStart(2, '0'); }) - .join(''); - abKey = WebCryptography.encoder.encode(hashHex.slice(0, 32)).buffer; - return [2 /*return*/, crypto.subtle.importKey('raw', abKey, 'AES-CBC', true, ['encrypt', 'decrypt'])]; - } + return [2 /*return*/, this.objects._removeUUIDMetadata(parametersOrCallback, callback)]; }); }); }; - WebCryptography.prototype.encryptArrayBuffer = function (key, plaintext) { + /** + * Fetch a paginated list of Space objects. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get all Space objects response or `void` in case if `callback` + * provided. + * + * @deprecated Use {@link PubNubCore#objects.getAllChannelMetadata} method instead. + */ + PubNubCore.prototype.fetchSpaces = function (parametersOrCallback, callback) { return __awaiter(this, void 0, void 0, function () { - var abIv, _a, _b; - return __generator(this, function (_c) { - switch (_c.label) { - case 0: - abIv = crypto.getRandomValues(new Uint8Array(16)); - _a = concatArrayBuffer; - _b = [abIv.buffer]; - return [4 /*yield*/, crypto.subtle.encrypt({ name: 'AES-CBC', iv: abIv }, key, plaintext)]; - case 1: return [2 /*return*/, _a.apply(void 0, _b.concat([_c.sent()]))]; - } + return __generator(this, function (_a) { + return [2 /*return*/, this.objects._getAllChannelMetadata(parametersOrCallback, callback)]; }); }); }; - WebCryptography.prototype.decryptArrayBuffer = function (key, ciphertext) { + /** + * Fetch a specific Space object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get Space object response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.getChannelMetadata} method instead. + */ + PubNubCore.prototype.fetchSpace = function (parameters, callback) { return __awaiter(this, void 0, void 0, function () { - var abIv, data; return __generator(this, function (_a) { - switch (_a.label) { - case 0: - abIv = ciphertext.slice(0, 16); - if (ciphertext.slice(WebCryptography.IV_LENGTH).byteLength <= 0) - throw new Error('decryption error: empty content'); - return [4 /*yield*/, crypto.subtle.decrypt({ name: 'AES-CBC', iv: abIv }, key, ciphertext.slice(WebCryptography.IV_LENGTH))]; - case 1: - data = _a.sent(); - return [2 /*return*/, data]; - } + return [2 /*return*/, this.objects._getChannelMetadata(parameters, callback)]; }); }); }; - WebCryptography.prototype.encryptString = function (key, plaintext) { + /** + * Create specific Space object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous create Space object response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.setChannelMetadata} method instead. + */ + PubNubCore.prototype.createSpace = function (parameters, callback) { return __awaiter(this, void 0, void 0, function () { - var abIv, abPlaintext, abPayload, ciphertext; return __generator(this, function (_a) { - switch (_a.label) { - case 0: - abIv = crypto.getRandomValues(new Uint8Array(16)); - abPlaintext = WebCryptography.encoder.encode(plaintext).buffer; - return [4 /*yield*/, crypto.subtle.encrypt({ name: 'AES-CBC', iv: abIv }, key, abPlaintext)]; - case 1: - abPayload = _a.sent(); - ciphertext = concatArrayBuffer(abIv.buffer, abPayload); - return [2 /*return*/, WebCryptography.decoder.decode(ciphertext)]; - } + return [2 /*return*/, this.objects._setChannelMetadata(parameters, callback)]; + }); + }); + }; + /** + * Update specific Space object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous update Space object response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.setChannelMetadata} method instead. + */ + PubNubCore.prototype.updateSpace = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this.objects._setChannelMetadata(parameters, callback)]; + }); + }); + }; + /** + * Remove a specific Space object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous Space object remove response or `void` in case if `callback` + * provided. + * + * @deprecated Use {@link PubNubCore#objects.removeChannelMetadata} method instead. + */ + PubNubCore.prototype.removeSpace = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this.objects._removeChannelMetadata(parameters, callback)]; }); }); }; - WebCryptography.prototype.decryptString = function (key, ciphertext) { + /** + * Fetch paginated list of specific Space members or specific User memberships. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get specific Space members or specific User memberships response or + * `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.getChannelMembers} or {@link PubNubCore#objects.getMemberships} + * methods instead. + */ + PubNubCore.prototype.fetchMemberships = function (parameters, callback) { return __awaiter(this, void 0, void 0, function () { - var abCiphertext, abIv, abPayload, abPlaintext; return __generator(this, function (_a) { - switch (_a.label) { - case 0: - abCiphertext = WebCryptography.encoder.encode(ciphertext).buffer; - abIv = abCiphertext.slice(0, 16); - abPayload = abCiphertext.slice(16); - return [4 /*yield*/, crypto.subtle.decrypt({ name: 'AES-CBC', iv: abIv }, key, abPayload)]; - case 1: - abPlaintext = _a.sent(); - return [2 /*return*/, WebCryptography.decoder.decode(abPlaintext)]; - } + return [2 /*return*/, this.objects.fetchMemberships(parameters, callback)]; }); }); }; - WebCryptography.IV_LENGTH = 16; - WebCryptography.encoder = new TextEncoder(); - WebCryptography.decoder = new TextDecoder(); - return WebCryptography; - }()); - - /* global File, FileReader */ - var _a; - var PubNubFile = (_a = /** @class */ (function () { - function PubNubFile(config) { - if (config instanceof File) { - this.data = config; - this.name = this.data.name; - this.mimeType = this.data.type; - } - else if (config.data) { - var contents = config.data; - this.data = new File([contents], config.name, { type: config.mimeType }); - this.name = config.name; - if (config.mimeType) { - this.mimeType = config.mimeType; - } - } - if (this.data === undefined) { - throw new Error("Couldn't construct a file out of supplied options."); - } - if (this.name === undefined) { - throw new Error("Couldn't guess filename out of the options. Please provide one."); - } - } - PubNubFile.create = function (config) { - return new this(config); - }; - PubNubFile.prototype.toBuffer = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - throw new Error('This feature is only supported in Node.js environments.'); - }); - }); - }; - PubNubFile.prototype.toStream = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - throw new Error('This feature is only supported in Node.js environments.'); - }); - }); - }; - PubNubFile.prototype.toFileUri = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - throw new Error('This feature is only supported in react native environments.'); - }); - }); - }; - PubNubFile.prototype.toBlob = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - return [2 /*return*/, this.data]; - }); - }); - }; - PubNubFile.prototype.toArrayBuffer = function () { - return __awaiter(this, void 0, void 0, function () { - var _this = this; - return __generator(this, function (_a) { - return [2 /*return*/, new Promise(function (resolve, reject) { - var reader = new FileReader(); - reader.addEventListener('load', function () { - if (reader.result instanceof ArrayBuffer) { - return resolve(reader.result); - } - }); - reader.addEventListener('error', function () { - reject(reader.error); - }); - reader.readAsArrayBuffer(_this.data); - })]; - }); - }); - }; - PubNubFile.prototype.toString = function () { - return __awaiter(this, void 0, void 0, function () { - var _this = this; - return __generator(this, function (_a) { - return [2 /*return*/, new Promise(function (resolve, reject) { - var reader = new FileReader(); - reader.addEventListener('load', function () { - if (typeof reader.result === 'string') { - return resolve(reader.result); - } - }); - reader.addEventListener('error', function () { - reject(reader.error); - }); - reader.readAsBinaryString(_this.data); - })]; - }); - }); - }; - PubNubFile.prototype.toFile = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - return [2 /*return*/, this.data]; - }); + /** + * Add members to specific Space or memberships specific User. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous add members to specific Space or memberships specific User response or + * `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.setChannelMembers} or {@link PubNubCore#objects.setMemberships} + * methods instead. + */ + PubNubCore.prototype.addMemberships = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this.objects.addMemberships(parameters, callback)]; }); - }; - return PubNubFile; - }()), - _a.supportsFile = typeof File !== 'undefined', - _a.supportsBlob = typeof Blob !== 'undefined', - _a.supportsArrayBuffer = typeof ArrayBuffer !== 'undefined', - _a.supportsBuffer = false, - _a.supportsStream = false, - _a.supportsString = true, - _a.supportsEncryptFile = true, - _a.supportsFileUri = false, - _a); - - var LegacyCryptor = /** @class */ (function () { - function LegacyCryptor(config) { - this.config = config; - this.cryptor = new default_1$a({ config: config }); - this.fileCryptor = new WebCryptography(); - } - Object.defineProperty(LegacyCryptor.prototype, "identifier", { - get: function () { - return ''; - }, - enumerable: false, - configurable: true - }); - LegacyCryptor.prototype.encrypt = function (data) { - var stringData = typeof data === 'string' ? data : new TextDecoder().decode(data); - return { - data: this.cryptor.encrypt(stringData), - metadata: null, - }; - }; - LegacyCryptor.prototype.decrypt = function (encryptedData) { - var data = typeof encryptedData.data === 'string' ? encryptedData.data : encode$1(encryptedData.data); - return this.cryptor.decrypt(data); + }); }; - LegacyCryptor.prototype.encryptFile = function (file, File) { - var _a; + /** + * Update specific Space members or User memberships. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous update Space members or User memberships response or `void` in case + * if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.setChannelMembers} or {@link PubNubCore#objects.setMemberships} + * methods instead. + */ + PubNubCore.prototype.updateMemberships = function (parameters, callback) { return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_b) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - //@ts-ignore: can not detect cipherKey from old Config - return [2 /*return*/, this.fileCryptor.encryptFile((_a = this.config) === null || _a === void 0 ? void 0 : _a.cipherKey, file, File)]; + return __generator(this, function (_a) { + return [2 /*return*/, this.objects.addMemberships(parameters, callback)]; }); }); }; - LegacyCryptor.prototype.decryptFile = function (file, File) { + /** + * Remove User membership. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous memberships modification response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.removeMemberships} or {@link PubNubCore#objects.removeChannelMembers} + * methods instead + * from `objects` API group.. + */ + PubNubCore.prototype.removeMemberships = function (parameters, callback) { return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - //@ts-ignore: can not detect cipherKey from old Config - return [2 /*return*/, this.fileCryptor.decryptFile(this.config.cipherKey, file, File)]; + var spaceParameters, requestParameters_1, userParameters, requestParameters; + var _a, _b, _c; + return __generator(this, function (_d) { + if ('spaceId' in parameters) { + spaceParameters = parameters; + requestParameters_1 = { + channel: (_a = spaceParameters.spaceId) !== null && _a !== void 0 ? _a : spaceParameters.channel, + uuids: (_b = spaceParameters.userIds) !== null && _b !== void 0 ? _b : spaceParameters.uuids, + limit: 0, + }; + if (callback) + return [2 /*return*/, this.objects.removeChannelMembers(requestParameters_1, callback)]; + return [2 /*return*/, this.objects.removeChannelMembers(requestParameters_1)]; + } + userParameters = parameters; + requestParameters = { + uuid: userParameters.userId, + channels: (_c = userParameters.spaceIds) !== null && _c !== void 0 ? _c : userParameters.channels, + limit: 0, + }; + if (callback) + return [2 /*return*/, this.objects.removeMemberships(requestParameters, callback)]; + return [2 /*return*/, this.objects.removeMemberships(requestParameters)]; }); }); }; - return LegacyCryptor; - }()); - - var AesCbcCryptor = /** @class */ (function () { - function AesCbcCryptor(configuration) { - this.cipherKey = configuration.cipherKey; - this.CryptoJS = hmacSha256; - this.encryptedKey = this.CryptoJS.SHA256(this.cipherKey); - } - Object.defineProperty(AesCbcCryptor.prototype, "algo", { + Object.defineProperty(PubNubCore.prototype, "channelGroups", { + // endregion + // endregion + // -------------------------------------------------------- + // ----------------- Channel Groups API ------------------- + // -------------------------------------------------------- + // region Channel Groups API + /** + * PubNub Channel Groups API group. + */ get: function () { - return 'AES-CBC'; + return this._channelGroups; }, enumerable: false, configurable: true }); - Object.defineProperty(AesCbcCryptor.prototype, "identifier", { + Object.defineProperty(PubNubCore.prototype, "push", { + // endregion + // -------------------------------------------------------- + // ---------------- Push Notifications API ----------------- + // -------------------------------------------------------- + // region Push Notifications API + /** + * PubNub Push Notifications API group. + */ get: function () { - return 'ACRH'; + return this._push; }, enumerable: false, configurable: true }); - AesCbcCryptor.prototype.getIv = function () { - return crypto.getRandomValues(new Uint8Array(AesCbcCryptor.BLOCK_SIZE)); - }; - AesCbcCryptor.prototype.getKey = function () { - return __awaiter(this, void 0, void 0, function () { - var bKey, abHash; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - bKey = AesCbcCryptor.encoder.encode(this.cipherKey); - return [4 /*yield*/, crypto.subtle.digest('SHA-256', bKey.buffer)]; - case 1: - abHash = _a.sent(); - return [2 /*return*/, crypto.subtle.importKey('raw', abHash, this.algo, true, ['encrypt', 'decrypt'])]; - } - }); - }); - }; - AesCbcCryptor.prototype.encrypt = function (data) { - var stringData = typeof data === 'string' ? data : AesCbcCryptor.decoder.decode(data); - if (stringData.length === 0) - throw new Error('encryption error. empty content'); - var abIv = this.getIv(); - return { - metadata: abIv, - data: decode$1(this.CryptoJS.AES.encrypt(data, this.encryptedKey, { - iv: this.bufferToWordArray(abIv), - mode: this.CryptoJS.mode.CBC, - }).ciphertext.toString(this.CryptoJS.enc.Base64)), - }; - }; - AesCbcCryptor.prototype.decrypt = function (encryptedData) { - var iv = this.bufferToWordArray(new Uint8ClampedArray(encryptedData.metadata)); - var data = this.bufferToWordArray(new Uint8ClampedArray(encryptedData.data)); - return AesCbcCryptor.encoder.encode(this.CryptoJS.AES.decrypt({ ciphertext: data }, this.encryptedKey, { - iv: iv, - mode: this.CryptoJS.mode.CBC, - }).toString(this.CryptoJS.enc.Utf8)).buffer; - }; - AesCbcCryptor.prototype.encryptFileData = function (data) { + /** + * Share file to a specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous file sharing response or `void` in case if `callback` provided. + */ + PubNubCore.prototype.sendFile = function (parameters, callback) { return __awaiter(this, void 0, void 0, function () { - var key, iv; + var sendFileRequest, status; var _a; return __generator(this, function (_b) { - switch (_b.label) { - case 0: return [4 /*yield*/, this.getKey()]; - case 1: - key = _b.sent(); - iv = this.getIv(); - _a = {}; - return [4 /*yield*/, crypto.subtle.encrypt({ name: this.algo, iv: iv }, key, data)]; - case 2: return [2 /*return*/, (_a.data = _b.sent(), - _a.metadata = iv, - _a)]; - } + if (!this._configuration.PubNubFile) + throw new Error("Validation failed: 'PubNubFile' not configured or file upload not supported by the platform."); + sendFileRequest = new SendFileRequest(__assign(__assign({}, parameters), { cipherKey: (_a = parameters.cipherKey) !== null && _a !== void 0 ? _a : this._configuration.cipherKey, keySet: this._configuration.keySet, PubNubFile: this._configuration.PubNubFile, fileUploadPublishRetryLimit: this._configuration.fileUploadPublishRetryLimit, file: parameters.file, sendRequest: this.sendRequest, publishFile: this.publishFile, crypto: this._configuration.cryptoModule, cryptography: this.cryptography ? this.cryptography : undefined })); + status = { + error: false, + operation: RequestOperation$1.PNPublishFileOperation, + statusCode: 0, + }; + return [2 /*return*/, sendFileRequest + .process() + .then(function (response) { + status.statusCode = response.status; + if (callback) + return callback(status, response); + return response; + }) + .catch(function (error) { + var errorStatus = error.toStatus(status.operation); + // Notify callback (if possible). + if (callback) + callback(errorStatus, null); + throw new PubNubError('REST API request processing error, check status for details', errorStatus); + })]; }); }); }; - AesCbcCryptor.prototype.decryptFileData = function (encryptedData) { + /** + * Publish file message to a specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous publish file message response or `void` in case if `callback` provided. + */ + PubNubCore.prototype.publishFile = function (parameters, callback) { return __awaiter(this, void 0, void 0, function () { - var key; + var request; return __generator(this, function (_a) { - switch (_a.label) { - case 0: return [4 /*yield*/, this.getKey()]; - case 1: - key = _a.sent(); - return [2 /*return*/, crypto.subtle.decrypt({ name: this.algo, iv: encryptedData.metadata }, key, encryptedData.data)]; - } + if (!this._configuration.PubNubFile) + throw new Error("Validation failed: 'PubNubFile' not configured or file upload not supported by the platform."); + request = new PublishFileMessageRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet, crypto: this._configuration.cryptoModule })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; }); }); }; - AesCbcCryptor.prototype.bufferToWordArray = function (b) { - var wa = []; - var i; - for (i = 0; i < b.length; i += 1) { - wa[(i / 4) | 0] |= b[i] << (24 - 8 * i); - } - return this.CryptoJS.lib.WordArray.create(wa, b.length); - }; - AesCbcCryptor.BLOCK_SIZE = 16; - AesCbcCryptor.encoder = new TextEncoder(); - AesCbcCryptor.decoder = new TextDecoder(); - return AesCbcCryptor; - }()); - - var CryptoModule = /** @class */ (function () { - function CryptoModule(cryptoModuleConfiguration) { - var _a; - this.defaultCryptor = cryptoModuleConfiguration.default; - this.cryptors = (_a = cryptoModuleConfiguration.cryptors) !== null && _a !== void 0 ? _a : []; - } - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - //@ts-ignore: type detection issue with old Config type assignment - CryptoModule.legacyCryptoModule = function (config) { - var _a; - return new this({ - default: new LegacyCryptor({ - cipherKey: config.cipherKey, - useRandomIVs: (_a = config.useRandomIVs) !== null && _a !== void 0 ? _a : true, - }), - cryptors: [new AesCbcCryptor({ cipherKey: config.cipherKey })], + /** + * Retrieve list of shared files in specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous shared files list response or `void` in case if `callback` provided. + */ + PubNubCore.prototype.listFiles = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new FilesListRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); }); }; - CryptoModule.aesCbcCryptoModule = function (config) { + // endregion + // region Get Download Url + /** + * Get file download Url. + * + * @param parameters - Request configuration parameters. + * + * @returns File download Url. + */ + PubNubCore.prototype.getFileUrl = function (parameters) { var _a; - return new this({ - default: new AesCbcCryptor({ cipherKey: config.cipherKey }), - cryptors: [ - new LegacyCryptor({ - cipherKey: config.cipherKey, - useRandomIVs: (_a = config.useRandomIVs) !== null && _a !== void 0 ? _a : true, - }), - ], - }); - }; - CryptoModule.withDefaultCryptor = function (defaultCryptor) { - return new this({ default: defaultCryptor }); - }; - CryptoModule.prototype.getAllCryptors = function () { - return __spreadArray$1([this.defaultCryptor], __read$1(this.cryptors), false); - }; - CryptoModule.prototype.encrypt = function (data) { - var encrypted = this.defaultCryptor.encrypt(data); - if (!encrypted.metadata) - return encrypted.data; - var headerData = this.getHeaderData(encrypted); - return this.concatArrayBuffer(headerData, encrypted.data); + var request = this.transport.request(new GetFileDownloadUrlRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet })).request()); + var query = (_a = request.queryParameters) !== null && _a !== void 0 ? _a : {}; + var queryString = Object.keys(query) + .map(function (key) { + var queryValue = query[key]; + if (!Array.isArray(queryValue)) + return "".concat(key, "=").concat(encodeString(queryValue)); + return queryValue.map(function (value) { return "".concat(key, "=").concat(encodeString(value)); }).join('&'); + }) + .join('&'); + return "".concat(request.origin).concat(request.path, "?").concat(queryString); }; - CryptoModule.prototype.decrypt = function (data) { - var encryptedData = typeof data === 'string' ? decode$1(data) : data; - var header = CryptorHeader.tryParse(encryptedData); - var cryptor = this.getCryptor(header); - var metadata = header.length > 0 - ? encryptedData.slice(header.length - header.metadataLength, header.length) - : null; - if (encryptedData.slice(header.length).byteLength <= 0) - throw new Error('decryption error. empty content'); - return cryptor.decrypt({ - data: encryptedData.slice(header.length), - metadata: metadata, + /** + * Download shared file from specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous download shared file response or `void` in case if `callback` provided. + */ + PubNubCore.prototype.downloadFile = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + var _a; + return __generator(this, function (_b) { + switch (_b.label) { + case 0: + if (!this._configuration.PubNubFile) + throw new Error("Validation failed: 'PubNubFile' not configured or file upload not supported by the platform."); + request = new DownloadFileRequest(__assign(__assign({}, parameters), { cipherKey: (_a = parameters.cipherKey) !== null && _a !== void 0 ? _a : this._configuration.cipherKey, keySet: this._configuration.keySet, PubNubFile: this._configuration.PubNubFile, cryptography: this.cryptography ? this.cryptography : undefined, crypto: this._configuration.cryptoModule })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [4 /*yield*/, this.sendRequest(request)]; + case 1: return [2 /*return*/, (_b.sent())]; + } + }); }); }; - CryptoModule.prototype.encryptFile = function (file, File) { + /** + * Delete shared file from specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous delete shared file response or `void` in case if `callback` provided. + */ + PubNubCore.prototype.deleteFile = function (parameters, callback) { return __awaiter(this, void 0, void 0, function () { - var fileData, encrypted; + var request; return __generator(this, function (_a) { - switch (_a.label) { - case 0: - if (this.defaultCryptor.identifier === CryptorHeader.LEGACY_IDENTIFIER) - return [2 /*return*/, this.defaultCryptor.encryptFile(file, File)]; - return [4 /*yield*/, this.getFileData(file.data)]; - case 1: - fileData = _a.sent(); - return [4 /*yield*/, this.defaultCryptor.encryptFileData(fileData)]; - case 2: - encrypted = _a.sent(); - return [2 /*return*/, File.create({ - name: file.name, - mimeType: 'application/octet-stream', - data: this.concatArrayBuffer(this.getHeaderData(encrypted), encrypted.data), - })]; - } + request = new DeleteFileRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; }); }); }; - CryptoModule.prototype.decryptFile = function (file, File) { + /** + Get current high-precision timetoken. + * + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get current timetoken response or `void` in case if `callback` provided. + */ + PubNubCore.prototype.time = function (callback) { return __awaiter(this, void 0, void 0, function () { - var data, header, cryptor, fileData, metadata, _a, _b; - var _c; - return __generator(this, function (_d) { - switch (_d.label) { - case 0: return [4 /*yield*/, file.data.arrayBuffer()]; - case 1: - data = _d.sent(); - header = CryptorHeader.tryParse(data); - cryptor = this.getCryptor(header); - if ((cryptor === null || cryptor === void 0 ? void 0 : cryptor.identifier) === CryptoModule.LEGACY_IDENTIFIER) { - return [2 /*return*/, cryptor.decryptFile(file, File)]; - } - return [4 /*yield*/, this.getFileData(data)]; - case 2: - fileData = _d.sent(); - metadata = fileData.slice(header.length - header.metadataLength, header.length); - _b = (_a = File).create; - _c = { - name: file.name - }; - return [4 /*yield*/, this.defaultCryptor.decryptFileData({ - data: data.slice(header.length), - metadata: metadata, - })]; - case 3: return [2 /*return*/, _b.apply(_a, [(_c.data = _d.sent(), - _c)])]; - } + var request; + return __generator(this, function (_a) { + request = new TimeRequest(); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; }); }); }; - CryptoModule.prototype.getCryptor = function (header) { - if (header === '') { - var cryptor = this.getAllCryptors().find(function (c) { return c.identifier === ''; }); - if (cryptor) - return cryptor; - throw new Error('unknown cryptor error'); - } - else if (header instanceof CryptorHeaderV1) { - return this.getCryptorFromId(header.identifier); + // endregion + // -------------------------------------------------------- + // ------------------ Cryptography API -------------------- + // -------------------------------------------------------- + // region Cryptography + // region Common + /** + * Encrypt data. + * + * @param data - Stringified data which should be encrypted using `CryptoModule`. + * @deprecated + * @param [customCipherKey] - Cipher key which should be used to encrypt data. **Deprecated:** + * use {@link Configuration#cryptoModule|cryptoModule} instead. + * + * @returns Data encryption result as a string. + */ + PubNubCore.prototype.encrypt = function (data, customCipherKey) { + if (typeof customCipherKey === 'undefined' && this._configuration.cryptoModule) { + var encrypted = this._configuration.cryptoModule.encrypt(data); + return typeof encrypted === 'string' ? encrypted : encode(encrypted); } + if (!this.crypto) + throw new Error('Encryption error: cypher key not set'); + return this.crypto.encrypt(data, customCipherKey); }; - CryptoModule.prototype.getCryptorFromId = function (id) { - var cryptor = this.getAllCryptors().find(function (c) { return id === c.identifier; }); - if (cryptor) { - return cryptor; + /** + * Decrypt data. + * + * @param data - Stringified data which should be encrypted using `CryptoModule`. + * @param [customCipherKey] - Cipher key which should be used to decrypt data. **Deprecated:** + * use {@link Configuration#cryptoModule|cryptoModule} instead. + * + * @returns Data decryption result as an object. + */ + PubNubCore.prototype.decrypt = function (data, customCipherKey) { + if (typeof customCipherKey === 'undefined' && this._configuration.cryptoModule) { + var decrypted = this._configuration.cryptoModule.decrypt(data); + return decrypted instanceof ArrayBuffer ? JSON.parse(new TextDecoder().decode(decrypted)) : decrypted; } - throw Error('unknown cryptor error'); - }; - CryptoModule.prototype.concatArrayBuffer = function (ab1, ab2) { - var tmp = new Uint8Array(ab1.byteLength + ab2.byteLength); - tmp.set(new Uint8Array(ab1), 0); - tmp.set(new Uint8Array(ab2), ab1.byteLength); - return tmp.buffer; + if (!this.crypto) + throw new Error('Decryption error: cypher key not set'); + return this.crypto.decrypt(data, customCipherKey); }; - CryptoModule.prototype.getHeaderData = function (encrypted) { - if (!encrypted.metadata) - return; - var header = CryptorHeader.from(this.defaultCryptor.identifier, encrypted.metadata); - var headerData = new Uint8Array(header.length); - var pos = 0; - headerData.set(header.data, pos); - pos += header.length - encrypted.metadata.byteLength; - headerData.set(new Uint8Array(encrypted.metadata), pos); - return headerData.buffer; + /** + * Encrypt file content. + * + * @param keyOrFile - Cipher key which should be used to encrypt data or file which should be + * encrypted using `CryptoModule`. + * @param [file] - File which should be encrypted using legacy cryptography. + * + * @returns Asynchronous file encryption result. + * + * @throws Error if source file not provided. + * @throws File constructor not provided. + * @throws Crypto module is missing (if non-legacy flow used). + */ + PubNubCore.prototype.encryptFile = function (keyOrFile, file) { + return __awaiter(this, void 0, void 0, function () { + var _a; + return __generator(this, function (_b) { + if (typeof keyOrFile !== 'string') + file = keyOrFile; + if (!file) + throw new Error('File encryption error. Source file is missing.'); + if (!this._configuration.PubNubFile) + throw new Error('File encryption error. File constructor not configured.'); + if (typeof keyOrFile !== 'string' && !this._configuration.cryptoModule) + throw new Error('File encryption error. Crypto module not configured.'); + if (typeof keyOrFile === 'string') { + if (!this.cryptography) + throw new Error('File encryption error. File encryption not available'); + return [2 /*return*/, this.cryptography.encryptFile(keyOrFile, file, this._configuration.PubNubFile)]; + } + return [2 /*return*/, (_a = this._configuration.cryptoModule) === null || _a === void 0 ? void 0 : _a.encryptFile(file, this._configuration.PubNubFile)]; + }); + }); }; - CryptoModule.prototype.getFileData = function (input) { + /** + * Decrypt file content. + * + * @param keyOrFile - Cipher key which should be used to decrypt data or file which should be + * decrypted using `CryptoModule`. + * @param [file] - File which should be decrypted using legacy cryptography. + * + * @returns Asynchronous file decryption result. + * + * @throws Error if source file not provided. + * @throws File constructor not provided. + * @throws Crypto module is missing (if non-legacy flow used). + */ + PubNubCore.prototype.decryptFile = function (keyOrFile, file) { return __awaiter(this, void 0, void 0, function () { - var fileData; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - if (!(input instanceof Blob)) return [3 /*break*/, 2]; - return [4 /*yield*/, input.arrayBuffer()]; - case 1: - fileData = _a.sent(); - return [2 /*return*/, fileData]; - case 2: - if (input instanceof ArrayBuffer) { - return [2 /*return*/, input]; - } - if (typeof input === 'string') { - return [2 /*return*/, CryptoModule.encoder.encode(input)]; - } - throw new Error('Cannot decrypt/encrypt file. In browsers file encrypt/decrypt supported for string, ArrayBuffer or Blob'); + var _a; + return __generator(this, function (_b) { + if (typeof keyOrFile !== 'string') + file = keyOrFile; + if (!file) + throw new Error('File encryption error. Source file is missing.'); + if (!this._configuration.PubNubFile) + throw new Error('File decryption error. File constructor' + ' not configured.'); + if (typeof keyOrFile === 'string' && !this._configuration.cryptoModule) + throw new Error('File decryption error. Crypto module not configured.'); + if (typeof keyOrFile === 'string') { + if (!this.cryptography) + throw new Error('File decryption error. File decryption not available'); + return [2 /*return*/, this.cryptography.decryptFile(keyOrFile, file, this._configuration.PubNubFile)]; } + return [2 /*return*/, (_a = this._configuration.cryptoModule) === null || _a === void 0 ? void 0 : _a.decryptFile(file, this._configuration.PubNubFile)]; }); }); }; - CryptoModule.LEGACY_IDENTIFIER = ''; - CryptoModule.encoder = new TextEncoder(); - CryptoModule.decoder = new TextDecoder(); - return CryptoModule; + // -------------------------------------------------------- + // ----------------------- Static ------------------------- + // -------------------------------------------------------- + // region Static + /** + * Type of REST API endpoint which reported status. + */ + PubNubCore.OPERATIONS = RequestOperation$1; + /** + * API call status category. + */ + PubNubCore.CATEGORIES = StatusCategory$1; + /** + * Exponential retry policy constructor. + */ + PubNubCore.ExponentialRetryPolicy = RetryPolicy.ExponentialRetryPolicy; + /** + * Linear retry policy constructor. + */ + PubNubCore.LinearRetryPolicy = RetryPolicy.LinearRetryPolicy; + return PubNubCore; }()); - // CryptorHeader Utility - var CryptorHeader = /** @class */ (function () { - function CryptorHeader() { + + var default_1 = /** @class */ (function () { + function default_1(decode, base64ToBinary) { + this._base64ToBinary = base64ToBinary; + this._decode = decode; } - CryptorHeader.from = function (id, metadata) { - if (id === CryptorHeader.LEGACY_IDENTIFIER) - return; - return new CryptorHeaderV1(id, metadata.byteLength); - }; - CryptorHeader.tryParse = function (data) { - var encryptedData = new Uint8Array(data); - var sentinel = ''; - var version = null; - if (encryptedData.byteLength >= 4) { - sentinel = encryptedData.slice(0, 4); - if (this.decoder.decode(sentinel) !== CryptorHeader.SENTINEL) - return ''; - } - if (encryptedData.byteLength >= 5) { - version = encryptedData[4]; - } - else { - throw new Error('decryption error. invalid header version'); - } - if (version > CryptorHeader.MAX_VERSION) - throw new Error('unknown cryptor error'); - var identifier = ''; - var pos = 5 + CryptorHeader.IDENTIFIER_LENGTH; - if (encryptedData.byteLength >= pos) { - identifier = encryptedData.slice(5, pos); - } - else { - throw new Error('decryption error. invalid crypto identifier'); - } - var metadataLength = null; - if (encryptedData.byteLength >= pos + 1) { - metadataLength = encryptedData[pos]; + default_1.prototype.decodeToken = function (tokenString) { + var padding = ''; + if (tokenString.length % 4 === 3) { + padding = '='; } - else { - throw new Error('decryption error. invalid metadata length'); + else if (tokenString.length % 4 === 2) { + padding = '=='; } - pos += 1; - if (metadataLength === 255 && encryptedData.byteLength >= pos + 2) { - metadataLength = new Uint16Array(encryptedData.slice(pos, pos + 2)).reduce(function (acc, val) { return (acc << 8) + val; }, 0); - pos += 2; + var cleaned = tokenString.replace(/-/gi, '+').replace(/_/gi, '/') + padding; + var result = this._decode(this._base64ToBinary(cleaned)); + if (typeof result === 'object') { + return result; } - return new CryptorHeaderV1(this.decoder.decode(identifier), metadataLength); + return undefined; }; - CryptorHeader.SENTINEL = 'PNED'; - CryptorHeader.LEGACY_IDENTIFIER = ''; - CryptorHeader.IDENTIFIER_LENGTH = 4; - CryptorHeader.VERSION = 1; - CryptorHeader.MAX_VERSION = 1; - CryptorHeader.decoder = new TextDecoder(); - return CryptorHeader; - }()); - // v1 CryptorHeader - var CryptorHeaderV1 = /** @class */ (function () { - function CryptorHeaderV1(id, metadataLength) { - this._identifier = id; - this._metadataLength = metadataLength; - } - Object.defineProperty(CryptorHeaderV1.prototype, "identifier", { - get: function () { - return this._identifier; - }, - set: function (value) { - this._identifier = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(CryptorHeaderV1.prototype, "metadataLength", { - get: function () { - return this._metadataLength; - }, - set: function (value) { - this._metadataLength = value; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(CryptorHeaderV1.prototype, "version", { - get: function () { - return CryptorHeader.VERSION; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(CryptorHeaderV1.prototype, "length", { - get: function () { - return (CryptorHeader.SENTINEL.length + - 1 + - CryptorHeader.IDENTIFIER_LENGTH + - (this.metadataLength < 255 ? 1 : 3) + - this.metadataLength); - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(CryptorHeaderV1.prototype, "data", { - get: function () { - var pos = 0; - var header = new Uint8Array(this.length); - var encoder = new TextEncoder(); - header.set(encoder.encode(CryptorHeader.SENTINEL)); - pos += CryptorHeader.SENTINEL.length; - header[pos] = this.version; - pos++; - if (this.identifier) - header.set(encoder.encode(this.identifier), pos); - pos += CryptorHeader.IDENTIFIER_LENGTH; - var metadataLength = this.metadataLength; - if (metadataLength < 255) { - header[pos] = metadataLength; - } - else { - header.set([255, metadataLength >> 8, metadataLength & 0xff], pos); - } - return header; - }, - enumerable: false, - configurable: true - }); - CryptorHeaderV1.IDENTIFIER_LENGTH = 4; - CryptorHeaderV1.SENTINEL = 'PNED'; - return CryptorHeaderV1; + return default_1; }()); /* eslint no-bitwise: ["error", { "allow": ["~", "&", ">>"] }] */ - function sendBeacon(url) { - if (navigator && navigator.sendBeacon) { - navigator.sendBeacon(url); - } - else { - return false; - } - } - var default_1 = /** @class */ (function (_super) { - __extends(default_1, _super); - function default_1(setup) { + /* global navigator, window */ + /** + * PubNub client for browser platform. + */ + var PubNub = /** @class */ (function (_super) { + __extends(PubNub, _super); + function PubNub(configuration) { var _this = this; - // extract config. - var _a = setup.listenToBrowserNetworkEvents, listenToBrowserNetworkEvents = _a === void 0 ? true : _a; - setup.sdkFamily = 'Web'; - setup.networking = new default_1$2({ - del: del, - get: get, - post: post, - patch: patch, - sendBeacon: sendBeacon, - getfile: getfile, - postfile: postfile, - }); - setup.cbor = new default_1$1(function (arrayBuffer) { return stringifyBufferKeys(CborReader.decode(arrayBuffer)); }, decode$1); - setup.PubNubFile = PubNubFile; - setup.cryptography = new WebCryptography(); - setup.initCryptoModule = function (cryptoConfiguration) { - return new CryptoModule({ - default: new LegacyCryptor({ - cipherKey: cryptoConfiguration.cipherKey, - useRandomIVs: cryptoConfiguration.useRandomIVs, - }), + var _a; + var configurationCopy = setDefaults(configuration); + var platformConfiguration = __assign(__assign({}, configurationCopy), { sdkFamily: 'Nodejs', PubNubFile: PubNubFile }); + // Prepare full client configuration. + var clientConfiguration = makeConfiguration(platformConfiguration, function (cryptoConfiguration) { + if (!cryptoConfiguration.cipherKey) + return undefined; + return new WebCryptoModule({ + default: new LegacyCryptor(__assign({}, cryptoConfiguration)), cryptors: [new AesCbcCryptor({ cipherKey: cryptoConfiguration.cipherKey })], }); - }; - _this = _super.call(this, setup) || this; - if (listenToBrowserNetworkEvents) { - // mount network events. + }); + // Prepare Token manager. + var tokenManager = new default_1$2(new default_1(function (arrayBuffer) { return stringifyBufferKeys(CborReader.decode(arrayBuffer)); }, decode)); + // Legacy crypto (legacy data encryption / decryption and request signature support). + var crypto; + if (clientConfiguration.cipherKey || clientConfiguration.secretKey) { + var secretKey = clientConfiguration.secretKey, cipherKey = clientConfiguration.cipherKey, useRandomIVs = clientConfiguration.useRandomIVs, customEncrypt = clientConfiguration.customEncrypt, customDecrypt = clientConfiguration.customDecrypt; + crypto = new default_1$3({ secretKey: secretKey, cipherKey: cipherKey, useRandomIVs: useRandomIVs, customEncrypt: customEncrypt, customDecrypt: customDecrypt }); + } + // Setup transport provider. + var transportMiddleware = new PubNubMiddleware({ + clientConfiguration: clientConfiguration, + tokenManager: tokenManager, + transport: new WebTransport(clientConfiguration.keepAlive, clientConfiguration.logVerbosity), + }); + _this = _super.call(this, { + configuration: clientConfiguration, + transport: transportMiddleware, + cryptography: new WebCryptography(), + tokenManager: tokenManager, + crypto: crypto, + }) || this; + if ((_a = configuration.listenToBrowserNetworkEvents) !== null && _a !== void 0 ? _a : true) { window.addEventListener('offline', function () { _this.networkDownDetected(); }); @@ -14630,10 +13765,24 @@ } return _this; } - default_1.CryptoModule = CryptoModule; - return default_1; - }(default_1$3)); + PubNub.prototype.networkDownDetected = function () { + this.listenerManager.announceNetworkDown(); + if (this._configuration.restore) + this.disconnect(); + else + this.destroy(true); + }; + PubNub.prototype.networkUpDetected = function () { + this.listenerManager.announceNetworkUp(); + this.reconnect(); + }; + /** + * Data encryption / decryption module constructor. + */ + PubNub.CryptoModule = WebCryptoModule; + return PubNub; + }(PubNubCore)); - return default_1; + return PubNub; })); diff --git a/dist/web/pubnub.min.js b/dist/web/pubnub.min.js index 97c551cf2..cff9a9e9b 100644 --- a/dist/web/pubnub.min.js +++ b/dist/web/pubnub.min.js @@ -1,17 +1,2 @@ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).PubNub=t()}(this,(function(){"use strict"; -/*! ***************************************************************************** - Copyright (c) Microsoft Corporation. - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY - AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - PERFORMANCE OF THIS SOFTWARE. - ***************************************************************************** */var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])},e(t,n)};function t(t,n){if("function"!=typeof n&&null!==n)throw new TypeError("Class extends value "+String(n)+" is not a constructor or null");function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}var n=function(){return n=Object.assign||function(e){for(var t,n=1,r=arguments.length;n0&&o[o.length-1])||6!==i[0]&&2!==i[0])){s=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]=e.length&&(e=void 0),{value:e&&e[r++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function a(e,t){var n="function"==typeof Symbol&&e[Symbol.iterator];if(!n)return e;var r,o,i=n.call(e),s=[];try{for(;(void 0===t||t-- >0)&&!(r=i.next()).done;)s.push(r.value)}catch(e){o={error:e}}finally{try{r&&!r.done&&(n=i.return)&&n.call(i)}finally{if(o)throw o.error}}return s}function u(e,t,n){if(n||2===arguments.length)for(var r,o=0,i=t.length;o>2,c=0;c>6),o.push(128|63&s)):s<55296?(o.push(224|s>>12),o.push(128|s>>6&63),o.push(128|63&s)):(s=(1023&s)<<10,s|=1023&t.charCodeAt(++r),s+=65536,o.push(240|s>>18),o.push(128|s>>12&63),o.push(128|s>>6&63),o.push(128|63&s))}return h(3,o.length),p(o);default:var f;if(Array.isArray(t))for(h(4,f=t.length),r=0;r>5!==e)throw"Invalid indefinite length element";return n}function g(e,t){for(var n=0;n>10),e.push(56320|1023&r))}}"function"!=typeof t&&(t=function(e){return e}),"function"!=typeof i&&(i=function(){return n});var m=function e(){var o,h,m=l(),b=m>>5,v=31&m;if(7===b)switch(v){case 25:return function(){var e=new ArrayBuffer(4),t=new DataView(e),n=p(),o=32768&n,i=31744&n,s=1023&n;if(31744===i)i=261120;else if(0!==i)i+=114688;else if(0!==s)return s*r;return t.setUint32(0,o<<16|i<<13|s<<13),t.getFloat32(0)}();case 26:return u(s.getFloat32(a),4);case 27:return u(s.getFloat64(a),8)}if((h=d(v))<0&&(b<2||6=0;)S+=h,_.push(c(h));var w=new Uint8Array(S),O=0;for(o=0;o<_.length;++o)w.set(_[o],O),O+=_[o].length;return w}return c(h);case 3:var P=[];if(h<0)for(;(h=y(b))>=0;)g(P,h);else g(P,h);return String.fromCharCode.apply(null,P);case 4:var E;if(h<0)for(E=[];!f();)E.push(e());else for(E=new Array(h),o=0;o=20?this._presenceTimeout=e:(this._presenceTimeout=20,console.log("WARNING: Presence timeout is less than the minimum. Using minimum value: ",this._presenceTimeout)),this.setHeartbeatInterval(this._presenceTimeout/2-1),this},e.prototype.setProxy=function(e){this.proxy=e},e.prototype.getHeartbeatInterval=function(){return this._heartbeatInterval},e.prototype.setHeartbeatInterval=function(e){return this._heartbeatInterval=e,this},e.prototype.getSubscribeTimeout=function(){return this._subscribeRequestTimeout},e.prototype.setSubscribeTimeout=function(e){return this._subscribeRequestTimeout=e,this},e.prototype.getTransactionTimeout=function(){return this._transactionalRequestTimeout},e.prototype.setTransactionTimeout=function(e){return this._transactionalRequestTimeout=e,this},e.prototype.isSendBeaconEnabled=function(){return this._useSendBeacon},e.prototype.setSendBeaconConfig=function(e){return this._useSendBeacon=e,this},e.prototype.getVersion=function(){return"7.6.0"},e.prototype._setRetryConfiguration=function(e){if(e.minimumdelay<2)throw new Error("Minimum delay can not be set less than 2 seconds for retry");if(e.maximumDelay>150)throw new Error("Maximum delay can not be set more than 150 seconds for retry");if(e.maximumDelay&&maximumRetry>6)throw new Error("Maximum retry for exponential retry policy can not be more than 6");if(e.maximumRetry>10)throw new Error("Maximum retry for linear retry policy can not be more than 10");this.retryConfiguration=e},e.prototype._addPnsdkSuffix=function(e,t){this._PNSDKSuffix[e]=t},e.prototype._getPnsdkSuffix=function(e){var t=this;return Object.keys(this._PNSDKSuffix).reduce((function(n,r){return n+e+t._PNSDKSuffix[r]}),"")},e}();function m(e){var t=e.replace(/==?$/,""),n=Math.floor(t.length/4*3),r=new ArrayBuffer(n),o=new Uint8Array(r),i=0;function s(){var e=t.charAt(i++),n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(e);if(-1===n)throw new Error("Illegal character at ".concat(i,": ").concat(t.charAt(i-1)));return n}for(var a=0;a>4,f=(15&c)<<4|l>>2,d=(3&l)<<6|p>>0;o[a]=h,64!=l&&(o[a+1]=f),64!=p&&(o[a+2]=d)}return r}function b(e){for(var t,n="",r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",o=new Uint8Array(e),i=o.byteLength,s=i%3,a=i-s,u=0;u>18]+r[(258048&t)>>12]+r[(4032&t)>>6]+r[63&t];return 1==s?n+=r[(252&(t=o[a]))>>2]+r[(3&t)<<4]+"==":2==s&&(n+=r[(64512&(t=o[a]<<8|o[a+1]))>>10]+r[(1008&t)>>4]+r[(15&t)<<2]+"="),n}var v,_,S,w,O,P=P||function(e,t){var n={},r=n.lib={},o=function(){},i=r.Base={extend:function(e){o.prototype=this;var t=new o;return e&&t.mixIn(e),t.hasOwnProperty("init")||(t.init=function(){t.$super.init.apply(this,arguments)}),t.init.prototype=t,t.$super=this,t},create:function(){var e=this.extend();return e.init.apply(e,arguments),e},init:function(){},mixIn:function(e){for(var t in e)e.hasOwnProperty(t)&&(this[t]=e[t]);e.hasOwnProperty("toString")&&(this.toString=e.toString)},clone:function(){return this.init.prototype.extend(this)}},s=r.WordArray=i.extend({init:function(e,t){e=this.words=e||[],this.sigBytes=null!=t?t:4*e.length},toString:function(e){return(e||u).stringify(this)},concat:function(e){var t=this.words,n=e.words,r=this.sigBytes;if(e=e.sigBytes,this.clamp(),r%4)for(var o=0;o>>2]|=(n[o>>>2]>>>24-o%4*8&255)<<24-(r+o)%4*8;else if(65535>>2]=n[o>>>2];else t.push.apply(t,n);return this.sigBytes+=e,this},clamp:function(){var t=this.words,n=this.sigBytes;t[n>>>2]&=4294967295<<32-n%4*8,t.length=e.ceil(n/4)},clone:function(){var e=i.clone.call(this);return e.words=this.words.slice(0),e},random:function(t){for(var n=[],r=0;r>>2]>>>24-r%4*8&255;n.push((o>>>4).toString(16)),n.push((15&o).toString(16))}return n.join("")},parse:function(e){for(var t=e.length,n=[],r=0;r>>3]|=parseInt(e.substr(r,2),16)<<24-r%8*4;return new s.init(n,t/2)}},c=a.Latin1={stringify:function(e){var t=e.words;e=e.sigBytes;for(var n=[],r=0;r>>2]>>>24-r%4*8&255));return n.join("")},parse:function(e){for(var t=e.length,n=[],r=0;r>>2]|=(255&e.charCodeAt(r))<<24-r%4*8;return new s.init(n,t)}},l=a.Utf8={stringify:function(e){try{return decodeURIComponent(escape(c.stringify(e)))}catch(e){throw Error("Malformed UTF-8 data")}},parse:function(e){return c.parse(unescape(encodeURIComponent(e)))}},p=r.BufferedBlockAlgorithm=i.extend({reset:function(){this._data=new s.init,this._nDataBytes=0},_append:function(e){"string"==typeof e&&(e=l.parse(e)),this._data.concat(e),this._nDataBytes+=e.sigBytes},_process:function(t){var n=this._data,r=n.words,o=n.sigBytes,i=this.blockSize,a=o/(4*i);if(t=(a=t?e.ceil(a):e.max((0|a)-this._minBufferSize,0))*i,o=e.min(4*t,o),t){for(var u=0;uc;){var l;e:{l=u;for(var p=e.sqrt(l),h=2;h<=p;h++)if(!(l%h)){l=!1;break e}l=!0}l&&(8>c&&(i[c]=a(e.pow(u,.5))),s[c]=a(e.pow(u,1/3)),c++),u++}var f=[];o=o.SHA256=r.extend({_doReset:function(){this._hash=new n.init(i.slice(0))},_doProcessBlock:function(e,t){for(var n=this._hash.words,r=n[0],o=n[1],i=n[2],a=n[3],u=n[4],c=n[5],l=n[6],p=n[7],h=0;64>h;h++){if(16>h)f[h]=0|e[t+h];else{var d=f[h-15],y=f[h-2];f[h]=((d<<25|d>>>7)^(d<<14|d>>>18)^d>>>3)+f[h-7]+((y<<15|y>>>17)^(y<<13|y>>>19)^y>>>10)+f[h-16]}d=p+((u<<26|u>>>6)^(u<<21|u>>>11)^(u<<7|u>>>25))+(u&c^~u&l)+s[h]+f[h],y=((r<<30|r>>>2)^(r<<19|r>>>13)^(r<<10|r>>>22))+(r&o^r&i^o&i),p=l,l=c,c=u,u=a+d|0,a=i,i=o,o=r,r=d+y|0}n[0]=n[0]+r|0,n[1]=n[1]+o|0,n[2]=n[2]+i|0,n[3]=n[3]+a|0,n[4]=n[4]+u|0,n[5]=n[5]+c|0,n[6]=n[6]+l|0,n[7]=n[7]+p|0},_doFinalize:function(){var t=this._data,n=t.words,r=8*this._nDataBytes,o=8*t.sigBytes;return n[o>>>5]|=128<<24-o%32,n[14+(o+64>>>9<<4)]=e.floor(r/4294967296),n[15+(o+64>>>9<<4)]=r,t.sigBytes=4*n.length,this._process(),this._hash},clone:function(){var e=r.clone.call(this);return e._hash=this._hash.clone(),e}});t.SHA256=r._createHelper(o),t.HmacSHA256=r._createHmacHelper(o)}(Math),_=(v=P).enc.Utf8,v.algo.HMAC=v.lib.Base.extend({init:function(e,t){e=this._hasher=new e.init,"string"==typeof t&&(t=_.parse(t));var n=e.blockSize,r=4*n;t.sigBytes>r&&(t=e.finalize(t)),t.clamp();for(var o=this._oKey=t.clone(),i=this._iKey=t.clone(),s=o.words,a=i.words,u=0;u>>2]>>>24-o%4*8&255)<<16|(t[o+1>>>2]>>>24-(o+1)%4*8&255)<<8|t[o+2>>>2]>>>24-(o+2)%4*8&255,s=0;4>s&&o+.75*s>>6*(3-s)&63));if(t=r.charAt(64))for(;e.length%4;)e.push(t);return e.join("")},parse:function(e){var t=e.length,n=this._map;(r=n.charAt(64))&&-1!=(r=e.indexOf(r))&&(t=r);for(var r=[],o=0,i=0;i>>6-i%4*2;r[o>>>2]|=(s|a)<<24-o%4*8,o++}return w.create(r,o)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="},function(e){function t(e,t,n,r,o,i,s){return((e=e+(t&n|~t&r)+o+s)<>>32-i)+t}function n(e,t,n,r,o,i,s){return((e=e+(t&r|n&~r)+o+s)<>>32-i)+t}function r(e,t,n,r,o,i,s){return((e=e+(t^n^r)+o+s)<>>32-i)+t}function o(e,t,n,r,o,i,s){return((e=e+(n^(t|~r))+o+s)<>>32-i)+t}for(var i=P,s=(u=i.lib).WordArray,a=u.Hasher,u=i.algo,c=[],l=0;64>l;l++)c[l]=4294967296*e.abs(e.sin(l+1))|0;u=u.MD5=a.extend({_doReset:function(){this._hash=new s.init([1732584193,4023233417,2562383102,271733878])},_doProcessBlock:function(e,i){for(var s=0;16>s;s++){var a=e[u=i+s];e[u]=16711935&(a<<8|a>>>24)|4278255360&(a<<24|a>>>8)}s=this._hash.words;var u=e[i+0],l=(a=e[i+1],e[i+2]),p=e[i+3],h=e[i+4],f=e[i+5],d=e[i+6],y=e[i+7],g=e[i+8],m=e[i+9],b=e[i+10],v=e[i+11],_=e[i+12],S=e[i+13],w=e[i+14],O=e[i+15],P=t(P=s[0],T=s[1],A=s[2],E=s[3],u,7,c[0]),E=t(E,P,T,A,a,12,c[1]),A=t(A,E,P,T,l,17,c[2]),T=t(T,A,E,P,p,22,c[3]);P=t(P,T,A,E,h,7,c[4]),E=t(E,P,T,A,f,12,c[5]),A=t(A,E,P,T,d,17,c[6]),T=t(T,A,E,P,y,22,c[7]),P=t(P,T,A,E,g,7,c[8]),E=t(E,P,T,A,m,12,c[9]),A=t(A,E,P,T,b,17,c[10]),T=t(T,A,E,P,v,22,c[11]),P=t(P,T,A,E,_,7,c[12]),E=t(E,P,T,A,S,12,c[13]),A=t(A,E,P,T,w,17,c[14]),P=n(P,T=t(T,A,E,P,O,22,c[15]),A,E,a,5,c[16]),E=n(E,P,T,A,d,9,c[17]),A=n(A,E,P,T,v,14,c[18]),T=n(T,A,E,P,u,20,c[19]),P=n(P,T,A,E,f,5,c[20]),E=n(E,P,T,A,b,9,c[21]),A=n(A,E,P,T,O,14,c[22]),T=n(T,A,E,P,h,20,c[23]),P=n(P,T,A,E,m,5,c[24]),E=n(E,P,T,A,w,9,c[25]),A=n(A,E,P,T,p,14,c[26]),T=n(T,A,E,P,g,20,c[27]),P=n(P,T,A,E,S,5,c[28]),E=n(E,P,T,A,l,9,c[29]),A=n(A,E,P,T,y,14,c[30]),P=r(P,T=n(T,A,E,P,_,20,c[31]),A,E,f,4,c[32]),E=r(E,P,T,A,g,11,c[33]),A=r(A,E,P,T,v,16,c[34]),T=r(T,A,E,P,w,23,c[35]),P=r(P,T,A,E,a,4,c[36]),E=r(E,P,T,A,h,11,c[37]),A=r(A,E,P,T,y,16,c[38]),T=r(T,A,E,P,b,23,c[39]),P=r(P,T,A,E,S,4,c[40]),E=r(E,P,T,A,u,11,c[41]),A=r(A,E,P,T,p,16,c[42]),T=r(T,A,E,P,d,23,c[43]),P=r(P,T,A,E,m,4,c[44]),E=r(E,P,T,A,_,11,c[45]),A=r(A,E,P,T,O,16,c[46]),P=o(P,T=r(T,A,E,P,l,23,c[47]),A,E,u,6,c[48]),E=o(E,P,T,A,y,10,c[49]),A=o(A,E,P,T,w,15,c[50]),T=o(T,A,E,P,f,21,c[51]),P=o(P,T,A,E,_,6,c[52]),E=o(E,P,T,A,p,10,c[53]),A=o(A,E,P,T,b,15,c[54]),T=o(T,A,E,P,a,21,c[55]),P=o(P,T,A,E,g,6,c[56]),E=o(E,P,T,A,O,10,c[57]),A=o(A,E,P,T,d,15,c[58]),T=o(T,A,E,P,S,21,c[59]),P=o(P,T,A,E,h,6,c[60]),E=o(E,P,T,A,v,10,c[61]),A=o(A,E,P,T,l,15,c[62]),T=o(T,A,E,P,m,21,c[63]);s[0]=s[0]+P|0,s[1]=s[1]+T|0,s[2]=s[2]+A|0,s[3]=s[3]+E|0},_doFinalize:function(){var t=this._data,n=t.words,r=8*this._nDataBytes,o=8*t.sigBytes;n[o>>>5]|=128<<24-o%32;var i=e.floor(r/4294967296);for(n[15+(o+64>>>9<<4)]=16711935&(i<<8|i>>>24)|4278255360&(i<<24|i>>>8),n[14+(o+64>>>9<<4)]=16711935&(r<<8|r>>>24)|4278255360&(r<<24|r>>>8),t.sigBytes=4*(n.length+1),this._process(),n=(t=this._hash).words,r=0;4>r;r++)o=n[r],n[r]=16711935&(o<<8|o>>>24)|4278255360&(o<<24|o>>>8);return t},clone:function(){var e=a.clone.call(this);return e._hash=this._hash.clone(),e}}),i.MD5=a._createHelper(u),i.HmacMD5=a._createHmacHelper(u)}(Math),function(){var e,t=P,n=(e=t.lib).Base,r=e.WordArray,o=(e=t.algo).EvpKDF=n.extend({cfg:n.extend({keySize:4,hasher:e.MD5,iterations:1}),init:function(e){this.cfg=this.cfg.extend(e)},compute:function(e,t){for(var n=(a=this.cfg).hasher.create(),o=r.create(),i=o.words,s=a.keySize,a=a.iterations;i.length>>2]}},t.BlockCipher=a.extend({cfg:a.cfg.extend({mode:u,padding:l}),reset:function(){a.reset.call(this);var e=(t=this.cfg).iv,t=t.mode;if(this._xformMode==this._ENC_XFORM_MODE)var n=t.createEncryptor;else n=t.createDecryptor,this._minBufferSize=1;this._mode=n.call(t,this,e&&e.words)},_doProcessBlock:function(e,t){this._mode.processBlock(e,t)},_doFinalize:function(){var e=this.cfg.padding;if(this._xformMode==this._ENC_XFORM_MODE){e.pad(this._data,this.blockSize);var t=this._process(!0)}else t=this._process(!0),e.unpad(t);return t},blockSize:4});var p=t.CipherParams=n.extend({init:function(e){this.mixIn(e)},toString:function(e){return(e||this.formatter).stringify(this)}}),h=(u=(f.format={}).OpenSSL={stringify:function(e){var t=e.ciphertext;return((e=e.salt)?r.create([1398893684,1701076831]).concat(e).concat(t):t).toString(i)},parse:function(e){var t=(e=i.parse(e)).words;if(1398893684==t[0]&&1701076831==t[1]){var n=r.create(t.slice(2,4));t.splice(0,4),e.sigBytes-=16}return p.create({ciphertext:e,salt:n})}},t.SerializableCipher=n.extend({cfg:n.extend({format:u}),encrypt:function(e,t,n,r){r=this.cfg.extend(r);var o=e.createEncryptor(n,r);return t=o.finalize(t),o=o.cfg,p.create({ciphertext:t,key:n,iv:o.iv,algorithm:e,mode:o.mode,padding:o.padding,blockSize:e.blockSize,formatter:r.format})},decrypt:function(e,t,n,r){return r=this.cfg.extend(r),t=this._parse(t,r.format),e.createDecryptor(n,r).finalize(t.ciphertext)},_parse:function(e,t){return"string"==typeof e?t.parse(e,this):e}})),f=(f.kdf={}).OpenSSL={execute:function(e,t,n,o){return o||(o=r.random(8)),e=s.create({keySize:t+n}).compute(e,o),n=r.create(e.words.slice(t),4*n),e.sigBytes=4*t,p.create({key:e,iv:n,salt:o})}},d=t.PasswordBasedCipher=h.extend({cfg:h.cfg.extend({kdf:f}),encrypt:function(e,t,n,r){return n=(r=this.cfg.extend(r)).kdf.execute(n,e.keySize,e.ivSize),r.iv=n.iv,(e=h.encrypt.call(this,e,t,n.key,r)).mixIn(n),e},decrypt:function(e,t,n,r){return r=this.cfg.extend(r),t=this._parse(t,r.format),n=r.kdf.execute(n,e.keySize,e.ivSize,t.salt),r.iv=n.iv,h.decrypt.call(this,e,t,n.key,r)}})}(),function(){for(var e=P,t=e.lib.BlockCipher,n=e.algo,r=[],o=[],i=[],s=[],a=[],u=[],c=[],l=[],p=[],h=[],f=[],d=0;256>d;d++)f[d]=128>d?d<<1:d<<1^283;var y=0,g=0;for(d=0;256>d;d++){var m=(m=g^g<<1^g<<2^g<<3^g<<4)>>>8^255&m^99;r[y]=m,o[m]=y;var b=f[y],v=f[b],_=f[v],S=257*f[m]^16843008*m;i[y]=S<<24|S>>>8,s[y]=S<<16|S>>>16,a[y]=S<<8|S>>>24,u[y]=S,S=16843009*_^65537*v^257*b^16843008*y,c[m]=S<<24|S>>>8,l[m]=S<<16|S>>>16,p[m]=S<<8|S>>>24,h[m]=S,y?(y=b^f[f[f[_^b]]],g^=f[f[g]]):y=g=1}var w=[0,1,2,4,8,16,32,64,128,27,54];n=n.AES=t.extend({_doReset:function(){for(var e=(n=this._key).words,t=n.sigBytes/4,n=4*((this._nRounds=t+6)+1),o=this._keySchedule=[],i=0;i>>24]<<24|r[s>>>16&255]<<16|r[s>>>8&255]<<8|r[255&s]):(s=r[(s=s<<8|s>>>24)>>>24]<<24|r[s>>>16&255]<<16|r[s>>>8&255]<<8|r[255&s],s^=w[i/t|0]<<24),o[i]=o[i-t]^s}for(e=this._invKeySchedule=[],t=0;tt||4>=i?s:c[r[s>>>24]]^l[r[s>>>16&255]]^p[r[s>>>8&255]]^h[r[255&s]]},encryptBlock:function(e,t){this._doCryptBlock(e,t,this._keySchedule,i,s,a,u,r)},decryptBlock:function(e,t){var n=e[t+1];e[t+1]=e[t+3],e[t+3]=n,this._doCryptBlock(e,t,this._invKeySchedule,c,l,p,h,o),n=e[t+1],e[t+1]=e[t+3],e[t+3]=n},_doCryptBlock:function(e,t,n,r,o,i,s,a){for(var u=this._nRounds,c=e[t]^n[0],l=e[t+1]^n[1],p=e[t+2]^n[2],h=e[t+3]^n[3],f=4,d=1;d>>24]^o[l>>>16&255]^i[p>>>8&255]^s[255&h]^n[f++],g=r[l>>>24]^o[p>>>16&255]^i[h>>>8&255]^s[255&c]^n[f++],m=r[p>>>24]^o[h>>>16&255]^i[c>>>8&255]^s[255&l]^n[f++];h=r[h>>>24]^o[c>>>16&255]^i[l>>>8&255]^s[255&p]^n[f++],c=y,l=g,p=m}y=(a[c>>>24]<<24|a[l>>>16&255]<<16|a[p>>>8&255]<<8|a[255&h])^n[f++],g=(a[l>>>24]<<24|a[p>>>16&255]<<16|a[h>>>8&255]<<8|a[255&c])^n[f++],m=(a[p>>>24]<<24|a[h>>>16&255]<<16|a[c>>>8&255]<<8|a[255&l])^n[f++],h=(a[h>>>24]<<24|a[c>>>16&255]<<16|a[l>>>8&255]<<8|a[255&p])^n[f++],e[t]=y,e[t+1]=g,e[t+2]=m,e[t+3]=h},keySize:8});e.AES=t._createHelper(n)}(),P.mode.ECB=((O=P.lib.BlockCipherMode.extend()).Encryptor=O.extend({processBlock:function(e,t){this._cipher.encryptBlock(e,t)}}),O.Decryptor=O.extend({processBlock:function(e,t){this._cipher.decryptBlock(e,t)}}),O);var E=P;function A(e){var t,n=[];for(t=0;t=this._config.maximumCacheSize&&this.hashHistory.shift(),this.hashHistory.push(this.getKey(e))},e.prototype.clearHistory=function(){this.hashHistory=[]},e}(),k={PNNetworkUpCategory:"PNNetworkUpCategory",PNNetworkDownCategory:"PNNetworkDownCategory",PNNetworkIssuesCategory:"PNNetworkIssuesCategory",PNTimeoutCategory:"PNTimeoutCategory",PNBadRequestCategory:"PNBadRequestCategory",PNAccessDeniedCategory:"PNAccessDeniedCategory",PNUnknownCategory:"PNUnknownCategory",PNReconnectedCategory:"PNReconnectedCategory",PNConnectedCategory:"PNConnectedCategory",PNRequestMessageCountExceededCategory:"PNRequestMessageCountExceededCategory",PNDisconnectedCategory:"PNDisconnectedCategory",PNConnectionErrorCategory:"PNConnectionErrorCategory",PNDisconnectedUnexpectedlyCategory:"PNDisconnectedUnexpectedlyCategory"},M=function(){function e(e){var t=e.subscribeEndpoint,n=e.leaveEndpoint,r=e.heartbeatEndpoint,o=e.setStateEndpoint,i=e.timeEndpoint,s=e.getFileUrl,a=e.config,u=e.crypto,c=e.listenerManager,l=e.cryptoModule,p=e.eventEmitter;this._listenerManager=c,this._config=a,this._leaveEndpoint=n,this._heartbeatEndpoint=r,this._setStateEndpoint=o,this._subscribeEndpoint=t,this._getFileUrl=s,this._crypto=u,this._cryptoModule=l,this._channels={},this._presenceChannels={},this._heartbeatChannels={},this._heartbeatChannelGroups={},this._channelGroups={},this._presenceChannelGroups={},this._pendingChannelSubscriptions=[],this._pendingChannelGroupSubscriptions=[],this._currentTimetoken=0,this._lastTimetoken=0,this._storedTimetoken=null,this._subscriptionStatusAnnounced=!1,this._isOnline=!0,this._reconnectionManager=new N({timeEndpoint:i}),this._dedupingManager=new C({config:a}),this._cryptoModule&&(this._decoder=new TextDecoder),this._eventEmitter=p}return e.prototype.adaptStateChange=function(e,t){var n=this,r=e.state,o=e.channels,i=void 0===o?[]:o,s=e.channelGroups,a=void 0===s?[]:s,u=e.withHeartbeat,c=void 0!==u&&u;if(i.forEach((function(e){e in n._channels&&(n._channels[e].state=r)})),a.forEach((function(e){e in n._channelGroups&&(n._channelGroups[e].state=r)})),c){var l={};return i.forEach((function(e){return l[e]=r})),a.forEach((function(e){return l[e]=r})),this._heartbeatEndpoint({channels:i,channelGroups:a,state:l},t)}return this._setStateEndpoint({state:r,channels:i,channelGroups:a},t)},e.prototype.adaptPresenceChange=function(e){var t=this,n=e.connected,r=e.channels,o=void 0===r?[]:r,i=e.channelGroups,s=void 0===i?[]:i;n?(o.forEach((function(e){t._heartbeatChannels[e]={state:{}}})),s.forEach((function(e){t._heartbeatChannelGroups[e]={state:{}}}))):(o.forEach((function(e){e in t._heartbeatChannels&&delete t._heartbeatChannels[e]})),s.forEach((function(e){e in t._heartbeatChannelGroups&&delete t._heartbeatChannelGroups[e]})),!1===this._config.suppressLeaveEvents&&this._leaveEndpoint({channels:o,channelGroups:s},(function(e){t._listenerManager.announceStatus(e)}))),this.reconnect()},e.prototype.adaptSubscribeChange=function(e){var t=this,n=e.timetoken,r=e.channels,o=void 0===r?[]:r,i=e.channelGroups,s=void 0===i?[]:i,a=e.withPresence,u=void 0!==a&&a,c=e.withHeartbeats,l=void 0!==c&&c;this._config.subscribeKey&&""!==this._config.subscribeKey?(n&&(this._lastTimetoken=this._currentTimetoken,this._currentTimetoken=n),"0"!==this._currentTimetoken&&0!==this._currentTimetoken&&(this._storedTimetoken=this._currentTimetoken,this._currentTimetoken=0),o.forEach((function(e){t._channels[e]={state:{}},u&&(t._presenceChannels[e]={}),(l||t._config.getHeartbeatInterval())&&(t._heartbeatChannels[e]={}),t._pendingChannelSubscriptions.push(e)})),s.forEach((function(e){t._channelGroups[e]={state:{}},u&&(t._presenceChannelGroups[e]={}),(l||t._config.getHeartbeatInterval())&&(t._heartbeatChannelGroups[e]={}),t._pendingChannelGroupSubscriptions.push(e)})),this._subscriptionStatusAnnounced=!1,this.reconnect()):console&&console.log&&console.log("subscribe key missing; aborting subscribe")},e.prototype.adaptUnsubscribeChange=function(e,t){var n=this,r=e.channels,o=void 0===r?[]:r,i=e.channelGroups,s=void 0===i?[]:i,a=[],u=[];o.forEach((function(e){e in n._channels&&(delete n._channels[e],a.push(e),e in n._heartbeatChannels&&delete n._heartbeatChannels[e]),e in n._presenceChannels&&(delete n._presenceChannels[e],a.push(e))})),s.forEach((function(e){e in n._channelGroups&&(delete n._channelGroups[e],u.push(e),e in n._heartbeatChannelGroups&&delete n._heartbeatChannelGroups[e]),e in n._presenceChannelGroups&&(delete n._presenceChannelGroups[e],u.push(e))})),0===a.length&&0===u.length||(!1!==this._config.suppressLeaveEvents||t||this._leaveEndpoint({channels:a,channelGroups:u},(function(e){e.affectedChannels=a,e.affectedChannelGroups=u,e.currentTimetoken=n._currentTimetoken,e.lastTimetoken=n._lastTimetoken,n._listenerManager.announceStatus(e)})),0===Object.keys(this._channels).length&&0===Object.keys(this._presenceChannels).length&&0===Object.keys(this._channelGroups).length&&0===Object.keys(this._presenceChannelGroups).length&&(this._lastTimetoken=0,this._currentTimetoken=0,this._storedTimetoken=null,this._region=null,this._reconnectionManager.stopPolling()),this.reconnect())},e.prototype.unsubscribeAll=function(e){this.adaptUnsubscribeChange({channels:this.getSubscribedChannels(),channelGroups:this.getSubscribedChannelGroups()},e)},e.prototype.getHeartbeatChannels=function(){return Object.keys(this._heartbeatChannels)},e.prototype.getHeartbeatChannelGroups=function(){return Object.keys(this._heartbeatChannelGroups)},e.prototype.getSubscribedChannels=function(){return Object.keys(this._channels)},e.prototype.getSubscribedChannelGroups=function(){return Object.keys(this._channelGroups)},e.prototype.reconnect=function(){this._startSubscribeLoop(),this._registerHeartbeatTimer()},e.prototype.disconnect=function(){this._stopSubscribeLoop(),this._stopHeartbeatTimer(),this._reconnectionManager.stopPolling()},e.prototype._registerHeartbeatTimer=function(){this._stopHeartbeatTimer(),0!==this._config.getHeartbeatInterval()&&void 0!==this._config.getHeartbeatInterval()&&(this._performHeartbeatLoop(),this._heartbeatTimer=setInterval(this._performHeartbeatLoop.bind(this),1e3*this._config.getHeartbeatInterval()))},e.prototype._stopHeartbeatTimer=function(){this._heartbeatTimer&&(clearInterval(this._heartbeatTimer),this._heartbeatTimer=null)},e.prototype._performHeartbeatLoop=function(){var e=this,t=this.getHeartbeatChannels(),n=this.getHeartbeatChannelGroups(),r={};if(0!==t.length||0!==n.length){this.getSubscribedChannels().forEach((function(t){var n=e._channels[t].state;Object.keys(n).length&&(r[t]=n)})),this.getSubscribedChannelGroups().forEach((function(t){var n=e._channelGroups[t].state;Object.keys(n).length&&(r[t]=n)}));this._heartbeatEndpoint({channels:t,channelGroups:n,state:r},function(t){t.error&&e._config.announceFailedHeartbeats&&e._listenerManager.announceStatus(t),t.error&&e._config.autoNetworkDetection&&e._isOnline&&(e._isOnline=!1,e.disconnect(),e._listenerManager.announceNetworkDown(),e.reconnect()),!t.error&&e._config.announceSuccessfulHeartbeats&&e._listenerManager.announceStatus(t)}.bind(this))}},e.prototype._startSubscribeLoop=function(){var e=this;this._stopSubscribeLoop();var t={},n=[],r=[];if(Object.keys(this._channels).forEach((function(r){var o=e._channels[r].state;Object.keys(o).length&&(t[r]=o),n.push(r)})),Object.keys(this._presenceChannels).forEach((function(e){n.push("".concat(e,"-pnpres"))})),Object.keys(this._channelGroups).forEach((function(n){var o=e._channelGroups[n].state;Object.keys(o).length&&(t[n]=o),r.push(n)})),Object.keys(this._presenceChannelGroups).forEach((function(e){r.push("".concat(e,"-pnpres"))})),0!==n.length||0!==r.length){var o={channels:n,channelGroups:r,state:t,timetoken:this._currentTimetoken,filterExpression:this._config.filterExpression,region:this._region};this._subscribeCall=this._subscribeEndpoint(o,this._processSubscribeResponse.bind(this))}},e.prototype._processSubscribeResponse=function(e,t){var n=this;if(e.error){if(e.errorData&&"Aborted"===e.errorData.message)return;e.category===k.PNTimeoutCategory?this._startSubscribeLoop():e.category===k.PNNetworkIssuesCategory?(this.disconnect(),e.error&&this._config.autoNetworkDetection&&this._isOnline&&(this._isOnline=!1,this._listenerManager.announceNetworkDown()),this._reconnectionManager.onReconnection((function(){n._config.autoNetworkDetection&&!n._isOnline&&(n._isOnline=!0,n._listenerManager.announceNetworkUp()),n.reconnect(),n._subscriptionStatusAnnounced=!0;var t={category:k.PNReconnectedCategory,operation:e.operation,lastTimetoken:n._lastTimetoken,currentTimetoken:n._currentTimetoken};n._listenerManager.announceStatus(t)})),this._reconnectionManager.startPolling(),this._listenerManager.announceStatus(e)):e.category===k.PNBadRequestCategory?(this._stopHeartbeatTimer(),this._listenerManager.announceStatus(e)):this._listenerManager.announceStatus(e)}else{if(this._storedTimetoken?(this._currentTimetoken=this._storedTimetoken,this._storedTimetoken=null):(this._lastTimetoken=this._currentTimetoken,this._currentTimetoken=t.metadata.timetoken),!this._subscriptionStatusAnnounced){var r={};r.category=k.PNConnectedCategory,r.operation=e.operation,r.affectedChannels=this._pendingChannelSubscriptions,r.subscribedChannels=this.getSubscribedChannels(),r.affectedChannelGroups=this._pendingChannelGroupSubscriptions,r.lastTimetoken=this._lastTimetoken,r.currentTimetoken=this._currentTimetoken,this._subscriptionStatusAnnounced=!0,this._listenerManager.announceStatus(r),this._pendingChannelSubscriptions=[],this._pendingChannelGroupSubscriptions=[]}var o=t.messages||[],i=this._config,s=i.requestMessageCountThreshold,a=i.dedupeOnSubscribe;if(s&&o.length>=s){var u={};u.category=k.PNRequestMessageCountExceededCategory,u.operation=e.operation,this._listenerManager.announceStatus(u)}o.forEach((function(e){if(e.channel,e.subscriptionMatch,a){if(n._dedupingManager.isDuplicate(e))return;n._dedupingManager.addEntry(e)}n._eventEmitter.emitEvent(e)})),this._region=t.metadata.region,this._startSubscribeLoop()}},e.prototype._stopSubscribeLoop=function(){this._subscribeCall&&("function"==typeof this._subscribeCall.abort&&this._subscribeCall.abort(),this._subscribeCall=null)},e.prototype._renameEvent=function(e){return"set"===e?"updated":"removed"},e.prototype._renameChannelField=function(e){var t=e.channel,n=r(e,["channel"]);return n.spaceId=t,n},e}(),j={PNTimeOperation:"PNTimeOperation",PNHistoryOperation:"PNHistoryOperation",PNDeleteMessagesOperation:"PNDeleteMessagesOperation",PNFetchMessagesOperation:"PNFetchMessagesOperation",PNMessageCounts:"PNMessageCountsOperation",PNSubscribeOperation:"PNSubscribeOperation",PNUnsubscribeOperation:"PNUnsubscribeOperation",PNPublishOperation:"PNPublishOperation",PNSignalOperation:"PNSignalOperation",PNAddMessageActionOperation:"PNAddActionOperation",PNRemoveMessageActionOperation:"PNRemoveMessageActionOperation",PNGetMessageActionsOperation:"PNGetMessageActionsOperation",PNCreateUserOperation:"PNCreateUserOperation",PNUpdateUserOperation:"PNUpdateUserOperation",PNDeleteUserOperation:"PNDeleteUserOperation",PNGetUserOperation:"PNGetUsersOperation",PNGetUsersOperation:"PNGetUsersOperation",PNCreateSpaceOperation:"PNCreateSpaceOperation",PNUpdateSpaceOperation:"PNUpdateSpaceOperation",PNDeleteSpaceOperation:"PNDeleteSpaceOperation",PNGetSpaceOperation:"PNGetSpacesOperation",PNGetSpacesOperation:"PNGetSpacesOperation",PNGetMembersOperation:"PNGetMembersOperation",PNUpdateMembersOperation:"PNUpdateMembersOperation",PNGetMembershipsOperation:"PNGetMembershipsOperation",PNUpdateMembershipsOperation:"PNUpdateMembershipsOperation",PNListFilesOperation:"PNListFilesOperation",PNGenerateUploadUrlOperation:"PNGenerateUploadUrlOperation",PNPublishFileOperation:"PNPublishFileOperation",PNGetFileUrlOperation:"PNGetFileUrlOperation",PNDownloadFileOperation:"PNDownloadFileOperation",PNGetAllUUIDMetadataOperation:"PNGetAllUUIDMetadataOperation",PNGetUUIDMetadataOperation:"PNGetUUIDMetadataOperation",PNSetUUIDMetadataOperation:"PNSetUUIDMetadataOperation",PNRemoveUUIDMetadataOperation:"PNRemoveUUIDMetadataOperation",PNGetAllChannelMetadataOperation:"PNGetAllChannelMetadataOperation",PNGetChannelMetadataOperation:"PNGetChannelMetadataOperation",PNSetChannelMetadataOperation:"PNSetChannelMetadataOperation",PNRemoveChannelMetadataOperation:"PNRemoveChannelMetadataOperation",PNSetMembersOperation:"PNSetMembersOperation",PNSetMembershipsOperation:"PNSetMembershipsOperation",PNPushNotificationEnabledChannelsOperation:"PNPushNotificationEnabledChannelsOperation",PNRemoveAllPushNotificationsOperation:"PNRemoveAllPushNotificationsOperation",PNWhereNowOperation:"PNWhereNowOperation",PNSetStateOperation:"PNSetStateOperation",PNHereNowOperation:"PNHereNowOperation",PNGetStateOperation:"PNGetStateOperation",PNHeartbeatOperation:"PNHeartbeatOperation",PNChannelGroupsOperation:"PNChannelGroupsOperation",PNRemoveGroupOperation:"PNRemoveGroupOperation",PNChannelsForGroupOperation:"PNChannelsForGroupOperation",PNAddChannelsToGroupOperation:"PNAddChannelsToGroupOperation",PNRemoveChannelsFromGroupOperation:"PNRemoveChannelsFromGroupOperation",PNAccessManagerGrant:"PNAccessManagerGrant",PNAccessManagerGrantToken:"PNAccessManagerGrantToken",PNAccessManagerAudit:"PNAccessManagerAudit",PNAccessManagerRevokeToken:"PNAccessManagerRevokeToken",PNHandshakeOperation:"PNHandshakeOperation",PNReceiveMessagesOperation:"PNReceiveMessagesOperation"},R=function(){function e(e){this._maximumSamplesCount=100,this._trackedLatencies={},this._latencies={},this._telemetryExcludeOperations=[j.PNSubscribeOperation,j.PNReceiveMessagesOperation,j.PNHandshakeOperation],this._maximumSamplesCount=e.maximumSamplesCount||this._maximumSamplesCount}return e.prototype.operationsLatencyForRequest=function(){var e=this,t={};return Object.keys(this._latencies).forEach((function(n){var r=e._latencies[n],o=e._averageLatency(r);o>0&&(t["l_".concat(n)]=o)})),t},e.prototype.startLatencyMeasure=function(e,t){!this._telemetryExcludeOperations.includes(e)&&t&&(this._trackedLatencies[t]=Date.now())},e.prototype.stopLatencyMeasure=function(e,t){if(!this._telemetryExcludeOperations.includes(e)&&t){var n=this._endpointName(e),r=this._latencies[n],o=this._trackedLatencies[t];r||(this._latencies[n]=[],r=this._latencies[n]),r.push(Date.now()-o),r.length>this._maximumSamplesCount&&r.splice(0,r.length-this._maximumSamplesCount),delete this._trackedLatencies[t]}},e.prototype._averageLatency=function(e){return Math.floor(e.reduce((function(e,t){return e+t}),0)/e.length)},e.prototype._endpointName=function(e){var t=null;switch(e){case j.PNPublishOperation:t="pub";break;case j.PNSignalOperation:t="sig";break;case j.PNHistoryOperation:case j.PNFetchMessagesOperation:case j.PNDeleteMessagesOperation:case j.PNMessageCounts:t="hist";break;case j.PNUnsubscribeOperation:case j.PNWhereNowOperation:case j.PNHereNowOperation:case j.PNHeartbeatOperation:case j.PNSetStateOperation:case j.PNGetStateOperation:t="pres";break;case j.PNAddChannelsToGroupOperation:case j.PNRemoveChannelsFromGroupOperation:case j.PNChannelGroupsOperation:case j.PNRemoveGroupOperation:case j.PNChannelsForGroupOperation:t="cg";break;case j.PNPushNotificationEnabledChannelsOperation:case j.PNRemoveAllPushNotificationsOperation:t="push";break;case j.PNCreateUserOperation:case j.PNUpdateUserOperation:case j.PNDeleteUserOperation:case j.PNGetUserOperation:case j.PNGetUsersOperation:case j.PNCreateSpaceOperation:case j.PNUpdateSpaceOperation:case j.PNDeleteSpaceOperation:case j.PNGetSpaceOperation:case j.PNGetSpacesOperation:case j.PNGetMembersOperation:case j.PNUpdateMembersOperation:case j.PNGetMembershipsOperation:case j.PNUpdateMembershipsOperation:t="obj";break;case j.PNAddMessageActionOperation:case j.PNRemoveMessageActionOperation:case j.PNGetMessageActionsOperation:t="msga";break;case j.PNAccessManagerGrant:case j.PNAccessManagerAudit:t="pam";break;case j.PNAccessManagerGrantToken:case j.PNAccessManagerRevokeToken:t="pamv3";break;default:t="time"}return t},e}(),x=function(){function e(e,t,n){this._payload=e,this._setDefaultPayloadStructure(),this.title=t,this.body=n}return Object.defineProperty(e.prototype,"payload",{get:function(){return this._payload},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"title",{set:function(e){this._title=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"subtitle",{set:function(e){this._subtitle=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"body",{set:function(e){this._body=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"badge",{set:function(e){this._badge=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"sound",{set:function(e){this._sound=e},enumerable:!1,configurable:!0}),e.prototype._setDefaultPayloadStructure=function(){},e.prototype.toObject=function(){return{}},e}(),U=function(e){function r(){return null!==e&&e.apply(this,arguments)||this}return t(r,e),Object.defineProperty(r.prototype,"configurations",{set:function(e){e&&e.length&&(this._configurations=e)},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"notification",{get:function(){return this._payload.aps},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"title",{get:function(){return this._title},set:function(e){e&&e.length&&(this._payload.aps.alert.title=e,this._title=e)},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"subtitle",{get:function(){return this._subtitle},set:function(e){e&&e.length&&(this._payload.aps.alert.subtitle=e,this._subtitle=e)},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"body",{get:function(){return this._body},set:function(e){e&&e.length&&(this._payload.aps.alert.body=e,this._body=e)},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"badge",{get:function(){return this._badge},set:function(e){null!=e&&(this._payload.aps.badge=e,this._badge=e)},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"sound",{get:function(){return this._sound},set:function(e){e&&e.length&&(this._payload.aps.sound=e,this._sound=e)},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"silent",{set:function(e){this._isSilent=e},enumerable:!1,configurable:!0}),r.prototype._setDefaultPayloadStructure=function(){this._payload.aps={alert:{}}},r.prototype.toObject=function(){var e=this,t=n({},this._payload),r=t.aps,o=r.alert;if(this._isSilent&&(r["content-available"]=1),"apns2"===this._apnsPushType){if(!this._configurations||!this._configurations.length)throw new ReferenceError("APNS2 configuration is missing");var i=[];this._configurations.forEach((function(t){i.push(e._objectFromAPNS2Configuration(t))})),i.length&&(t.pn_push=i)}return o&&Object.keys(o).length||delete r.alert,this._isSilent&&(delete r.alert,delete r.badge,delete r.sound,o={}),this._isSilent||Object.keys(o).length?t:null},r.prototype._objectFromAPNS2Configuration=function(e){var t=this;if(!e.targets||!e.targets.length)throw new ReferenceError("At least one APNS2 target should be provided");var n=[];e.targets.forEach((function(e){n.push(t._objectFromAPNSTarget(e))}));var r=e.collapseId,o=e.expirationDate,i={auth_method:"token",targets:n,version:"v2"};return r&&r.length&&(i.collapse_id=r),o&&(i.expiration=o.toISOString()),i},r.prototype._objectFromAPNSTarget=function(e){if(!e.topic||!e.topic.length)throw new TypeError("Target 'topic' undefined.");var t=e.topic,n=e.environment,r=void 0===n?"development":n,o=e.excludedDevices,i=void 0===o?[]:o,s={topic:t,environment:r};return i.length&&(s.excluded_devices=i),s},r}(x),I=function(e){function r(){return null!==e&&e.apply(this,arguments)||this}return t(r,e),Object.defineProperty(r.prototype,"backContent",{get:function(){return this._backContent},set:function(e){e&&e.length&&(this._payload.back_content=e,this._backContent=e)},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"backTitle",{get:function(){return this._backTitle},set:function(e){e&&e.length&&(this._payload.back_title=e,this._backTitle=e)},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"count",{get:function(){return this._count},set:function(e){null!=e&&(this._payload.count=e,this._count=e)},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"title",{get:function(){return this._title},set:function(e){e&&e.length&&(this._payload.title=e,this._title=e)},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"type",{get:function(){return this._type},set:function(e){e&&e.length&&(this._payload.type=e,this._type=e)},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"subtitle",{get:function(){return this.backTitle},set:function(e){this.backTitle=e},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"body",{get:function(){return this.backContent},set:function(e){this.backContent=e},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"badge",{get:function(){return this.count},set:function(e){this.count=e},enumerable:!1,configurable:!0}),r.prototype.toObject=function(){return Object.keys(this._payload).length?n({},this._payload):null},r}(x),D=function(e){function o(){return null!==e&&e.apply(this,arguments)||this}return t(o,e),Object.defineProperty(o.prototype,"notification",{get:function(){return this._payload.notification},enumerable:!1,configurable:!0}),Object.defineProperty(o.prototype,"data",{get:function(){return this._payload.data},enumerable:!1,configurable:!0}),Object.defineProperty(o.prototype,"title",{get:function(){return this._title},set:function(e){e&&e.length&&(this._payload.notification.title=e,this._title=e)},enumerable:!1,configurable:!0}),Object.defineProperty(o.prototype,"body",{get:function(){return this._body},set:function(e){e&&e.length&&(this._payload.notification.body=e,this._body=e)},enumerable:!1,configurable:!0}),Object.defineProperty(o.prototype,"sound",{get:function(){return this._sound},set:function(e){e&&e.length&&(this._payload.notification.sound=e,this._sound=e)},enumerable:!1,configurable:!0}),Object.defineProperty(o.prototype,"icon",{get:function(){return this._icon},set:function(e){e&&e.length&&(this._payload.notification.icon=e,this._icon=e)},enumerable:!1,configurable:!0}),Object.defineProperty(o.prototype,"tag",{get:function(){return this._tag},set:function(e){e&&e.length&&(this._payload.notification.tag=e,this._tag=e)},enumerable:!1,configurable:!0}),Object.defineProperty(o.prototype,"silent",{set:function(e){this._isSilent=e},enumerable:!1,configurable:!0}),o.prototype._setDefaultPayloadStructure=function(){this._payload.notification={},this._payload.data={}},o.prototype.toObject=function(){var e=n({},this._payload.data),t=null,o={};if(Object.keys(this._payload).length>2){var i=this._payload;i.notification,i.data;var s=r(i,["notification","data"]);e=n(n({},e),s)}return this._isSilent?e.notification=this._payload.notification:t=this._payload.notification,Object.keys(e).length&&(o.data=e),t&&Object.keys(t).length&&(o.notification=t),Object.keys(o).length?o:null},o}(x),F=function(){function e(e,t){this._payload={apns:{},mpns:{},fcm:{}},this._title=e,this._body=t,this.apns=new U(this._payload.apns,e,t),this.mpns=new I(this._payload.mpns,e,t),this.fcm=new D(this._payload.fcm,e,t)}return Object.defineProperty(e.prototype,"debugging",{set:function(e){this._debugging=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"title",{get:function(){return this._title},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"body",{get:function(){return this._body},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"subtitle",{get:function(){return this._subtitle},set:function(e){this._subtitle=e,this.apns.subtitle=e,this.mpns.subtitle=e,this.fcm.subtitle=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"badge",{get:function(){return this._badge},set:function(e){this._badge=e,this.apns.badge=e,this.mpns.badge=e,this.fcm.badge=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"sound",{get:function(){return this._sound},set:function(e){this._sound=e,this.apns.sound=e,this.mpns.sound=e,this.fcm.sound=e},enumerable:!1,configurable:!0}),e.prototype.buildPayload=function(e){var t={};if(e.includes("apns")||e.includes("apns2")){this.apns._apnsPushType=e.includes("apns")?"apns":"apns2";var n=this.apns.toObject();n&&Object.keys(n).length&&(t.pn_apns=n)}if(e.includes("mpns")){var r=this.mpns.toObject();r&&Object.keys(r).length&&(t.pn_mpns=r)}if(e.includes("fcm")){var o=this.fcm.toObject();o&&Object.keys(o).length&&(t.pn_gcm=o)}return Object.keys(t).length&&this._debugging&&(t.pn_debug=!0),t},e}(),L=function(){function e(){this._listeners=[]}return e.prototype.addListener=function(e){this._listeners.includes(e)||this._listeners.push(e)},e.prototype.removeListener=function(e){var t=[];this._listeners.forEach((function(n){n!==e&&t.push(n)})),this._listeners=t},e.prototype.removeAllListeners=function(){this._listeners=[]},e.prototype.announcePresence=function(e){this._listeners.forEach((function(t){t.presence&&t.presence(e)}))},e.prototype.announceStatus=function(e){this._listeners.forEach((function(t){t.status&&t.status(e)}))},e.prototype.announceMessage=function(e){this._listeners.forEach((function(t){t.message&&t.message(e)}))},e.prototype.announceSignal=function(e){this._listeners.forEach((function(t){t.signal&&t.signal(e)}))},e.prototype.announceMessageAction=function(e){this._listeners.forEach((function(t){t.messageAction&&t.messageAction(e)}))},e.prototype.announceFile=function(e){this._listeners.forEach((function(t){t.file&&t.file(e)}))},e.prototype.announceObjects=function(e){this._listeners.forEach((function(t){t.objects&&t.objects(e)}))},e.prototype.announceUser=function(e){this._listeners.forEach((function(t){t.user&&t.user(e)}))},e.prototype.announceSpace=function(e){this._listeners.forEach((function(t){t.space&&t.space(e)}))},e.prototype.announceMembership=function(e){this._listeners.forEach((function(t){t.membership&&t.membership(e)}))},e.prototype.announceNetworkUp=function(){var e={};e.category=k.PNNetworkUpCategory,this.announceStatus(e)},e.prototype.announceNetworkDown=function(){var e={};e.category=k.PNNetworkDownCategory,this.announceStatus(e)},e}(),G=function(){function e(e,t){this._config=e,this._cbor=t}return e.prototype.setToken=function(e){e&&e.length>0?this._token=e:this._token=void 0},e.prototype.getToken=function(){return this._token},e.prototype.extractPermissions=function(e){var t={read:!1,write:!1,manage:!1,delete:!1,get:!1,update:!1,join:!1};return 128==(128&e)&&(t.join=!0),64==(64&e)&&(t.update=!0),32==(32&e)&&(t.get=!0),8==(8&e)&&(t.delete=!0),4==(4&e)&&(t.manage=!0),2==(2&e)&&(t.write=!0),1==(1&e)&&(t.read=!0),t},e.prototype.parseToken=function(e){var t=this,n=this._cbor.decodeToken(e);if(void 0!==n){var r=n.res.uuid?Object.keys(n.res.uuid):[],o=Object.keys(n.res.chan),i=Object.keys(n.res.grp),s=n.pat.uuid?Object.keys(n.pat.uuid):[],a=Object.keys(n.pat.chan),u=Object.keys(n.pat.grp),c={version:n.v,timestamp:n.t,ttl:n.ttl,authorized_uuid:n.uuid},l=r.length>0,p=o.length>0,h=i.length>0;(l||p||h)&&(c.resources={},l&&(c.resources.uuids={},r.forEach((function(e){c.resources.uuids[e]=t.extractPermissions(n.res.uuid[e])}))),p&&(c.resources.channels={},o.forEach((function(e){c.resources.channels[e]=t.extractPermissions(n.res.chan[e])}))),h&&(c.resources.groups={},i.forEach((function(e){c.resources.groups[e]=t.extractPermissions(n.res.grp[e])}))));var f=s.length>0,d=a.length>0,y=u.length>0;return(f||d||y)&&(c.patterns={},f&&(c.patterns.uuids={},s.forEach((function(e){c.patterns.uuids[e]=t.extractPermissions(n.pat.uuid[e])}))),d&&(c.patterns.channels={},a.forEach((function(e){c.patterns.channels[e]=t.extractPermissions(n.pat.chan[e])}))),y&&(c.patterns.groups={},u.forEach((function(e){c.patterns.groups[e]=t.extractPermissions(n.pat.grp[e])})))),Object.keys(n.meta).length>0&&(c.meta=n.meta),c.signature=n.sig,c}},e}();function K(e){return encodeURIComponent(e).replace(/[!~*'()]/g,(function(e){return"%".concat(e.charCodeAt(0).toString(16).toUpperCase())}))}function B(e){return function(e){var t=[];return Object.keys(e).forEach((function(e){return t.push(e)})),t}(e).sort()}var H={signPamFromParams:function(e){return B(e).map((function(t){return"".concat(t,"=").concat(K(e[t]))})).join("&")},endsWith:function(e,t){return-1!==e.indexOf(t,this.length-t.length)},createPromise:function(){var e,t;return{promise:new Promise((function(n,r){e=n,t=r})),reject:t,fulfill:e}},encodeString:K,stringToArrayBuffer:function(e){for(var t=new ArrayBuffer(2*e.length),n=new Uint16Array(t),r=0,o=e.length;r0&&(t+=n),t}function J(e,t,n){return t.usePost&&t.usePost(e,n)?"POST":t.usePatch&&t.usePatch(e,n)?"PATCH":t.useDelete&&t.useDelete(e,n)?"DELETE":t.useGetFile&&t.useGetFile(e,n)?"GETFILE":"GET"}function $(e,t,n,r,o){var i=e.config,s=e.crypto,a=J(e,o,r);n.timestamp=Math.floor((new Date).getTime()/1e3),"PNPublishOperation"===o.getOperation()&&o.usePost&&o.usePost(e,r)&&(a="GET"),"GETFILE"===a&&(a="GET");var u="".concat(a,"\n").concat(i.publishKey,"\n").concat(t,"\n").concat(H.signPamFromParams(n),"\n");if("POST"===a)u+="string"==typeof(c=o.postPayload(e,r))?c:JSON.stringify(c);else if("PATCH"===a){var c;u+="string"==typeof(c=o.patchPayload(e,r))?c:JSON.stringify(c)}var l="v2.".concat(s.HMACSHA256(u));l=(l=(l=l.replace(/\+/g,"-")).replace(/\//g,"_")).replace(/=+$/,""),n.signature=l}function Q(e,t){for(var r=[],o=2;o0?o.join(","):",";return"/v2/presence/sub-key/".concat(n.subscribeKey,"/channel/").concat(H.encodeString(i),"/leave")},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n=t.channelGroups,r=void 0===n?[]:n,o={};return r.length>0&&(o["channel-group"]=r.join(",")),o},handleResponse:function(){return{}}});var ae=Object.freeze({__proto__:null,getOperation:function(){return j.PNWhereNowOperation},validateParams:function(e){if(!e.config.subscribeKey)return"Missing Subscribe Key"},getURL:function(e,t){var n=e.config,r=t.uuid,o=void 0===r?n.UUID:r;return"/v2/presence/sub-key/".concat(n.subscribeKey,"/uuid/").concat(H.encodeString(o))},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(){return{}},handleResponse:function(e,t){return t.payload?{channels:t.payload.channels}:{channels:[]}}});var ue=Object.freeze({__proto__:null,getOperation:function(){return j.PNHeartbeatOperation},validateParams:function(e){if(!e.config.subscribeKey)return"Missing Subscribe Key"},getURL:function(e,t){var n=e.config,r=t.channels,o=void 0===r?[]:r,i=o.length>0?o.join(","):",";return"/v2/presence/sub-key/".concat(n.subscribeKey,"/channel/").concat(H.encodeString(i),"/heartbeat")},isAuthSupported:function(){return!0},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},prepareParams:function(e,t){var n=t.channelGroups,r=void 0===n?[]:n,o=t.state,i=e.config,s={};return r.length>0&&(s["channel-group"]=r.join(",")),o&&(s.state=JSON.stringify(o)),s.heartbeat=i.getPresenceTimeout(),s},handleResponse:function(){return{}}});var ce=Object.freeze({__proto__:null,getOperation:function(){return j.PNGetStateOperation},validateParams:function(e){if(!e.config.subscribeKey)return"Missing Subscribe Key"},getURL:function(e,t){var n=e.config,r=t.uuid,o=void 0===r?n.UUID:r,i=t.channels,s=void 0===i?[]:i,a=s.length>0?s.join(","):",";return"/v2/presence/sub-key/".concat(n.subscribeKey,"/channel/").concat(H.encodeString(a),"/uuid/").concat(o)},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n=t.channelGroups,r=void 0===n?[]:n,o={};return r.length>0&&(o["channel-group"]=r.join(",")),o},handleResponse:function(e,t,n){var r=n.channels,o=void 0===r?[]:r,i=n.channelGroups,s=void 0===i?[]:i,a={};return 1===o.length&&0===s.length?a[o[0]]=t.payload:a=t.payload,{channels:a}}});var le=Object.freeze({__proto__:null,getOperation:function(){return j.PNSetStateOperation},validateParams:function(e,t){var n=e.config,r=t.state,o=t.channels,i=void 0===o?[]:o,s=t.channelGroups,a=void 0===s?[]:s;return r?n.subscribeKey?0===i.length&&0===a.length?"Please provide a list of channels and/or channel-groups":void 0:"Missing Subscribe Key":"Missing State"},getURL:function(e,t){var n=e.config,r=t.channels,o=void 0===r?[]:r,i=o.length>0?o.join(","):",";return"/v2/presence/sub-key/".concat(n.subscribeKey,"/channel/").concat(H.encodeString(i),"/uuid/").concat(H.encodeString(n.UUID),"/data")},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n=t.state,r=t.channelGroups,o=void 0===r?[]:r,i={};return i.state=JSON.stringify(n),o.length>0&&(i["channel-group"]=o.join(",")),i},handleResponse:function(e,t){return{state:t.payload}}});var pe=Object.freeze({__proto__:null,getOperation:function(){return j.PNHereNowOperation},validateParams:function(e){if(!e.config.subscribeKey)return"Missing Subscribe Key"},getURL:function(e,t){var n=e.config,r=t.channels,o=void 0===r?[]:r,i=t.channelGroups,s=void 0===i?[]:i,a="/v2/presence/sub-key/".concat(n.subscribeKey);if(o.length>0||s.length>0){var u=o.length>0?o.join(","):",";a+="/channel/".concat(H.encodeString(u))}return a},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var r=t.channelGroups,o=void 0===r?[]:r,i=t.includeUUIDs,s=void 0===i||i,a=t.includeState,u=void 0!==a&&a,c=t.queryParameters,l=void 0===c?{}:c,p={};return s||(p.disable_uuids=1),u&&(p.state=1),o.length>0&&(p["channel-group"]=o.join(",")),p=n(n({},p),l)},handleResponse:function(e,t,n){var r=n.channels,o=void 0===r?[]:r,i=n.channelGroups,s=void 0===i?[]:i,a=n.includeUUIDs,u=void 0===a||a,c=n.includeState,l=void 0!==c&&c;return o.length>1||s.length>0||0===s.length&&0===o.length?function(){var e={};return e.totalChannels=t.payload.total_channels,e.totalOccupancy=t.payload.total_occupancy,e.channels={},Object.keys(t.payload.channels).forEach((function(n){var r=t.payload.channels[n],o=[];return e.channels[n]={occupants:o,name:n,occupancy:r.occupancy},u&&r.uuids.forEach((function(e){l?o.push({state:e.state,uuid:e.uuid}):o.push({state:null,uuid:e})})),e})),e}():function(){var e={},n=[];return e.totalChannels=1,e.totalOccupancy=t.occupancy,e.channels={},e.channels[o[0]]={occupants:n,name:o[0],occupancy:t.occupancy},u&&t.uuids&&t.uuids.forEach((function(e){l?n.push({state:e.state,uuid:e.uuid}):n.push({state:null,uuid:e})})),e}()},handleError:function(e,t,n){402!==n.statusCode||this.getURL(e,t).includes("channel")||(n.errorData.message="You have tried to perform a Global Here Now operation, your keyset configuration does not support that. Please provide a channel, or enable the Global Here Now feature from the Portal.")}});var he=Object.freeze({__proto__:null,getOperation:function(){return j.PNAddMessageActionOperation},validateParams:function(e,t){var n=e.config,r=t.action,o=t.channel;return t.messageTimetoken?n.subscribeKey?o?r?r.value?r.type?r.type.length>15?"Action.type value exceed maximum length of 15":void 0:"Missing Action.type":"Missing Action.value":"Missing Action":"Missing message channel":"Missing Subscribe Key":"Missing message timetoken"},usePost:function(){return!0},postURL:function(e,t){var n=e.config,r=t.channel,o=t.messageTimetoken;return"/v1/message-actions/".concat(n.subscribeKey,"/channel/").concat(H.encodeString(r),"/message/").concat(o)},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},getRequestHeaders:function(){return{"Content-Type":"application/json"}},isAuthSupported:function(){return!0},prepareParams:function(){return{}},postPayload:function(e,t){return t.action},handleResponse:function(e,t){return{data:t.data}}});var fe=Object.freeze({__proto__:null,getOperation:function(){return j.PNRemoveMessageActionOperation},validateParams:function(e,t){var n=e.config,r=t.channel,o=t.actionTimetoken;return t.messageTimetoken?o?n.subscribeKey?r?void 0:"Missing message channel":"Missing Subscribe Key":"Missing action timetoken":"Missing message timetoken"},useDelete:function(){return!0},getURL:function(e,t){var n=e.config,r=t.channel,o=t.actionTimetoken,i=t.messageTimetoken;return"/v1/message-actions/".concat(n.subscribeKey,"/channel/").concat(H.encodeString(r),"/message/").concat(i,"/action/").concat(o)},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(){return{}},handleResponse:function(e,t){return{data:t.data}}});var de=Object.freeze({__proto__:null,getOperation:function(){return j.PNGetMessageActionsOperation},validateParams:function(e,t){var n=e.config,r=t.channel;return n.subscribeKey?r?void 0:"Missing message channel":"Missing Subscribe Key"},getURL:function(e,t){var n=e.config,r=t.channel;return"/v1/message-actions/".concat(n.subscribeKey,"/channel/").concat(H.encodeString(r))},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n=t.limit,r=t.start,o=t.end,i={};return n&&(i.limit=n),r&&(i.start=r),o&&(i.end=o),i},handleResponse:function(e,t){var n={data:t.data,start:null,end:null};return n.data.length&&(n.end=n.data[n.data.length-1].actionTimetoken,n.start=n.data[0].actionTimetoken),n}}),ye={getOperation:function(){return j.PNListFilesOperation},validateParams:function(e,t){if(!(null==t?void 0:t.channel))return"channel can't be empty"},getURL:function(e,t){var n=e.config;return"/v1/files/".concat(n.subscribeKey,"/channels/").concat(H.encodeString(t.channel),"/files")},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n={};return t.limit&&(n.limit=t.limit),t.next&&(n.next=t.next),n},handleResponse:function(e,t){return{status:t.status,data:t.data,next:t.next,count:t.count}}},ge={getOperation:function(){return j.PNGenerateUploadUrlOperation},validateParams:function(e,t){return(null==t?void 0:t.channel)?(null==t?void 0:t.name)?void 0:"name can't be empty":"channel can't be empty"},usePost:function(){return!0},postURL:function(e,t){var n=e.config;return"/v1/files/".concat(n.subscribeKey,"/channels/").concat(H.encodeString(t.channel),"/generate-upload-url")},postPayload:function(e,t){return{name:t.name}},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(){return{}},handleResponse:function(e,t){return{status:t.status,data:t.data,file_upload_request:t.file_upload_request}}},me={getOperation:function(){return j.PNPublishFileOperation},validateParams:function(e,t){return(null==t?void 0:t.channel)?(null==t?void 0:t.fileId)?(null==t?void 0:t.fileName)?void 0:"file name can't be empty":"file id can't be empty":"channel can't be empty"},getURL:function(e,t){var n=e.config,r=n.publishKey,o=n.subscribeKey,i=function(e,t){var n=JSON.stringify(t);if(e.cryptoModule){var r=e.cryptoModule.encrypt(n);n="string"==typeof r?r:b(r),n=JSON.stringify(n)}return n||""}(e,{message:t.message,file:{name:t.fileName,id:t.fileId}});return"/v1/files/publish-file/".concat(r,"/").concat(o,"/0/").concat(H.encodeString(t.channel),"/0/").concat(H.encodeString(i))},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n={};return t.ttl&&(n.ttl=t.ttl),void 0!==t.storeInHistory&&(n.store=t.storeInHistory?"1":"0"),t.meta&&"object"==typeof t.meta&&(n.meta=JSON.stringify(t.meta)),n},handleResponse:function(e,t){return{timetoken:t[2]}}},be=function(e){var t=function(e){var t=this,n=e.generateUploadUrl,r=e.publishFile,s=e.modules,a=s.PubNubFile,u=s.config,c=s.cryptography,l=s.cryptoModule,p=s.networking;return function(e){var s=e.channel,h=e.file,f=e.message,d=e.cipherKey,y=e.meta,g=e.ttl,m=e.storeInHistory;return o(t,void 0,void 0,(function(){var e,t,o,b,v,_,S,w,O,P,E,A,T,N,C,k,M,j,R,x,U,I,D,F,L,G,K,B,H;return i(this,(function(i){switch(i.label){case 0:if(!s)throw new q("Validation failed, check status for details",z("channel can't be empty"));if(!h)throw new q("Validation failed, check status for details",z("file can't be empty"));return e=a.create(h),[4,n({channel:s,name:e.name})];case 1:return t=i.sent(),o=t.file_upload_request,b=o.url,v=o.form_fields,_=t.data,S=_.id,w=_.name,a.supportsEncryptFile&&(d||l)?null!=d?[3,3]:[4,l.encryptFile(e,a)]:[3,6];case 2:return O=i.sent(),[3,5];case 3:return[4,c.encryptFile(d,e,a)];case 4:O=i.sent(),i.label=5;case 5:e=O,i.label=6;case 6:P=v,e.mimeType&&(P=v.map((function(t){return"Content-Type"===t.key?{key:t.key,value:e.mimeType}:t}))),i.label=7;case 7:return i.trys.push([7,21,,22]),a.supportsFileUri&&h.uri?(T=(A=p).POSTFILE,N=[b,P],[4,e.toFileUri()]):[3,10];case 8:return[4,T.apply(A,N.concat([i.sent()]))];case 9:return E=i.sent(),[3,20];case 10:return a.supportsFile?(k=(C=p).POSTFILE,M=[b,P],[4,e.toFile()]):[3,13];case 11:return[4,k.apply(C,M.concat([i.sent()]))];case 12:return E=i.sent(),[3,20];case 13:return a.supportsBuffer?(R=(j=p).POSTFILE,x=[b,P],[4,e.toBuffer()]):[3,16];case 14:return[4,R.apply(j,x.concat([i.sent()]))];case 15:return E=i.sent(),[3,20];case 16:return a.supportsBlob?(I=(U=p).POSTFILE,D=[b,P],[4,e.toBlob()]):[3,19];case 17:return[4,I.apply(U,D.concat([i.sent()]))];case 18:return E=i.sent(),[3,20];case 19:throw new Error("Unsupported environment");case 20:return[3,22];case 21:throw(F=i.sent()).response&&"string"==typeof F.response.text?(L=F.response.text,G=/(.*)<\/Message>/gi.exec(L),new q(G?"Upload to bucket failed: ".concat(G[1]):"Upload to bucket failed.",F)):new q("Upload to bucket failed.",F);case 22:if(204!==E.status)throw new q("Upload to bucket was unsuccessful",E);K=u.fileUploadPublishRetryLimit,B=!1,H={timetoken:"0"},i.label=23;case 23:return i.trys.push([23,25,,26]),[4,r({channel:s,message:f,fileId:S,fileName:w,meta:y,storeInHistory:m,ttl:g})];case 24:return H=i.sent(),B=!0,[3,26];case 25:return i.sent(),K-=1,[3,26];case 26:if(!B&&K>0)return[3,23];i.label=27;case 27:if(B)return[2,{timetoken:H.timetoken,id:S,name:w}];throw new q("Publish failed. You may want to execute that operation manually using pubnub.publishFile",{channel:s,id:S,name:w})}}))}))}}(e);return function(e,n){var r=t(e);return"function"==typeof n?(r.then((function(e){return n(null,e)})).catch((function(e){return n(e,null)})),r):r}},ve=function(e,t){var n=t.channel,r=t.id,o=t.name,i=e.config,s=e.networking,a=e.tokenManager;if(!n)throw new q("Validation failed, check status for details",z("channel can't be empty"));if(!r)throw new q("Validation failed, check status for details",z("file id can't be empty"));if(!o)throw new q("Validation failed, check status for details",z("file name can't be empty"));var u="/v1/files/".concat(i.subscribeKey,"/channels/").concat(H.encodeString(n),"/files/").concat(r,"/").concat(o),c={};c.uuid=i.getUUID(),c.pnsdk=W(i);var l=a.getToken()||i.getAuthKey();l&&(c.auth=l),i.secretKey&&$(e,u,c,{},{getOperation:function(){return"PubNubGetFileUrlOperation"}});var p=Object.keys(c).map((function(e){return"".concat(encodeURIComponent(e),"=").concat(encodeURIComponent(c[e]))})).join("&");return""!==p?"".concat(s.getStandardOrigin()).concat(u,"?").concat(p):"".concat(s.getStandardOrigin()).concat(u)},_e={getOperation:function(){return j.PNDownloadFileOperation},validateParams:function(e,t){return(null==t?void 0:t.channel)?(null==t?void 0:t.name)?(null==t?void 0:t.id)?void 0:"id can't be empty":"name can't be empty":"channel can't be empty"},useGetFile:function(){return!0},getFileURL:function(e,t){var n=e.config;return"/v1/files/".concat(n.subscribeKey,"/channels/").concat(H.encodeString(t.channel),"/files/").concat(t.id,"/").concat(t.name)},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},ignoreBody:function(){return!0},forceBuffered:function(){return!0},prepareParams:function(){return{}},handleResponse:function(e,t,n){var r=e.PubNubFile,s=e.config,a=e.cryptography,u=e.cryptoModule;return o(void 0,void 0,void 0,(function(){var e,o,c,l;return i(this,(function(i){switch(i.label){case 0:return e=t.response.body,r.supportsEncryptFile&&(n.cipherKey||u)?null!=n.cipherKey?[3,2]:[4,u.decryptFile(r.create({data:e,name:n.name}),r)]:[3,5];case 1:return o=i.sent().data,[3,4];case 2:return[4,a.decrypt(null!==(c=n.cipherKey)&&void 0!==c?c:s.cipherKey,e)];case 3:o=i.sent(),i.label=4;case 4:e=o,i.label=5;case 5:return[2,r.create({data:e,name:null!==(l=t.response.name)&&void 0!==l?l:n.name,mimeType:t.response.type})]}}))}))}},Se={getOperation:function(){return j.PNListFilesOperation},validateParams:function(e,t){return(null==t?void 0:t.channel)?(null==t?void 0:t.id)?(null==t?void 0:t.name)?void 0:"file name can't be empty":"file id can't be empty":"channel can't be empty"},useDelete:function(){return!0},getURL:function(e,t){var n=e.config;return"/v1/files/".concat(n.subscribeKey,"/channels/").concat(H.encodeString(t.channel),"/files/").concat(t.id,"/").concat(t.name)},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(){return{}},handleResponse:function(e,t){return{status:t.status}}},we={getOperation:function(){return j.PNGetAllUUIDMetadataOperation},validateParams:function(){},getURL:function(e){var t=e.config;return"/v2/objects/".concat(t.subscribeKey,"/uuids")},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n,r,o,i,s,u,c,l,p,h={include:["status","type"]};return(null==t?void 0:t.include)&&(null===(n=t.include)||void 0===n?void 0:n.customFields)&&h.include.push("custom"),h.include=h.include.join(","),(null===(r=null==t?void 0:t.include)||void 0===r?void 0:r.totalCount)&&(h.count=null===(o=t.include)||void 0===o?void 0:o.totalCount),(null===(i=null==t?void 0:t.page)||void 0===i?void 0:i.next)&&(h.start=null===(s=t.page)||void 0===s?void 0:s.next),(null===(u=null==t?void 0:t.page)||void 0===u?void 0:u.prev)&&(h.end=null===(c=t.page)||void 0===c?void 0:c.prev),(null==t?void 0:t.filter)&&(h.filter=t.filter),h.limit=null!==(l=null==t?void 0:t.limit)&&void 0!==l?l:100,(null==t?void 0:t.sort)&&(h.sort=Object.entries(null!==(p=t.sort)&&void 0!==p?p:{}).map((function(e){var t=a(e,2),n=t[0],r=t[1];return"asc"===r||"desc"===r?"".concat(n,":").concat(r):n}))),h},handleResponse:function(e,t){return{status:t.status,data:t.data,totalCount:t.totalCount,next:t.next,prev:t.prev}}},Oe={getOperation:function(){return j.PNGetUUIDMetadataOperation},validateParams:function(){},getURL:function(e,t){var n,r=e.config;return"/v2/objects/".concat(r.subscribeKey,"/uuids/").concat(H.encodeString(null!==(n=null==t?void 0:t.uuid)&&void 0!==n?n:r.getUUID()))},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n,r,o=e.config,i={};return i.uuid=null!==(n=null==t?void 0:t.uuid)&&void 0!==n?n:o.getUUID(),i.include=["status","type","custom"],(null==t?void 0:t.include)&&!1===(null===(r=t.include)||void 0===r?void 0:r.customFields)&&i.include.pop(),i.include=i.include.join(","),i},handleResponse:function(e,t){return{status:t.status,data:t.data}}},Pe={getOperation:function(){return j.PNSetUUIDMetadataOperation},validateParams:function(e,t){if(!(null==t?void 0:t.data))return"Data cannot be empty"},usePatch:function(){return!0},patchURL:function(e,t){var n,r=e.config;return"/v2/objects/".concat(r.subscribeKey,"/uuids/").concat(H.encodeString(null!==(n=t.uuid)&&void 0!==n?n:r.getUUID()))},patchPayload:function(e,t){return t.data},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n,r,o=e.config,i={};return i.uuid=null!==(n=null==t?void 0:t.uuid)&&void 0!==n?n:o.getUUID(),i.include=["status","type","custom"],(null==t?void 0:t.include)&&!1===(null===(r=t.include)||void 0===r?void 0:r.customFields)&&i.include.pop(),i.include=i.include.join(","),i},handleResponse:function(e,t){return{status:t.status,data:t.data}}},Ee={getOperation:function(){return j.PNRemoveUUIDMetadataOperation},validateParams:function(){},getURL:function(e,t){var n,r=e.config;return"/v2/objects/".concat(r.subscribeKey,"/uuids/").concat(H.encodeString(null!==(n=null==t?void 0:t.uuid)&&void 0!==n?n:r.getUUID()))},useDelete:function(){return!0},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n,r=e.config;return{uuid:null!==(n=null==t?void 0:t.uuid)&&void 0!==n?n:r.getUUID()}},handleResponse:function(e,t){return{status:t.status,data:t.data}}},Ae={getOperation:function(){return j.PNGetAllChannelMetadataOperation},validateParams:function(){},getURL:function(e){var t=e.config;return"/v2/objects/".concat(t.subscribeKey,"/channels")},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n,r,o,i,s,u,c,l,p,h={include:["status","type"]};return(null==t?void 0:t.include)&&(null===(n=t.include)||void 0===n?void 0:n.customFields)&&h.include.push("custom"),h.include=h.include.join(","),(null===(r=null==t?void 0:t.include)||void 0===r?void 0:r.totalCount)&&(h.count=null===(o=t.include)||void 0===o?void 0:o.totalCount),(null===(i=null==t?void 0:t.page)||void 0===i?void 0:i.next)&&(h.start=null===(s=t.page)||void 0===s?void 0:s.next),(null===(u=null==t?void 0:t.page)||void 0===u?void 0:u.prev)&&(h.end=null===(c=t.page)||void 0===c?void 0:c.prev),(null==t?void 0:t.filter)&&(h.filter=t.filter),h.limit=null!==(l=null==t?void 0:t.limit)&&void 0!==l?l:100,(null==t?void 0:t.sort)&&(h.sort=Object.entries(null!==(p=t.sort)&&void 0!==p?p:{}).map((function(e){var t=a(e,2),n=t[0],r=t[1];return"asc"===r||"desc"===r?"".concat(n,":").concat(r):n}))),h},handleResponse:function(e,t){return{status:t.status,data:t.data,totalCount:t.totalCount,prev:t.prev,next:t.next}}},Te={getOperation:function(){return j.PNGetChannelMetadataOperation},validateParams:function(e,t){if(!(null==t?void 0:t.channel))return"Channel cannot be empty"},getURL:function(e,t){var n=e.config;return"/v2/objects/".concat(n.subscribeKey,"/channels/").concat(H.encodeString(t.channel))},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n,r={include:["status","type","custom"]};return(null==t?void 0:t.include)&&!1===(null===(n=t.include)||void 0===n?void 0:n.customFields)&&r.include.pop(),r.include=r.include.join(","),r},handleResponse:function(e,t){return{status:t.status,data:t.data}}},Ne={getOperation:function(){return j.PNSetChannelMetadataOperation},validateParams:function(e,t){return(null==t?void 0:t.channel)?(null==t?void 0:t.data)?void 0:"Data cannot be empty":"Channel cannot be empty"},usePatch:function(){return!0},patchURL:function(e,t){var n=e.config;return"/v2/objects/".concat(n.subscribeKey,"/channels/").concat(H.encodeString(t.channel))},patchPayload:function(e,t){return t.data},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n,r={include:["status","type","custom"]};return(null==t?void 0:t.include)&&!1===(null===(n=t.include)||void 0===n?void 0:n.customFields)&&r.include.pop(),r.include=r.include.join(","),r},handleResponse:function(e,t){return{status:t.status,data:t.data}}},Ce={getOperation:function(){return j.PNRemoveChannelMetadataOperation},validateParams:function(e,t){if(!(null==t?void 0:t.channel))return"Channel cannot be empty"},getURL:function(e,t){var n=e.config;return"/v2/objects/".concat(n.subscribeKey,"/channels/").concat(H.encodeString(t.channel))},useDelete:function(){return!0},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(){return{}},handleResponse:function(e,t){return{status:t.status,data:t.data}}},ke={getOperation:function(){return j.PNGetMembersOperation},validateParams:function(e,t){if(!(null==t?void 0:t.channel))return"channel cannot be empty"},getURL:function(e,t){var n=e.config;return"/v2/objects/".concat(n.subscribeKey,"/channels/").concat(H.encodeString(t.channel),"/uuids")},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n,r,o,i,s,u,c,l,p,h,f,d,y,g,m={include:[]};return(null==t?void 0:t.include)&&((null===(n=t.include)||void 0===n?void 0:n.statusField)&&m.include.push("status"),(null===(r=t.include)||void 0===r?void 0:r.customFields)&&m.include.push("custom"),(null===(o=t.include)||void 0===o?void 0:o.UUIDFields)&&m.include.push("uuid"),(null===(i=t.include)||void 0===i?void 0:i.customUUIDFields)&&m.include.push("uuid.custom"),(null===(s=t.include)||void 0===s?void 0:s.UUIDStatusField)&&m.include.push("uuid.status"),(null===(u=t.include)||void 0===u?void 0:u.UUIDTypeField)&&m.include.push("uuid.type")),m.include=m.include.join(","),(null===(c=null==t?void 0:t.include)||void 0===c?void 0:c.totalCount)&&(m.count=null===(l=t.include)||void 0===l?void 0:l.totalCount),(null===(p=null==t?void 0:t.page)||void 0===p?void 0:p.next)&&(m.start=null===(h=t.page)||void 0===h?void 0:h.next),(null===(f=null==t?void 0:t.page)||void 0===f?void 0:f.prev)&&(m.end=null===(d=t.page)||void 0===d?void 0:d.prev),(null==t?void 0:t.filter)&&(m.filter=t.filter),m.limit=null!==(y=null==t?void 0:t.limit)&&void 0!==y?y:100,(null==t?void 0:t.sort)&&(m.sort=Object.entries(null!==(g=t.sort)&&void 0!==g?g:{}).map((function(e){var t=a(e,2),n=t[0],r=t[1];return"asc"===r||"desc"===r?"".concat(n,":").concat(r):n}))),m},handleResponse:function(e,t){return{status:t.status,data:t.data,totalCount:t.totalCount,prev:t.prev,next:t.next}}},Me={getOperation:function(){return j.PNSetMembersOperation},validateParams:function(e,t){return(null==t?void 0:t.channel)?(null==t?void 0:t.uuids)&&0!==(null==t?void 0:t.uuids.length)?void 0:"UUIDs cannot be empty":"Channel cannot be empty"},usePatch:function(){return!0},patchURL:function(e,t){var n=e.config;return"/v2/objects/".concat(n.subscribeKey,"/channels/").concat(H.encodeString(t.channel),"/uuids")},patchPayload:function(e,t){var n;return(n={set:[],delete:[]})[t.type]=t.uuids.map((function(e){return"string"==typeof e?{uuid:{id:e}}:{uuid:{id:e.id},custom:e.custom,status:e.status}})),n},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n,r,o,i,s,u,c,l,p,h={include:["uuid.status","uuid.type","type"]};return(null==t?void 0:t.include)&&((null===(n=t.include)||void 0===n?void 0:n.customFields)&&h.include.push("custom"),(null===(r=t.include)||void 0===r?void 0:r.customUUIDFields)&&h.include.push("uuid.custom"),(null===(o=t.include)||void 0===o?void 0:o.UUIDFields)&&h.include.push("uuid")),h.include=h.include.join(","),(null===(i=null==t?void 0:t.include)||void 0===i?void 0:i.totalCount)&&(h.count=!0),(null===(s=null==t?void 0:t.page)||void 0===s?void 0:s.next)&&(h.start=null===(u=t.page)||void 0===u?void 0:u.next),(null===(c=null==t?void 0:t.page)||void 0===c?void 0:c.prev)&&(h.end=null===(l=t.page)||void 0===l?void 0:l.prev),(null==t?void 0:t.filter)&&(h.filter=t.filter),null!=t.limit&&(h.limit=t.limit),(null==t?void 0:t.sort)&&(h.sort=Object.entries(null!==(p=t.sort)&&void 0!==p?p:{}).map((function(e){var t=a(e,2),n=t[0],r=t[1];return"asc"===r||"desc"===r?"".concat(n,":").concat(r):n}))),h},handleResponse:function(e,t){return{status:t.status,data:t.data,totalCount:t.totalCount,prev:t.prev,next:t.next}}},je={getOperation:function(){return j.PNGetMembershipsOperation},validateParams:function(){},getURL:function(e,t){var n,r=e.config;return"/v2/objects/".concat(r.subscribeKey,"/uuids/").concat(H.encodeString(null!==(n=null==t?void 0:t.uuid)&&void 0!==n?n:r.getUUID()),"/channels")},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n,r,o,i,s,u,c,l,p,h,f,d,y,g,m={include:[]};return(null==t?void 0:t.include)&&((null===(n=t.include)||void 0===n?void 0:n.statusField)&&m.include.push("status"),(null===(r=t.include)||void 0===r?void 0:r.customFields)&&m.include.push("custom"),(null===(o=t.include)||void 0===o?void 0:o.channelFields)&&m.include.push("channel"),(null===(i=t.include)||void 0===i?void 0:i.customChannelFields)&&m.include.push("channel.custom"),(null===(s=t.include)||void 0===s?void 0:s.channelStatusField)&&m.include.push("channel.status"),(null===(u=t.include)||void 0===u?void 0:u.channelTypeField)&&m.include.push("channel.type")),m.include=m.include.join(","),(null===(c=null==t?void 0:t.include)||void 0===c?void 0:c.totalCount)&&(m.count=null===(l=t.include)||void 0===l?void 0:l.totalCount),(null===(p=null==t?void 0:t.page)||void 0===p?void 0:p.next)&&(m.start=null===(h=t.page)||void 0===h?void 0:h.next),(null===(f=null==t?void 0:t.page)||void 0===f?void 0:f.prev)&&(m.end=null===(d=t.page)||void 0===d?void 0:d.prev),(null==t?void 0:t.filter)&&(m.filter=t.filter),m.limit=null!==(y=null==t?void 0:t.limit)&&void 0!==y?y:100,(null==t?void 0:t.sort)&&(m.sort=Object.entries(null!==(g=t.sort)&&void 0!==g?g:{}).map((function(e){var t=a(e,2),n=t[0],r=t[1];return"asc"===r||"desc"===r?"".concat(n,":").concat(r):n}))),m},handleResponse:function(e,t){return{status:t.status,data:t.data,totalCount:t.totalCount,prev:t.prev,next:t.next}}},Re={getOperation:function(){return j.PNSetMembershipsOperation},validateParams:function(e,t){if(!(null==t?void 0:t.channels)||0===(null==t?void 0:t.channels.length))return"Channels cannot be empty"},usePatch:function(){return!0},patchURL:function(e,t){var n,r=e.config;return"/v2/objects/".concat(r.subscribeKey,"/uuids/").concat(H.encodeString(null!==(n=t.uuid)&&void 0!==n?n:r.getUUID()),"/channels")},patchPayload:function(e,t){var n;return(n={set:[],delete:[]})[t.type]=t.channels.map((function(e){return"string"==typeof e?{channel:{id:e}}:{channel:{id:e.id},custom:e.custom,status:e.status}})),n},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n,r,o,i,s,u,c,l,p,h={include:["channel.status","channel.type","status"]};return(null==t?void 0:t.include)&&((null===(n=t.include)||void 0===n?void 0:n.customFields)&&h.include.push("custom"),(null===(r=t.include)||void 0===r?void 0:r.customChannelFields)&&h.include.push("channel.custom"),(null===(o=t.include)||void 0===o?void 0:o.channelFields)&&h.include.push("channel")),h.include=h.include.join(","),(null===(i=null==t?void 0:t.include)||void 0===i?void 0:i.totalCount)&&(h.count=!0),(null===(s=null==t?void 0:t.page)||void 0===s?void 0:s.next)&&(h.start=null===(u=t.page)||void 0===u?void 0:u.next),(null===(c=null==t?void 0:t.page)||void 0===c?void 0:c.prev)&&(h.end=null===(l=t.page)||void 0===l?void 0:l.prev),(null==t?void 0:t.filter)&&(h.filter=t.filter),null!=t.limit&&(h.limit=t.limit),(null==t?void 0:t.sort)&&(h.sort=Object.entries(null!==(p=t.sort)&&void 0!==p?p:{}).map((function(e){var t=a(e,2),n=t[0],r=t[1];return"asc"===r||"desc"===r?"".concat(n,":").concat(r):n}))),h},handleResponse:function(e,t){return{status:t.status,data:t.data,totalCount:t.totalCount,prev:t.prev,next:t.next}}};var xe=Object.freeze({__proto__:null,getOperation:function(){return j.PNAccessManagerAudit},validateParams:function(e){if(!e.config.subscribeKey)return"Missing Subscribe Key"},getURL:function(e){var t=e.config;return"/v2/auth/audit/sub-key/".concat(t.subscribeKey)},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!1},prepareParams:function(e,t){var n=t.channel,r=t.channelGroup,o=t.authKeys,i=void 0===o?[]:o,s={};return n&&(s.channel=n),r&&(s["channel-group"]=r),i.length>0&&(s.auth=i.join(",")),s},handleResponse:function(e,t){return t.payload}});var Ue=Object.freeze({__proto__:null,getOperation:function(){return j.PNAccessManagerGrant},validateParams:function(e,t){var n=e.config;return n.subscribeKey?n.publishKey?n.secretKey?null==t.uuids||t.authKeys?null==t.uuids||null==t.channels&&null==t.channelGroups?void 0:"Both channel/channelgroup and uuid cannot be used in the same request":"authKeys are required for grant request on uuids":"Missing Secret Key":"Missing Publish Key":"Missing Subscribe Key"},getURL:function(e){var t=e.config;return"/v2/auth/grant/sub-key/".concat(t.subscribeKey)},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!1},prepareParams:function(e,t){var n=t.channels,r=void 0===n?[]:n,o=t.channelGroups,i=void 0===o?[]:o,s=t.uuids,a=void 0===s?[]:s,u=t.ttl,c=t.read,l=void 0!==c&&c,p=t.write,h=void 0!==p&&p,f=t.manage,d=void 0!==f&&f,y=t.get,g=void 0!==y&&y,m=t.join,b=void 0!==m&&m,v=t.update,_=void 0!==v&&v,S=t.authKeys,w=void 0===S?[]:S,O=t.delete,P={};return P.r=l?"1":"0",P.w=h?"1":"0",P.m=d?"1":"0",P.d=O?"1":"0",P.g=g?"1":"0",P.j=b?"1":"0",P.u=_?"1":"0",r.length>0&&(P.channel=r.join(",")),i.length>0&&(P["channel-group"]=i.join(",")),w.length>0&&(P.auth=w.join(",")),a.length>0&&(P["target-uuid"]=a.join(",")),(u||0===u)&&(P.ttl=u),P},handleResponse:function(){return{}}});function Ie(e){var t,n,r,o,i=void 0!==(null==e?void 0:e.authorizedUserId),s=void 0!==(null===(t=null==e?void 0:e.resources)||void 0===t?void 0:t.users),a=void 0!==(null===(n=null==e?void 0:e.resources)||void 0===n?void 0:n.spaces),u=void 0!==(null===(r=null==e?void 0:e.patterns)||void 0===r?void 0:r.users),c=void 0!==(null===(o=null==e?void 0:e.patterns)||void 0===o?void 0:o.spaces);return u||s||c||a||i}function De(e){var t=0;return e.join&&(t|=128),e.update&&(t|=64),e.get&&(t|=32),e.delete&&(t|=8),e.manage&&(t|=4),e.write&&(t|=2),e.read&&(t|=1),t}function Fe(e,t){if(Ie(t))return function(e,t){var n=t.ttl,r=t.resources,o=t.patterns,i=t.meta,s=t.authorizedUserId,a={ttl:0,permissions:{resources:{channels:{},groups:{},uuids:{},users:{},spaces:{}},patterns:{channels:{},groups:{},uuids:{},users:{},spaces:{}},meta:{}}};if(r){var u=r.users,c=r.spaces,l=r.groups;u&&Object.keys(u).forEach((function(e){a.permissions.resources.uuids[e]=De(u[e])})),c&&Object.keys(c).forEach((function(e){a.permissions.resources.channels[e]=De(c[e])})),l&&Object.keys(l).forEach((function(e){a.permissions.resources.groups[e]=De(l[e])}))}if(o){var p=o.users,h=o.spaces,f=o.groups;p&&Object.keys(p).forEach((function(e){a.permissions.patterns.uuids[e]=De(p[e])})),h&&Object.keys(h).forEach((function(e){a.permissions.patterns.channels[e]=De(h[e])})),f&&Object.keys(f).forEach((function(e){a.permissions.patterns.groups[e]=De(f[e])}))}return(n||0===n)&&(a.ttl=n),i&&(a.permissions.meta=i),s&&(a.permissions.uuid="".concat(s)),a}(0,t);var n=t.ttl,r=t.resources,o=t.patterns,i=t.meta,s=t.authorized_uuid,a={ttl:0,permissions:{resources:{channels:{},groups:{},uuids:{},users:{},spaces:{}},patterns:{channels:{},groups:{},uuids:{},users:{},spaces:{}},meta:{}}};if(r){var u=r.uuids,c=r.channels,l=r.groups;u&&Object.keys(u).forEach((function(e){a.permissions.resources.uuids[e]=De(u[e])})),c&&Object.keys(c).forEach((function(e){a.permissions.resources.channels[e]=De(c[e])})),l&&Object.keys(l).forEach((function(e){a.permissions.resources.groups[e]=De(l[e])}))}if(o){var p=o.uuids,h=o.channels,f=o.groups;p&&Object.keys(p).forEach((function(e){a.permissions.patterns.uuids[e]=De(p[e])})),h&&Object.keys(h).forEach((function(e){a.permissions.patterns.channels[e]=De(h[e])})),f&&Object.keys(f).forEach((function(e){a.permissions.patterns.groups[e]=De(f[e])}))}return(n||0===n)&&(a.ttl=n),i&&(a.permissions.meta=i),s&&(a.permissions.uuid="".concat(s)),a}var Le=Object.freeze({__proto__:null,getOperation:function(){return j.PNAccessManagerGrantToken},extractPermissions:De,validateParams:function(e,t){var n,r,o,i,s,a,u=e.config;if(!u.subscribeKey)return"Missing Subscribe Key";if(!u.publishKey)return"Missing Publish Key";if(!u.secretKey)return"Missing Secret Key";if(!t.resources&&!t.patterns)return"Missing either Resources or Patterns.";var c=void 0!==(null==t?void 0:t.authorized_uuid),l=void 0!==(null===(n=null==t?void 0:t.resources)||void 0===n?void 0:n.uuids),p=void 0!==(null===(r=null==t?void 0:t.resources)||void 0===r?void 0:r.channels),h=void 0!==(null===(o=null==t?void 0:t.resources)||void 0===o?void 0:o.groups),f=void 0!==(null===(i=null==t?void 0:t.patterns)||void 0===i?void 0:i.uuids),d=void 0!==(null===(s=null==t?void 0:t.patterns)||void 0===s?void 0:s.channels),y=void 0!==(null===(a=null==t?void 0:t.patterns)||void 0===a?void 0:a.groups),g=c||l||f||p||d||h||y;return Ie(t)&&g?"Cannot mix `users`, `spaces` and `authorizedUserId` with `uuids`, `channels`, `groups` and `authorized_uuid`":(!t.resources||t.resources.uuids&&0!==Object.keys(t.resources.uuids).length||t.resources.channels&&0!==Object.keys(t.resources.channels).length||t.resources.groups&&0!==Object.keys(t.resources.groups).length||t.resources.users&&0!==Object.keys(t.resources.users).length||t.resources.spaces&&0!==Object.keys(t.resources.spaces).length)&&(!t.patterns||t.patterns.uuids&&0!==Object.keys(t.patterns.uuids).length||t.patterns.channels&&0!==Object.keys(t.patterns.channels).length||t.patterns.groups&&0!==Object.keys(t.patterns.groups).length||t.patterns.users&&0!==Object.keys(t.patterns.users).length||t.patterns.spaces&&0!==Object.keys(t.patterns.spaces).length)?void 0:"Missing values for either Resources or Patterns."},postURL:function(e){var t=e.config;return"/v3/pam/".concat(t.subscribeKey,"/grant")},usePost:function(){return!0},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!1},prepareParams:function(){return{}},postPayload:function(e,t){return Fe(0,t)},handleResponse:function(e,t){return t.data.token}}),Ge={getOperation:function(){return j.PNAccessManagerRevokeToken},validateParams:function(e,t){return e.config.secretKey?t?void 0:"token can't be empty":"Missing Secret Key"},getURL:function(e,t){var n=e.config;return"/v3/pam/".concat(n.subscribeKey,"/grant/").concat(H.encodeString(t))},useDelete:function(){return!0},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!1},prepareParams:function(e){return{uuid:e.config.getUUID()}},handleResponse:function(e,t){return{status:t.status,data:t.data}}};function Ke(e,t){var n=JSON.stringify(t);if(e.cryptoModule){var r=e.cryptoModule.encrypt(n);n="string"==typeof r?r:b(r),n=JSON.stringify(n)}return n||""}var Be=Object.freeze({__proto__:null,getOperation:function(){return j.PNPublishOperation},validateParams:function(e,t){var n=e.config,r=t.message;return t.channel?r?n.subscribeKey?void 0:"Missing Subscribe Key":"Missing Message":"Missing Channel"},usePost:function(e,t){var n=t.sendByPost;return void 0!==n&&n},getURL:function(e,t){var n=e.config,r=t.channel,o=Ke(e,t.message);return"/publish/".concat(n.publishKey,"/").concat(n.subscribeKey,"/0/").concat(H.encodeString(r),"/0/").concat(H.encodeString(o))},postURL:function(e,t){var n=e.config,r=t.channel;return"/publish/".concat(n.publishKey,"/").concat(n.subscribeKey,"/0/").concat(H.encodeString(r),"/0")},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},postPayload:function(e,t){return Ke(e,t.message)},prepareParams:function(e,t){var n=t.meta,r=t.replicate,o=void 0===r||r,i=t.storeInHistory,s=t.ttl,a={};return null!=i&&(a.store=i?"1":"0"),s&&(a.ttl=s),!1===o&&(a.norep="true"),n&&"object"==typeof n&&(a.meta=JSON.stringify(n)),a},handleResponse:function(e,t){return{timetoken:t[2]}}});var He=Object.freeze({__proto__:null,getOperation:function(){return j.PNSignalOperation},validateParams:function(e,t){var n=e.config,r=t.message;return t.channel?r?n.subscribeKey?void 0:"Missing Subscribe Key":"Missing Message":"Missing Channel"},getURL:function(e,t){var n,r=e.config,o=t.channel,i=t.message,s=(n=i,JSON.stringify(n));return"/signal/".concat(r.publishKey,"/").concat(r.subscribeKey,"/0/").concat(H.encodeString(o),"/0/").concat(H.encodeString(s))},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(){return{}},handleResponse:function(e,t){return{timetoken:t[2]}}});var qe=Object.freeze({__proto__:null,getOperation:function(){return j.PNHistoryOperation},validateParams:function(e,t){var n=t.channel,r=e.config;return n?r.subscribeKey?void 0:"Missing Subscribe Key":"Missing channel"},getURL:function(e,t){var n=t.channel,r=e.config;return"/v2/history/sub-key/".concat(r.subscribeKey,"/channel/").concat(H.encodeString(n))},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n=t.start,r=t.end,o=t.reverse,i=t.count,s=void 0===i?100:i,a=t.stringifiedTimeToken,u=void 0!==a&&a,c=t.includeMeta,l=void 0!==c&&c,p={include_token:"true"};return p.count=s,n&&(p.start=n),r&&(p.end=r),u&&(p.string_message_token="true"),null!=o&&(p.reverse=o.toString()),l&&(p.include_meta="true"),p},handleResponse:function(e,t){var n={messages:[],startTimeToken:t[1],endTimeToken:t[2]};return Array.isArray(t[0])&&t[0].forEach((function(t){var r=function(e,t){var n={};if(!e.cryptoModule)return n.payload=t,n;try{var r=e.cryptoModule.decrypt(t),o=r instanceof ArrayBuffer?JSON.parse((new TextDecoder).decode(r)):r;return n.payload=o,n}catch(r){e.config.logVerbosity&&console&&console.log&&console.log("decryption error",r.message),n.payload=t,n.error="Error while decrypting message content: ".concat(r.message)}return n}(e,t.message),o={timetoken:t.timetoken,entry:r.payload};t.meta&&(o.meta=t.meta),r.error&&(o.error=r.error),n.messages.push(o)})),n}});var ze=Object.freeze({__proto__:null,getOperation:function(){return j.PNDeleteMessagesOperation},validateParams:function(e,t){var n=t.channel,r=e.config;return n?r.subscribeKey?void 0:"Missing Subscribe Key":"Missing channel"},useDelete:function(){return!0},getURL:function(e,t){var n=t.channel,r=e.config;return"/v3/history/sub-key/".concat(r.subscribeKey,"/channel/").concat(H.encodeString(n))},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n=t.start,r=t.end,o={};return n&&(o.start=n),r&&(o.end=r),o},handleResponse:function(e,t){return t.payload}});var Ve=Object.freeze({__proto__:null,getOperation:function(){return j.PNMessageCounts},validateParams:function(e,t){var n=t.channels,r=t.timetoken,o=t.channelTimetokens,i=e.config;return n?r&&o?"timetoken and channelTimetokens are incompatible together":o&&o.length>1&&n.length!==o.length?"Length of channelTimetokens and channels do not match":i.subscribeKey?void 0:"Missing Subscribe Key":"Missing channel"},getURL:function(e,t){var n=t.channels,r=e.config,o=n.join(",");return"/v3/history/sub-key/".concat(r.subscribeKey,"/message-counts/").concat(H.encodeString(o))},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n=t.timetoken,r=t.channelTimetokens,o={};if(r&&1===r.length){var i=a(r,1)[0];o.timetoken=i}else r?o.channelsTimetoken=r.join(","):n&&(o.timetoken=n);return o},handleResponse:function(e,t){return{channels:t.channels}}});var We=Object.freeze({__proto__:null,getOperation:function(){return j.PNFetchMessagesOperation},validateParams:function(e,t){var n=t.channels,r=t.includeMessageActions,o=void 0!==r&&r,i=e.config;if(!n||0===n.length)return"Missing channels";if(!i.subscribeKey)return"Missing Subscribe Key";if(o&&n.length>1)throw new TypeError("History can return actions data for a single channel only. Either pass a single channel or disable the includeMessageActions flag.")},getURL:function(e,t){var n=t.channels,r=void 0===n?[]:n,o=t.includeMessageActions,i=void 0!==o&&o,s=e.config,a=i?"history-with-actions":"history",u=r.length>0?r.join(","):",";return"/v3/".concat(a,"/sub-key/").concat(s.subscribeKey,"/channel/").concat(H.encodeString(u))},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n=t.channels,r=t.start,o=t.end,i=t.includeMessageActions,s=t.count,a=t.stringifiedTimeToken,u=void 0!==a&&a,c=t.includeMeta,l=void 0!==c&&c,p=t.includeUuid,h=t.includeUUID,f=void 0===h||h,d=t.includeMessageType,y=void 0===d||d,g={};return g.max=s||(n.length>1||!0===i?25:100),r&&(g.start=r),o&&(g.end=o),u&&(g.string_message_token="true"),l&&(g.include_meta="true"),f&&!1!==p&&(g.include_uuid="true"),y&&(g.include_message_type="true"),g},handleResponse:function(e,t){var n={channels:{}};return Object.keys(t.channels||{}).forEach((function(r){n.channels[r]=[],(t.channels[r]||[]).forEach((function(t){var o={},i=function(e,t){var n={};if(!e.cryptoModule)return n.payload=t,n;try{var r=e.cryptoModule.decrypt(t),o=r instanceof ArrayBuffer?JSON.parse((new TextDecoder).decode(r)):r;return n.payload=o,n}catch(r){e.config.logVerbosity&&console&&console.log&&console.log("decryption error",r.message),n.payload=t,n.error="Error while decrypting message content: ".concat(r.message)}return n}(e,t.message);o.channel=r,o.timetoken=t.timetoken,o.message=i.payload,o.messageType=t.message_type,o.uuid=t.uuid,t.actions&&(o.actions=t.actions,o.data=t.actions),t.meta&&(o.meta=t.meta),i.error&&(o.error=i.error),n.channels[r].push(o)}))})),t.more&&(n.more=t.more),n}});var Je=Object.freeze({__proto__:null,getOperation:function(){return j.PNTimeOperation},getURL:function(){return"/time/0"},getRequestTimeout:function(e){return e.config.getTransactionTimeout()},prepareParams:function(){return{}},isAuthSupported:function(){return!1},handleResponse:function(e,t){return{timetoken:t[0]}},validateParams:function(){}});var $e=Object.freeze({__proto__:null,getOperation:function(){return j.PNSubscribeOperation},validateParams:function(e){if(!e.config.subscribeKey)return"Missing Subscribe Key"},getURL:function(e,t){var n=e.config,r=t.channels,o=void 0===r?[]:r,i=o.length>0?o.join(","):",";return"/v2/subscribe/".concat(n.subscribeKey,"/").concat(H.encodeString(i),"/0")},getRequestTimeout:function(e){return e.config.getSubscribeTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n=e.config,r=t.state,o=t.channelGroups,i=void 0===o?[]:o,s=t.timetoken,a=t.filterExpression,u=t.region,c={heartbeat:n.getPresenceTimeout()};return i.length>0&&(c["channel-group"]=i.join(",")),a&&a.length>0&&(c["filter-expr"]=a),Object.keys(r).length&&(c.state=JSON.stringify(r)),s&&(c.tt=s),u&&(c.tr=u),c},handleResponse:function(e,t){var n=[];t.m.forEach((function(e){var t={publishTimetoken:e.p.t,region:e.p.r},r={shard:parseInt(e.a,10),subscriptionMatch:e.b,channel:e.c,messageType:e.e,payload:e.d,flags:e.f,issuingClientId:e.i,subscribeKey:e.k,originationTimetoken:e.o,userMetadata:e.u,publishMetaData:t};n.push(r)}));var r={timetoken:t.t.t,region:t.t.r};return{messages:n,metadata:r}}}),Qe={getOperation:function(){return j.PNHandshakeOperation},validateParams:function(e,t){if(!(null==t?void 0:t.channels)&&!(null==t?void 0:t.channelGroups))return"channels and channleGroups both should not be empty"},getURL:function(e,t){var n=e.config,r=t.channels,o=void 0===r?[]:r,i=o.length>0?o.join(","):",";return"/v2/subscribe/".concat(n.subscribeKey,"/").concat(H.encodeString(i),"/0")},getRequestTimeout:function(e){return e.config.getSubscribeTimeout()},isAuthSupported:function(){return!0},prepareParams:function(e,t){var n={};return t.channelGroups&&t.channelGroups.length>0&&(n["channel-group"]=t.channelGroups.join(",")),n.tt=0,t.state&&(n.state=JSON.stringify(t.state)),t.filterExpression&&t.filterExpression.length>0&&(n["filter-expr"]=t.filterExpression),n.ee="",n},handleResponse:function(e,t){return{region:t.t.r,timetoken:t.t.t}}},Xe={getOperation:function(){return j.PNReceiveMessagesOperation},validateParams:function(e,t){return(null==t?void 0:t.channels)||(null==t?void 0:t.channelGroups)?(null==t?void 0:t.timetoken)?(null==t?void 0:t.region)?void 0:"region can not be empty":"timetoken can not be empty":"channels and channleGroups both should not be empty"},getURL:function(e,t){var n=e.config,r=t.channels,o=void 0===r?[]:r,i=o.length>0?o.join(","):",";return"/v2/subscribe/".concat(n.subscribeKey,"/").concat(H.encodeString(i),"/0")},getRequestTimeout:function(e){return e.config.getSubscribeTimeout()},isAuthSupported:function(){return!0},getAbortSignal:function(e,t){return t.abortSignal},prepareParams:function(e,t){var n={};return t.channelGroups&&t.channelGroups.length>0&&(n["channel-group"]=t.channelGroups.join(",")),t.filterExpression&&t.filterExpression.length>0&&(n["filter-expr"]=t.filterExpression),n.tt=t.timetoken,n.tr=t.region,n.ee="",n},handleResponse:function(e,t){var n=[];return t.m.forEach((function(e){var t={shard:parseInt(e.a,10),subscriptionMatch:e.b,channel:e.c,messageType:e.e,payload:e.d,flags:e.f,issuingClientId:e.i,subscribeKey:e.k,originationTimetoken:e.o,publishMetaData:{timetoken:e.p.t,region:e.p.r}};n.push(t)})),{messages:n,metadata:{region:t.t.r,timetoken:t.t.t}}}},Ye=function(){function e(e){void 0===e&&(e=!1),this.sync=e,this.listeners=new Set}return e.prototype.subscribe=function(e){var t=this;return this.listeners.add(e),function(){t.listeners.delete(e)}},e.prototype.notify=function(e){var t=this,n=function(){t.listeners.forEach((function(t){t(e)}))};this.sync?n():setTimeout(n,0)},e}(),Ze=function(){function e(e){this.label=e,this.transitionMap=new Map,this.enterEffects=[],this.exitEffects=[]}return e.prototype.transition=function(e,t){var n;if(this.transitionMap.has(t.type))return null===(n=this.transitionMap.get(t.type))||void 0===n?void 0:n(e,t)},e.prototype.on=function(e,t){return this.transitionMap.set(e,t),this},e.prototype.with=function(e,t){return[this,e,null!=t?t:[]]},e.prototype.onEnter=function(e){return this.enterEffects.push(e),this},e.prototype.onExit=function(e){return this.exitEffects.push(e),this},e}(),et=function(e){function n(){return null!==e&&e.apply(this,arguments)||this}return t(n,e),n.prototype.describe=function(e){return new Ze(e)},n.prototype.start=function(e,t){this.currentState=e,this.currentContext=t,this.notify({type:"engineStarted",state:e,context:t})},n.prototype.transition=function(e){var t,n,r,o,i,u;if(!this.currentState)throw new Error("Start the engine first");this.notify({type:"eventReceived",event:e});var c=this.currentState.transition(this.currentContext,e);if(c){var l=a(c,3),p=l[0],h=l[1],f=l[2];try{for(var d=s(this.currentState.exitEffects),y=d.next();!y.done;y=d.next()){var g=y.value;this.notify({type:"invocationDispatched",invocation:g(this.currentContext)})}}catch(e){t={error:e}}finally{try{y&&!y.done&&(n=d.return)&&n.call(d)}finally{if(t)throw t.error}}var m=this.currentState;this.currentState=p;var b=this.currentContext;this.currentContext=h,this.notify({type:"transitionDone",fromState:m,fromContext:b,toState:p,toContext:h,event:e});try{for(var v=s(f),_=v.next();!_.done;_=v.next()){g=_.value;this.notify({type:"invocationDispatched",invocation:g})}}catch(e){r={error:e}}finally{try{_&&!_.done&&(o=v.return)&&o.call(v)}finally{if(r)throw r.error}}try{for(var S=s(this.currentState.enterEffects),w=S.next();!w.done;w=S.next()){g=w.value;this.notify({type:"invocationDispatched",invocation:g(this.currentContext)})}}catch(e){i={error:e}}finally{try{w&&!w.done&&(u=S.return)&&u.call(S)}finally{if(i)throw i.error}}}},n}(Ye),tt=function(){function e(e){this.dependencies=e,this.instances=new Map,this.handlers=new Map}return e.prototype.on=function(e,t){this.handlers.set(e,t)},e.prototype.dispatch=function(e){if("CANCEL"!==e.type){var t=this.handlers.get(e.type);if(!t)throw new Error("Unhandled invocation '".concat(e.type,"'"));var n=t(e.payload,this.dependencies);e.managed&&this.instances.set(e.type,n),n.start()}else if(this.instances.has(e.payload)){var r=this.instances.get(e.payload);null==r||r.cancel(),this.instances.delete(e.payload)}},e.prototype.dispose=function(){var e,t;try{for(var n=s(this.instances.entries()),r=n.next();!r.done;r=n.next()){var o=a(r.value,2),i=o[0];o[1].cancel(),this.instances.delete(i)}}catch(t){e={error:t}}finally{try{r&&!r.done&&(t=n.return)&&t.call(n)}finally{if(e)throw e.error}}},e}();function nt(e,t){var n=function(){for(var n=[],r=0;r0&&r(e),[2]}))}))}))),s.on(ht.type,ut((function(e,t,n){var r=n.emitStatus;return o(s,void 0,void 0,(function(){return i(this,(function(t){return r(e),[2]}))}))}))),s.on(ft.type,ut((function(e,n,r){var a=r.receiveMessages,u=r.delay,c=r.config;return o(s,void 0,void 0,(function(){var r,o;return i(this,(function(i){switch(i.label){case 0:return c.retryConfiguration&&c.retryConfiguration.shouldRetry(e.reason,e.attempts)?(n.throwIfAborted(),[4,u(c.retryConfiguration.getDelay(e.attempts,e.reason))]):[3,6];case 1:i.sent(),n.throwIfAborted(),i.label=2;case 2:return i.trys.push([2,4,,5]),[4,a({abortSignal:n,channels:e.channels,channelGroups:e.groups,timetoken:e.cursor.timetoken,region:e.cursor.region,filterExpression:c.filterExpression})];case 3:return r=i.sent(),[2,t.transition(Pt(r.metadata,r.messages))];case 4:return(o=i.sent())instanceof Error&&"Aborted"===o.message?[2]:o instanceof q?[2,t.transition(Et(o))]:[3,5];case 5:return[3,7];case 6:return[2,t.transition(At(new q(c.retryConfiguration.getGiveupReason(e.reason,e.attempts))))];case 7:return[2]}}))}))}))),s.on(dt.type,ut((function(e,r,a){var u=a.handshake,c=a.delay,l=a.presenceState,p=a.config;return o(s,void 0,void 0,(function(){var o,s;return i(this,(function(i){switch(i.label){case 0:return p.retryConfiguration&&p.retryConfiguration.shouldRetry(e.reason,e.attempts)?(r.throwIfAborted(),[4,c(p.retryConfiguration.getDelay(e.attempts,e.reason))]):[3,6];case 1:i.sent(),r.throwIfAborted(),i.label=2;case 2:return i.trys.push([2,4,,5]),[4,u(n({abortSignal:r,channels:e.channels,channelGroups:e.groups,filterExpression:p.filterExpression},p.maintainPresenceState&&{state:l}))];case 3:return o=i.sent(),[2,t.transition(vt(o))];case 4:return(s=i.sent())instanceof Error&&"Aborted"===s.message?[2]:s instanceof q?[2,t.transition(_t(s))]:[3,5];case 5:return[3,7];case 6:return[2,t.transition(St(new q(p.retryConfiguration.getGiveupReason(e.reason,e.attempts))))];case 7:return[2]}}))}))}))),s}return t(r,e),r}(tt),Mt=new Ze("HANDSHAKE_FAILED");Mt.on(yt.type,(function(e,t){return Ft.with({channels:t.payload.channels,groups:t.payload.groups,cursor:e.cursor})})),Mt.on(Nt.type,(function(e,t){return Ft.with({channels:e.channels,groups:e.groups,cursor:t.payload.cursor||e.cursor})})),Mt.on(gt.type,(function(e,t){var n,r;return Ft.with({channels:t.payload.channels,groups:t.payload.groups,cursor:{timetoken:t.payload.cursor.timetoken,region:t.payload.cursor.region?t.payload.cursor.region:null!==(r=null===(n=null==e?void 0:e.cursor)||void 0===n?void 0:n.region)&&void 0!==r?r:0}})})),Mt.on(Ct.type,(function(e){return Lt.with()}));var jt=new Ze("HANDSHAKE_STOPPED");jt.on(yt.type,(function(e,t){return jt.with({channels:t.payload.channels,groups:t.payload.groups,cursor:e.cursor})})),jt.on(Nt.type,(function(e,t){return Ft.with(n(n({},e),{cursor:t.payload.cursor||e.cursor}))})),jt.on(gt.type,(function(e,t){var n;return jt.with({channels:t.payload.channels,groups:t.payload.groups,cursor:{timetoken:t.payload.cursor.timetoken,region:t.payload.cursor.region||(null===(n=null==e?void 0:e.cursor)||void 0===n?void 0:n.region)||0}})})),jt.on(Ct.type,(function(e){return Lt.with()}));var Rt=new Ze("RECEIVE_FAILED");Rt.on(Nt.type,(function(e,t){var n;return Ft.with({channels:e.channels,groups:e.groups,cursor:{timetoken:t.payload.cursor.timetoken?null===(n=t.payload.cursor)||void 0===n?void 0:n.timetoken:e.cursor.timetoken,region:t.payload.cursor.region||e.cursor.region}})})),Rt.on(yt.type,(function(e,t){return Ft.with({channels:t.payload.channels,groups:t.payload.groups,cursor:e.cursor})})),Rt.on(gt.type,(function(e,t){return Ft.with({channels:t.payload.channels,groups:t.payload.groups,cursor:{timetoken:t.payload.cursor.timetoken,region:t.payload.cursor.region||e.cursor.region}})})),Rt.on(Ct.type,(function(e){return Lt.with(void 0)}));var xt=new Ze("RECEIVE_STOPPED");xt.on(yt.type,(function(e,t){return xt.with({channels:t.payload.channels,groups:t.payload.groups,cursor:e.cursor})})),xt.on(gt.type,(function(e,t){return xt.with({channels:t.payload.channels,groups:t.payload.groups,cursor:{timetoken:t.payload.cursor.timetoken,region:t.payload.cursor.region||e.cursor.region}})})),xt.on(Nt.type,(function(e,t){var n;return Ft.with({channels:e.channels,groups:e.groups,cursor:{timetoken:t.payload.cursor.timetoken?null===(n=t.payload.cursor)||void 0===n?void 0:n.timetoken:e.cursor.timetoken,region:t.payload.cursor.region||e.cursor.region}})})),xt.on(Ct.type,(function(){return Lt.with(void 0)}));var Ut=new Ze("RECEIVE_RECONNECTING");Ut.onEnter((function(e){return ft(e)})),Ut.onExit((function(){return ft.cancel})),Ut.on(Pt.type,(function(e,t){return It.with({channels:e.channels,groups:e.groups,cursor:t.payload.cursor},[pt(t.payload.events)])})),Ut.on(Et.type,(function(e,t){return Ut.with(n(n({},e),{attempts:e.attempts+1,reason:t.payload}))})),Ut.on(At.type,(function(e,t){var n;return Rt.with({groups:e.groups,channels:e.channels,cursor:e.cursor,reason:t.payload},[ht({category:k.PNDisconnectedUnexpectedlyCategory,error:null===(n=t.payload)||void 0===n?void 0:n.message})])})),Ut.on(Tt.type,(function(e){return xt.with({channels:e.channels,groups:e.groups,cursor:e.cursor},[ht({category:k.PNDisconnectedCategory})])})),Ut.on(gt.type,(function(e,t){return It.with({channels:t.payload.channels,groups:t.payload.groups,cursor:{timetoken:t.payload.cursor.timetoken,region:t.payload.cursor.region||e.cursor.region}})})),Ut.on(yt.type,(function(e,t){return It.with({channels:t.payload.channels,groups:t.payload.groups,cursor:e.cursor})})),Ut.on(Ct.type,(function(e){return Lt.with(void 0,[ht({category:k.PNDisconnectedCategory})])}));var It=new Ze("RECEIVING");It.onEnter((function(e){return lt(e.channels,e.groups,e.cursor)})),It.onExit((function(){return lt.cancel})),It.on(wt.type,(function(e,t){return It.with({channels:e.channels,groups:e.groups,cursor:t.payload.cursor},[pt(t.payload.events)])})),It.on(yt.type,(function(e,t){return 0===t.payload.channels.length&&0===t.payload.groups.length?Lt.with(void 0):It.with({cursor:e.cursor,channels:t.payload.channels,groups:t.payload.groups})})),It.on(gt.type,(function(e,t){return 0===t.payload.channels.length&&0===t.payload.groups.length?Lt.with(void 0):It.with({channels:t.payload.channels,groups:t.payload.groups,cursor:{timetoken:t.payload.cursor.timetoken,region:t.payload.cursor.region||e.cursor.region}})})),It.on(Ot.type,(function(e,t){return Ut.with(n(n({},e),{attempts:0,reason:t.payload}))})),It.on(Tt.type,(function(e){return xt.with({channels:e.channels,groups:e.groups,cursor:e.cursor},[ht({category:k.PNDisconnectedCategory})])})),It.on(Ct.type,(function(e){return Lt.with(void 0,[ht({category:k.PNDisconnectedCategory})])}));var Dt=new Ze("HANDSHAKE_RECONNECTING");Dt.onEnter((function(e){return dt(e)})),Dt.onExit((function(){return dt.cancel})),Dt.on(vt.type,(function(e,t){var n,r,o={timetoken:(null===(n=e.cursor)||void 0===n?void 0:n.timetoken)?null===(r=e.cursor)||void 0===r?void 0:r.timetoken:t.payload.cursor.timetoken,region:t.payload.cursor.region};return It.with({channels:e.channels,groups:e.groups,cursor:o},[ht({category:k.PNConnectedCategory})])})),Dt.on(_t.type,(function(e,t){return Dt.with(n(n({},e),{attempts:e.attempts+1,reason:t.payload}))})),Dt.on(St.type,(function(e,t){var n;return Mt.with({groups:e.groups,channels:e.channels,cursor:e.cursor,reason:t.payload},[ht({category:k.PNConnectionErrorCategory,error:null===(n=t.payload)||void 0===n?void 0:n.message})])})),Dt.on(Tt.type,(function(e){return jt.with({channels:e.channels,groups:e.groups,cursor:e.cursor})})),Dt.on(yt.type,(function(e,t){return Ft.with({channels:t.payload.channels,groups:t.payload.groups,cursor:e.cursor})})),Dt.on(gt.type,(function(e,t){var n,r;return Ft.with({channels:t.payload.channels,groups:t.payload.groups,cursor:{timetoken:t.payload.cursor.timetoken,region:(null===(n=t.payload.cursor)||void 0===n?void 0:n.region)||(null===(r=null==e?void 0:e.cursor)||void 0===r?void 0:r.region)||0}})})),Dt.on(Ct.type,(function(e){return Lt.with(void 0)}));var Ft=new Ze("HANDSHAKING");Ft.onEnter((function(e){return ct(e.channels,e.groups)})),Ft.onExit((function(){return ct.cancel})),Ft.on(yt.type,(function(e,t){return 0===t.payload.channels.length&&0===t.payload.groups.length?Lt.with(void 0):Ft.with({channels:t.payload.channels,groups:t.payload.groups,cursor:e.cursor})})),Ft.on(mt.type,(function(e,t){var n,r;return It.with({channels:e.channels,groups:e.groups,cursor:{timetoken:(null===(n=null==e?void 0:e.cursor)||void 0===n?void 0:n.timetoken)?null===(r=null==e?void 0:e.cursor)||void 0===r?void 0:r.timetoken:t.payload.timetoken,region:t.payload.region}},[ht({category:k.PNConnectedCategory})])})),Ft.on(bt.type,(function(e,t){return Dt.with({channels:e.channels,groups:e.groups,cursor:e.cursor,attempts:0,reason:t.payload})})),Ft.on(Tt.type,(function(e){return jt.with({channels:e.channels,groups:e.groups,cursor:e.cursor})})),Ft.on(gt.type,(function(e,t){var n;return Ft.with({channels:t.payload.channels,groups:t.payload.groups,cursor:{timetoken:t.payload.cursor.timetoken,region:t.payload.cursor.region||(null===(n=null==e?void 0:e.cursor)||void 0===n?void 0:n.region)||0}})})),Ft.on(Ct.type,(function(e){return Lt.with()}));var Lt=new Ze("UNSUBSCRIBED");Lt.on(yt.type,(function(e,t){return Ft.with({channels:t.payload.channels,groups:t.payload.groups})})),Lt.on(gt.type,(function(e,t){return Ft.with({channels:t.payload.channels,groups:t.payload.groups,cursor:t.payload.cursor})}));var Gt=function(){function e(e){var t=this;this.engine=new et,this.channels=[],this.groups=[],this.dependencies=e,this.dispatcher=new kt(this.engine,e),this._unsubscribeEngine=this.engine.subscribe((function(e){"invocationDispatched"===e.type&&t.dispatcher.dispatch(e.invocation)})),this.engine.start(Lt,void 0)}return Object.defineProperty(e.prototype,"_engine",{get:function(){return this.engine},enumerable:!1,configurable:!0}),e.prototype.subscribe=function(e){var t=this,n=e.channels,r=e.channelGroups,o=e.timetoken,i=e.withPresence;this.channels=u(u([],a(this.channels),!1),a(null!=n?n:[]),!1),this.groups=u(u([],a(this.groups),!1),a(null!=r?r:[]),!1),i&&(this.channels.map((function(e){return t.channels.push("".concat(e,"-pnpres"))})),this.groups.map((function(e){return t.groups.push("".concat(e,"-pnpres"))}))),o?this.engine.transition(gt(Array.from(new Set(u(u([],a(this.channels),!1),a(null!=n?n:[]),!1))),Array.from(new Set(u(u([],a(this.groups),!1),a(null!=r?r:[]),!1))),o)):this.engine.transition(yt(Array.from(new Set(u(u([],a(this.channels),!1),a(null!=n?n:[]),!1))),Array.from(new Set(u(u([],a(this.groups),!1),a(null!=r?r:[]),!1))))),this.dependencies.join&&this.dependencies.join({channels:Array.from(new Set(this.channels.filter((function(e){return!e.endsWith("-pnpres")})))),groups:Array.from(new Set(this.groups.filter((function(e){return!e.endsWith("-pnpres")}))))})},e.prototype.unsubscribe=function(e){var t=this,n=e.channels,r=void 0===n?[]:n,o=e.channelGroups,i=void 0===o?[]:o,s=H.removeSingleOccurance(this.channels,u(u([],a(r),!1),a(r.map((function(e){return"".concat(e,"-pnpres")}))),!1)),c=H.removeSingleOccurance(this.groups,u(u([],a(i),!1),a(i.map((function(e){return"".concat(e,"-pnpres")}))),!1));if(new Set(this.channels).size!==new Set(s).size||new Set(this.groups).size!==new Set(c).size){var l=H.findUniqueCommonElements(this.channels,r),p=H.findUniqueCommonElements(this.groups,i);this.dependencies.presenceState&&(null==l||l.forEach((function(e){return delete t.dependencies.presenceState[e]})),null==p||p.forEach((function(e){return delete t.dependencies.presenceState[e]}))),this.channels=s,this.groups=c,this.engine.transition(yt(Array.from(new Set(this.channels.slice(0))),Array.from(new Set(this.groups.slice(0))))),this.dependencies.leave&&this.dependencies.leave({channels:l.slice(0),groups:p.slice(0)})}},e.prototype.unsubscribeAll=function(){this.channels=[],this.groups=[],this.dependencies.presenceState&&(this.dependencies.presenceState={}),this.engine.transition(yt(this.channels.slice(0),this.groups.slice(0))),this.dependencies.leaveAll&&this.dependencies.leaveAll()},e.prototype.reconnect=function(e){var t=e.timetoken,n=e.region;this.engine.transition(Nt(t,n))},e.prototype.disconnect=function(){this.engine.transition(Tt()),this.dependencies.leaveAll&&this.dependencies.leaveAll()},e.prototype.getSubscribedChannels=function(){return this.channels.slice(0)},e.prototype.getSubscribedChannelGroups=function(){return this.groups.slice(0)},e.prototype.dispose=function(){this.disconnect(),this._unsubscribeEngine(),this.dispatcher.dispose()},e}(),Kt=nt("RECONNECT",(function(){return{}})),Bt=nt("DISCONNECT",(function(){return{}})),Ht=nt("JOINED",(function(e,t){return{channels:e,groups:t}})),qt=nt("LEFT",(function(e,t){return{channels:e,groups:t}})),zt=nt("LEFT_ALL",(function(){return{}})),Vt=nt("HEARTBEAT_SUCCESS",(function(e){return{statusCode:e}})),Wt=nt("HEARTBEAT_FAILURE",(function(e){return e})),Jt=nt("HEARTBEAT_GIVEUP",(function(){return{}})),$t=nt("TIMES_UP",(function(){return{}})),Qt=rt("HEARTBEAT",(function(e,t){return{channels:e,groups:t}})),Xt=rt("LEAVE",(function(e,t){return{channels:e,groups:t}})),Yt=rt("EMIT_STATUS",(function(e){return e})),Zt=ot("WAIT",(function(){return{}})),en=ot("DELAYED_HEARTBEAT",(function(e){return e})),tn=function(e){function r(t,r){var s=e.call(this,r)||this;return s.on(Qt.type,ut((function(e,r,a){var u=a.heartbeat,c=a.presenceState,l=a.config;return o(s,void 0,void 0,(function(){var r;return i(this,(function(o){switch(o.label){case 0:return o.trys.push([0,2,,3]),[4,u(n({channels:e.channels,channelGroups:e.groups},l.maintainPresenceState&&{state:c}))];case 1:return o.sent(),t.transition(Vt(200)),[3,3];case 2:return(r=o.sent())instanceof q?[2,t.transition(Wt(r))]:[3,3];case 3:return[2]}}))}))}))),s.on(Xt.type,ut((function(e,t,n){var r=n.leave,a=n.config;return o(s,void 0,void 0,(function(){return i(this,(function(t){switch(t.label){case 0:if(a.suppressLeaveEvents)return[3,4];t.label=1;case 1:return t.trys.push([1,3,,4]),[4,r({channels:e.channels,channelGroups:e.groups})];case 2:case 3:return t.sent(),[3,4];case 4:return[2]}}))}))}))),s.on(Zt.type,ut((function(e,n,r){var a=r.heartbeatDelay;return o(s,void 0,void 0,(function(){return i(this,(function(e){switch(e.label){case 0:return n.throwIfAborted(),[4,a()];case 1:return e.sent(),n.throwIfAborted(),[2,t.transition($t())]}}))}))}))),s.on(en.type,ut((function(e,r,a){var u=a.heartbeat,c=a.retryDelay,l=a.presenceState,p=a.config;return o(s,void 0,void 0,(function(){var o;return i(this,(function(i){switch(i.label){case 0:return p.retryConfiguration&&p.retryConfiguration.shouldRetry(e.reason,e.attempts)?(r.throwIfAborted(),[4,c(p.retryConfiguration.getDelay(e.attempts,e.reason))]):[3,6];case 1:i.sent(),r.throwIfAborted(),i.label=2;case 2:return i.trys.push([2,4,,5]),[4,u(n({channels:e.channels,channelGroups:e.groups},p.maintainPresenceState&&{state:l}))];case 3:return i.sent(),[2,t.transition(Vt(200))];case 4:return(o=i.sent())instanceof Error&&"Aborted"===o.message?[2]:o instanceof q?[2,t.transition(Wt(o))]:[3,5];case 5:return[3,7];case 6:return[2,t.transition(Jt())];case 7:return[2]}}))}))}))),s.on(Yt.type,ut((function(e,t,r){var a=r.emitStatus,u=r.config;return o(s,void 0,void 0,(function(){var t;return i(this,(function(r){return u.announceFailedHeartbeats&&!0===(null===(t=null==e?void 0:e.status)||void 0===t?void 0:t.error)?a(e.status):u.announceSuccessfulHeartbeats&&200===e.statusCode&&a(n(n({},e),{operation:j.PNHeartbeatOperation,error:!1})),[2]}))}))}))),s}return t(r,e),r}(tt),nn=new Ze("HEARTBEAT_STOPPED");nn.on(Ht.type,(function(e,t){return nn.with({channels:u(u([],a(e.channels),!1),a(t.payload.channels),!1),groups:u(u([],a(e.groups),!1),a(t.payload.groups),!1)})})),nn.on(qt.type,(function(e,t){return nn.with({channels:e.channels.filter((function(e){return!t.payload.channels.includes(e)})),groups:e.groups.filter((function(e){return!t.payload.groups.includes(e)}))})})),nn.on(Kt.type,(function(e,t){return an.with({channels:e.channels,groups:e.groups})})),nn.on(zt.type,(function(e,t){return un.with(void 0)}));var rn=new Ze("HEARTBEAT_COOLDOWN");rn.onEnter((function(){return Zt()})),rn.onExit((function(){return Zt.cancel})),rn.on($t.type,(function(e,t){return an.with({channels:e.channels,groups:e.groups})})),rn.on(Ht.type,(function(e,t){return an.with({channels:u(u([],a(e.channels),!1),a(t.payload.channels),!1),groups:u(u([],a(e.groups),!1),a(t.payload.groups),!1)})})),rn.on(qt.type,(function(e,t){return an.with({channels:e.channels.filter((function(e){return!t.payload.channels.includes(e)})),groups:e.groups.filter((function(e){return!t.payload.groups.includes(e)}))},[Xt(t.payload.channels,t.payload.groups)])})),rn.on(Bt.type,(function(e){return nn.with({channels:e.channels,groups:e.groups},[Xt(e.channels,e.groups)])})),rn.on(zt.type,(function(e,t){return un.with(void 0,[Xt(e.channels,e.groups)])}));var on=new Ze("HEARTBEAT_FAILED");on.on(Ht.type,(function(e,t){return an.with({channels:u(u([],a(e.channels),!1),a(t.payload.channels),!1),groups:u(u([],a(e.groups),!1),a(t.payload.groups),!1)})})),on.on(qt.type,(function(e,t){return an.with({channels:e.channels.filter((function(e){return!t.payload.channels.includes(e)})),groups:e.groups.filter((function(e){return!t.payload.groups.includes(e)}))},[Xt(t.payload.channels,t.payload.groups)])})),on.on(Kt.type,(function(e,t){return an.with({channels:e.channels,groups:e.groups})})),on.on(Bt.type,(function(e,t){return nn.with({channels:e.channels,groups:e.groups},[Xt(e.channels,e.groups)])})),on.on(zt.type,(function(e,t){return un.with(void 0,[Xt(e.channels,e.groups)])}));var sn=new Ze("HEARBEAT_RECONNECTING");sn.onEnter((function(e){return en(e)})),sn.onExit((function(){return en.cancel})),sn.on(Ht.type,(function(e,t){return an.with({channels:u(u([],a(e.channels),!1),a(t.payload.channels),!1),groups:u(u([],a(e.groups),!1),a(t.payload.groups),!1)})})),sn.on(qt.type,(function(e,t){return an.with({channels:e.channels.filter((function(e){return!t.payload.channels.includes(e)})),groups:e.groups.filter((function(e){return!t.payload.groups.includes(e)}))},[Xt(t.payload.channels,t.payload.groups)])})),sn.on(Bt.type,(function(e,t){nn.with({channels:e.channels,groups:e.groups},[Xt(e.channels,e.groups)])})),sn.on(Vt.type,(function(e,t){return rn.with({channels:e.channels,groups:e.groups})})),sn.on(Wt.type,(function(e,t){return sn.with(n(n({},e),{attempts:e.attempts+1,reason:t.payload}))})),sn.on(Jt.type,(function(e,t){return on.with({channels:e.channels,groups:e.groups})})),sn.on(zt.type,(function(e,t){return un.with(void 0,[Xt(e.channels,e.groups)])}));var an=new Ze("HEARTBEATING");an.onEnter((function(e){return Qt(e.channels,e.groups)})),an.on(Vt.type,(function(e,t){return rn.with({channels:e.channels,groups:e.groups})})),an.on(Ht.type,(function(e,t){return an.with({channels:u(u([],a(e.channels),!1),a(t.payload.channels),!1),groups:u(u([],a(e.groups),!1),a(t.payload.groups),!1)})})),an.on(qt.type,(function(e,t){return an.with({channels:e.channels.filter((function(e){return!t.payload.channels.includes(e)})),groups:e.groups.filter((function(e){return!t.payload.groups.includes(e)}))},[Xt(t.payload.channels,t.payload.groups)])})),an.on(Wt.type,(function(e,t){return sn.with(n(n({},e),{attempts:0,reason:t.payload}))})),an.on(Bt.type,(function(e){return nn.with({channels:e.channels,groups:e.groups},[Xt(e.channels,e.groups)])})),an.on(zt.type,(function(e,t){return un.with(void 0,[Xt(e.channels,e.groups)])}));var un=new Ze("HEARTBEAT_INACTIVE");un.on(Ht.type,(function(e,t){return an.with({channels:t.payload.channels,groups:t.payload.groups})}));var cn=function(){function e(e){var t=this;this.engine=new et,this.channels=[],this.groups=[],this.dispatcher=new tn(this.engine,e),this.dependencies=e,this._unsubscribeEngine=this.engine.subscribe((function(e){"invocationDispatched"===e.type&&t.dispatcher.dispatch(e.invocation)})),this.engine.start(un,void 0)}return Object.defineProperty(e.prototype,"_engine",{get:function(){return this.engine},enumerable:!1,configurable:!0}),e.prototype.join=function(e){var t=e.channels,n=e.groups;this.channels=u(u([],a(this.channels),!1),a(null!=t?t:[]),!1),this.groups=u(u([],a(this.groups),!1),a(null!=n?n:[]),!1),this.engine.transition(Ht(this.channels.slice(0),this.groups.slice(0)))},e.prototype.leave=function(e){var t=this,n=e.channels,r=e.groups;this.dependencies.presenceState&&(null==n||n.forEach((function(e){return delete t.dependencies.presenceState[e]})),null==r||r.forEach((function(e){return delete t.dependencies.presenceState[e]}))),this.engine.transition(qt(null!=n?n:[],null!=r?r:[]))},e.prototype.leaveAll=function(){this.engine.transition(zt())},e.prototype.dispose=function(){this._unsubscribeEngine(),this.dispatcher.dispose()},e}(),ln=function(){function e(){}return e.LinearRetryPolicy=function(e){return{delay:e.delay,maximumRetry:e.maximumRetry,shouldRetry:function(e,t){var n;return 403!==(null===(n=null==e?void 0:e.status)||void 0===n?void 0:n.statusCode)&&this.maximumRetry>t},getDelay:function(e,t){var n;return 1e3*((null!==(n=t.retryAfter)&&void 0!==n?n:this.delay)+Math.random())},getGiveupReason:function(e,t){var n;return this.maximumRetry<=t?"retry attempts exhaused.":403===(null===(n=null==e?void 0:e.status)||void 0===n?void 0:n.statusCode)?"forbidden operation.":"unknown error"}}},e.ExponentialRetryPolicy=function(e){return{minimumDelay:e.minimumDelay,maximumDelay:e.maximumDelay,maximumRetry:e.maximumRetry,shouldRetry:function(e,t){var n;return 403!==(null===(n=null==e?void 0:e.status)||void 0===n?void 0:n.statusCode)&&this.maximumRetry>t},getDelay:function(e,t){var n;return 1e3*((null!==(n=t.retryAfter)&&void 0!==n?n:Math.min(Math.pow(2,e),this.maximumDelay))+Math.random())},getGiveupReason:function(e,t){var n;return this.maximumRetry<=t?"retry attempts exhaused.":403===(null===(n=null==e?void 0:e.status)||void 0===n?void 0:n.statusCode)?"forbidden operation.":"unknown error"}}},e}(),pn=function(){function e(e){var t=e.modules,n=e.listenerManager,r=e.getFileUrl;this.modules=t,this.listenerManager=n,this.getFileUrl=r,this._channelListenerMap=new Map,this._groupListenerMap=new Map,t.cryptoModule&&(this._decoder=new TextDecoder)}return e.prototype.emitEvent=function(e){var t=e.channel,o=e.publishMetaData,i=e.subscriptionMatch;if(t===i&&(i=null),e.channel.endsWith("-pnpres")){var s={channel:null,subscription:null};t&&(s.channel=t.substring(0,t.lastIndexOf("-pnpres"))),i&&(s.subscription=i.substring(0,i.lastIndexOf("-pnpres"))),s.action=e.payload.action,s.state=e.payload.data,s.timetoken=o.publishTimetoken,s.occupancy=e.payload.occupancy,s.uuid=e.payload.uuid,s.timestamp=e.payload.timestamp,e.payload.join&&(s.join=e.payload.join),e.payload.leave&&(s.leave=e.payload.leave),e.payload.timeout&&(s.timeout=e.payload.timeout),s.actualChannel=null!=i?t:null,s.subscribedChannel=null!=i?i:t,this.listenerManager.announcePresence(s),this._announce("presence",s,s.channel,s.subscription)}else if(1===e.messageType){(s={channel:null,subscription:null}).channel=t,s.subscription=i,s.timetoken=o.publishTimetoken,s.publisher=e.issuingClientId,e.userMetadata&&(s.userMetadata=e.userMetadata),s.message=e.payload,this.listenerManager.announceSignal(s),this._announce("signal",s,s.channel,s.subscription)}else if(2===e.messageType){if((s={channel:null,subscription:null}).channel=t,s.subscription=i,s.timetoken=o.publishTimetoken,s.publisher=e.issuingClientId,e.userMetadata&&(s.userMetadata=e.userMetadata),s.message={event:e.payload.event,type:e.payload.type,data:e.payload.data},this.listenerManager.announceObjects(s),this._announce("objects",s,s.channel,s.subscription),"uuid"===e.payload.type){var a=this._renameChannelField(s),u=n(n({},a),{message:n(n({},a.message),{event:this._renameEvent(a.message.event),type:"user"})});this.listenerManager.announceUser(u),this._announce("user",u,s.channel,s.subscription)}else if("channel"===message.payload.type){a=this._renameChannelField(s);var c=n(n({},a),{message:n(n({},a.message),{event:this._renameEvent(a.message.event),type:"space"})});this.listenerManager.announceSpace(c),this._announce("space",c,s.channel,s.subscription)}else if("membership"===message.payload.type){var l=(a=this._renameChannelField(s)).message.data,p=l.uuid,h=l.channel,f=r(l,["uuid","channel"]);f.user=p,f.space=h;var d=n(n({},a),{message:n(n({},a.message),{event:this._renameEvent(a.message.event),data:f})});this.listenerManager.announceMembership(d),this._announce("membership",d,s.channel,s.subscription)}}else if(3===e.messageType){(s={}).channel=t,s.subscription=i,s.timetoken=o.publishTimetoken,s.publisher=e.issuingClientId,s.data={messageTimetoken:e.payload.data.messageTimetoken,actionTimetoken:e.payload.data.actionTimetoken,type:e.payload.data.type,uuid:e.issuingClientId,value:e.payload.data.value},s.event=e.payload.event,this.listenerManager.announceMessageAction(s),this._announce("messageAction",s,s.channel,s.subscription)}else if(4===e.messageType){(s={}).channel=t,s.subscription=i,s.timetoken=o.publishTimetoken,s.publisher=e.issuingClientId;var y=e.payload;if(this.modules.cryptoModule){var g=void 0;try{g=(m=this.modules.cryptoModule.decrypt(e.payload))instanceof ArrayBuffer?JSON.parse(this._decoder.decode(m)):m}catch(e){g=null,s.error="Error while decrypting message content: ".concat(e.message)}null!==g&&(y=g)}e.userMetadata&&(s.userMetadata=e.userMetadata),s.message=y.message,s.file={id:y.file.id,name:y.file.name,url:this.getFileUrl({id:y.file.id,name:y.file.name,channel:t})},this.listenerManager.announceFile(s),this._announce("file",s,s.channel,s.subscription)}else{if((s={channel:null,subscription:null}).channel=t,s.subscription=i,s.timetoken=o.publishTimetoken,s.publisher=e.issuingClientId,e.userMetadata&&(s.userMetadata=e.userMetadata),this.modules.cryptoModule){g=void 0;try{var m;g=(m=this.modules.cryptoModule.decrypt(e.payload))instanceof ArrayBuffer?JSON.parse(this._decoder.decode(m)):m}catch(e){g=null,s.error="Error while decrypting message content: ".concat(e.message)}s.message=null!=g?g:e.payload}else s.message=e.payload;s.actualChannel=null!=i?t:null,s.subscribedChannel=null!=i?i:t,this.listenerManager.announceMessage(s),this._announce("message",s,s.channel,s.subscription)}},e.prototype.addListener=function(e,t,n){var r=this;t&&n?(null==t||t.forEach((function(t){r._channelListenerMap[t]?r._channelListenerMap[t].includes(e)||r._channelListenerMap[t].push(e):r._channelListenerMap[t]=[e]})),null==n||n.forEach((function(t){r._groupListenerMap[t]?r._groupListenerMap[t].includes(e)||r._groupListenerMap[t].push(e):r._groupListenerMap[t]=[e]}))):this.listenerManager.addListener(e)},e.prototype.removeListener=function(e,t,n){var r=this;t&&n?(null==t||t.forEach((function(t){var n;r._channelListenerMap[t]=null===(n=r._channelListenerMap[t])||void 0===n?void 0:n.filter((function(t){return t!==e}))})),null==n||n.forEach((function(t){var n;r._groupListenerMap[t]=null===(n=r._groupListenerMap[t])||void 0===n?void 0:n.filter((function(t){return t!==e}))}))):this.listenerManager.removeListener(e)},e.prototype.removeAllListeners=function(){this.listenerManager.removeAllListeners()},e.prototype._renameEvent=function(e){return"set"===e?"updated":"removed"},e.prototype._renameChannelField=function(e){var t=e.channel,n=r(e,["channel"]);return n.spaceId=t,n},e.prototype._announce=function(e,t,n,r){var o,i;null===(o=this._channelListenerMap[n])||void 0===o||o.forEach((function(n){return n[e]&&n[e](t)})),null===(i=this._groupListenerMap[r])||void 0===i||i.forEach((function(n){return n[e]&&n[e](t)}))},e}(),hn=function(){function e(){}return e.prototype.subscribe=function(){var e,t;this.pubnub.subscribe(n({channels:this.channelNames,channelGroups:this.groupNames},(null===(t=null===(e=this.options)||void 0===e?void 0:e.cursor)||void 0===t?void 0:t.timetoken)&&{timetoken:this.options.cursor.timetoken}))},e.prototype.unsubscribe=function(){this.pubnub.unsubscribe({channels:this.channelNames.filter((function(e){return!e.endsWith("-pnpres")})),channelGroups:this.groupNames.filter((function(e){return!e.endsWith("-pnpres")}))})},Object.defineProperty(e.prototype,"onMessage",{set:function(e){this.listener.message=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"onPresence",{set:function(e){this.listener.presence=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"onSignal",{set:function(e){this.listener.signal=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"onObjects",{set:function(e){this.listener.objects=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"onMessageAction",{set:function(e){this.listener.messageAction=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"onFile",{set:function(e){this.listener.file=e},enumerable:!1,configurable:!0}),e.prototype.addListener=function(e){this.eventEmitter.addListener(e,this.channelNames.filter((function(e){return!e.endsWith("-pnpres")})),this.groupNames.filter((function(e){return!e.endsWith("-pnpres")})))},e.prototype.removeListener=function(e){this.eventEmitter.removeListener(e,this.channelNames,this.groupNames)},Object.defineProperty(e.prototype,"channels",{get:function(){return this.channelNames.slice(0)},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"channelGroups",{get:function(){return this.groupNames.slice(0)},enumerable:!1,configurable:!0}),e}(),fn=function(e){function n(t){var n=t.channels,r=void 0===n?[]:n,o=t.channelGroups,i=void 0===o?[]:o,s=t.subscriptionOptions,c=t.eventEmitter,l=t.pubnub,p=e.call(this)||this;return p.channelNames=[],p.groupNames=[],p.subscriptionList=[],p.options=s,p.eventEmitter=c,p.pubnub=l,r.forEach((function(e){var t=p.pubnub.channel(e).subscription(p.options);p.channelNames=u(u([],a(p.channelNames),!1),a(t.channels),!1),p.subscriptionList.push(t)})),i.forEach((function(e){var t=p.pubnub.channelGroup(e).subscription(p.options);p.groupNames=u(u([],a(p.groupNames),!1),a(t.channelGroups),!1),p.subscriptionList.push(t)})),p.listener={},c.addListener(p.listener,p.channelNames.filter((function(e){return!e.endsWith("-pnpres")})),p.groupNames.filter((function(e){return!e.endsWith("-pnpres")}))),p}return t(n,e),n.prototype.addSubscription=function(e){this.subscriptionList.push(e),this.channelNames=u(u([],a(this.channelNames),!1),a(e.channels),!1),this.groupNames=u(u([],a(this.groupNames),!1),a(e.channelGroups),!1)},n.prototype.removeSubscription=function(e){var t=e.channels,n=e.channelGroups;this.channelNames=this.channelNames.filter((function(e){return!t.includes(e)})),this.groupNames=this.groupNames.filter((function(e){return!n.includes(e)})),this.subscriptionList=this.subscriptionList.filter((function(t){return t!==e}))},n.prototype.addSubscriptionSet=function(e){this.subscriptionList=u(u([],a(this.subscriptionList),!1),a(e.subscriptions),!1),this.channelNames=u(u([],a(this.channelNames),!1),a(e.channels),!1),this.groupNames=u(u([],a(this.groupNames),!1),a(e.channelGroups),!1)},n.prototype.removeSubscriptionSet=function(e){var t=e.channels,n=e.channelGroups;this.channelNames=this.channelNames.filter((function(e){return!t.includes(e)})),this.groupNames=this.groupNames.filter((function(e){return!n.includes(e)})),this.subscriptionList=this.subscriptionList.filter((function(t){return!e.subscriptions.includes(t)}))},Object.defineProperty(n.prototype,"subscriptions",{get:function(){return this.subscriptionList.slice(0)},enumerable:!1,configurable:!0}),n}(hn),dn=function(e){function r(t){var n=t.channels,r=t.channelGroups,o=t.subscriptionOptions,i=t.eventEmitter,s=t.pubnub,a=e.call(this)||this;return a.channelNames=[],a.groupNames=[],a.channelNames=n,a.groupNames=r,a.options=o,a.pubnub=s,a.eventEmitter=i,a.listener={},i.addListener(a.listener,a.channelNames.filter((function(e){return!e.endsWith("-pnpres")})),a.groupNames.filter((function(e){return!e.endsWith("-pnpres")}))),a}return t(r,e),r.prototype.addSubscription=function(e){return new fn({channels:u(u([],a(this.channelNames),!1),a(e.channels),!1),channelGroups:u(u([],a(this.groupNames),!1),a(e.channelGroups),!1),subscriptionOptions:n(n({},this.options),null==e?void 0:e.options),eventEmitter:this.eventEmitter,pubnub:this.pubnub})},r}(hn),yn=function(){function e(e,t,n){this.name=e,this.eventEmitter=t,this.pubnub=n}return e.prototype.subscription=function(e){return new dn({channels:(null==e?void 0:e.receivePresenceEvents)?[this.name,"".concat(this.name,"-pnpres")]:[this.name],channelGroups:[],subscriptionOptions:e,eventEmitter:this.eventEmitter,pubnub:this.pubnub})},e}(),gn=function(){function e(e,t,n){this.name=e,this.eventEmitter=t,this.pubnub=n}return e.prototype.subscription=function(e){return new dn({channels:[],channelGroups:(null==e?void 0:e.receivePresenceEvents)?[this.name,"".concat(this.name,"-pnpres")]:[this.name],subscriptionOptions:e,eventEmitter:this.eventEmitter,pubnub:this.pubnub})},e}(),mn=function(){function e(e,t,n){this.id=e,this.eventEmitter=t,this.pubnub=n}return e.prototype.subscription=function(e){return new dn({channels:[this.id],channelGroups:[],subscriptionOptions:e,eventEmitter:this.eventEmitter,pubnub:this.pubnub})},e}(),bn=function(){function e(e,t,n){this.id=e,this.eventEmitter=t,this.pubnub=n}return e.prototype.subscription=function(e){return new dn({channels:[this.id],channelGroups:[],subscriptionOptions:e,eventEmitter:this.eventEmitter,pubnub:this.pubnub})},e}(),vn=function(){function e(e){var t=this,r=e.networking,o=e.cbor,i=new g({setup:e});this._config=i;var c=new T({config:i}),l=e.cryptography;r.init(i);var p=new G(i,o);this._tokenManager=p;var h=new R({maximumSamplesCount:6e4});this._telemetryManager=h;var f=this._config.cryptoModule,d={config:i,networking:r,crypto:c,cryptography:l,tokenManager:p,telemetryManager:h,PubNubFile:e.PubNubFile,cryptoModule:f};this.File=e.PubNubFile,this.encryptFile=function(e,t){return 1==arguments.length&&"string"!=typeof e&&d.cryptoModule?(t=e,d.cryptoModule.encryptFile(t,this.File)):l.encryptFile(e,t,this.File)},this.decryptFile=function(e,t){return 1==arguments.length&&"string"!=typeof e&&d.cryptoModule?(t=e,d.cryptoModule.decryptFile(t,this.File)):l.decryptFile(e,t,this.File)};var y=Q.bind(this,d,Je),m=Q.bind(this,d,se),v=Q.bind(this,d,ue),_=Q.bind(this,d,le),S=Q.bind(this,d,$e),w=new L;if(this._listenerManager=w,this.iAmHere=Q.bind(this,d,ue),this.iAmAway=Q.bind(this,d,se),this.setPresenceState=Q.bind(this,d,le),this.handshake=Q.bind(this,d,Qe),this.receiveMessages=Q.bind(this,d,Xe),this._eventEmitter=new pn({modules:d,listenerManager:this._listenerManager,getFileUrl:function(e){return ve(d,e)}}),!0===i.enableEventEngine){if(i.maintainPresenceState&&(this.presenceState={},this.setState=function(e){var n,r;return null===(n=e.channels)||void 0===n||n.forEach((function(n){return t.presenceState[n]=e.state})),null===(r=e.channelGroups)||void 0===r||r.forEach((function(n){return t.presenceState[n]=e.state})),t.setPresenceState({channels:e.channels,channelGroups:e.channelGroups,state:t.presenceState})}),i.getHeartbeatInterval()){var O=new cn({heartbeat:this.iAmHere,leave:this.iAmAway,heartbeatDelay:function(){return new Promise((function(e){return setTimeout(e,1e3*d.config.getHeartbeatInterval())}))},retryDelay:function(e){return new Promise((function(t){return setTimeout(t,e)}))},config:d.config,presenceState:this.presenceState,emitStatus:function(e){w.announceStatus(e)}});this.presenceEventEngine=O,this.join=this.presenceEventEngine.join.bind(O),this.leave=this.presenceEventEngine.leave.bind(O),this.leaveAll=this.presenceEventEngine.leaveAll.bind(O)}var P=new Gt({handshake:this.handshake,receiveMessages:this.receiveMessages,delay:function(e){return new Promise((function(t){return setTimeout(t,e)}))},join:this.join,leave:this.leave,leaveAll:this.leaveAll,presenceState:this.presenceState,config:d.config,emitMessages:function(e){var n,r;try{for(var o=s(e),i=o.next();!i.done;i=o.next()){var a=i.value;t._eventEmitter.emitEvent(a)}}catch(e){n={error:e}}finally{try{i&&!i.done&&(r=o.return)&&r.call(o)}finally{if(n)throw n.error}}},emitStatus:function(e){w.announceStatus(e)}});this.subscribe=P.subscribe.bind(P),this.unsubscribe=P.unsubscribe.bind(P),this.unsubscribeAll=P.unsubscribeAll.bind(P),this.reconnect=P.reconnect.bind(P),this.disconnect=P.disconnect.bind(P),this.destroy=P.dispose.bind(P),this.getSubscribedChannels=P.getSubscribedChannels.bind(P),this.getSubscribedChannelGroups=P.getSubscribedChannelGroups.bind(P),this.eventEngine=P}else{var E=new M({timeEndpoint:y,leaveEndpoint:m,heartbeatEndpoint:v,setStateEndpoint:_,subscribeEndpoint:S,crypto:d.crypto,config:d.config,listenerManager:w,getFileUrl:function(e){return ve(d,e)},cryptoModule:d.cryptoModule,eventEmitter:this._eventEmitter});this.subscribe=E.adaptSubscribeChange.bind(E),this.unsubscribe=E.adaptUnsubscribeChange.bind(E),this.disconnect=E.disconnect.bind(E),this.reconnect=E.reconnect.bind(E),this.unsubscribeAll=E.unsubscribeAll.bind(E),this.getSubscribedChannels=E.getSubscribedChannels.bind(E),this.getSubscribedChannelGroups=E.getSubscribedChannelGroups.bind(E),this.setState=E.adaptStateChange.bind(E),this.presence=E.adaptPresenceChange.bind(E),this.destroy=function(e){E.unsubscribeAll(e),E.disconnect()}}this.addListener=this._eventEmitter.addListener.bind(this._eventEmitter),this.removeListener=this._eventEmitter.removeListener.bind(this._eventEmitter),this.removeAllListeners=this._eventEmitter.removeAllListeners.bind(this._eventEmitter),this.parseToken=p.parseToken.bind(p),this.setToken=p.setToken.bind(p),this.getToken=p.getToken.bind(p),this.channelGroups={listGroups:Q.bind(this,d,ee),listChannels:Q.bind(this,d,te),addChannels:Q.bind(this,d,X),removeChannels:Q.bind(this,d,Y),deleteGroup:Q.bind(this,d,Z)},this.push={addChannels:Q.bind(this,d,ne),removeChannels:Q.bind(this,d,re),deleteDevice:Q.bind(this,d,ie),listChannels:Q.bind(this,d,oe)},this.hereNow=Q.bind(this,d,pe),this.whereNow=Q.bind(this,d,ae),this.getState=Q.bind(this,d,ce),this.grant=Q.bind(this,d,Ue),this.grantToken=Q.bind(this,d,Le),this.audit=Q.bind(this,d,xe),this.revokeToken=Q.bind(this,d,Ge),this.publish=Q.bind(this,d,Be),this.fire=function(e,n){return e.replicate=!1,e.storeInHistory=!1,t.publish(e,n)},this.signal=Q.bind(this,d,He),this.history=Q.bind(this,d,qe),this.deleteMessages=Q.bind(this,d,ze),this.messageCounts=Q.bind(this,d,Ve),this.fetchMessages=Q.bind(this,d,We),this.addMessageAction=Q.bind(this,d,he),this.removeMessageAction=Q.bind(this,d,fe),this.getMessageActions=Q.bind(this,d,de),this.listFiles=Q.bind(this,d,ye);var A=Q.bind(this,d,ge);this.publishFile=Q.bind(this,d,me),this.sendFile=be({generateUploadUrl:A,publishFile:this.publishFile,modules:d}),this.getFileUrl=function(e){return ve(d,e)},this.downloadFile=Q.bind(this,d,_e),this.deleteFile=Q.bind(this,d,Se),this.channel=function(e){return new yn(e,t._eventEmitter,t)},this.channelGroup=function(e){return new gn(e,t._eventEmitter,t)},this.channelMetadata=function(e){return new mn(e,t._eventEmitter,t)},this.userMetadata=function(e){return new bn(e,t._eventEmitter,t)},this.subscriptionSet=function(e){return new fn({channels:e.channels,channelGroups:e.channelGroups,subscriptionOptions:e.subscriptionOptions,eventEmitter:t._eventEmitter,pubnub:t})},this.objects={getAllUUIDMetadata:Q.bind(this,d,we),getUUIDMetadata:Q.bind(this,d,Oe),setUUIDMetadata:Q.bind(this,d,Pe),removeUUIDMetadata:Q.bind(this,d,Ee),getAllChannelMetadata:Q.bind(this,d,Ae),getChannelMetadata:Q.bind(this,d,Te),setChannelMetadata:Q.bind(this,d,Ne),removeChannelMetadata:Q.bind(this,d,Ce),getChannelMembers:Q.bind(this,d,ke),setChannelMembers:function(e){for(var r=[],o=1;o=this._config.origin.length&&(this._currentSubDomain=0);var t=this._config.origin[this._currentSubDomain];return"".concat(e).concat(t)},e.prototype.hasModule=function(e){return e in this._modules},e.prototype.shiftStandardOrigin=function(){return this._standardOrigin=this.nextOrigin(),this._standardOrigin},e.prototype.getStandardOrigin=function(){return this._standardOrigin},e.prototype.POSTFILE=function(e,t,n){return this._modules.postfile(e,t,n)},e.prototype.GETFILE=function(e,t,n){return this._modules.getfile(e,t,n)},e.prototype.POST=function(e,t,n,r){return this._modules.post(e,t,n,r)},e.prototype.PATCH=function(e,t,n,r){return this._modules.patch(e,t,n,r)},e.prototype.GET=function(e,t,n){return this._modules.get(e,t,n)},e.prototype.DELETE=function(e,t,n){return this._modules.del(e,t,n)},e.prototype._detectErrorCategory=function(e){if("ENOTFOUND"===e.code)return k.PNNetworkIssuesCategory;if("ECONNREFUSED"===e.code)return k.PNNetworkIssuesCategory;if("ECONNRESET"===e.code)return k.PNNetworkIssuesCategory;if("EAI_AGAIN"===e.code)return k.PNNetworkIssuesCategory;if(0===e.status||e.hasOwnProperty("status")&&void 0===e.status)return k.PNNetworkIssuesCategory;if(e.timeout)return k.PNTimeoutCategory;if("ETIMEDOUT"===e.code)return k.PNNetworkIssuesCategory;if(e.response){if(e.response.badRequest)return k.PNBadRequestCategory;if(e.response.forbidden)return k.PNAccessDeniedCategory}return k.PNUnknownCategory},e}();function Sn(e){var t=function(e){return e&&"object"==typeof e&&e.constructor===Object};if(!t(e))return e;var n={};return Object.keys(e).forEach((function(r){var o=function(e){return"string"==typeof e||e instanceof String}(r),i=r,s=e[r];Array.isArray(r)||o&&r.indexOf(",")>=0?i=(o?r.split(","):r).reduce((function(e,t){return e+=String.fromCharCode(t)}),""):(function(e){return"number"==typeof e&&isFinite(e)}(r)||o&&!isNaN(r))&&(i=String.fromCharCode(o?parseInt(r,10):10));n[i]=t(s)?Sn(s):s})),n}var wn=function(){function e(e,t){this._base64ToBinary=t,this._decode=e}return e.prototype.decodeToken=function(e){var t="";e.length%4==3?t="=":e.length%4==2&&(t="==");var n=e.replace(/-/gi,"+").replace(/_/gi,"/")+t,r=this._decode(this._base64ToBinary(n));if("object"==typeof r)return r},e}(),On={exports:{}},Pn={exports:{}};!function(e){function t(e){if(e)return function(e){for(var n in t.prototype)e[n]=t.prototype[n];return e}(e)}e.exports=t,t.prototype.on=t.prototype.addEventListener=function(e,t){return this._callbacks=this._callbacks||{},(this._callbacks["$"+e]=this._callbacks["$"+e]||[]).push(t),this},t.prototype.once=function(e,t){function n(){this.off(e,n),t.apply(this,arguments)}return n.fn=t,this.on(e,n),this},t.prototype.off=t.prototype.removeListener=t.prototype.removeAllListeners=t.prototype.removeEventListener=function(e,t){if(this._callbacks=this._callbacks||{},0==arguments.length)return this._callbacks={},this;var n,r=this._callbacks["$"+e];if(!r)return this;if(1==arguments.length)return delete this._callbacks["$"+e],this;for(var o=0;os.depthLimit)return void jn(An,e,t,o);if(void 0!==s.edgesLimit&&n+1>s.edgesLimit)return void jn(An,e,t,o);if(r.push(e),Array.isArray(e))for(a=0;at?1:0}function Un(e,t,n,r){void 0===r&&(r=kn());var o,i=In(e,"",0,[],void 0,0,r)||e;try{o=0===Cn.length?JSON.stringify(i,t,n):JSON.stringify(i,Dn(t),n)}catch(e){return JSON.stringify("[unable to serialize, circular reference is too complex to analyze]")}finally{for(;0!==Nn.length;){var s=Nn.pop();4===s.length?Object.defineProperty(s[0],s[1],s[3]):s[0][s[1]]=s[2]}}return o}function In(e,t,n,r,o,i,s){var a;if(i+=1,"object"==typeof e&&null!==e){for(a=0;as.depthLimit)return void jn(An,e,t,o);if(void 0!==s.edgesLimit&&n+1>s.edgesLimit)return void jn(An,e,t,o);if(r.push(e),Array.isArray(e))for(a=0;a0)for(var r=0;r1&&"boolean"!=typeof t)throw new Qn('"allowMissing" argument must be a boolean');var n=gr(e),r=n.length>0?n[0]:"",o=mr("%"+r+"%",t),i=o.name,s=o.value,a=!1,u=o.alias;u&&(r=u[0],pr(n,lr([0,1],u)));for(var c=1,l=!0;c=n.length){var d=Yn(s,p);s=(l=!!d)&&"get"in d&&!("originalValue"in d.get)?d.get:s[p]}else l=cr(s,p),s=s[p];l&&!a&&(ir[i]=s)}}return s},vr={exports:{}};!function(e){var t=Vn,n=br,r=n("%Function.prototype.apply%"),o=n("%Function.prototype.call%"),i=n("%Reflect.apply%",!0)||t.call(o,r),s=n("%Object.getOwnPropertyDescriptor%",!0),a=n("%Object.defineProperty%",!0),u=n("%Math.max%");if(a)try{a({},"a",{value:1})}catch(e){a=null}e.exports=function(e){var n=i(t,o,arguments);if(s&&a){var r=s(n,"length");r.configurable&&a(n,"length",{value:1+u(0,e.length-(arguments.length-1))})}return n};var c=function(){return i(t,r,arguments)};a?a(e.exports,"apply",{value:c}):e.exports.apply=c}(vr);var _r=br,Sr=vr.exports,wr=Sr(_r("String.prototype.indexOf")),Or=l(Object.freeze({__proto__:null,default:{}})),Pr="function"==typeof Map&&Map.prototype,Er=Object.getOwnPropertyDescriptor&&Pr?Object.getOwnPropertyDescriptor(Map.prototype,"size"):null,Ar=Pr&&Er&&"function"==typeof Er.get?Er.get:null,Tr=Pr&&Map.prototype.forEach,Nr="function"==typeof Set&&Set.prototype,Cr=Object.getOwnPropertyDescriptor&&Nr?Object.getOwnPropertyDescriptor(Set.prototype,"size"):null,kr=Nr&&Cr&&"function"==typeof Cr.get?Cr.get:null,Mr=Nr&&Set.prototype.forEach,jr="function"==typeof WeakMap&&WeakMap.prototype?WeakMap.prototype.has:null,Rr="function"==typeof WeakSet&&WeakSet.prototype?WeakSet.prototype.has:null,xr="function"==typeof WeakRef&&WeakRef.prototype?WeakRef.prototype.deref:null,Ur=Boolean.prototype.valueOf,Ir=Object.prototype.toString,Dr=Function.prototype.toString,Fr=String.prototype.match,Lr=String.prototype.slice,Gr=String.prototype.replace,Kr=String.prototype.toUpperCase,Br=String.prototype.toLowerCase,Hr=RegExp.prototype.test,qr=Array.prototype.concat,zr=Array.prototype.join,Vr=Array.prototype.slice,Wr=Math.floor,Jr="function"==typeof BigInt?BigInt.prototype.valueOf:null,$r=Object.getOwnPropertySymbols,Qr="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?Symbol.prototype.toString:null,Xr="function"==typeof Symbol&&"object"==typeof Symbol.iterator,Yr="function"==typeof Symbol&&Symbol.toStringTag&&(typeof Symbol.toStringTag===Xr||"symbol")?Symbol.toStringTag:null,Zr=Object.prototype.propertyIsEnumerable,eo=("function"==typeof Reflect?Reflect.getPrototypeOf:Object.getPrototypeOf)||([].__proto__===Array.prototype?function(e){return e.__proto__}:null);function to(e,t){if(e===1/0||e===-1/0||e!=e||e&&e>-1e3&&e<1e3||Hr.call(/e/,t))return t;var n=/[0-9](?=(?:[0-9]{3})+(?![0-9]))/g;if("number"==typeof e){var r=e<0?-Wr(-e):Wr(e);if(r!==e){var o=String(r),i=Lr.call(t,o.length+1);return Gr.call(o,n,"$&_")+"."+Gr.call(Gr.call(i,/([0-9]{3})/g,"$&_"),/_$/,"")}}return Gr.call(t,n,"$&_")}var no=Or,ro=no.custom,oo=co(ro)?ro:null;function io(e,t,n){var r="double"===(n.quoteStyle||t)?'"':"'";return r+e+r}function so(e){return Gr.call(String(e),/"/g,""")}function ao(e){return!("[object Array]"!==ho(e)||Yr&&"object"==typeof e&&Yr in e)}function uo(e){return!("[object RegExp]"!==ho(e)||Yr&&"object"==typeof e&&Yr in e)}function co(e){if(Xr)return e&&"object"==typeof e&&e instanceof Symbol;if("symbol"==typeof e)return!0;if(!e||"object"!=typeof e||!Qr)return!1;try{return Qr.call(e),!0}catch(e){}return!1}var lo=Object.prototype.hasOwnProperty||function(e){return e in this};function po(e,t){return lo.call(e,t)}function ho(e){return Ir.call(e)}function fo(e,t){if(e.indexOf)return e.indexOf(t);for(var n=0,r=e.length;nt.maxStringLength){var n=e.length-t.maxStringLength,r="... "+n+" more character"+(n>1?"s":"");return yo(Lr.call(e,0,t.maxStringLength),t)+r}return io(Gr.call(Gr.call(e,/(['\\])/g,"\\$1"),/[\x00-\x1f]/g,go),"single",t)}function go(e){var t=e.charCodeAt(0),n={8:"b",9:"t",10:"n",12:"f",13:"r"}[t];return n?"\\"+n:"\\x"+(t<16?"0":"")+Kr.call(t.toString(16))}function mo(e){return"Object("+e+")"}function bo(e){return e+" { ? }"}function vo(e,t,n,r){return e+" ("+t+") {"+(r?_o(n,r):zr.call(n,", "))+"}"}function _o(e,t){if(0===e.length)return"";var n="\n"+t.prev+t.base;return n+zr.call(e,","+n)+"\n"+t.prev}function So(e,t){var n=ao(e),r=[];if(n){r.length=e.length;for(var o=0;o-1?Sr(n):n},Po=function e(t,n,r,o){var i=n||{};if(po(i,"quoteStyle")&&"single"!==i.quoteStyle&&"double"!==i.quoteStyle)throw new TypeError('option "quoteStyle" must be "single" or "double"');if(po(i,"maxStringLength")&&("number"==typeof i.maxStringLength?i.maxStringLength<0&&i.maxStringLength!==1/0:null!==i.maxStringLength))throw new TypeError('option "maxStringLength", if provided, must be a positive integer, Infinity, or `null`');var s=!po(i,"customInspect")||i.customInspect;if("boolean"!=typeof s&&"symbol"!==s)throw new TypeError("option \"customInspect\", if provided, must be `true`, `false`, or `'symbol'`");if(po(i,"indent")&&null!==i.indent&&"\t"!==i.indent&&!(parseInt(i.indent,10)===i.indent&&i.indent>0))throw new TypeError('option "indent" must be "\\t", an integer > 0, or `null`');if(po(i,"numericSeparator")&&"boolean"!=typeof i.numericSeparator)throw new TypeError('option "numericSeparator", if provided, must be `true` or `false`');var a=i.numericSeparator;if(void 0===t)return"undefined";if(null===t)return"null";if("boolean"==typeof t)return t?"true":"false";if("string"==typeof t)return yo(t,i);if("number"==typeof t){if(0===t)return 1/0/t>0?"0":"-0";var u=String(t);return a?to(t,u):u}if("bigint"==typeof t){var l=String(t)+"n";return a?to(t,l):l}var p=void 0===i.depth?5:i.depth;if(void 0===r&&(r=0),r>=p&&p>0&&"object"==typeof t)return ao(t)?"[Array]":"[Object]";var h=function(e,t){var n;if("\t"===e.indent)n="\t";else{if(!("number"==typeof e.indent&&e.indent>0))return null;n=zr.call(Array(e.indent+1)," ")}return{base:n,prev:zr.call(Array(t+1),n)}}(i,r);if(void 0===o)o=[];else if(fo(o,t)>=0)return"[Circular]";function f(t,n,s){if(n&&(o=Vr.call(o)).push(n),s){var a={depth:i.depth};return po(i,"quoteStyle")&&(a.quoteStyle=i.quoteStyle),e(t,a,r+1,o)}return e(t,i,r+1,o)}if("function"==typeof t&&!uo(t)){var d=function(e){if(e.name)return e.name;var t=Fr.call(Dr.call(e),/^function\s*([\w$]+)/);if(t)return t[1];return null}(t),y=So(t,f);return"[Function"+(d?": "+d:" (anonymous)")+"]"+(y.length>0?" { "+zr.call(y,", ")+" }":"")}if(co(t)){var g=Xr?Gr.call(String(t),/^(Symbol\(.*\))_[^)]*$/,"$1"):Qr.call(t);return"object"!=typeof t||Xr?g:mo(g)}if(function(e){if(!e||"object"!=typeof e)return!1;if("undefined"!=typeof HTMLElement&&e instanceof HTMLElement)return!0;return"string"==typeof e.nodeName&&"function"==typeof e.getAttribute}(t)){for(var m="<"+Br.call(String(t.nodeName)),b=t.attributes||[],v=0;v"}if(ao(t)){if(0===t.length)return"[]";var _=So(t,f);return h&&!function(e){for(var t=0;t=0)return!1;return!0}(_)?"["+_o(_,h)+"]":"[ "+zr.call(_,", ")+" ]"}if(function(e){return!("[object Error]"!==ho(e)||Yr&&"object"==typeof e&&Yr in e)}(t)){var S=So(t,f);return"cause"in Error.prototype||!("cause"in t)||Zr.call(t,"cause")?0===S.length?"["+String(t)+"]":"{ ["+String(t)+"] "+zr.call(S,", ")+" }":"{ ["+String(t)+"] "+zr.call(qr.call("[cause]: "+f(t.cause),S),", ")+" }"}if("object"==typeof t&&s){if(oo&&"function"==typeof t[oo]&&no)return no(t,{depth:p-r});if("symbol"!==s&&"function"==typeof t.inspect)return t.inspect()}if(function(e){if(!Ar||!e||"object"!=typeof e)return!1;try{Ar.call(e);try{kr.call(e)}catch(e){return!0}return e instanceof Map}catch(e){}return!1}(t)){var w=[];return Tr&&Tr.call(t,(function(e,n){w.push(f(n,t,!0)+" => "+f(e,t))})),vo("Map",Ar.call(t),w,h)}if(function(e){if(!kr||!e||"object"!=typeof e)return!1;try{kr.call(e);try{Ar.call(e)}catch(e){return!0}return e instanceof Set}catch(e){}return!1}(t)){var O=[];return Mr&&Mr.call(t,(function(e){O.push(f(e,t))})),vo("Set",kr.call(t),O,h)}if(function(e){if(!jr||!e||"object"!=typeof e)return!1;try{jr.call(e,jr);try{Rr.call(e,Rr)}catch(e){return!0}return e instanceof WeakMap}catch(e){}return!1}(t))return bo("WeakMap");if(function(e){if(!Rr||!e||"object"!=typeof e)return!1;try{Rr.call(e,Rr);try{jr.call(e,jr)}catch(e){return!0}return e instanceof WeakSet}catch(e){}return!1}(t))return bo("WeakSet");if(function(e){if(!xr||!e||"object"!=typeof e)return!1;try{return xr.call(e),!0}catch(e){}return!1}(t))return bo("WeakRef");if(function(e){return!("[object Number]"!==ho(e)||Yr&&"object"==typeof e&&Yr in e)}(t))return mo(f(Number(t)));if(function(e){if(!e||"object"!=typeof e||!Jr)return!1;try{return Jr.call(e),!0}catch(e){}return!1}(t))return mo(f(Jr.call(t)));if(function(e){return!("[object Boolean]"!==ho(e)||Yr&&"object"==typeof e&&Yr in e)}(t))return mo(Ur.call(t));if(function(e){return!("[object String]"!==ho(e)||Yr&&"object"==typeof e&&Yr in e)}(t))return mo(f(String(t)));if("undefined"!=typeof window&&t===window)return"{ [object Window] }";if(t===c)return"{ [object globalThis] }";if(!function(e){return!("[object Date]"!==ho(e)||Yr&&"object"==typeof e&&Yr in e)}(t)&&!uo(t)){var P=So(t,f),E=eo?eo(t)===Object.prototype:t instanceof Object||t.constructor===Object,A=t instanceof Object?"":"null prototype",T=!E&&Yr&&Object(t)===t&&Yr in t?Lr.call(ho(t),8,-1):A?"Object":"",N=(E||"function"!=typeof t.constructor?"":t.constructor.name?t.constructor.name+" ":"")+(T||A?"["+zr.call(qr.call([],T||[],A||[]),": ")+"] ":"");return 0===P.length?N+"{}":h?N+"{"+_o(P,h)+"}":N+"{ "+zr.call(P,", ")+" }"}return String(t)},Eo=wo("%TypeError%"),Ao=wo("%WeakMap%",!0),To=wo("%Map%",!0),No=Oo("WeakMap.prototype.get",!0),Co=Oo("WeakMap.prototype.set",!0),ko=Oo("WeakMap.prototype.has",!0),Mo=Oo("Map.prototype.get",!0),jo=Oo("Map.prototype.set",!0),Ro=Oo("Map.prototype.has",!0),xo=function(e,t){for(var n,r=e;null!==(n=r.next);r=n)if(n.key===t)return r.next=n.next,n.next=e.next,e.next=n,n},Uo=String.prototype.replace,Io=/%20/g,Do="RFC3986",Fo={default:Do,formatters:{RFC1738:function(e){return Uo.call(e,Io,"+")},RFC3986:function(e){return String(e)}},RFC1738:"RFC1738",RFC3986:Do},Lo=Fo,Go=Object.prototype.hasOwnProperty,Ko=Array.isArray,Bo=function(){for(var e=[],t=0;t<256;++t)e.push("%"+((t<16?"0":"")+t.toString(16)).toUpperCase());return e}(),Ho=function(e,t){for(var n=t&&t.plainObjects?Object.create(null):{},r=0;r1;){var t=e.pop(),n=t.obj[t.prop];if(Ko(n)){for(var r=[],o=0;o=48&&u<=57||u>=65&&u<=90||u>=97&&u<=122||o===Lo.RFC1738&&(40===u||41===u)?s+=i.charAt(a):u<128?s+=Bo[u]:u<2048?s+=Bo[192|u>>6]+Bo[128|63&u]:u<55296||u>=57344?s+=Bo[224|u>>12]+Bo[128|u>>6&63]+Bo[128|63&u]:(a+=1,u=65536+((1023&u)<<10|1023&i.charCodeAt(a)),s+=Bo[240|u>>18]+Bo[128|u>>12&63]+Bo[128|u>>6&63]+Bo[128|63&u])}return s},isBuffer:function(e){return!(!e||"object"!=typeof e)&&!!(e.constructor&&e.constructor.isBuffer&&e.constructor.isBuffer(e))},isRegExp:function(e){return"[object RegExp]"===Object.prototype.toString.call(e)},maybeMap:function(e,t){if(Ko(e)){for(var n=[],r=0;r0?b.join(",")||null:void 0}];else if(Qo(u))O=u;else{var E=Object.keys(b);O=c?E.sort(c):E}for(var A=o&&Qo(b)&&1===b.length?n+"[]":n,T=0;T-1?e.split(","):e},li=function(e,t,n,r){if(e){var o=n.allowDots?e.replace(/\.([^.[]+)/g,"[$1]"):e,i=/(\[[^[\]]*])/g,s=n.depth>0&&/(\[[^[\]]*])/.exec(o),a=s?o.slice(0,s.index):o,u=[];if(a){if(!n.plainObjects&&ii.call(Object.prototype,a)&&!n.allowPrototypes)return;u.push(a)}for(var c=0;n.depth>0&&null!==(s=i.exec(o))&&c=0;--i){var s,a=e[i];if("[]"===a&&n.parseArrays)s=[].concat(o);else{s=n.plainObjects?Object.create(null):{};var u="["===a.charAt(0)&&"]"===a.charAt(a.length-1)?a.slice(1,-1):a,c=parseInt(u,10);n.parseArrays||""!==u?!isNaN(c)&&a!==u&&String(c)===u&&c>=0&&n.parseArrays&&c<=n.arrayLimit?(s=[])[c]=o:"__proto__"!==u&&(s[u]=o):s={0:o}}o=s}return o}(u,t,n,r)}},pi=function(e,t){var n,r=e,o=function(e){if(!e)return ti;if(null!==e.encoder&&void 0!==e.encoder&&"function"!=typeof e.encoder)throw new TypeError("Encoder has to be a function.");var t=e.charset||ti.charset;if(void 0!==e.charset&&"utf-8"!==e.charset&&"iso-8859-1"!==e.charset)throw new TypeError("The charset option must be either utf-8, iso-8859-1, or undefined");var n=Wo.default;if(void 0!==e.format){if(!Jo.call(Wo.formatters,e.format))throw new TypeError("Unknown format option provided.");n=e.format}var r=Wo.formatters[n],o=ti.filter;return("function"==typeof e.filter||Qo(e.filter))&&(o=e.filter),{addQueryPrefix:"boolean"==typeof e.addQueryPrefix?e.addQueryPrefix:ti.addQueryPrefix,allowDots:void 0===e.allowDots?ti.allowDots:!!e.allowDots,charset:t,charsetSentinel:"boolean"==typeof e.charsetSentinel?e.charsetSentinel:ti.charsetSentinel,delimiter:void 0===e.delimiter?ti.delimiter:e.delimiter,encode:"boolean"==typeof e.encode?e.encode:ti.encode,encoder:"function"==typeof e.encoder?e.encoder:ti.encoder,encodeValuesOnly:"boolean"==typeof e.encodeValuesOnly?e.encodeValuesOnly:ti.encodeValuesOnly,filter:o,format:n,formatter:r,serializeDate:"function"==typeof e.serializeDate?e.serializeDate:ti.serializeDate,skipNulls:"boolean"==typeof e.skipNulls?e.skipNulls:ti.skipNulls,sort:"function"==typeof e.sort?e.sort:null,strictNullHandling:"boolean"==typeof e.strictNullHandling?e.strictNullHandling:ti.strictNullHandling}}(t);"function"==typeof o.filter?r=(0,o.filter)("",r):Qo(o.filter)&&(n=o.filter);var i,s=[];if("object"!=typeof r||null===r)return"";i=t&&t.arrayFormat in $o?t.arrayFormat:t&&"indices"in t?t.indices?"indices":"repeat":"indices";var a=$o[i];if(t&&"commaRoundTrip"in t&&"boolean"!=typeof t.commaRoundTrip)throw new TypeError("`commaRoundTrip` must be a boolean, or absent");var u="comma"===a&&t&&t.commaRoundTrip;n||(n=Object.keys(r)),o.sort&&n.sort(o.sort);for(var c=zo(),l=0;l0?f+h:""},hi={formats:Fo,parse:function(e,t){var n=function(e){if(!e)return ai;if(null!==e.decoder&&void 0!==e.decoder&&"function"!=typeof e.decoder)throw new TypeError("Decoder has to be a function.");if(void 0!==e.charset&&"utf-8"!==e.charset&&"iso-8859-1"!==e.charset)throw new TypeError("The charset option must be either utf-8, iso-8859-1, or undefined");var t=void 0===e.charset?ai.charset:e.charset;return{allowDots:void 0===e.allowDots?ai.allowDots:!!e.allowDots,allowPrototypes:"boolean"==typeof e.allowPrototypes?e.allowPrototypes:ai.allowPrototypes,allowSparse:"boolean"==typeof e.allowSparse?e.allowSparse:ai.allowSparse,arrayLimit:"number"==typeof e.arrayLimit?e.arrayLimit:ai.arrayLimit,charset:t,charsetSentinel:"boolean"==typeof e.charsetSentinel?e.charsetSentinel:ai.charsetSentinel,comma:"boolean"==typeof e.comma?e.comma:ai.comma,decoder:"function"==typeof e.decoder?e.decoder:ai.decoder,delimiter:"string"==typeof e.delimiter||oi.isRegExp(e.delimiter)?e.delimiter:ai.delimiter,depth:"number"==typeof e.depth||!1===e.depth?+e.depth:ai.depth,ignoreQueryPrefix:!0===e.ignoreQueryPrefix,interpretNumericEntities:"boolean"==typeof e.interpretNumericEntities?e.interpretNumericEntities:ai.interpretNumericEntities,parameterLimit:"number"==typeof e.parameterLimit?e.parameterLimit:ai.parameterLimit,parseArrays:!1!==e.parseArrays,plainObjects:"boolean"==typeof e.plainObjects?e.plainObjects:ai.plainObjects,strictNullHandling:"boolean"==typeof e.strictNullHandling?e.strictNullHandling:ai.strictNullHandling}}(t);if(""===e||null==e)return n.plainObjects?Object.create(null):{};for(var r="string"==typeof e?function(e,t){var n,r={__proto__:null},o=t.ignoreQueryPrefix?e.replace(/^\?/,""):e,i=t.parameterLimit===1/0?void 0:t.parameterLimit,s=o.split(t.delimiter,i),a=-1,u=t.charset;if(t.charsetSentinel)for(n=0;n-1&&(l=si(l)?[l]:l),ii.call(r,c)?r[c]=oi.combine(r[c],l):r[c]=l}return r}(e,n):e,o=n.plainObjects?Object.create(null):{},i=Object.keys(r),s=0;s=e.length?{done:!0}:{done:!1,value:e[o++]}},e:function(e){throw e},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var s,a=!0,u=!1;return{s:function(){r=r.call(e)},n:function(){var e=r.next();return a=e.done,e},e:function(e){u=!0,s=e},f:function(){try{a||null==r.return||r.return()}finally{if(u)throw s}}}}function n(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);ne.split(/ *; */).shift(),e.params=e=>{const n={};var r,o=t(e.split(/ *; */));try{for(o.s();!(r=o.n()).done;){const e=r.value.split(/ *= */),t=e.shift(),o=e.shift();t&&o&&(n[t]=o)}}catch(e){o.e(e)}finally{o.f()}return n},e.parseLinks=e=>{const n={};var r,o=t(e.split(/ *, */));try{for(o.s();!(r=o.n()).done;){const e=r.value.split(/ *; */),t=e[0].slice(1,-1);n[e[1].split(/ *= */)[1].slice(1,-1)]=t}}catch(e){o.e(e)}finally{o.f()}return n},e.cleanHeader=(e,t)=>(delete e["content-type"],delete e["content-length"],delete e["transfer-encoding"],delete e.host,t&&(delete e.authorization,delete e.cookie),e),e.isObject=e=>null!==e&&"object"==typeof e,e.hasOwn=Object.hasOwn||function(e,t){if(null==e)throw new TypeError("Cannot convert undefined or null to object");return Object.prototype.hasOwnProperty.call(new Object(e),t)},e.mixin=(t,n)=>{for(const r in n)e.hasOwn(n,r)&&(t[r]=n[r])}}(fi);const di=Or,yi=fi.isObject,gi=fi.hasOwn;var mi=bi;function bi(){}bi.prototype.clearTimeout=function(){return clearTimeout(this._timer),clearTimeout(this._responseTimeoutTimer),clearTimeout(this._uploadTimeoutTimer),delete this._timer,delete this._responseTimeoutTimer,delete this._uploadTimeoutTimer,this},bi.prototype.parse=function(e){return this._parser=e,this},bi.prototype.responseType=function(e){return this._responseType=e,this},bi.prototype.serialize=function(e){return this._serializer=e,this},bi.prototype.timeout=function(e){if(!e||"object"!=typeof e)return this._timeout=e,this._responseTimeout=0,this._uploadTimeout=0,this;for(const t in e)if(gi(e,t))switch(t){case"deadline":this._timeout=e.deadline;break;case"response":this._responseTimeout=e.response;break;case"upload":this._uploadTimeout=e.upload;break;default:console.warn("Unknown timeout option",t)}return this},bi.prototype.retry=function(e,t){return 0!==arguments.length&&!0!==e||(e=1),e<=0&&(e=0),this._maxRetries=e,this._retries=0,this._retryCallback=t,this};const vi=new Set(["ETIMEDOUT","ECONNRESET","EADDRINUSE","ECONNREFUSED","EPIPE","ENOTFOUND","ENETUNREACH","EAI_AGAIN"]),_i=new Set([408,413,429,500,502,503,504,521,522,524]);bi.prototype._shouldRetry=function(e,t){if(!this._maxRetries||this._retries++>=this._maxRetries)return!1;if(this._retryCallback)try{const n=this._retryCallback(e,t);if(!0===n)return!0;if(!1===n)return!1}catch(e){console.error(e)}if(t&&t.status&&_i.has(t.status))return!0;if(e){if(e.code&&vi.has(e.code))return!0;if(e.timeout&&"ECONNABORTED"===e.code)return!0;if(e.crossDomain)return!0}return!1},bi.prototype._retry=function(){return this.clearTimeout(),this.req&&(this.req=null,this.req=this.request()),this._aborted=!1,this.timedout=!1,this.timedoutError=null,this._end()},bi.prototype.then=function(e,t){if(!this._fullfilledPromise){const e=this;this._endCalled&&console.warn("Warning: superagent request was sent twice, because both .end() and .then() were called. Never call .end() if you use promises"),this._fullfilledPromise=new Promise(((t,n)=>{e.on("abort",(()=>{if(this._maxRetries&&this._maxRetries>this._retries)return;if(this.timedout&&this.timedoutError)return void n(this.timedoutError);const e=new Error("Aborted");e.code="ABORTED",e.status=this.status,e.method=this.method,e.url=this.url,n(e)})),e.end(((e,r)=>{e?n(e):t(r)}))}))}return this._fullfilledPromise.then(e,t)},bi.prototype.catch=function(e){return this.then(void 0,e)},bi.prototype.use=function(e){return e(this),this},bi.prototype.ok=function(e){if("function"!=typeof e)throw new Error("Callback required");return this._okCallback=e,this},bi.prototype._isResponseOK=function(e){return!!e&&(this._okCallback?this._okCallback(e):e.status>=200&&e.status<300)},bi.prototype.get=function(e){return this._header[e.toLowerCase()]},bi.prototype.getHeader=bi.prototype.get,bi.prototype.set=function(e,t){if(yi(e)){for(const t in e)gi(e,t)&&this.set(t,e[t]);return this}return this._header[e.toLowerCase()]=t,this.header[e]=t,this},bi.prototype.unset=function(e){return delete this._header[e.toLowerCase()],delete this.header[e],this},bi.prototype.field=function(e,t,n){if(null==e)throw new Error(".field(name, val) name can not be empty");if(this._data)throw new Error(".field() can't be used if .send() is used. Please use only .send() or only .field() & .attach()");if(yi(e)){for(const t in e)gi(e,t)&&this.field(t,e[t]);return this}if(Array.isArray(t)){for(const n in t)gi(t,n)&&this.field(e,t[n]);return this}if(null==t)throw new Error(".field(name, val) val can not be empty");return"boolean"==typeof t&&(t=String(t)),n?this._getFormData().append(e,t,n):this._getFormData().append(e,t),this},bi.prototype.abort=function(){if(this._aborted)return this;if(this._aborted=!0,this.xhr&&this.xhr.abort(),this.req){if(di.gte(process.version,"v13.0.0")&&di.lt(process.version,"v14.0.0"))throw new Error("Superagent does not work in v13 properly with abort() due to Node.js core changes");this.req.abort()}return this.clearTimeout(),this.emit("abort"),this},bi.prototype._auth=function(e,t,n,r){switch(n.type){case"basic":this.set("Authorization",`Basic ${r(`${e}:${t}`)}`);break;case"auto":this.username=e,this.password=t;break;case"bearer":this.set("Authorization",`Bearer ${e}`)}return this},bi.prototype.withCredentials=function(e){return void 0===e&&(e=!0),this._withCredentials=e,this},bi.prototype.redirects=function(e){return this._maxRedirects=e,this},bi.prototype.maxResponseSize=function(e){if("number"!=typeof e)throw new TypeError("Invalid argument");return this._maxResponseSize=e,this},bi.prototype.toJSON=function(){return{method:this.method,url:this.url,data:this._data,headers:this._header}},bi.prototype.send=function(e){const t=yi(e);let n=this._header["content-type"];if(this._formData)throw new Error(".send() can't be used if .attach() or .field() is used. Please use only .send() or only .field() & .attach()");if(t&&!this._data)Array.isArray(e)?this._data=[]:this._isHost(e)||(this._data={});else if(e&&this._data&&this._isHost(this._data))throw new Error("Can't merge these send calls");if(t&&yi(this._data))for(const t in e){if("bigint"==typeof e[t]&&!e[t].toJSON)throw new Error("Cannot serialize BigInt value to json");gi(e,t)&&(this._data[t]=e[t])}else{if("bigint"==typeof e)throw new Error("Cannot send value of type BigInt");"string"==typeof e?(n||this.type("form"),n=this._header["content-type"],n&&(n=n.toLowerCase().trim()),this._data="application/x-www-form-urlencoded"===n?this._data?`${this._data}&${e}`:e:(this._data||"")+e):this._data=e}return!t||this._isHost(e)||n||this.type("json"),this},bi.prototype.sortQuery=function(e){return this._sort=void 0===e||e,this},bi.prototype._finalizeQueryString=function(){const e=this._query.join("&");if(e&&(this.url+=(this.url.includes("?")?"&":"?")+e),this._query.length=0,this._sort){const e=this.url.indexOf("?");if(e>=0){const t=this.url.slice(e+1).split("&");"function"==typeof this._sort?t.sort(this._sort):t.sort(),this.url=this.url.slice(0,e)+"?"+t.join("&")}}},bi.prototype._appendQueryString=()=>{console.warn("Unsupported")},bi.prototype._timeoutError=function(e,t,n){if(this._aborted)return;const r=new Error(`${e+t}ms exceeded`);r.timeout=t,r.code="ECONNABORTED",r.errno=n,this.timedout=!0,this.timedoutError=r,this.abort(),this.callback(r)},bi.prototype._setTimeouts=function(){const e=this;this._timeout&&!this._timer&&(this._timer=setTimeout((()=>{e._timeoutError("Timeout of ",e._timeout,"ETIME")}),this._timeout)),this._responseTimeout&&!this._responseTimeoutTimer&&(this._responseTimeoutTimer=setTimeout((()=>{e._timeoutError("Response timeout of ",e._responseTimeout,"ETIMEDOUT")}),this._responseTimeout))};const Si=fi;var wi=Oi;function Oi(){}function Pi(e,t){var n="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(!n){if(Array.isArray(e)||(n=function(e,t){if(!e)return;if("string"==typeof e)return Ei(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return Ei(e,t)}(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var r=0,o=function(){};return{s:o,n:function(){return r>=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:o}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var i,s=!0,a=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return s=e.done,e},e:function(e){a=!0,i=e},f:function(){try{s||null==n.return||n.return()}finally{if(a)throw i}}}}function Ei(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n=e.length?{done:!0}:{done:!1,value:e[o++]}},e:function(e){throw e},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var s,a=!0,u=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return a=e.done,e},e:function(e){u=!0,s=e},f:function(){try{a||null==n.return||n.return()}finally{if(u)throw s}}}}function r(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n{if(o.XMLHttpRequest)return new o.XMLHttpRequest;throw new Error("Browser-only version of superagent could not find XHR")};const g="".trim?e=>e.trim():e=>e.replace(/(^\s*|\s*$)/g,"");function m(e){if(!c(e))return e;const t=[];for(const n in e)p(e,n)&&b(t,n,e[n]);return t.join("&")}function b(e,t,r){if(void 0!==r)if(null!==r)if(Array.isArray(r)){var o,i=n(r);try{for(i.s();!(o=i.n()).done;){b(e,t,o.value)}}catch(e){i.e(e)}finally{i.f()}}else if(c(r))for(const n in r)p(r,n)&&b(e,`${t}[${n}]`,r[n]);else e.push(encodeURI(t)+"="+encodeURIComponent(r));else e.push(encodeURI(t))}function v(e){const t={},n=e.split("&");let r,o;for(let e=0,i=n.length;e{let e,t=null,r=null;try{r=new S(n)}catch(e){return t=new Error("Parser is unable to parse the response"),t.parse=!0,t.original=e,n.xhr?(t.rawResponse=void 0===n.xhr.responseType?n.xhr.responseText:n.xhr.response,t.status=n.xhr.status?n.xhr.status:null,t.statusCode=t.status):(t.rawResponse=null,t.status=null),n.callback(t)}n.emit("response",r);try{n._isResponseOK(r)||(e=new Error(r.statusText||r.text||"Unsuccessful HTTP response"))}catch(t){e=t}e?(e.original=t,e.response=r,e.status=e.status||r.status,n.callback(e,r)):n.callback(null,r)}))}y.serializeObject=m,y.parseString=v,y.types={html:"text/html",json:"application/json",xml:"text/xml",urlencoded:"application/x-www-form-urlencoded",form:"application/x-www-form-urlencoded","form-data":"application/x-www-form-urlencoded"},y.serialize={"application/x-www-form-urlencoded":a.stringify,"application/json":s},y.parse={"application/x-www-form-urlencoded":v,"application/json":JSON.parse},l(S.prototype,h.prototype),S.prototype._parseBody=function(e){let t=y.parse[this.type];return this.req._parser?this.req._parser(this,e):(!t&&_(this.type)&&(t=y.parse["application/json"]),t&&e&&(e.length>0||e instanceof Object)?t(e):null)},S.prototype.toError=function(){const e=this.req,t=e.method,n=e.url,r=`cannot ${t} ${n} (${this.status})`,o=new Error(r);return o.status=this.status,o.method=t,o.url=n,o},y.Response=S,i(w.prototype),l(w.prototype,u.prototype),w.prototype.type=function(e){return this.set("Content-Type",y.types[e]||e),this},w.prototype.accept=function(e){return this.set("Accept",y.types[e]||e),this},w.prototype.auth=function(e,t,n){1===arguments.length&&(t=""),"object"==typeof t&&null!==t&&(n=t,t=""),n||(n={type:"function"==typeof btoa?"basic":"auto"});const r=n.encoder?n.encoder:e=>{if("function"==typeof btoa)return btoa(e);throw new Error("Cannot use basic auth, btoa is not a function")};return this._auth(e,t,n,r)},w.prototype.query=function(e){return"string"!=typeof e&&(e=m(e)),e&&this._query.push(e),this},w.prototype.attach=function(e,t,n){if(t){if(this._data)throw new Error("superagent can't mix .send() and .attach()");this._getFormData().append(e,t,n||t.name)}return this},w.prototype._getFormData=function(){return this._formData||(this._formData=new o.FormData),this._formData},w.prototype.callback=function(e,t){if(this._shouldRetry(e,t))return this._retry();const n=this._callback;this.clearTimeout(),e&&(this._maxRetries&&(e.retries=this._retries-1),this.emit("error",e)),n(e,t)},w.prototype.crossDomainError=function(){const e=new Error("Request has been terminated\nPossible causes: the network is offline, Origin is not allowed by Access-Control-Allow-Origin, the page is being unloaded, etc.");e.crossDomain=!0,e.status=this.status,e.method=this.method,e.url=this.url,this.callback(e)},w.prototype.agent=function(){return console.warn("This is not supported in browser version of superagent"),this},w.prototype.ca=w.prototype.agent,w.prototype.buffer=w.prototype.ca,w.prototype.write=()=>{throw new Error("Streaming is not supported in browser version of superagent")},w.prototype.pipe=w.prototype.write,w.prototype._isHost=function(e){return e&&"object"==typeof e&&!Array.isArray(e)&&"[object Object]"!==Object.prototype.toString.call(e)},w.prototype.end=function(e){this._endCalled&&console.warn("Warning: .end() was called twice. This is not supported in superagent"),this._endCalled=!0,this._callback=e||d,this._finalizeQueryString(),this._end()},w.prototype._setUploadTimeout=function(){const e=this;this._uploadTimeout&&!this._uploadTimeoutTimer&&(this._uploadTimeoutTimer=setTimeout((()=>{e._timeoutError("Upload timeout of ",e._uploadTimeout,"ETIMEDOUT")}),this._uploadTimeout))},w.prototype._end=function(){if(this._aborted)return this.callback(new Error("The request has been aborted even before .end() was called"));const e=this;this.xhr=y.getXHR();const t=this.xhr;let n=this._formData||this._data;this._setTimeouts(),t.addEventListener("readystatechange",(()=>{const n=t.readyState;if(n>=2&&e._responseTimeoutTimer&&clearTimeout(e._responseTimeoutTimer),4!==n)return;let r;try{r=t.status}catch(e){r=0}if(!r){if(e.timedout||e._aborted)return;return e.crossDomainError()}e.emit("end")}));const r=(t,n)=>{n.total>0&&(n.percent=n.loaded/n.total*100,100===n.percent&&clearTimeout(e._uploadTimeoutTimer)),n.direction=t,e.emit("progress",n)};if(this.hasListeners("progress"))try{t.addEventListener("progress",r.bind(null,"download")),t.upload&&t.upload.addEventListener("progress",r.bind(null,"upload"))}catch(e){}t.upload&&this._setUploadTimeout();try{this.username&&this.password?t.open(this.method,this.url,!0,this.username,this.password):t.open(this.method,this.url,!0)}catch(e){return this.callback(e)}if(this._withCredentials&&(t.withCredentials=!0),!this._formData&&"GET"!==this.method&&"HEAD"!==this.method&&"string"!=typeof n&&!this._isHost(n)){const e=this._header["content-type"];let t=this._serializer||y.serialize[e?e.split(";")[0]:""];!t&&_(e)&&(t=y.serialize["application/json"]),t&&(n=t(n))}for(const e in this.header)null!==this.header[e]&&p(this.header,e)&&t.setRequestHeader(e,this.header[e]);this._responseType&&(t.responseType=this._responseType),this.emit("request",this),t.send(void 0===n?null:n)},y.agent=()=>new f;for(var O=0,P=["GET","POST","OPTIONS","PATCH","PUT","DELETE"];O{const r=y("GET",e);return"function"==typeof t&&(n=t,t=null),t&&r.query(t),n&&r.end(n),r},y.head=(e,t,n)=>{const r=y("HEAD",e);return"function"==typeof t&&(n=t,t=null),t&&r.query(t),n&&r.end(n),r},y.options=(e,t,n)=>{const r=y("OPTIONS",e);return"function"==typeof t&&(n=t,t=null),t&&r.send(t),n&&r.end(n),r},y.del=E,y.delete=E,y.patch=(e,t,n)=>{const r=y("PATCH",e);return"function"==typeof t&&(n=t,t=null),t&&r.send(t),n&&r.end(n),r},y.post=(e,t,n)=>{const r=y("POST",e);return"function"==typeof t&&(n=t,t=null),t&&r.send(t),n&&r.end(n),r},y.put=(e,t,n)=>{const r=y("PUT",e);return"function"==typeof t&&(n=t,t=null),t&&r.send(t),n&&r.end(n),r}}(On,On.exports);var ki=On.exports;function Mi(e){var t=(new Date).getTime(),n=(new Date).toISOString(),r=console&&console.log?console:window&&window.console&&window.console.log?window.console:console;r.log("<<<<<"),r.log("[".concat(n,"]"),"\n",e.url,"\n",e.qs),r.log("-----"),e.on("response",(function(n){var o=(new Date).getTime()-t,i=(new Date).toISOString();r.log(">>>>>>"),r.log("[".concat(i," / ").concat(o,"]"),"\n",e.url,"\n",e.qs,"\n",n.text),r.log("-----")}))}function ji(e,t,n){var r=this;this._config.logVerbosity&&(e=e.use(Mi)),this._config.proxy&&this._modules.proxy&&(e=this._modules.proxy.call(this,e)),this._config.keepAlive&&this._modules.keepAlive&&(e=this._modules.keepAlive(e));var o=e;if(t.abortSignal)var i=t.abortSignal.subscribe((function(){o.abort(),i()}));return!0===t.forceBuffered?o="undefined"==typeof Blob?o.buffer().responseType("arraybuffer"):o.responseType("arraybuffer"):!1===t.forceBuffered&&(o=o.buffer(!1)),(o=o.timeout(t.timeout)).on("abort",(function(){return n({category:k.PNUnknownCategory,error:!0,operation:t.operation,errorData:new Error("Aborted")},null)})),o.end((function(e,o){var i,s={};if(s.error=null!==e,s.operation=t.operation,o&&o.status&&(s.statusCode=o.status),e){if(e.response&&e.response.text&&!r._config.logVerbosity)try{s.errorData=JSON.parse(e.response.text)}catch(t){s.errorData=e}else s.errorData=e;return s.category=r._detectErrorCategory(e),n(s,null)}if(t.ignoreBody)i={headers:o.headers,redirects:o.redirects,response:o};else try{i=JSON.parse(o.text)}catch(e){return s.errorData=o,s.error=!0,n(s,null)}return i.error&&1===i.error&&i.status&&i.message&&i.service?(s.errorData=i,s.statusCode=i.status,s.error=!0,s.category=r._detectErrorCategory(s),n(s,null)):(i.error&&i.error.message&&(s.errorData=i.error),n(s,i))})),o}function Ri(e,t,n){return o(this,void 0,void 0,(function(){var r;return i(this,(function(o){switch(o.label){case 0:return r=ki.post(e),t.forEach((function(e){var t=e.key,n=e.value;r=r.field(t,n)})),r.attach("file",n,{contentType:"application/octet-stream"}),[4,r];case 1:return[2,o.sent()]}}))}))}function xi(e,t,n){var r=ki.get(this.getStandardOrigin()+t.url).set(t.headers).query(e);return ji.call(this,r,t,n)}function Ui(e,t,n){var r=ki.get(this.getStandardOrigin()+t.url).set(t.headers).query(e);return ji.call(this,r,t,n)}function Ii(e,t,n,r){var o=ki.post(this.getStandardOrigin()+n.url).query(e).set(n.headers).send(t);return ji.call(this,o,n,r)}function Di(e,t,n,r){var o=ki.patch(this.getStandardOrigin()+n.url).query(e).set(n.headers).send(t);return ji.call(this,o,n,r)}function Fi(e,t,n){var r=ki.delete(this.getStandardOrigin()+t.url).set(t.headers).query(e);return ji.call(this,r,t,n)}function Li(e,t){var n=new Uint8Array(e.byteLength+t.byteLength);return n.set(new Uint8Array(e),0),n.set(new Uint8Array(t),e.byteLength),n.buffer}var Gi,Ki=function(){function e(){}return Object.defineProperty(e.prototype,"algo",{get:function(){return"aes-256-cbc"},enumerable:!1,configurable:!0}),e.prototype.encrypt=function(e,t){return o(this,void 0,void 0,(function(){var n;return i(this,(function(r){switch(r.label){case 0:return[4,this.getKey(e)];case 1:if(n=r.sent(),t instanceof ArrayBuffer)return[2,this.encryptArrayBuffer(n,t)];if("string"==typeof t)return[2,this.encryptString(n,t)];throw new Error("Cannot encrypt this file. In browsers file encryption supports only string or ArrayBuffer")}}))}))},e.prototype.decrypt=function(e,t){return o(this,void 0,void 0,(function(){var n;return i(this,(function(r){switch(r.label){case 0:return[4,this.getKey(e)];case 1:if(n=r.sent(),t instanceof ArrayBuffer)return[2,this.decryptArrayBuffer(n,t)];if("string"==typeof t)return[2,this.decryptString(n,t)];throw new Error("Cannot decrypt this file. In browsers file decryption supports only string or ArrayBuffer")}}))}))},e.prototype.encryptFile=function(e,t,n){return o(this,void 0,void 0,(function(){var r,o,s;return i(this,(function(i){switch(i.label){case 0:if(t.data.byteLength<=0)throw new Error("encryption error. empty content");return[4,this.getKey(e)];case 1:return r=i.sent(),[4,t.data.arrayBuffer()];case 2:return o=i.sent(),[4,this.encryptArrayBuffer(r,o)];case 3:return s=i.sent(),[2,n.create({name:t.name,mimeType:"application/octet-stream",data:s})]}}))}))},e.prototype.decryptFile=function(e,t,n){return o(this,void 0,void 0,(function(){var r,o,s;return i(this,(function(i){switch(i.label){case 0:return[4,this.getKey(e)];case 1:return r=i.sent(),[4,t.data.arrayBuffer()];case 2:return o=i.sent(),[4,this.decryptArrayBuffer(r,o)];case 3:return s=i.sent(),[2,n.create({name:t.name,data:s})]}}))}))},e.prototype.getKey=function(t){return o(this,void 0,void 0,(function(){var n,r,o;return i(this,(function(i){switch(i.label){case 0:return[4,crypto.subtle.digest("SHA-256",e.encoder.encode(t))];case 1:return n=i.sent(),r=Array.from(new Uint8Array(n)).map((function(e){return e.toString(16).padStart(2,"0")})).join(""),o=e.encoder.encode(r.slice(0,32)).buffer,[2,crypto.subtle.importKey("raw",o,"AES-CBC",!0,["encrypt","decrypt"])]}}))}))},e.prototype.encryptArrayBuffer=function(e,t){return o(this,void 0,void 0,(function(){var n,r,o;return i(this,(function(i){switch(i.label){case 0:return n=crypto.getRandomValues(new Uint8Array(16)),r=Li,o=[n.buffer],[4,crypto.subtle.encrypt({name:"AES-CBC",iv:n},e,t)];case 1:return[2,r.apply(void 0,o.concat([i.sent()]))]}}))}))},e.prototype.decryptArrayBuffer=function(t,n){return o(this,void 0,void 0,(function(){var r;return i(this,(function(o){switch(o.label){case 0:if(r=n.slice(0,16),n.slice(e.IV_LENGTH).byteLength<=0)throw new Error("decryption error: empty content");return[4,crypto.subtle.decrypt({name:"AES-CBC",iv:r},t,n.slice(e.IV_LENGTH))];case 1:return[2,o.sent()]}}))}))},e.prototype.encryptString=function(t,n){return o(this,void 0,void 0,(function(){var r,o,s,a;return i(this,(function(i){switch(i.label){case 0:return r=crypto.getRandomValues(new Uint8Array(16)),o=e.encoder.encode(n).buffer,[4,crypto.subtle.encrypt({name:"AES-CBC",iv:r},t,o)];case 1:return s=i.sent(),a=Li(r.buffer,s),[2,e.decoder.decode(a)]}}))}))},e.prototype.decryptString=function(t,n){return o(this,void 0,void 0,(function(){var r,o,s,a;return i(this,(function(i){switch(i.label){case 0:return r=e.encoder.encode(n).buffer,o=r.slice(0,16),s=r.slice(16),[4,crypto.subtle.decrypt({name:"AES-CBC",iv:o},t,s)];case 1:return a=i.sent(),[2,e.decoder.decode(a)]}}))}))},e.IV_LENGTH=16,e.encoder=new TextEncoder,e.decoder=new TextDecoder,e}(),Bi=(Gi=function(){function e(e){if(e instanceof File)this.data=e,this.name=this.data.name,this.mimeType=this.data.type;else if(e.data){var t=e.data;this.data=new File([t],e.name,{type:e.mimeType}),this.name=e.name,e.mimeType&&(this.mimeType=e.mimeType)}if(void 0===this.data)throw new Error("Couldn't construct a file out of supplied options.");if(void 0===this.name)throw new Error("Couldn't guess filename out of the options. Please provide one.")}return e.create=function(e){return new this(e)},e.prototype.toBuffer=function(){return o(this,void 0,void 0,(function(){return i(this,(function(e){throw new Error("This feature is only supported in Node.js environments.")}))}))},e.prototype.toStream=function(){return o(this,void 0,void 0,(function(){return i(this,(function(e){throw new Error("This feature is only supported in Node.js environments.")}))}))},e.prototype.toFileUri=function(){return o(this,void 0,void 0,(function(){return i(this,(function(e){throw new Error("This feature is only supported in react native environments.")}))}))},e.prototype.toBlob=function(){return o(this,void 0,void 0,(function(){return i(this,(function(e){return[2,this.data]}))}))},e.prototype.toArrayBuffer=function(){return o(this,void 0,void 0,(function(){var e=this;return i(this,(function(t){return[2,new Promise((function(t,n){var r=new FileReader;r.addEventListener("load",(function(){if(r.result instanceof ArrayBuffer)return t(r.result)})),r.addEventListener("error",(function(){n(r.error)})),r.readAsArrayBuffer(e.data)}))]}))}))},e.prototype.toString=function(){return o(this,void 0,void 0,(function(){var e=this;return i(this,(function(t){return[2,new Promise((function(t,n){var r=new FileReader;r.addEventListener("load",(function(){if("string"==typeof r.result)return t(r.result)})),r.addEventListener("error",(function(){n(r.error)})),r.readAsBinaryString(e.data)}))]}))}))},e.prototype.toFile=function(){return o(this,void 0,void 0,(function(){return i(this,(function(e){return[2,this.data]}))}))},e}(),Gi.supportsFile="undefined"!=typeof File,Gi.supportsBlob="undefined"!=typeof Blob,Gi.supportsArrayBuffer="undefined"!=typeof ArrayBuffer,Gi.supportsBuffer=!1,Gi.supportsStream=!1,Gi.supportsString=!0,Gi.supportsEncryptFile=!0,Gi.supportsFileUri=!1,Gi),Hi=function(){function e(e){this.config=e,this.cryptor=new T({config:e}),this.fileCryptor=new Ki}return Object.defineProperty(e.prototype,"identifier",{get:function(){return""},enumerable:!1,configurable:!0}),e.prototype.encrypt=function(e){var t="string"==typeof e?e:(new TextDecoder).decode(e);return{data:this.cryptor.encrypt(t),metadata:null}},e.prototype.decrypt=function(e){var t="string"==typeof e.data?e.data:b(e.data);return this.cryptor.decrypt(t)},e.prototype.encryptFile=function(e,t){var n;return o(this,void 0,void 0,(function(){return i(this,(function(r){return[2,this.fileCryptor.encryptFile(null===(n=this.config)||void 0===n?void 0:n.cipherKey,e,t)]}))}))},e.prototype.decryptFile=function(e,t){return o(this,void 0,void 0,(function(){return i(this,(function(n){return[2,this.fileCryptor.decryptFile(this.config.cipherKey,e,t)]}))}))},e}(),qi=function(){function e(e){this.cipherKey=e.cipherKey,this.CryptoJS=E,this.encryptedKey=this.CryptoJS.SHA256(this.cipherKey)}return Object.defineProperty(e.prototype,"algo",{get:function(){return"AES-CBC"},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"identifier",{get:function(){return"ACRH"},enumerable:!1,configurable:!0}),e.prototype.getIv=function(){return crypto.getRandomValues(new Uint8Array(e.BLOCK_SIZE))},e.prototype.getKey=function(){return o(this,void 0,void 0,(function(){var t,n;return i(this,(function(r){switch(r.label){case 0:return t=e.encoder.encode(this.cipherKey),[4,crypto.subtle.digest("SHA-256",t.buffer)];case 1:return n=r.sent(),[2,crypto.subtle.importKey("raw",n,this.algo,!0,["encrypt","decrypt"])]}}))}))},e.prototype.encrypt=function(t){if(0===("string"==typeof t?t:e.decoder.decode(t)).length)throw new Error("encryption error. empty content");var n=this.getIv();return{metadata:n,data:m(this.CryptoJS.AES.encrypt(t,this.encryptedKey,{iv:this.bufferToWordArray(n),mode:this.CryptoJS.mode.CBC}).ciphertext.toString(this.CryptoJS.enc.Base64))}},e.prototype.decrypt=function(t){var n=this.bufferToWordArray(new Uint8ClampedArray(t.metadata)),r=this.bufferToWordArray(new Uint8ClampedArray(t.data));return e.encoder.encode(this.CryptoJS.AES.decrypt({ciphertext:r},this.encryptedKey,{iv:n,mode:this.CryptoJS.mode.CBC}).toString(this.CryptoJS.enc.Utf8)).buffer},e.prototype.encryptFileData=function(e){return o(this,void 0,void 0,(function(){var t,n,r;return i(this,(function(o){switch(o.label){case 0:return[4,this.getKey()];case 1:return t=o.sent(),n=this.getIv(),r={},[4,crypto.subtle.encrypt({name:this.algo,iv:n},t,e)];case 2:return[2,(r.data=o.sent(),r.metadata=n,r)]}}))}))},e.prototype.decryptFileData=function(e){return o(this,void 0,void 0,(function(){var t;return i(this,(function(n){switch(n.label){case 0:return[4,this.getKey()];case 1:return t=n.sent(),[2,crypto.subtle.decrypt({name:this.algo,iv:e.metadata},t,e.data)]}}))}))},e.prototype.bufferToWordArray=function(e){var t,n=[];for(t=0;t0?t.slice(n.length-n.metadataLength,n.length):null;if(t.slice(n.length).byteLength<=0)throw new Error("decryption error. empty content");return r.decrypt({data:t.slice(n.length),metadata:o})},e.prototype.encryptFile=function(e,t){return o(this,void 0,void 0,(function(){var n,r;return i(this,(function(o){switch(o.label){case 0:return this.defaultCryptor.identifier===Vi.LEGACY_IDENTIFIER?[2,this.defaultCryptor.encryptFile(e,t)]:[4,this.getFileData(e.data)];case 1:return n=o.sent(),[4,this.defaultCryptor.encryptFileData(n)];case 2:return r=o.sent(),[2,t.create({name:e.name,mimeType:"application/octet-stream",data:this.concatArrayBuffer(this.getHeaderData(r),r.data)})]}}))}))},e.prototype.decryptFile=function(t,n){return o(this,void 0,void 0,(function(){var r,o,s,a,u,c,l,p;return i(this,(function(i){switch(i.label){case 0:return[4,t.data.arrayBuffer()];case 1:return r=i.sent(),o=Vi.tryParse(r),(null==(s=this.getCryptor(o))?void 0:s.identifier)===e.LEGACY_IDENTIFIER?[2,s.decryptFile(t,n)]:[4,this.getFileData(r)];case 2:return a=i.sent(),u=a.slice(o.length-o.metadataLength,o.length),l=(c=n).create,p={name:t.name},[4,this.defaultCryptor.decryptFileData({data:r.slice(o.length),metadata:u})];case 3:return[2,l.apply(c,[(p.data=i.sent(),p)])]}}))}))},e.prototype.getCryptor=function(e){if(""===e){var t=this.getAllCryptors().find((function(e){return""===e.identifier}));if(t)return t;throw new Error("unknown cryptor error")}if(e instanceof Wi)return this.getCryptorFromId(e.identifier)},e.prototype.getCryptorFromId=function(e){var t=this.getAllCryptors().find((function(t){return e===t.identifier}));if(t)return t;throw Error("unknown cryptor error")},e.prototype.concatArrayBuffer=function(e,t){var n=new Uint8Array(e.byteLength+t.byteLength);return n.set(new Uint8Array(e),0),n.set(new Uint8Array(t),e.byteLength),n.buffer},e.prototype.getHeaderData=function(e){if(e.metadata){var t=Vi.from(this.defaultCryptor.identifier,e.metadata),n=new Uint8Array(t.length),r=0;return n.set(t.data,r),r+=t.length-e.metadata.byteLength,n.set(new Uint8Array(e.metadata),r),n.buffer}},e.prototype.getFileData=function(t){return o(this,void 0,void 0,(function(){return i(this,(function(n){switch(n.label){case 0:return t instanceof Blob?[4,t.arrayBuffer()]:[3,2];case 1:return[2,n.sent()];case 2:if(t instanceof ArrayBuffer)return[2,t];if("string"==typeof t)return[2,e.encoder.encode(t)];throw new Error("Cannot decrypt/encrypt file. In browsers file encrypt/decrypt supported for string, ArrayBuffer or Blob")}}))}))},e.LEGACY_IDENTIFIER="",e.encoder=new TextEncoder,e.decoder=new TextDecoder,e}(),Vi=function(){function e(){}return e.from=function(t,n){if(t!==e.LEGACY_IDENTIFIER)return new Wi(t,n.byteLength)},e.tryParse=function(t){var n=new Uint8Array(t),r="";if(n.byteLength>=4&&(r=n.slice(0,4),this.decoder.decode(r)!==e.SENTINEL))return"";if(!(n.byteLength>=5))throw new Error("decryption error. invalid header version");if(n[4]>e.MAX_VERSION)throw new Error("unknown cryptor error");var o="",i=5+e.IDENTIFIER_LENGTH;if(!(n.byteLength>=i))throw new Error("decryption error. invalid crypto identifier");o=n.slice(5,i);var s=null;if(!(n.byteLength>=i+1))throw new Error("decryption error. invalid metadata length");return s=n[i],i+=1,255===s&&n.byteLength>=i+2&&(s=new Uint16Array(n.slice(i,i+2)).reduce((function(e,t){return(e<<8)+t}),0),i+=2),new Wi(this.decoder.decode(o),s)},e.SENTINEL="PNED",e.LEGACY_IDENTIFIER="",e.IDENTIFIER_LENGTH=4,e.VERSION=1,e.MAX_VERSION=1,e.decoder=new TextDecoder,e}(),Wi=function(){function e(e,t){this._identifier=e,this._metadataLength=t}return Object.defineProperty(e.prototype,"identifier",{get:function(){return this._identifier},set:function(e){this._identifier=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"metadataLength",{get:function(){return this._metadataLength},set:function(e){this._metadataLength=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"version",{get:function(){return Vi.VERSION},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"length",{get:function(){return Vi.SENTINEL.length+1+Vi.IDENTIFIER_LENGTH+(this.metadataLength<255?1:3)+this.metadataLength},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"data",{get:function(){var e=0,t=new Uint8Array(this.length),n=new TextEncoder;t.set(n.encode(Vi.SENTINEL)),t[e+=Vi.SENTINEL.length]=this.version,e++,this.identifier&&t.set(n.encode(this.identifier),e),e+=Vi.IDENTIFIER_LENGTH;var r=this.metadataLength;return r<255?t[e]=r:t.set([255,r>>8,255&r],e),t},enumerable:!1,configurable:!0}),e.IDENTIFIER_LENGTH=4,e.SENTINEL="PNED",e}();function Ji(e){if(!navigator||!navigator.sendBeacon)return!1;navigator.sendBeacon(e)}var $i=function(e){function n(t){var n=this,r=t.listenToBrowserNetworkEvents,o=void 0===r||r;return t.sdkFamily="Web",t.networking=new _n({del:Fi,get:Ui,post:Ii,patch:Di,sendBeacon:Ji,getfile:xi,postfile:Ri}),t.cbor=new wn((function(e){return Sn(h.decode(e))}),m),t.PubNubFile=Bi,t.cryptography=new Ki,t.initCryptoModule=function(e){return new zi({default:new Hi({cipherKey:e.cipherKey,useRandomIVs:e.useRandomIVs}),cryptors:[new qi({cipherKey:e.cipherKey})]})},n=e.call(this,t)||this,o&&(window.addEventListener("offline",(function(){n.networkDownDetected()})),window.addEventListener("online",(function(){n.networkUpDetected()}))),n}return t(n,e),n.CryptoModule=zi,n}(vn);return $i})); +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).PubNub=t()}(this,(function(){"use strict";var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(e[n]=t[n])},e(t,n)};function t(t,n){if("function"!=typeof n&&null!==n)throw new TypeError("Class extends value "+String(n)+" is not a constructor or null");function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}var n=function(){return n=Object.assign||function(e){for(var t,n=1,r=arguments.length;n0&&i[i.length-1])||6!==a[0]&&2!==a[0])){s=0;continue}if(3===a[0]&&(!i||a[1]>i[0]&&a[1]=e.length&&(e=void 0),{value:e&&e[r++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function a(e,t){var n="function"==typeof Symbol&&e[Symbol.iterator];if(!n)return e;var r,i,o=n.call(e),s=[];try{for(;(void 0===t||t-- >0)&&!(r=o.next()).done;)s.push(r.value)}catch(e){i={error:e}}finally{try{r&&!r.done&&(n=o.return)&&n.call(o)}finally{if(i)throw i.error}}return s}function u(e,t,n){if(n||2===arguments.length)for(var r,i=0,o=t.length;i>2,c=0;c>6),i.push(128|63&s)):s<55296?(i.push(224|s>>12),i.push(128|s>>6&63),i.push(128|63&s)):(s=(1023&s)<<10,s|=1023&t.charCodeAt(++r),s+=65536,i.push(240|s>>18),i.push(128|s>>12&63),i.push(128|s>>6&63),i.push(128|63&s))}return h(3,i.length),l(i);default:var f;if(Array.isArray(t))for(h(4,f=t.length),r=0;r>5!==e)throw"Invalid indefinite length element";return n}function g(e,t){for(var n=0;n>10),e.push(56320|1023&r))}}"function"!=typeof t&&(t=function(e){return e}),"function"!=typeof o&&(o=function(){return n});var v=function e(){var i,h,v=p(),b=v>>5,m=31&v;if(7===b)switch(m){case 25:return function(){var e=new ArrayBuffer(4),t=new DataView(e),n=l(),i=32768&n,o=31744&n,s=1023&n;if(31744===o)o=261120;else if(0!==o)o+=114688;else if(0!==s)return s*r;return t.setUint32(0,i<<16|o<<13|s<<13),t.getFloat32(0)}();case 26:return u(s.getFloat32(a),4);case 27:return u(s.getFloat64(a),8)}if((h=d(m))<0&&(b<2||6=0;)S+=h,w.push(c(h));var k=new Uint8Array(S),P=0;for(i=0;i=0;)g(E,h);else g(E,h);return String.fromCharCode.apply(null,E);case 4:var O;if(h<0)for(O=[];!f();)O.push(e());else for(O=new Array(h),i=0;i>4,f=(15&c)<<4|p>>2,d=(3&p)<<6|l;i[a]=h,64!=p&&(i[a+1]=f),64!=l&&(i[a+2]=d)}return r}function g(e){for(var t,n="",r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",i=new Uint8Array(e),o=i.byteLength,s=o%3,a=o-s,u=0;u>18]+r[(258048&t)>>12]+r[(4032&t)>>6]+r[63&t];return 1==s?n+=r[(252&(t=i[a]))>>2]+r[(3&t)<<4]+"==":2==s&&(n+=r[(64512&(t=i[a]<<8|i[a+1]))>>10]+r[(1008&t)>>4]+r[(15&t)<<2]+"="),n}var v=function(e){function n(t,n){var r=this.constructor,i=e.call(this,t)||this;return i.status=n,i.name=i.constructor.name,i.message=t,Object.setPrototypeOf(i,r.prototype),i}return t(n,e),n}(Error);function b(e,t){return r=n({message:e},void 0!==t?{statusCode:t}:{}),i="validationError",null!==(o=r.statusCode)&&void 0!==o||(r.statusCode=0),n(n({},r),{statusCode:r.statusCode,error:!0,type:i});var r,i,o}var m,w,S,k,P,E=E||function(e,t){var n={},r=n.lib={},i=function(){},o=r.Base={extend:function(e){i.prototype=this;var t=new i;return e&&t.mixIn(e),t.hasOwnProperty("init")||(t.init=function(){t.$super.init.apply(this,arguments)}),t.init.prototype=t,t.$super=this,t},create:function(){var e=this.extend();return e.init.apply(e,arguments),e},init:function(){},mixIn:function(e){for(var t in e)e.hasOwnProperty(t)&&(this[t]=e[t]);e.hasOwnProperty("toString")&&(this.toString=e.toString)},clone:function(){return this.init.prototype.extend(this)}},s=r.WordArray=o.extend({init:function(e,t){e=this.words=e||[],this.sigBytes=null!=t?t:4*e.length},toString:function(e){return(e||u).stringify(this)},concat:function(e){var t=this.words,n=e.words,r=this.sigBytes;if(e=e.sigBytes,this.clamp(),r%4)for(var i=0;i>>2]|=(n[i>>>2]>>>24-i%4*8&255)<<24-(r+i)%4*8;else if(65535>>2]=n[i>>>2];else t.push.apply(t,n);return this.sigBytes+=e,this},clamp:function(){var t=this.words,n=this.sigBytes;t[n>>>2]&=4294967295<<32-n%4*8,t.length=e.ceil(n/4)},clone:function(){var e=o.clone.call(this);return e.words=this.words.slice(0),e},random:function(t){for(var n=[],r=0;r>>2]>>>24-r%4*8&255;n.push((i>>>4).toString(16)),n.push((15&i).toString(16))}return n.join("")},parse:function(e){for(var t=e.length,n=[],r=0;r>>3]|=parseInt(e.substr(r,2),16)<<24-r%8*4;return new s.init(n,t/2)}},c=a.Latin1={stringify:function(e){var t=e.words;e=e.sigBytes;for(var n=[],r=0;r>>2]>>>24-r%4*8&255));return n.join("")},parse:function(e){for(var t=e.length,n=[],r=0;r>>2]|=(255&e.charCodeAt(r))<<24-r%4*8;return new s.init(n,t)}},p=a.Utf8={stringify:function(e){try{return decodeURIComponent(escape(c.stringify(e)))}catch(e){throw Error("Malformed UTF-8 data")}},parse:function(e){return c.parse(unescape(encodeURIComponent(e)))}},l=r.BufferedBlockAlgorithm=o.extend({reset:function(){this._data=new s.init,this._nDataBytes=0},_append:function(e){"string"==typeof e&&(e=p.parse(e)),this._data.concat(e),this._nDataBytes+=e.sigBytes},_process:function(t){var n=this._data,r=n.words,i=n.sigBytes,o=this.blockSize,a=i/(4*o);if(t=(a=t?e.ceil(a):e.max((0|a)-this._minBufferSize,0))*o,i=e.min(4*t,i),t){for(var u=0;uc;){var p;e:{p=u;for(var l=e.sqrt(p),h=2;h<=l;h++)if(!(p%h)){p=!1;break e}p=!0}p&&(8>c&&(o[c]=a(e.pow(u,.5))),s[c]=a(e.pow(u,1/3)),c++),u++}var f=[];i=i.SHA256=r.extend({_doReset:function(){this._hash=new n.init(o.slice(0))},_doProcessBlock:function(e,t){for(var n=this._hash.words,r=n[0],i=n[1],o=n[2],a=n[3],u=n[4],c=n[5],p=n[6],l=n[7],h=0;64>h;h++){if(16>h)f[h]=0|e[t+h];else{var d=f[h-15],y=f[h-2];f[h]=((d<<25|d>>>7)^(d<<14|d>>>18)^d>>>3)+f[h-7]+((y<<15|y>>>17)^(y<<13|y>>>19)^y>>>10)+f[h-16]}d=l+((u<<26|u>>>6)^(u<<21|u>>>11)^(u<<7|u>>>25))+(u&c^~u&p)+s[h]+f[h],y=((r<<30|r>>>2)^(r<<19|r>>>13)^(r<<10|r>>>22))+(r&i^r&o^i&o),l=p,p=c,c=u,u=a+d|0,a=o,o=i,i=r,r=d+y|0}n[0]=n[0]+r|0,n[1]=n[1]+i|0,n[2]=n[2]+o|0,n[3]=n[3]+a|0,n[4]=n[4]+u|0,n[5]=n[5]+c|0,n[6]=n[6]+p|0,n[7]=n[7]+l|0},_doFinalize:function(){var t=this._data,n=t.words,r=8*this._nDataBytes,i=8*t.sigBytes;return n[i>>>5]|=128<<24-i%32,n[14+(i+64>>>9<<4)]=e.floor(r/4294967296),n[15+(i+64>>>9<<4)]=r,t.sigBytes=4*n.length,this._process(),this._hash},clone:function(){var e=r.clone.call(this);return e._hash=this._hash.clone(),e}});t.SHA256=r._createHelper(i),t.HmacSHA256=r._createHmacHelper(i)}(Math),w=(m=E).enc.Utf8,m.algo.HMAC=m.lib.Base.extend({init:function(e,t){e=this._hasher=new e.init,"string"==typeof t&&(t=w.parse(t));var n=e.blockSize,r=4*n;t.sigBytes>r&&(t=e.finalize(t)),t.clamp();for(var i=this._oKey=t.clone(),o=this._iKey=t.clone(),s=i.words,a=o.words,u=0;u>>2]>>>24-i%4*8&255)<<16|(t[i+1>>>2]>>>24-(i+1)%4*8&255)<<8|t[i+2>>>2]>>>24-(i+2)%4*8&255,s=0;4>s&&i+.75*s>>6*(3-s)&63));if(t=r.charAt(64))for(;e.length%4;)e.push(t);return e.join("")},parse:function(e){var t=e.length,n=this._map;(r=n.charAt(64))&&-1!=(r=e.indexOf(r))&&(t=r);for(var r=[],i=0,o=0;o>>6-o%4*2;r[i>>>2]|=(s|a)<<24-i%4*8,i++}return k.create(r,i)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="},function(e){function t(e,t,n,r,i,o,s){return((e=e+(t&n|~t&r)+i+s)<>>32-o)+t}function n(e,t,n,r,i,o,s){return((e=e+(t&r|n&~r)+i+s)<>>32-o)+t}function r(e,t,n,r,i,o,s){return((e=e+(t^n^r)+i+s)<>>32-o)+t}function i(e,t,n,r,i,o,s){return((e=e+(n^(t|~r))+i+s)<>>32-o)+t}for(var o=E,s=(u=o.lib).WordArray,a=u.Hasher,u=o.algo,c=[],p=0;64>p;p++)c[p]=4294967296*e.abs(e.sin(p+1))|0;u=u.MD5=a.extend({_doReset:function(){this._hash=new s.init([1732584193,4023233417,2562383102,271733878])},_doProcessBlock:function(e,o){for(var s=0;16>s;s++){var a=e[u=o+s];e[u]=16711935&(a<<8|a>>>24)|4278255360&(a<<24|a>>>8)}s=this._hash.words;var u=e[o+0],p=(a=e[o+1],e[o+2]),l=e[o+3],h=e[o+4],f=e[o+5],d=e[o+6],y=e[o+7],g=e[o+8],v=e[o+9],b=e[o+10],m=e[o+11],w=e[o+12],S=e[o+13],k=e[o+14],P=e[o+15],E=t(E=s[0],_=s[1],C=s[2],O=s[3],u,7,c[0]),O=t(O,E,_,C,a,12,c[1]),C=t(C,O,E,_,p,17,c[2]),_=t(_,C,O,E,l,22,c[3]);E=t(E,_,C,O,h,7,c[4]),O=t(O,E,_,C,f,12,c[5]),C=t(C,O,E,_,d,17,c[6]),_=t(_,C,O,E,y,22,c[7]),E=t(E,_,C,O,g,7,c[8]),O=t(O,E,_,C,v,12,c[9]),C=t(C,O,E,_,b,17,c[10]),_=t(_,C,O,E,m,22,c[11]),E=t(E,_,C,O,w,7,c[12]),O=t(O,E,_,C,S,12,c[13]),C=t(C,O,E,_,k,17,c[14]),E=n(E,_=t(_,C,O,E,P,22,c[15]),C,O,a,5,c[16]),O=n(O,E,_,C,d,9,c[17]),C=n(C,O,E,_,m,14,c[18]),_=n(_,C,O,E,u,20,c[19]),E=n(E,_,C,O,f,5,c[20]),O=n(O,E,_,C,b,9,c[21]),C=n(C,O,E,_,P,14,c[22]),_=n(_,C,O,E,h,20,c[23]),E=n(E,_,C,O,v,5,c[24]),O=n(O,E,_,C,k,9,c[25]),C=n(C,O,E,_,l,14,c[26]),_=n(_,C,O,E,g,20,c[27]),E=n(E,_,C,O,S,5,c[28]),O=n(O,E,_,C,p,9,c[29]),C=n(C,O,E,_,y,14,c[30]),E=r(E,_=n(_,C,O,E,w,20,c[31]),C,O,f,4,c[32]),O=r(O,E,_,C,g,11,c[33]),C=r(C,O,E,_,m,16,c[34]),_=r(_,C,O,E,k,23,c[35]),E=r(E,_,C,O,a,4,c[36]),O=r(O,E,_,C,h,11,c[37]),C=r(C,O,E,_,y,16,c[38]),_=r(_,C,O,E,b,23,c[39]),E=r(E,_,C,O,S,4,c[40]),O=r(O,E,_,C,u,11,c[41]),C=r(C,O,E,_,l,16,c[42]),_=r(_,C,O,E,d,23,c[43]),E=r(E,_,C,O,v,4,c[44]),O=r(O,E,_,C,w,11,c[45]),C=r(C,O,E,_,P,16,c[46]),E=i(E,_=r(_,C,O,E,p,23,c[47]),C,O,u,6,c[48]),O=i(O,E,_,C,y,10,c[49]),C=i(C,O,E,_,k,15,c[50]),_=i(_,C,O,E,f,21,c[51]),E=i(E,_,C,O,w,6,c[52]),O=i(O,E,_,C,l,10,c[53]),C=i(C,O,E,_,b,15,c[54]),_=i(_,C,O,E,a,21,c[55]),E=i(E,_,C,O,g,6,c[56]),O=i(O,E,_,C,P,10,c[57]),C=i(C,O,E,_,d,15,c[58]),_=i(_,C,O,E,S,21,c[59]),E=i(E,_,C,O,h,6,c[60]),O=i(O,E,_,C,m,10,c[61]),C=i(C,O,E,_,p,15,c[62]),_=i(_,C,O,E,v,21,c[63]);s[0]=s[0]+E|0,s[1]=s[1]+_|0,s[2]=s[2]+C|0,s[3]=s[3]+O|0},_doFinalize:function(){var t=this._data,n=t.words,r=8*this._nDataBytes,i=8*t.sigBytes;n[i>>>5]|=128<<24-i%32;var o=e.floor(r/4294967296);for(n[15+(i+64>>>9<<4)]=16711935&(o<<8|o>>>24)|4278255360&(o<<24|o>>>8),n[14+(i+64>>>9<<4)]=16711935&(r<<8|r>>>24)|4278255360&(r<<24|r>>>8),t.sigBytes=4*(n.length+1),this._process(),n=(t=this._hash).words,r=0;4>r;r++)i=n[r],n[r]=16711935&(i<<8|i>>>24)|4278255360&(i<<24|i>>>8);return t},clone:function(){var e=a.clone.call(this);return e._hash=this._hash.clone(),e}}),o.MD5=a._createHelper(u),o.HmacMD5=a._createHmacHelper(u)}(Math),function(){var e,t=E,n=(e=t.lib).Base,r=e.WordArray,i=(e=t.algo).EvpKDF=n.extend({cfg:n.extend({keySize:4,hasher:e.MD5,iterations:1}),init:function(e){this.cfg=this.cfg.extend(e)},compute:function(e,t){for(var n=(a=this.cfg).hasher.create(),i=r.create(),o=i.words,s=a.keySize,a=a.iterations;o.length>>2]}},t.BlockCipher=a.extend({cfg:a.cfg.extend({mode:u,padding:p}),reset:function(){a.reset.call(this);var e=(t=this.cfg).iv,t=t.mode;if(this._xformMode==this._ENC_XFORM_MODE)var n=t.createEncryptor;else n=t.createDecryptor,this._minBufferSize=1;this._mode=n.call(t,this,e&&e.words)},_doProcessBlock:function(e,t){this._mode.processBlock(e,t)},_doFinalize:function(){var e=this.cfg.padding;if(this._xformMode==this._ENC_XFORM_MODE){e.pad(this._data,this.blockSize);var t=this._process(!0)}else t=this._process(!0),e.unpad(t);return t},blockSize:4});var l=t.CipherParams=n.extend({init:function(e){this.mixIn(e)},toString:function(e){return(e||this.formatter).stringify(this)}}),h=(u=(f.format={}).OpenSSL={stringify:function(e){var t=e.ciphertext;return((e=e.salt)?r.create([1398893684,1701076831]).concat(e).concat(t):t).toString(o)},parse:function(e){var t=(e=o.parse(e)).words;if(1398893684==t[0]&&1701076831==t[1]){var n=r.create(t.slice(2,4));t.splice(0,4),e.sigBytes-=16}return l.create({ciphertext:e,salt:n})}},t.SerializableCipher=n.extend({cfg:n.extend({format:u}),encrypt:function(e,t,n,r){r=this.cfg.extend(r);var i=e.createEncryptor(n,r);return t=i.finalize(t),i=i.cfg,l.create({ciphertext:t,key:n,iv:i.iv,algorithm:e,mode:i.mode,padding:i.padding,blockSize:e.blockSize,formatter:r.format})},decrypt:function(e,t,n,r){return r=this.cfg.extend(r),t=this._parse(t,r.format),e.createDecryptor(n,r).finalize(t.ciphertext)},_parse:function(e,t){return"string"==typeof e?t.parse(e,this):e}})),f=(f.kdf={}).OpenSSL={execute:function(e,t,n,i){return i||(i=r.random(8)),e=s.create({keySize:t+n}).compute(e,i),n=r.create(e.words.slice(t),4*n),e.sigBytes=4*t,l.create({key:e,iv:n,salt:i})}},d=t.PasswordBasedCipher=h.extend({cfg:h.cfg.extend({kdf:f}),encrypt:function(e,t,n,r){return n=(r=this.cfg.extend(r)).kdf.execute(n,e.keySize,e.ivSize),r.iv=n.iv,(e=h.encrypt.call(this,e,t,n.key,r)).mixIn(n),e},decrypt:function(e,t,n,r){return r=this.cfg.extend(r),t=this._parse(t,r.format),n=r.kdf.execute(n,e.keySize,e.ivSize,t.salt),r.iv=n.iv,h.decrypt.call(this,e,t,n.key,r)}})}(),function(){for(var e=E,t=e.lib.BlockCipher,n=e.algo,r=[],i=[],o=[],s=[],a=[],u=[],c=[],p=[],l=[],h=[],f=[],d=0;256>d;d++)f[d]=128>d?d<<1:d<<1^283;var y=0,g=0;for(d=0;256>d;d++){var v=(v=g^g<<1^g<<2^g<<3^g<<4)>>>8^255&v^99;r[y]=v,i[v]=y;var b=f[y],m=f[b],w=f[m],S=257*f[v]^16843008*v;o[y]=S<<24|S>>>8,s[y]=S<<16|S>>>16,a[y]=S<<8|S>>>24,u[y]=S,S=16843009*w^65537*m^257*b^16843008*y,c[v]=S<<24|S>>>8,p[v]=S<<16|S>>>16,l[v]=S<<8|S>>>24,h[v]=S,y?(y=b^f[f[f[w^b]]],g^=f[f[g]]):y=g=1}var k=[0,1,2,4,8,16,32,64,128,27,54];n=n.AES=t.extend({_doReset:function(){for(var e=(n=this._key).words,t=n.sigBytes/4,n=4*((this._nRounds=t+6)+1),i=this._keySchedule=[],o=0;o>>24]<<24|r[s>>>16&255]<<16|r[s>>>8&255]<<8|r[255&s]):(s=r[(s=s<<8|s>>>24)>>>24]<<24|r[s>>>16&255]<<16|r[s>>>8&255]<<8|r[255&s],s^=k[o/t|0]<<24),i[o]=i[o-t]^s}for(e=this._invKeySchedule=[],t=0;tt||4>=o?s:c[r[s>>>24]]^p[r[s>>>16&255]]^l[r[s>>>8&255]]^h[r[255&s]]},encryptBlock:function(e,t){this._doCryptBlock(e,t,this._keySchedule,o,s,a,u,r)},decryptBlock:function(e,t){var n=e[t+1];e[t+1]=e[t+3],e[t+3]=n,this._doCryptBlock(e,t,this._invKeySchedule,c,p,l,h,i),n=e[t+1],e[t+1]=e[t+3],e[t+3]=n},_doCryptBlock:function(e,t,n,r,i,o,s,a){for(var u=this._nRounds,c=e[t]^n[0],p=e[t+1]^n[1],l=e[t+2]^n[2],h=e[t+3]^n[3],f=4,d=1;d>>24]^i[p>>>16&255]^o[l>>>8&255]^s[255&h]^n[f++],g=r[p>>>24]^i[l>>>16&255]^o[h>>>8&255]^s[255&c]^n[f++],v=r[l>>>24]^i[h>>>16&255]^o[c>>>8&255]^s[255&p]^n[f++];h=r[h>>>24]^i[c>>>16&255]^o[p>>>8&255]^s[255&l]^n[f++],c=y,p=g,l=v}y=(a[c>>>24]<<24|a[p>>>16&255]<<16|a[l>>>8&255]<<8|a[255&h])^n[f++],g=(a[p>>>24]<<24|a[l>>>16&255]<<16|a[h>>>8&255]<<8|a[255&c])^n[f++],v=(a[l>>>24]<<24|a[h>>>16&255]<<16|a[c>>>8&255]<<8|a[255&p])^n[f++],h=(a[h>>>24]<<24|a[c>>>16&255]<<16|a[p>>>8&255]<<8|a[255&l])^n[f++],e[t]=y,e[t+1]=g,e[t+2]=v,e[t+3]=h},keySize:8});e.AES=t._createHelper(n)}(),E.mode.ECB=((P=E.lib.BlockCipherMode.extend()).Encryptor=P.extend({processBlock:function(e,t){this._cipher.encryptBlock(e,t)}}),P.Decryptor=P.extend({processBlock:function(e,t){this._cipher.decryptBlock(e,t)}}),P);var O=p(E),C=function(){function e(e){var t=e.cipherKey;this.cipherKey=t,this.CryptoJS=O,this.encryptedKey=this.CryptoJS.SHA256(t)}return e.prototype.encrypt=function(t){if(0===("string"==typeof t?t:e.decoder.decode(t)).length)throw new Error("encryption error. empty content");var n=this.getIv();return{metadata:n,data:y(this.CryptoJS.AES.encrypt(t,this.encryptedKey,{iv:this.bufferToWordArray(n),mode:this.CryptoJS.mode.CBC}).ciphertext.toString(this.CryptoJS.enc.Base64))}},e.prototype.encryptFileData=function(e){return i(this,void 0,void 0,(function(){var t,n,r;return o(this,(function(i){switch(i.label){case 0:return[4,this.getKey()];case 1:return t=i.sent(),n=this.getIv(),r={},[4,crypto.subtle.encrypt({name:this.algo,iv:n},t,e)];case 2:return[2,(r.data=i.sent(),r.metadata=n,r)]}}))}))},e.prototype.decrypt=function(t){var n=this.bufferToWordArray(new Uint8ClampedArray(t.metadata)),r=this.bufferToWordArray(new Uint8ClampedArray(t.data));return e.encoder.encode(this.CryptoJS.AES.decrypt({ciphertext:r},this.encryptedKey,{iv:n,mode:this.CryptoJS.mode.CBC}).toString(this.CryptoJS.enc.Utf8)).buffer},e.prototype.decryptFileData=function(e){return i(this,void 0,void 0,(function(){var t;return o(this,(function(n){switch(n.label){case 0:return[4,this.getKey()];case 1:return t=n.sent(),[2,crypto.subtle.decrypt({name:this.algo,iv:e.metadata},t,e.data)]}}))}))},Object.defineProperty(e.prototype,"identifier",{get:function(){return"ACRH"},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"algo",{get:function(){return"AES-CBC"},enumerable:!1,configurable:!0}),e.prototype.getIv=function(){return crypto.getRandomValues(new Uint8Array(e.BLOCK_SIZE))},e.prototype.getKey=function(){return i(this,void 0,void 0,(function(){var t,n;return o(this,(function(r){switch(r.label){case 0:return t=e.encoder.encode(this.cipherKey),[4,crypto.subtle.digest("SHA-256",t.buffer)];case 1:return n=r.sent(),[2,crypto.subtle.importKey("raw",n,this.algo,!0,["encrypt","decrypt"])]}}))}))},e.prototype.bufferToWordArray=function(e){var t,n=[];for(t=0;t0?t.slice(n.length-n.metadataLength,n.length):null;if(t.slice(n.length).byteLength<=0)throw new Error("Decryption error: empty content");return r.decrypt({data:t.slice(n.length),metadata:i})},r.prototype.decryptFile=function(e,t){return i(this,void 0,void 0,(function(){var n,r,i,s,a,u,c,p;return o(this,(function(o){switch(o.label){case 0:return[4,e.data.arrayBuffer()];case 1:return n=o.sent(),r=I.tryParse(n),(null==(i=this.getCryptor(r))?void 0:i.identifier)===I.LEGACY_IDENTIFIER?[2,i.decryptFile(e,t)]:[4,this.getFileData(n)];case 2:return s=o.sent(),a=s.slice(r.length-r.metadataLength,r.length),c=(u=t).create,p={name:e.name},[4,this.defaultCryptor.decryptFileData({data:n.slice(r.length),metadata:a})];case 3:return[2,c.apply(u,[(p.data=o.sent(),p)])]}}))}))},r.prototype.getCryptorFromId=function(e){var t=this.getAllCryptors().find((function(t){return e===t.identifier}));if(t)return t;throw Error("Unknown cryptor error")},r.prototype.getCryptor=function(e){if("string"==typeof e){var t=this.getAllCryptors().find((function(t){return t.identifier===e}));if(t)return t;throw new Error("Unknown cryptor error")}if(e instanceof T)return this.getCryptorFromId(e.identifier)},r.prototype.getHeaderData=function(e){if(e.metadata){var t=I.from(this.defaultCryptor.identifier,e.metadata),n=new Uint8Array(t.length),r=0;return n.set(t.data,r),r+=t.length-e.metadata.byteLength,n.set(new Uint8Array(e.metadata),r),n.buffer}},r.prototype.concatArrayBuffer=function(e,t){var n=new Uint8Array(e.byteLength+t.byteLength);return n.set(new Uint8Array(e),0),n.set(new Uint8Array(t),e.byteLength),n.buffer},r.prototype.getFileData=function(e){return i(this,void 0,void 0,(function(){return o(this,(function(t){if(e instanceof ArrayBuffer)return[2,e];if(e instanceof d)return[2,e.toArrayBuffer()];throw new Error("Cannot decrypt/encrypt file. In browsers file encrypt/decrypt supported for string, ArrayBuffer or Blob")}))}))},r.LEGACY_IDENTIFIER="",r}(f),I=function(){function e(){}return e.from=function(t,n){if(t!==e.LEGACY_IDENTIFIER)return new T(t,n.byteLength)},e.tryParse=function(t){var n,r,i=new Uint8Array(t);if(i.byteLength>=4&&(n=i.slice(0,4),this.decoder.decode(n)!==e.SENTINEL))return j.LEGACY_IDENTIFIER;if(!(i.byteLength>=5))throw new Error("Decryption error: invalid header version");if(i[4]>e.MAX_VERSION)throw new Error("Decryption error: Unknown cryptor error");var o=5+e.IDENTIFIER_LENGTH;if(!(i.byteLength>=o))throw new Error("Decryption error: invalid crypto identifier");r=i.slice(5,o);var s=null;if(!(i.byteLength>=o+1))throw new Error("Decryption error: invalid metadata length");return s=i[o],o+=1,255===s&&i.byteLength>=o+2&&(s=new Uint16Array(i.slice(o,o+2)).reduce((function(e,t){return(e<<8)+t}),0)),new T(this.decoder.decode(r),s)},e.SENTINEL="PNED",e.LEGACY_IDENTIFIER="",e.IDENTIFIER_LENGTH=4,e.VERSION=1,e.MAX_VERSION=1,e.decoder=new TextDecoder,e}(),T=function(){function e(e,t){this._identifier=e,this._metadataLength=t}return Object.defineProperty(e.prototype,"identifier",{get:function(){return this._identifier},set:function(e){this._identifier=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"metadataLength",{get:function(){return this._metadataLength},set:function(e){this._metadataLength=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"version",{get:function(){return I.VERSION},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"length",{get:function(){return I.SENTINEL.length+1+I.IDENTIFIER_LENGTH+(this.metadataLength<255?1:3)+this.metadataLength},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"data",{get:function(){var e=0,t=new Uint8Array(this.length),n=new TextEncoder;t.set(n.encode(I.SENTINEL)),t[e+=I.SENTINEL.length]=this.version,e++,this.identifier&&t.set(n.encode(this.identifier),e);var r=this.metadataLength;return e+=I.IDENTIFIER_LENGTH,r<255?t[e]=r:t.set([255,r>>8,255&r],e),t},enumerable:!1,configurable:!0}),e.IDENTIFIER_LENGTH=4,e.SENTINEL="PNED",e}();function U(e){var t=function(e){return e&&"object"==typeof e&&e.constructor===Object};if(!t(e))return e;var n={};return Object.keys(e).forEach((function(r){var i=function(e){return"string"==typeof e||e instanceof String}(r),o=r,s=e[r];Array.isArray(r)||i&&r.indexOf(",")>=0?o=(i?r.split(","):r).reduce((function(e,t){return e+=String.fromCharCode(t)}),""):(function(e){return"number"==typeof e&&isFinite(e)}(r)||i&&!isNaN(r))&&(o=String.fromCharCode(i?parseInt(r,10):10));n[o]=t(s)?U(s):s})),n}var F={exports:{}}; +/*! lil-uuid - v0.1 - MIT License - https://github.com/lil-js/uuid */!function(e,t){!function(e){var t="0.1.0",n={3:/^[0-9A-F]{8}-[0-9A-F]{4}-3[0-9A-F]{3}-[0-9A-F]{4}-[0-9A-F]{12}$/i,4:/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,5:/^[0-9A-F]{8}-[0-9A-F]{4}-5[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,all:/^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i};function r(){var e,t,n="";for(e=0;e<32;e++)t=16*Math.random()|0,8!==e&&12!==e&&16!==e&&20!==e||(n+="-"),n+=(12===e?4:16===e?3&t|8:t).toString(16);return n}function i(e,t){var r=n[t||"all"];return r&&r.test(e)||!1}r.isUUID=i,r.VERSION=t,e.uuid=r,e.isUUID=i}(t),null!==e&&(e.exports=t.uuid)}(F,F.exports);var D,x=p(F.exports),K=function(){return x.uuid?x.uuid():x()},G=function(e,t){var n=e?"https://":"http://";return"string"==typeof t?"".concat(n).concat(t):"".concat(n).concat(t[Math.floor(Math.random()*t.length)])},q=function(e){var t,r;return n(n({},function(e){var t,r,i,o,s,a,u,c,p,l,h,f,d=n({},e);null!==(t=d.logVerbosity)&&void 0!==t||(d.logVerbosity=!1),null!==(r=d.ssl)&&void 0!==r||(d.ssl=!0),null!==(i=d.transactionalRequestTimeout)&&void 0!==i||(d.transactionalRequestTimeout=15),null!==(o=d.subscribeRequestTimeout)&&void 0!==o||(d.subscribeRequestTimeout=310),null!==(s=d.restore)&&void 0!==s||(d.restore=!1),null!==(a=d.useInstanceId)&&void 0!==a||(d.useInstanceId=!1),null!==(u=d.suppressLeaveEvents)&&void 0!==u||(d.suppressLeaveEvents=!1),null!==(c=d.requestMessageCountThreshold)&&void 0!==c||(d.requestMessageCountThreshold=100),null!==(p=d.autoNetworkDetection)&&void 0!==p||(d.autoNetworkDetection=!1),null!==(l=d.enableEventEngine)&&void 0!==l||(d.enableEventEngine=!1),null!==(h=d.maintainPresenceState)&&void 0!==h||(d.maintainPresenceState=!0),null!==(f=d.keepAlive)&&void 0!==f||(d.keepAlive=!1),d.origin||(d.origin=Array.from({length:20},(function(e,t){return"ps".concat(t+1,".pndsn.com")})));var y={subscribeKey:d.subscribeKey,publishKey:d.publishKey,secretKey:d.secretKey};d.presenceTimeout&&d.presenceTimeout<20&&(d.presenceTimeout=20,console.log("WARNING: Presence timeout is less than the minimum. Using minimum value: ",20)),d.presenceTimeout?d.heartbeatInterval=d.presenceTimeout/2-1:d.presenceTimeout=300;var g=!1,v=!0,b=5,m=!1,w=!1;return d.dedupeOnSubscribe&&"boolean"==typeof d.dedupeOnSubscribe&&(m=d.dedupeOnSubscribe),d.useRequestId&&"boolean"==typeof d.useRequestId&&(w=d.useRequestId),d.announceSuccessfulHeartbeats&&"boolean"==typeof d.announceSuccessfulHeartbeats&&(g=d.announceSuccessfulHeartbeats),d.announceFailedHeartbeats&&"boolean"==typeof d.announceFailedHeartbeats&&(v=d.announceFailedHeartbeats),d.fileUploadPublishRetryLimit&&"number"==typeof d.fileUploadPublishRetryLimit&&(b=d.fileUploadPublishRetryLimit),n(n({},d),{keySet:y,dedupeOnSubscribe:m,maximumCacheSize:100,useRequestId:w,announceSuccessfulHeartbeats:g,announceFailedHeartbeats:v,fileUploadPublishRetryLimit:b})}(e)),{listenToBrowserNetworkEvents:null===(t=e.listenToBrowserNetworkEvents)||void 0===t||t,keepAlive:null===(r=e.keepAlive)||void 0===r||r})},L=function(){function e(e){this._cbor=e}return e.prototype.setToken=function(e){e&&e.length>0?this._token=e:this._token=void 0},e.prototype.getToken=function(){return this._token},e.prototype.extractPermissions=function(e){var t={read:!1,write:!1,manage:!1,delete:!1,get:!1,update:!1,join:!1};return 128&~e||(t.join=!0),64&~e||(t.update=!0),32&~e||(t.get=!0),8&~e||(t.delete=!0),4&~e||(t.manage=!0),2&~e||(t.write=!0),1&~e||(t.read=!0),t},e.prototype.parseToken=function(e){var t=this,n=this._cbor.decodeToken(e);if(void 0!==n){var r=n.res.uuid?Object.keys(n.res.uuid):[],i=Object.keys(n.res.chan),o=Object.keys(n.res.grp),s=n.pat.uuid?Object.keys(n.pat.uuid):[],a=Object.keys(n.pat.chan),u=Object.keys(n.pat.grp),c={version:n.v,timestamp:n.t,ttl:n.ttl,authorized_uuid:n.uuid},p=r.length>0,l=i.length>0,h=o.length>0;(p||l||h)&&(c.resources={},p&&(c.resources.uuids={},r.forEach((function(e){c.resources.uuids[e]=t.extractPermissions(n.res.uuid[e])}))),l&&(c.resources.channels={},i.forEach((function(e){c.resources.channels[e]=t.extractPermissions(n.res.chan[e])}))),h&&(c.resources.groups={},o.forEach((function(e){c.resources.groups[e]=t.extractPermissions(n.res.grp[e])}))));var f=s.length>0,d=a.length>0,y=u.length>0;return(f||d||y)&&(c.patterns={},f&&(c.patterns.uuids={},s.forEach((function(e){c.patterns.uuids[e]=t.extractPermissions(n.pat.uuid[e])}))),d&&(c.patterns.channels={},a.forEach((function(e){c.patterns.channels[e]=t.extractPermissions(n.pat.chan[e])}))),y&&(c.patterns.groups={},u.forEach((function(e){c.patterns.groups[e]=t.extractPermissions(n.pat.grp[e])})))),Object.keys(n.meta).length>0&&(c.meta=n.meta),c.signature=n.sig,c}},e}();!function(e){e.GET="GET",e.POST="POST",e.PATCH="PATCH",e.DELETE="DELETE",e.LOCAL="LOCAL"}(D||(D={}));var B,H=function(e){return encodeURIComponent(e).replace(/[!~*'()]/g,(function(e){return"%".concat(e.charCodeAt(0).toString(16).toUpperCase())}))},z=function(e,t){var n=Object.fromEntries(t.map((function(e){return[e,!1]})));return e.filter((function(e){return!(t.includes(e)&&!n[e])||(n[e]=!0,!1)}))},V=function(e,t){return u([],a(e),!1).filter((function(n){return t.includes(n)&&e.indexOf(n)===e.lastIndexOf(n)&&t.indexOf(n)===t.lastIndexOf(n)}))},W=function(){function e(e,t,n){this.publishKey=e,this.secretKey=t,this.hasher=n}return e.prototype.signature=function(t){var n=t.path.startsWith("/publish")?D.GET:t.method,r="".concat(n,"\n").concat(this.publishKey,"\n").concat(t.path,"\n").concat(this.queryParameters(t.queryParameters),"\n");if(n===D.POST||n===D.PATCH){var i=t.body,o=void 0;i&&i instanceof ArrayBuffer?o=e.textDecoder.decode(i):i&&"object"!=typeof i&&(o=i),o&&(r+=o)}return"v2.".concat(this.hasher(r,this.secretKey)).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")},e.prototype.queryParameters=function(e){return Object.keys(e).sort().map((function(t){var n=e[t];return Array.isArray(n)?n.sort().map((function(e){return"".concat(t,"=").concat(H(e))})).join("&"):"".concat(t,"=").concat(H(n))})).join("&")},e.textDecoder=new TextDecoder("utf-8"),e}(),J=function(){function e(e){this.configuration=e;var t=e.clientConfiguration.keySet,n=e.shaHMAC;t.secretKey&&n&&(this.signatureGenerator=new W(t.publishKey,t.secretKey,n))}return e.prototype.makeSendable=function(e){return this.configuration.transport.makeSendable(this.request(e))},e.prototype.request=function(e){var t,n=this.configuration.clientConfiguration;return e.queryParameters||(e.queryParameters={}),n.useInstanceId&&(e.queryParameters.instanceid=n.instanceId),e.queryParameters.uuid||(e.queryParameters.uuid=n.userId),e.queryParameters.requestid=e.identifier,e.queryParameters.pnsdk=this.generatePNSDK(),null!==(t=e.origin)&&void 0!==t||(e.origin=n.origin),this.authenticateRequest(e),this.signRequest(e),e},e.prototype.authenticateRequest=function(e){var t;if(!(e.path.startsWith("/v2/auth/")||e.path.startsWith("/v3/pam/")||e.path.startsWith("/time"))){var n=this.configuration,r=n.clientConfiguration,i=null!==(t=n.tokenManager.getToken())&&void 0!==t?t:r.authKey;i&&(e.queryParameters.auth=i)}},e.prototype.signRequest=function(e){this.signatureGenerator&&!e.path.startsWith("/time")&&(e.queryParameters.timestamp=String(Math.floor((new Date).getTime()/1e3)),e.queryParameters.signature=this.signatureGenerator.signature(e))},e.prototype.generatePNSDK=function(){var e=this.configuration.clientConfiguration;if(e.sdkName)return e.sdkName;var t="PubNub-JS-".concat(e.sdkFamily);e.partnerId&&(t+="-".concat(e.partnerId)),t+="/".concat(e.version);var n=e._getPnsdkSuffix(" ");return n.length>0&&(t+=n),t},e}();!function(e){e.PNNetworkIssuesCategory="PNNetworkIssuesCategory",e.PNTimeoutCategory="PNTimeoutCategory",e.PNCancelledCategory="PNCancelledCategory",e.PNBadRequestCategory="PNBadRequestCategory",e.PNAccessDeniedCategory="PNAccessDeniedCategory",e.PNUnknownCategory="PNUnknownCategory",e.PNNetworkUpCategory="PNNetworkUpCategory",e.PNNetworkDownCategory="PNNetworkDownCategory",e.PNReconnectedCategory="PNReconnectedCategory",e.PNConnectedCategory="PNConnectedCategory",e.PNRequestMessageCountExceededCategory="PNRequestMessageCountExceededCategory",e.PNDisconnectedCategory="PNDisconnectedCategory",e.PNConnectionErrorCategory="PNConnectionErrorCategory",e.PNDisconnectedUnexpectedlyCategory="PNDisconnectedUnexpectedlyCategory"}(B||(B={}));var Y,X=B,$=function(e){function n(t,n,r,i){var o=e.call(this,t)||this;return o.category=n,o.statusCode=r,o.errorData=i,o.name=o.constructor.name,o}return t(n,e),n.create=function(e,t){return e instanceof Error?n.createFromError(e):n.createFromServiceResponse(e,t)},n.createFromError=function(e){var t=X.PNUnknownCategory,r="Unknown error",i="Error";if(!e)return new n(r,t,0);if(e instanceof Error&&(r=e.message,i=e.name),"AbortError"===i)t=X.PNCancelledCategory,r="Request cancelled";else if("FetchError"===i){var o=e.code;o in["ECONNREFUSED","ENOTFOUND","ECONNRESET","EAI_AGAIN"]&&(t=X.PNNetworkIssuesCategory),"ECONNREFUSED"===o?r="Connection refused":"ENOTFOUND"===o?r="Server not found":"ECONNRESET"===o?r="Connection reset by peer":"EAI_AGAIN"===o?r="Name resolution error":"ETIMEDOUT"===o?(t=X.PNTimeoutCategory,r="Request timeout"):r="Unknown system error: ".concat(e)}else"Request timeout"===r&&(t=X.PNTimeoutCategory);return new n(r,t,0,e)},n.createFromServiceResponse=function(e,t){var r,i=X.PNUnknownCategory,o="Unknown error",s=e.status;if(402===s?o="Not available for used key set. Contact support@pubnub.com":400===s?(i=X.PNBadRequestCategory,o="Bad request"):403===s&&(i=X.PNAccessDeniedCategory,o="Access denied"),t&&t.byteLength>0){var a=(new TextDecoder).decode(t);if(e.headers["content-type"].includes("application/json"))try{var u=JSON.parse(a);"object"!=typeof u||Array.isArray(u)||("error"in u&&1===u.error&&"status"in u&&"number"==typeof u.status&&"message"in u&&"service"in u&&(r=u,s=u.status),"error"in u&&"object"==typeof u.error&&!Array.isArray(u.error)&&"message"in u.error&&(r=u.error))}catch(e){r=a}else r=a}return new n(o,i,s,r)},n.prototype.toStatus=function(e){return{error:!0,category:this.category,operation:e,statusCode:this.statusCode,errorData:this.errorData}},n}(Error),Z=function(){function e(e,t){void 0===e&&(e=!1),this.keepAlive=e,this.logVerbosity=t,this.setupWorker()}return e.prototype.makeSendable=function(e){var t,n=this,r={type:"send-request",request:e};return e.cancellable&&(t={abort:function(){var t={type:"cancel-request",identifier:e.identifier};n.worker.postMessage(t)}}),[new Promise((function(t,i){n.callbacks.set(e.identifier,{resolve:t,reject:i}),n.worker.postMessage(r)})),t]},e.prototype.request=function(e){return e},e.prototype.setupWorker=function(){var e=this;this.worker=new Worker(URL.createObjectURL(new Blob([""],{type:"application/javascript"})),{name:"/pubnub",type:"module"}),this.callbacks=new Map;var t={type:"setup",logVerbosity:this.logVerbosity,keepAlive:this.keepAlive};this.worker.postMessage(t),this.worker.onmessage=function(t){var n=t.data;if("request-progress-start"===n.type||"request-progress-end"===n.type)e.logRequestProgress(n);else if("request-process-success"===n.type||"request-process-error"===n.type){var r=e.callbacks.get(n.identifier),i=r.resolve,o=r.reject;if("request-process-success"===n.type)i({status:n.response.status,url:n.url,headers:n.response.headers,body:n.response.body});else{var s=X.PNUnknownCategory,a="Unknown error";if(n.error)"NETWORK_ISSUE"===n.error.type?s=X.PNNetworkIssuesCategory:"TIMEOUT"===n.error.type&&(s=X.PNTimeoutCategory),a=n.error.message;else if(n.response)return o($.create({url:n.url,headers:n.response.headers,body:n.response.body,status:n.response.status}));o(new $(a,s,0))}}}},e.prototype.logRequestProgress=function(e){var t,n;"request-progress-start"===e.type?(console.log("<<<<<"),console.log("[".concat(e.timestamp,"]"),"\n",e.url,"\n",JSON.stringify(null!==(t=e.query)&&void 0!==t?t:{})),console.log("-----")):(console.log(">>>>>>"),console.log("[".concat(e.timestamp," / ").concat(e.duration,"]"),"\n",e.url,"\n",JSON.stringify(null!==(n=e.query)&&void 0!==n?n:{}),"\n",e.response),console.log("-----"))},e}(),Q=function(){function e(){this.listeners=[]}return e.prototype.addListener=function(e){this.listeners.includes(e)||this.listeners.push(e)},e.prototype.removeListener=function(e){this.listeners=this.listeners.filter((function(t){return t!==e}))},e.prototype.removeAllListeners=function(){this.listeners=[]},e.prototype.announceStatus=function(e){this.listeners.forEach((function(t){t.status&&t.status(e)}))},e.prototype.announcePresence=function(e){this.listeners.forEach((function(t){t.presence&&t.presence(e)}))},e.prototype.announceMessage=function(e){this.listeners.forEach((function(t){t.message&&t.message(e)}))},e.prototype.announceSignal=function(e){this.listeners.forEach((function(t){t.signal&&t.signal(e)}))},e.prototype.announceMessageAction=function(e){this.listeners.forEach((function(t){t.messageAction&&t.messageAction(e)}))},e.prototype.announceFile=function(e){this.listeners.forEach((function(t){t.file&&t.file(e)}))},e.prototype.announceObjects=function(e){this.listeners.forEach((function(t){t.objects&&t.objects(e)}))},e.prototype.announceNetworkUp=function(){this.listeners.forEach((function(e){e.status&&e.status({category:X.PNNetworkUpCategory})}))},e.prototype.announceNetworkDown=function(){this.listeners.forEach((function(e){e.status&&e.status({category:X.PNNetworkDownCategory})}))},e.prototype.announceUser=function(e){this.listeners.forEach((function(t){t.user&&t.user(e)}))},e.prototype.announceSpace=function(e){this.listeners.forEach((function(t){t.space&&t.space(e)}))},e.prototype.announceMembership=function(e){this.listeners.forEach((function(t){t.membership&&t.membership(e)}))},e}(),ee=function(){function e(e){this.time=e}return e.prototype.onReconnect=function(e){this.callback=e},e.prototype.startPolling=function(){var e=this;this.timeTimer=setInterval((function(){return e.callTime()}),3e3)},e.prototype.stopPolling=function(){this.timeTimer&&clearInterval(this.timeTimer),this.timeTimer=null},e.prototype.callTime=function(){var e=this;this.time((function(t){t.error||(e.stopPolling(),e.callback&&e.callback())}))},e}(),te=function(){function e(e){var t=e.config;this.hashHistory=[],this._config=t}return e.prototype.getKey=function(e){var t=function(e){var t=0;if(0===e.length)return t;for(var n=0;n=this._config.maximumCacheSize&&this.hashHistory.shift(),this.hashHistory.push(this.getKey(e))},e.prototype.clearHistory=function(){this.hashHistory=[]},e}(),ne=function(){function e(e,t,n,r,i,o,s){this.configuration=e,this.listenerManager=t,this.eventEmitter=n,this.subscribeCall=r,this.heartbeatCall=i,this.leaveCall=o,this.reconnectionManager=new ee(s),this.dedupingManager=new te({config:this.configuration}),this.heartbeatChannelGroups={},this.heartbeatChannels={},this.presenceChannelGroups={},this.presenceChannels={},this.heartbeatTimer=null,this.presenceState={},this.pendingChannelGroupSubscriptions=[],this.pendingChannelSubscriptions=[],this.channelGroups={},this.channels={},this.currentTimetoken="0",this.lastTimetoken="0",this.storedTimetoken=null,this.subscriptionStatusAnnounced=!1,this.isOnline=!0}return Object.defineProperty(e.prototype,"subscribedChannels",{get:function(){return Object.keys(this.channels)},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"subscribedChannelGroups",{get:function(){return Object.keys(this.channelGroups)},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"abort",{set:function(e){this._subscribeAbort=e},enumerable:!1,configurable:!0}),e.prototype.disconnect=function(){this.stopSubscribeLoop(),this.stopHeartbeatTimer(),this.reconnectionManager.stopPolling()},e.prototype.reconnect=function(){this.startSubscribeLoop(),this.startHeartbeatTimer()},e.prototype.subscribe=function(e){var t=this,n=e.channels,r=e.channelGroups,i=e.timetoken,o=e.withPresence,s=void 0!==o&&o,a=e.withHeartbeats,u=void 0!==a&&a;i&&(this.lastTimetoken=this.currentTimetoken,this.currentTimetoken=i),"0"!==this.currentTimetoken&&0!==this.currentTimetoken&&(this.storedTimetoken=this.currentTimetoken,this.currentTimetoken=0),null==n||n.forEach((function(e){t.pendingChannelSubscriptions.push(e),t.channels[e]={},s&&(t.presenceChannels[e]={}),(u||t.configuration.getHeartbeatInterval())&&(t.heartbeatChannels[e]={})})),null==r||r.forEach((function(e){t.pendingChannelGroupSubscriptions.push(e),t.channelGroups[e]={},s&&(t.presenceChannelGroups[e]={}),(u||t.configuration.getHeartbeatInterval())&&(t.heartbeatChannelGroups[e]={})})),this.subscriptionStatusAnnounced=!1,this.reconnect()},e.prototype.unsubscribe=function(e,t){var r=this,i=e.channels,o=e.channelGroups,s=[],a=[];null==i||i.forEach((function(e){e in r.channels&&(delete r.channels[e],a.push(e),e in r.heartbeatChannels&&delete r.heartbeatChannels[e]),e in r.presenceState&&delete r.presenceState[e],e in r.presenceChannels&&(delete r.presenceChannels[e],a.push(e))})),null==o||o.forEach((function(e){e in r.channelGroups&&(delete r.channelGroups[e],s.push(e),e in r.heartbeatChannelGroups&&delete r.heartbeatChannelGroups[e]),e in r.presenceState&&delete r.presenceState[e],e in r.presenceChannelGroups&&(delete r.presenceChannelGroups[e],s.push(e))})),0===a.length&&0===s.length||(!1!==this.configuration.suppressLeaveEvents||t||this.leaveCall({channels:a,channelGroups:s},(function(e){r.listenerManager.announceStatus(n(n({},e),{affectedChannels:a,affectedChannelGroups:s,currentTimetoken:r.currentTimetoken,lastTimetoken:r.lastTimetoken}))})),0===Object.keys(this.channels).length&&0===Object.keys(this.presenceChannels).length&&0===Object.keys(this.channelGroups).length&&0===Object.keys(this.presenceChannelGroups).length&&(this.lastTimetoken=0,this.currentTimetoken=0,this.storedTimetoken=null,this.region=null,this.reconnectionManager.stopPolling()),this.reconnect())},e.prototype.unsubscribeAll=function(e){this.unsubscribe({channels:this.subscribedChannels,channelGroups:this.subscribedChannelGroups},e)},e.prototype.startSubscribeLoop=function(){var e=this;this.stopSubscribeLoop();var t=u([],a(Object.keys(this.channelGroups)),!1),n=u([],a(Object.keys(this.channels)),!1);Object.keys(this.presenceChannelGroups).forEach((function(e){return t.push("".concat(e,"-pnpres"))})),Object.keys(this.presenceChannels).forEach((function(e){return n.push("".concat(e,"-pnpres"))})),0===n.length&&0===t.length||this.subscribeCall({channels:n,channelGroups:t,state:this.presenceState,timetoken:this.currentTimetoken,region:null!==this.region?this.region:void 0,filterExpression:this.configuration.filterExpression},(function(t,n){e.processSubscribeResponse(t,n)}))},e.prototype.stopSubscribeLoop=function(){this._subscribeAbort&&(this._subscribeAbort(),this._subscribeAbort=null)},e.prototype.processSubscribeResponse=function(e,t){var n=this;if(e.error){if("object"==typeof e.errorData&&"name"in e.errorData&&"AbortError"===e.errorData.name)return;e.category===X.PNTimeoutCategory?this.startSubscribeLoop():e.category===X.PNNetworkIssuesCategory?(this.disconnect(),e.error&&this.configuration.autoNetworkDetection&&this.isOnline&&(this.isOnline=!1,this.listenerManager.announceNetworkDown()),this.reconnectionManager.onReconnect((function(){n.configuration.autoNetworkDetection&&!n.isOnline&&(n.isOnline=!0,n.listenerManager.announceNetworkUp()),n.reconnect(),n.subscriptionStatusAnnounced=!0;var t={category:X.PNReconnectedCategory,operation:e.operation,lastTimetoken:n.lastTimetoken,currentTimetoken:n.currentTimetoken};n.listenerManager.announceStatus(t)})),this.reconnectionManager.startPolling(),this.listenerManager.announceStatus(e)):e.category===X.PNBadRequestCategory?(this.stopHeartbeatTimer(),this.listenerManager.announceStatus(e)):this.listenerManager.announceStatus(e)}else{if(this.storedTimetoken?(this.currentTimetoken=this.storedTimetoken,this.storedTimetoken=null):(this.lastTimetoken=this.currentTimetoken,this.currentTimetoken=t.cursor.timetoken),!this.subscriptionStatusAnnounced){var r={category:X.PNConnectedCategory,operation:e.operation,affectedChannels:this.pendingChannelSubscriptions,subscribedChannels:this.subscribedChannels,affectedChannelGroups:this.pendingChannelGroupSubscriptions,lastTimetoken:this.lastTimetoken,currentTimetoken:this.currentTimetoken};this.subscriptionStatusAnnounced=!0,this.listenerManager.announceStatus(r),this.pendingChannelGroupSubscriptions=[],this.pendingChannelSubscriptions=[]}var i=t.messages,o=this.configuration,s=o.requestMessageCountThreshold,a=o.dedupeOnSubscribe;s&&i.length>=s&&this.listenerManager.announceStatus({category:X.PNRequestMessageCountExceededCategory,operation:e.operation}),i.forEach((function(e){if(a){if(n.dedupingManager.isDuplicate(e))return;n.dedupingManager.addEntry(e)}n.eventEmitter.emitEvent(e)})),this.region=t.cursor.region,this.startSubscribeLoop()}},e.prototype.setState=function(e){var t=this,n=e.state,r=e.channels,i=e.channelGroups;null==r||r.forEach((function(e){return e in t.channels&&(t.presenceState[e]=n)})),null==i||i.forEach((function(e){return e in t.channelGroups&&(t.presenceState[e]=n)}))},e.prototype.changePresence=function(e){var t=this,n=e.connected,r=e.channels,i=e.channelGroups;n?(null==r||r.forEach((function(e){return t.heartbeatChannels[e]={}})),null==i||i.forEach((function(e){return t.heartbeatChannelGroups[e]={}}))):(null==r||r.forEach((function(e){e in t.heartbeatChannels&&delete t.heartbeatChannels[e]})),null==i||i.forEach((function(e){e in t.heartbeatChannelGroups&&delete t.heartbeatChannelGroups[e]})),!1===this.configuration.suppressLeaveEvents&&this.leaveCall({channels:r,channelGroups:i},(function(e){return t.listenerManager.announceStatus(e)}))),this.reconnect()},e.prototype.startHeartbeatTimer=function(){var e=this;this.stopHeartbeatTimer();var t=this.configuration.getHeartbeatInterval();t&&0!==t&&(this.sendHeartbeat(),this.heartbeatTimer=setInterval((function(){return e.sendHeartbeat()}),1e3*t))},e.prototype.stopHeartbeatTimer=function(){this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=null)},e.prototype.sendHeartbeat=function(){var e=this,t=Object.keys(this.heartbeatChannelGroups),n=Object.keys(this.heartbeatChannels);0===n.length&&0===t.length||this.heartbeatCall({channels:n,channelGroups:t,heartbeat:this.configuration.getPresenceTimeout(),state:this.presenceState},(function(t){t.error&&e.configuration.announceFailedHeartbeats&&e.listenerManager.announceStatus(t),t.error&&e.configuration.autoNetworkDetection&&e.isOnline&&(e.isOnline=!1,e.disconnect(),e.listenerManager.announceNetworkDown(),e.reconnect()),!t.error&&e.configuration.announceSuccessfulHeartbeats&&e.listenerManager.announceNetworkUp()}))},e}(),re=function(){function e(e,t,n){this._payload=e,this._setDefaultPayloadStructure(),this.title=t,this.body=n}return Object.defineProperty(e.prototype,"payload",{get:function(){return this._payload},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"title",{set:function(e){this._title=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"subtitle",{set:function(e){this._subtitle=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"body",{set:function(e){this._body=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"badge",{set:function(e){this._badge=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"sound",{set:function(e){this._sound=e},enumerable:!1,configurable:!0}),e.prototype._setDefaultPayloadStructure=function(){},e.prototype.toObject=function(){return{}},e}(),ie=function(e){function r(){return null!==e&&e.apply(this,arguments)||this}return t(r,e),Object.defineProperty(r.prototype,"configurations",{set:function(e){e&&e.length&&(this._configurations=e)},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"notification",{get:function(){return this._payload.aps},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"title",{get:function(){return this._title},set:function(e){e&&e.length&&(this._payload.aps.alert.title=e,this._title=e)},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"subtitle",{get:function(){return this._subtitle},set:function(e){e&&e.length&&(this._payload.aps.alert.subtitle=e,this._subtitle=e)},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"body",{get:function(){return this._body},set:function(e){e&&e.length&&(this._payload.aps.alert.body=e,this._body=e)},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"badge",{get:function(){return this._badge},set:function(e){null!=e&&(this._payload.aps.badge=e,this._badge=e)},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"sound",{get:function(){return this._sound},set:function(e){e&&e.length&&(this._payload.aps.sound=e,this._sound=e)},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"silent",{set:function(e){this._isSilent=e},enumerable:!1,configurable:!0}),r.prototype._setDefaultPayloadStructure=function(){this._payload.aps={alert:{}}},r.prototype.toObject=function(){var e=this,t=n({},this._payload),r=t.aps,i=r.alert;if(this._isSilent&&(r["content-available"]=1),"apns2"===this._apnsPushType){if(!this._configurations||!this._configurations.length)throw new ReferenceError("APNS2 configuration is missing");var o=[];this._configurations.forEach((function(t){o.push(e._objectFromAPNS2Configuration(t))})),o.length&&(t.pn_push=o)}return i&&Object.keys(i).length||delete r.alert,this._isSilent&&(delete r.alert,delete r.badge,delete r.sound,i={}),this._isSilent||Object.keys(i).length?t:null},r.prototype._objectFromAPNS2Configuration=function(e){var t=this;if(!e.targets||!e.targets.length)throw new ReferenceError("At least one APNS2 target should be provided");var n=[];e.targets.forEach((function(e){n.push(t._objectFromAPNSTarget(e))}));var r=e.collapseId,i=e.expirationDate,o={auth_method:"token",targets:n,version:"v2"};return r&&r.length&&(o.collapse_id=r),i&&(o.expiration=i.toISOString()),o},r.prototype._objectFromAPNSTarget=function(e){if(!e.topic||!e.topic.length)throw new TypeError("Target 'topic' undefined.");var t=e.topic,n=e.environment,r=void 0===n?"development":n,i=e.excludedDevices,o=void 0===i?[]:i,s={topic:t,environment:r};return o.length&&(s.excluded_devices=o),s},r}(re),oe=function(e){function r(){return null!==e&&e.apply(this,arguments)||this}return t(r,e),Object.defineProperty(r.prototype,"backContent",{get:function(){return this._backContent},set:function(e){e&&e.length&&(this._payload.back_content=e,this._backContent=e)},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"backTitle",{get:function(){return this._backTitle},set:function(e){e&&e.length&&(this._payload.back_title=e,this._backTitle=e)},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"count",{get:function(){return this._count},set:function(e){null!=e&&(this._payload.count=e,this._count=e)},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"title",{get:function(){return this._title},set:function(e){e&&e.length&&(this._payload.title=e,this._title=e)},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"type",{get:function(){return this._type},set:function(e){e&&e.length&&(this._payload.type=e,this._type=e)},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"subtitle",{get:function(){return this.backTitle},set:function(e){this.backTitle=e},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"body",{get:function(){return this.backContent},set:function(e){this.backContent=e},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"badge",{get:function(){return this.count},set:function(e){this.count=e},enumerable:!1,configurable:!0}),r.prototype.toObject=function(){return Object.keys(this._payload).length?n({},this._payload):null},r}(re),se=function(e){function i(){return null!==e&&e.apply(this,arguments)||this}return t(i,e),Object.defineProperty(i.prototype,"notification",{get:function(){return this._payload.notification},enumerable:!1,configurable:!0}),Object.defineProperty(i.prototype,"data",{get:function(){return this._payload.data},enumerable:!1,configurable:!0}),Object.defineProperty(i.prototype,"title",{get:function(){return this._title},set:function(e){e&&e.length&&(this._payload.notification.title=e,this._title=e)},enumerable:!1,configurable:!0}),Object.defineProperty(i.prototype,"body",{get:function(){return this._body},set:function(e){e&&e.length&&(this._payload.notification.body=e,this._body=e)},enumerable:!1,configurable:!0}),Object.defineProperty(i.prototype,"sound",{get:function(){return this._sound},set:function(e){e&&e.length&&(this._payload.notification.sound=e,this._sound=e)},enumerable:!1,configurable:!0}),Object.defineProperty(i.prototype,"icon",{get:function(){return this._icon},set:function(e){e&&e.length&&(this._payload.notification.icon=e,this._icon=e)},enumerable:!1,configurable:!0}),Object.defineProperty(i.prototype,"tag",{get:function(){return this._tag},set:function(e){e&&e.length&&(this._payload.notification.tag=e,this._tag=e)},enumerable:!1,configurable:!0}),Object.defineProperty(i.prototype,"silent",{set:function(e){this._isSilent=e},enumerable:!1,configurable:!0}),i.prototype._setDefaultPayloadStructure=function(){this._payload.notification={},this._payload.data={}},i.prototype.toObject=function(){var e=n({},this._payload.data),t=null,i={};if(Object.keys(this._payload).length>2){var o=this._payload;o.notification,o.data;var s=r(o,["notification","data"]);e=n(n({},e),s)}return this._isSilent?e.notification=this._payload.notification:t=this._payload.notification,Object.keys(e).length&&(i.data=e),t&&Object.keys(t).length&&(i.notification=t),Object.keys(i).length?i:null},i}(re),ae=function(){function e(e,t){this._payload={apns:{},mpns:{},fcm:{}},this._title=e,this._body=t,this.apns=new ie(this._payload.apns,e,t),this.mpns=new oe(this._payload.mpns,e,t),this.fcm=new se(this._payload.fcm,e,t)}return Object.defineProperty(e.prototype,"debugging",{set:function(e){this._debugging=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"title",{get:function(){return this._title},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"body",{get:function(){return this._body},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"subtitle",{get:function(){return this._subtitle},set:function(e){this._subtitle=e,this.apns.subtitle=e,this.mpns.subtitle=e,this.fcm.subtitle=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"badge",{get:function(){return this._badge},set:function(e){this._badge=e,this.apns.badge=e,this.mpns.badge=e,this.fcm.badge=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"sound",{get:function(){return this._sound},set:function(e){this._sound=e,this.apns.sound=e,this.mpns.sound=e,this.fcm.sound=e},enumerable:!1,configurable:!0}),e.prototype.buildPayload=function(e){var t={};if(e.includes("apns")||e.includes("apns2")){this.apns._apnsPushType=e.includes("apns")?"apns":"apns2";var n=this.apns.toObject();n&&Object.keys(n).length&&(t.pn_apns=n)}if(e.includes("mpns")){var r=this.mpns.toObject();r&&Object.keys(r).length&&(t.pn_mpns=r)}if(e.includes("fcm")){var i=this.fcm.toObject();i&&Object.keys(i).length&&(t.pn_gcm=i)}return Object.keys(t).length&&this._debugging&&(t.pn_debug=!0),t},e}(),ue=function(){function e(e){this.params=e,this._cancellationController=null}return Object.defineProperty(e.prototype,"cancellationController",{get:function(){return this._cancellationController},set:function(e){this._cancellationController=e},enumerable:!1,configurable:!0}),e.prototype.abort=function(){this.cancellationController&&this.cancellationController.abort()},e.prototype.operation=function(){throw Error("Should be implemented by subclass.")},e.prototype.validate=function(){},e.prototype.parse=function(e){return i(this,void 0,void 0,(function(){return o(this,(function(e){throw Error("Should be implemented by subclass.")}))}))},e.prototype.request=function(){var e,t,n,r,i={method:null!==(t=null===(e=this.params)||void 0===e?void 0:e.method)&&void 0!==t?t:D.GET,path:this.path,queryParameters:this.queryParameters,cancellable:null!==(r=null===(n=this.params)||void 0===n?void 0:n.cancellable)&&void 0!==r&&r,timeout:1e4,identifier:K()},o=this.headers;if(o&&(i.headers=o),i.method===D.POST||i.method===D.PATCH){var s=a([this.body,this.formData],2),u=s[0],c=s[1];c&&(i.formData=c),u&&(i.body=u)}return i},Object.defineProperty(e.prototype,"headers",{get:function(){},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"path",{get:function(){throw Error("`path` getter should be implemented by subclass.")},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"queryParameters",{get:function(){return{}},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"formData",{get:function(){},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"body",{get:function(){},enumerable:!1,configurable:!0}),e.prototype.deserializeResponse=function(t){var n=t.headers["content-type"];if(-1!==n.indexOf("javascript")&&-1!==n.indexOf("json")){var r=e.decoder.decode(t.body);try{return JSON.parse(r)}catch(e){return void console.error("Error parsing JSON response:",e)}}},e.decoder=new TextDecoder,e}();!function(e){e.PNPublishOperation="PNPublishOperation",e.PNSignalOperation="PNSignalOperation",e.PNSubscribeOperation="PNSubscribeOperation",e.PNUnsubscribeOperation="PNUnsubscribeOperation",e.PNWhereNowOperation="PNWhereNowOperation",e.PNHereNowOperation="PNHereNowOperation",e.PNSetStateOperation="PNSetStateOperation",e.PNGetStateOperation="PNGetStateOperation",e.PNHeartbeatOperation="PNHeartbeatOperation",e.PNAddMessageActionOperation="PNAddActionOperation",e.PNRemoveMessageActionOperation="PNRemoveMessageActionOperation",e.PNGetMessageActionsOperation="PNGetMessageActionsOperation",e.PNTimeOperation="PNTimeOperation",e.PNHistoryOperation="PNHistoryOperation",e.PNDeleteMessagesOperation="PNDeleteMessagesOperation",e.PNFetchMessagesOperation="PNFetchMessagesOperation",e.PNMessageCounts="PNMessageCountsOperation",e.PNGetAllUUIDMetadataOperation="PNGetAllUUIDMetadataOperation",e.PNGetUUIDMetadataOperation="PNGetUUIDMetadataOperation",e.PNSetUUIDMetadataOperation="PNSetUUIDMetadataOperation",e.PNRemoveUUIDMetadataOperation="PNRemoveUUIDMetadataOperation",e.PNGetAllChannelMetadataOperation="PNGetAllChannelMetadataOperation",e.PNGetChannelMetadataOperation="PNGetChannelMetadataOperation",e.PNSetChannelMetadataOperation="PNSetChannelMetadataOperation",e.PNRemoveChannelMetadataOperation="PNRemoveChannelMetadataOperation",e.PNGetMembersOperation="PNGetMembersOperation",e.PNSetMembersOperation="PNSetMembersOperation",e.PNGetMembershipsOperation="PNGetMembershipsOperation",e.PNSetMembershipsOperation="PNSetMembershipsOperation",e.PNListFilesOperation="PNListFilesOperation",e.PNGenerateUploadUrlOperation="PNGenerateUploadUrlOperation",e.PNPublishFileOperation="PNPublishFileOperation",e.PNPublishFileMessageOperation="PNPublishFileMessageOperation",e.PNGetFileUrlOperation="PNGetFileUrlOperation",e.PNDownloadFileOperation="PNDownloadFileOperation",e.PNDeleteFileOperation="PNDeleteFileOperation",e.PNAddPushNotificationEnabledChannelsOperation="PNAddPushNotificationEnabledChannelsOperation",e.PNRemovePushNotificationEnabledChannelsOperation="PNRemovePushNotificationEnabledChannelsOperation",e.PNPushNotificationEnabledChannelsOperation="PNPushNotificationEnabledChannelsOperation",e.PNRemoveAllPushNotificationsOperation="PNRemoveAllPushNotificationsOperation",e.PNChannelGroupsOperation="PNChannelGroupsOperation",e.PNRemoveGroupOperation="PNRemoveGroupOperation",e.PNChannelsForGroupOperation="PNChannelsForGroupOperation",e.PNAddChannelsToGroupOperation="PNAddChannelsToGroupOperation",e.PNRemoveChannelsFromGroupOperation="PNRemoveChannelsFromGroupOperation",e.PNAccessManagerGrant="PNAccessManagerGrant",e.PNAccessManagerGrantToken="PNAccessManagerGrantToken",e.PNAccessManagerAudit="PNAccessManagerAudit",e.PNAccessManagerRevokeToken="PNAccessManagerRevokeToken",e.PNHandshakeOperation="PNHandshakeOperation",e.PNReceiveMessagesOperation="PNReceiveMessagesOperation"}(Y||(Y={}));var ce,pe=Y;!function(e){e[e.Presence=-2]="Presence",e[e.Message=-1]="Message",e[e.Signal=1]="Signal",e[e.AppContext=2]="AppContext",e[e.MessageAction=3]="MessageAction",e[e.Files=4]="Files"}(ce||(ce={}));var le=function(e){function r(t){var n,r,i,o,s,a,u=e.call(this,{cancellable:!0})||this;return u.parameters=t,null!==(n=(o=u.parameters).withPresence)&&void 0!==n||(o.withPresence=false),null!==(r=(s=u.parameters).channelGroups)&&void 0!==r||(s.channelGroups=[]),null!==(i=(a=u.parameters).channels)&&void 0!==i||(a.channels=[]),u}return t(r,e),r.prototype.operation=function(){return pe.PNSubscribeOperation},r.prototype.validate=function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.channels,r=e.channelGroups;return t?n||r?void 0:"`channels` and `channelGroups` both should not be empty":"Missing Subscribe Key"},r.prototype.parse=function(e){return i(this,void 0,void 0,(function(){var t,n,r=this;return o(this,(function(i){if(!(t=this.deserializeResponse(e)))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return n=t.m.map((function(e){var t=e.e;return null!=t||(t=e.c.endsWith("-pnpres")?ce.Presence:ce.Message),"string"==typeof e.d?t==ce.Message?{type:ce.Message,data:r.messageFromEnvelope(e)}:{type:ce.Files,data:r.fileFromEnvelope(e)}:t===ce.Presence?{type:ce.Presence,data:r.presenceEventFromEnvelope(e)}:t==ce.Signal?{type:ce.Signal,data:r.signalFromEnvelope(e)}:t===ce.AppContext?{type:ce.AppContext,data:r.appContextFromEnvelope(e)}:t===ce.MessageAction?{type:ce.MessageAction,data:r.messageActionFromEnvelope(e)}:{type:ce.Files,data:r.fileFromEnvelope(e)}})),[2,{cursor:{timetoken:t.t.t,region:t.t.r},messages:n}]}))}))},r.prototype.presenceEventFromEnvelope=function(e){var t=e.d,r=a(this.subscriptionChannelFromEnvelope(e),2),i=r[0],o=r[1];return i=i.replace("-pnpres",""),o&&(o=o.replace("-pnpres","")),n({channel:i,subscription:o,actualChannel:null!==o?i:null,subscribedChannel:null!==o?o:i,timetoken:e.p.t},t)},r.prototype.messageFromEnvelope=function(e){var t=a(this.subscriptionChannelFromEnvelope(e),2),n=t[0],r=t[1],i=a(this.decryptedData(e.d),2),o=i[0],s=i[1],u={channel:n,subscription:r,actualChannel:null!==r?n:null,subscribedChannel:null!==r?r:n,timetoken:e.p.t,publisher:e.i,userMetadata:e.u,message:o};return s&&(u.error=s),u},r.prototype.signalFromEnvelope=function(e){var t=a(this.subscriptionChannelFromEnvelope(e),2);return{channel:t[0],subscription:t[1],timetoken:e.p.t,publisher:e.i,userMetadata:e.u,message:e.d}},r.prototype.messageActionFromEnvelope=function(e){var t=a(this.subscriptionChannelFromEnvelope(e),2),r=t[0],i=t[1],o=e.d;return{channel:r,subscription:i,timetoken:e.p.t,publisher:e.i,event:o.event,data:n(n({},o.data),{uuid:e.i})}},r.prototype.appContextFromEnvelope=function(e){var t=a(this.subscriptionChannelFromEnvelope(e),2),n=t[0],r=t[1],i=e.d;return{channel:n,subscription:r,timetoken:e.p.t,message:i}},r.prototype.fileFromEnvelope=function(e){var t=a(this.subscriptionChannelFromEnvelope(e),2),n=t[0],r=t[1],i=a(this.decryptedData(e.d),2),o=i[0],s=i[1],u={channel:n,subscription:r,timetoken:e.p.t,publisher:e.i,userMetadata:e.u};return o?"string"==typeof o?null!=s||(s="Unexpected file information payload data type."):(u.message=o.message,o.file&&(u.file={id:o.file.id,name:o.file.name,url:this.parameters.getFileUrl({id:o.file.id,name:o.file.name,channel:n})})):null!=s||(s="File information payload is missing."),s&&(u.error=s),u},r.prototype.subscriptionChannelFromEnvelope=function(e){return[e.c,void 0===e.b||e.b===e.c?null:e.b]},r.prototype.decryptedData=function(e){if(!this.parameters.crypto||"string"!=typeof e)return[e,void 0];var t,n;try{var r=this.parameters.crypto.decrypt(e);t=r instanceof ArrayBuffer?JSON.parse(he.decoder.decode(r)):r}catch(e){t=null,n="Error while decrypting file message content: ".concat(e.message)}return[null!=t?t:e,n]},r}(ue),he=function(e){function n(){return null!==e&&e.apply(this,arguments)||this}return t(n,e),Object.defineProperty(n.prototype,"path",{get:function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.channels;return"/v2/subscribe/".concat(t,"/").concat(H(n.length>0?n.join(","):","),"/0")},enumerable:!1,configurable:!0}),Object.defineProperty(n.prototype,"queryParameters",{get:function(){var e=this.parameters,t=e.channelGroups,n=e.filterExpression,r=e.state,i=e.timetoken,o=e.region,s={};return t&&t.length>0&&(s["channel-group"]=t.join(",")),n&&n.length>0&&(s["filter-expr"]=n),r&&Object.keys(r).length>0&&(s.state=JSON.stringify(r)),"string"==typeof i?i&&i.length>0&&(s.tt=i):i&&i>0&&(s.tt=i),o&&(s.tr=o),s},enumerable:!1,configurable:!0}),n}(le),fe=function(){function e(e){this.listenerManager=e,this.channelListenerMap=new Map,this.groupListenerMap=new Map}return e.prototype.emitEvent=function(e){if(e.type===ce.Message)this.listenerManager.announceMessage(e.data),this.announce("message",e.data,e.data.channel,e.data.subscription);else if(e.type===ce.Signal)this.listenerManager.announceSignal(e.data),this.announce("signal",e.data,e.data.channel,e.data.subscription);else if(e.type===ce.Presence)this.listenerManager.announcePresence(e.data),this.announce("presence",e.data,e.data.channel,e.data.subscription);else if(e.type===ce.AppContext){var t=e.data,i=t.message;if(this.listenerManager.announceObjects(t),this.announce("objects",t,t.channel,t.subscription),"uuid"===i.type){t.message;var o=t.channel,s=r(t,["message","channel"]),a=i.event;i.type;var u=r(i,["event","type"]),c=n(n({},s),{spaceId:o,message:n(n({},u),{event:"set"===a?"updated":"removed",type:"user"})});this.listenerManager.announceUser(c),this.announce("user",c,c.spaceId,c.subscription)}else if("channel"===i.type){t.message;o=t.channel,s=r(t,["message","channel"]);var p=i.event;i.type;u=r(i,["event","type"]);var l=n(n({},s),{spaceId:o,message:n(n({},u),{event:"set"===p?"updated":"removed",type:"space"})});this.listenerManager.announceSpace(l),this.announce("space",l,l.spaceId,l.subscription)}else if("membership"===i.type){t.message;o=t.channel,s=r(t,["message","channel"]);var h=i.event,f=i.data,d=(u=r(i,["event","data"]),f.uuid),y=f.channel,g=r(f,["uuid","channel"]),v=n(n({},s),{spaceId:o,message:n(n({},u),{event:"set"===h?"updated":"removed",data:n(n({},g),{user:d,space:y})})});this.listenerManager.announceMembership(v),this.announce("membership",v,v.spaceId,v.subscription)}}else e.type===ce.MessageAction?(this.listenerManager.announceMessageAction(e.data),this.announce("messageAction",e.data,e.data.channel,e.data.subscription)):e.type===ce.Files&&(this.listenerManager.announceFile(e.data),this.announce("file",e.data,e.data.channel,e.data.subscription))},e.prototype.addListener=function(e,t,n){var r=this;t&&n?(null==t||t.forEach((function(t){if(r.channelListenerMap.has(t)){var n=r.channelListenerMap.get(t);n.includes(e)||n.push(e)}else r.channelListenerMap.set(t,[e])})),null==n||n.forEach((function(t){if(r.groupListenerMap.has(t)){var n=r.groupListenerMap.get(t);n.includes(e)||n.push(e)}else r.groupListenerMap.set(t,[e])}))):this.listenerManager.addListener(e)},e.prototype.removeListener=function(e,t,n){var r=this;t&&n?(null==t||t.forEach((function(t){r.channelListenerMap.has(t)&&r.channelListenerMap.set(t,r.channelListenerMap.get(t).filter((function(t){return t!==e})))})),null==n||n.forEach((function(t){r.groupListenerMap.has(t)&&r.groupListenerMap.set(t,r.groupListenerMap.get(t).filter((function(t){return t!==e})))}))):this.listenerManager.removeListener(e)},e.prototype.removeAllListeners=function(){this.listenerManager.removeAllListeners(),this.channelListenerMap.clear(),this.groupListenerMap.clear()},e.prototype.announce=function(e,t,n,r){t&&this.channelListenerMap.has(n)&&this.channelListenerMap.get(n).forEach((function(n){var r=n[e];r&&r(t)})),r&&this.groupListenerMap.has(r)&&this.groupListenerMap.get(r).forEach((function(n){var r=n[e];r&&r(t)}))},e}(),de=function(){function e(e){void 0===e&&(e=!1),this.sync=e,this.listeners=new Set}return e.prototype.subscribe=function(e){var t=this;return this.listeners.add(e),function(){t.listeners.delete(e)}},e.prototype.notify=function(e){var t=this,n=function(){t.listeners.forEach((function(t){t(e)}))};this.sync?n():setTimeout(n,0)},e}(),ye=function(){function e(e){this.label=e,this.transitionMap=new Map,this.enterEffects=[],this.exitEffects=[]}return e.prototype.transition=function(e,t){var n;if(this.transitionMap.has(t.type))return null===(n=this.transitionMap.get(t.type))||void 0===n?void 0:n(e,t)},e.prototype.on=function(e,t){return this.transitionMap.set(e,t),this},e.prototype.with=function(e,t){return[this,e,null!=t?t:[]]},e.prototype.onEnter=function(e){return this.enterEffects.push(e),this},e.prototype.onExit=function(e){return this.exitEffects.push(e),this},e}(),ge=function(e){function n(){return null!==e&&e.apply(this,arguments)||this}return t(n,e),n.prototype.describe=function(e){return new ye(e)},n.prototype.start=function(e,t){this.currentState=e,this.currentContext=t,this.notify({type:"engineStarted",state:e,context:t})},n.prototype.transition=function(e){var t,n,r,i,o,u;if(!this.currentState)throw new Error("Start the engine first");this.notify({type:"eventReceived",event:e});var c=this.currentState.transition(this.currentContext,e);if(c){var p=a(c,3),l=p[0],h=p[1],f=p[2];try{for(var d=s(this.currentState.exitEffects),y=d.next();!y.done;y=d.next()){var g=y.value;this.notify({type:"invocationDispatched",invocation:g(this.currentContext)})}}catch(e){t={error:e}}finally{try{y&&!y.done&&(n=d.return)&&n.call(d)}finally{if(t)throw t.error}}var v=this.currentState;this.currentState=l;var b=this.currentContext;this.currentContext=h,this.notify({type:"transitionDone",fromState:v,fromContext:b,toState:l,toContext:h,event:e});try{for(var m=s(f),w=m.next();!w.done;w=m.next()){g=w.value;this.notify({type:"invocationDispatched",invocation:g})}}catch(e){r={error:e}}finally{try{w&&!w.done&&(i=m.return)&&i.call(m)}finally{if(r)throw r.error}}try{for(var S=s(this.currentState.enterEffects),k=S.next();!k.done;k=S.next()){g=k.value;this.notify({type:"invocationDispatched",invocation:g(this.currentContext)})}}catch(e){o={error:e}}finally{try{k&&!k.done&&(u=S.return)&&u.call(S)}finally{if(o)throw o.error}}}},n}(de),ve=function(){function e(e){this.dependencies=e,this.instances=new Map,this.handlers=new Map}return e.prototype.on=function(e,t){this.handlers.set(e,t)},e.prototype.dispatch=function(e){if("CANCEL"!==e.type){var t=this.handlers.get(e.type);if(!t)throw new Error("Unhandled invocation '".concat(e.type,"'"));var n=t(e.payload,this.dependencies);e.managed&&this.instances.set(e.type,n),n.start()}else if(this.instances.has(e.payload)){var r=this.instances.get(e.payload);null==r||r.cancel(),this.instances.delete(e.payload)}},e.prototype.dispose=function(){var e,t;try{for(var n=s(this.instances.entries()),r=n.next();!r.done;r=n.next()){var i=a(r.value,2),o=i[0];i[1].cancel(),this.instances.delete(o)}}catch(t){e={error:t}}finally{try{r&&!r.done&&(t=n.return)&&t.call(n)}finally{if(e)throw e.error}}},e}();function be(e,t){var n=function(){for(var n=[],r=0;rt},getDelay:function(e,t){var n;return 1e3*((null!==(n=t.retryAfter)&&void 0!==n?n:this.delay)+Math.random())},getGiveupReason:function(e,t){var n;return this.maximumRetry<=t?"retry attempts exhaused.":403===(null===(n=null==e?void 0:e.status)||void 0===n?void 0:n.statusCode)?"forbidden operation.":"unknown error"},validate:function(){if(this.maximumRetry>10)throw new Error("Maximum retry for linear retry policy can not be more than 10")}}},e.ExponentialRetryPolicy=function(e){return{minimumDelay:e.minimumDelay,maximumDelay:e.maximumDelay,maximumRetry:e.maximumRetry,shouldRetry:function(e,t){var n;return 403!==(null===(n=null==e?void 0:e.status)||void 0===n?void 0:n.statusCode)&&this.maximumRetry>t},getDelay:function(e,t){var n;return 1e3*((null!==(n=t.retryAfter)&&void 0!==n?n:Math.min(Math.pow(2,e),this.maximumDelay))+Math.random())},getGiveupReason:function(e,t){var n;return this.maximumRetry<=t?"retry attempts exhausted.":403===(null===(n=null==e?void 0:e.status)||void 0===n?void 0:n.statusCode)?"forbidden operation.":"unknown error"},validate:function(){if(this.minimumDelay<2)throw new Error("Minimum delay can not be set less than 2 seconds for retry");if(this.maximumDelay)throw new Error("Maximum delay can not be set more than 150 seconds for retry");if(this.maximumRetry>6)throw new Error("Maximum retry for exponential retry policy can not be more than 6")}}},e}(),Je=we("HANDSHAKE",(function(e,t){return{channels:e,groups:t}})),Ye=we("RECEIVE_MESSAGES",(function(e,t,n){return{channels:e,groups:t,cursor:n}})),Xe=me("EMIT_MESSAGES",(function(e){return e})),$e=me("EMIT_STATUS",(function(e){return e})),Ze=we("RECEIVE_RECONNECT",(function(e){return e})),Qe=we("HANDSHAKE_RECONNECT",(function(e){return e})),et=be("SUBSCRIPTION_CHANGED",(function(e,t){return{channels:e,groups:t}})),tt=be("SUBSCRIPTION_RESTORED",(function(e,t,n,r){return{channels:e,groups:t,cursor:{timetoken:n,region:null!=r?r:0}}})),nt=be("HANDSHAKE_SUCCESS",(function(e){return e})),rt=be("HANDSHAKE_FAILURE",(function(e){return e})),it=be("HANDSHAKE_RECONNECT_SUCCESS",(function(e){return{cursor:e}})),ot=be("HANDSHAKE_RECONNECT_FAILURE",(function(e){return e})),st=be("HANDSHAKE_RECONNECT_GIVEUP",(function(e){return e})),at=be("RECEIVE_SUCCESS",(function(e,t){return{cursor:e,events:t}})),ut=be("RECEIVE_FAILURE",(function(e){return e})),ct=be("RECEIVE_RECONNECT_SUCCESS",(function(e,t){return{cursor:e,events:t}})),pt=be("RECEIVE_RECONNECT_FAILURE",(function(e){return e})),lt=be("RECEIVING_RECONNECT_GIVEUP",(function(e){return e})),ht=be("DISCONNECT",(function(){return{}})),ft=be("RECONNECT",(function(e,t){return{cursor:{timetoken:null!=e?e:"",region:null!=t?t:0}}})),dt=be("UNSUBSCRIBE_ALL",(function(){return{}})),yt=function(e){function r(t,r){var s=e.call(this,r)||this;return s.on(Je.type,Ee((function(e,r,a){return i(s,[e,r,a],void 0,(function(e,r,i){var s,a,u=i.handshake,c=i.presenceState,p=i.config;return o(this,(function(i){switch(i.label){case 0:r.throwIfAborted(),i.label=1;case 1:return i.trys.push([1,3,,4]),[4,u(n({abortSignal:r,channels:e.channels,channelGroups:e.groups,filterExpression:p.filterExpression},p.maintainPresenceState&&{state:c}))];case 2:return s=i.sent(),[2,t.transition(nt(s))];case 3:return(a=i.sent())instanceof Error&&"Aborted"===a.message?[2]:a instanceof v?[2,t.transition(rt(a))]:[3,4];case 4:return[2]}}))}))}))),s.on(Ye.type,Ee((function(e,n,r){return i(s,[e,n,r],void 0,(function(e,n,r){var i,s,a=r.receiveMessages,u=r.config;return o(this,(function(r){switch(r.label){case 0:n.throwIfAborted(),r.label=1;case 1:return r.trys.push([1,3,,4]),[4,a({abortSignal:n,channels:e.channels,channelGroups:e.groups,timetoken:e.cursor.timetoken,region:e.cursor.region,filterExpression:u.filterExpression})];case 2:return i=r.sent(),t.transition(at(i.cursor,i.messages)),[3,4];case 3:return(s=r.sent())instanceof Error&&"Aborted"===s.message?[2]:s instanceof v&&!n.aborted?[2,t.transition(ut(s))]:[3,4];case 4:return[2]}}))}))}))),s.on(Xe.type,Ee((function(e,t,n){return i(s,[e,t,n],void 0,(function(e,t,n){var r=n.emitMessages;return o(this,(function(t){return e.length>0&&r(e),[2]}))}))}))),s.on($e.type,Ee((function(e,t,n){return i(s,[e,t,n],void 0,(function(e,t,n){var r=n.emitStatus;return o(this,(function(t){return r(e),[2]}))}))}))),s.on(Ze.type,Ee((function(e,n,r){return i(s,[e,n,r],void 0,(function(e,n,r){var i,s,a=r.receiveMessages,u=r.delay,c=r.config;return o(this,(function(r){switch(r.label){case 0:return c.retryConfiguration&&c.retryConfiguration.shouldRetry(e.reason,e.attempts)?(n.throwIfAborted(),[4,u(c.retryConfiguration.getDelay(e.attempts,e.reason))]):[3,6];case 1:r.sent(),n.throwIfAborted(),r.label=2;case 2:return r.trys.push([2,4,,5]),[4,a({abortSignal:n,channels:e.channels,channelGroups:e.groups,timetoken:e.cursor.timetoken,region:e.cursor.region,filterExpression:c.filterExpression})];case 3:return i=r.sent(),[2,t.transition(ct(i.cursor,i.messages))];case 4:return(s=r.sent())instanceof Error&&"Aborted"===s.message?[2]:s instanceof v?[2,t.transition(pt(s))]:[3,5];case 5:return[3,7];case 6:return[2,t.transition(lt(new v(c.retryConfiguration?c.retryConfiguration.getGiveupReason(e.reason,e.attempts):"Unable to complete subscribe messages receive.")))];case 7:return[2]}}))}))}))),s.on(Qe.type,Ee((function(e,r,a){return i(s,[e,r,a],void 0,(function(e,r,i){var s,a,u=i.handshake,c=i.delay,p=i.presenceState,l=i.config;return o(this,(function(i){switch(i.label){case 0:return l.retryConfiguration&&l.retryConfiguration.shouldRetry(e.reason,e.attempts)?(r.throwIfAborted(),[4,c(l.retryConfiguration.getDelay(e.attempts,e.reason))]):[3,6];case 1:i.sent(),r.throwIfAborted(),i.label=2;case 2:return i.trys.push([2,4,,5]),[4,u(n({abortSignal:r,channels:e.channels,channelGroups:e.groups,filterExpression:l.filterExpression},l.maintainPresenceState&&{state:p}))];case 3:return s=i.sent(),[2,t.transition(it(s))];case 4:return(a=i.sent())instanceof Error&&"Aborted"===a.message?[2]:a instanceof v?[2,t.transition(ot(a))]:[3,5];case 5:return[3,7];case 6:return[2,t.transition(st(new v(l.retryConfiguration?l.retryConfiguration.getGiveupReason(e.reason,e.attempts):"Unable to complete subscribe handshake")))];case 7:return[2]}}))}))}))),s}return t(r,e),r}(ve),gt=new ye("HANDSHAKE_FAILED");gt.on(et.type,(function(e,t){return Pt.with({channels:t.payload.channels,groups:t.payload.groups,cursor:e.cursor})})),gt.on(ft.type,(function(e,t){return Pt.with({channels:e.channels,groups:e.groups,cursor:t.payload.cursor||e.cursor})})),gt.on(tt.type,(function(e,t){var n,r;return Pt.with({channels:t.payload.channels,groups:t.payload.groups,cursor:{timetoken:t.payload.cursor.timetoken,region:t.payload.cursor.region?t.payload.cursor.region:null!==(r=null===(n=null==e?void 0:e.cursor)||void 0===n?void 0:n.region)&&void 0!==r?r:0}})})),gt.on(dt.type,(function(e){return Et.with()}));var vt=new ye("HANDSHAKE_STOPPED");vt.on(et.type,(function(e,t){return vt.with({channels:t.payload.channels,groups:t.payload.groups,cursor:e.cursor})})),vt.on(ft.type,(function(e,t){return Pt.with(n(n({},e),{cursor:t.payload.cursor||e.cursor}))})),vt.on(tt.type,(function(e,t){var n;return vt.with({channels:t.payload.channels,groups:t.payload.groups,cursor:{timetoken:t.payload.cursor.timetoken,region:t.payload.cursor.region||(null===(n=null==e?void 0:e.cursor)||void 0===n?void 0:n.region)||0}})})),vt.on(dt.type,(function(e){return Et.with()}));var bt=new ye("RECEIVE_FAILED");bt.on(ft.type,(function(e,t){var n;return Pt.with({channels:e.channels,groups:e.groups,cursor:{timetoken:t.payload.cursor.timetoken?null===(n=t.payload.cursor)||void 0===n?void 0:n.timetoken:e.cursor.timetoken,region:t.payload.cursor.region||e.cursor.region}})})),bt.on(et.type,(function(e,t){return Pt.with({channels:t.payload.channels,groups:t.payload.groups,cursor:e.cursor})})),bt.on(tt.type,(function(e,t){return Pt.with({channels:t.payload.channels,groups:t.payload.groups,cursor:{timetoken:t.payload.cursor.timetoken,region:t.payload.cursor.region||e.cursor.region}})})),bt.on(dt.type,(function(e){return Et.with(void 0)}));var mt=new ye("RECEIVE_STOPPED");mt.on(et.type,(function(e,t){return mt.with({channels:t.payload.channels,groups:t.payload.groups,cursor:e.cursor})})),mt.on(tt.type,(function(e,t){return mt.with({channels:t.payload.channels,groups:t.payload.groups,cursor:{timetoken:t.payload.cursor.timetoken,region:t.payload.cursor.region||e.cursor.region}})})),mt.on(ft.type,(function(e,t){var n;return Pt.with({channels:e.channels,groups:e.groups,cursor:{timetoken:t.payload.cursor.timetoken?null===(n=t.payload.cursor)||void 0===n?void 0:n.timetoken:e.cursor.timetoken,region:t.payload.cursor.region||e.cursor.region}})})),mt.on(dt.type,(function(){return Et.with(void 0)}));var wt=new ye("RECEIVE_RECONNECTING");wt.onEnter((function(e){return Ze(e)})),wt.onExit((function(){return Ze.cancel})),wt.on(ct.type,(function(e,t){return St.with({channels:e.channels,groups:e.groups,cursor:t.payload.cursor},[Xe(t.payload.events)])})),wt.on(pt.type,(function(e,t){return wt.with(n(n({},e),{attempts:e.attempts+1,reason:t.payload}))})),wt.on(lt.type,(function(e,t){var n;return bt.with({groups:e.groups,channels:e.channels,cursor:e.cursor,reason:t.payload},[$e({category:X.PNDisconnectedUnexpectedlyCategory,error:null===(n=t.payload)||void 0===n?void 0:n.message})])})),wt.on(ht.type,(function(e){return mt.with({channels:e.channels,groups:e.groups,cursor:e.cursor},[$e({category:X.PNDisconnectedCategory})])})),wt.on(tt.type,(function(e,t){return St.with({channels:t.payload.channels,groups:t.payload.groups,cursor:{timetoken:t.payload.cursor.timetoken,region:t.payload.cursor.region||e.cursor.region}})})),wt.on(et.type,(function(e,t){return St.with({channels:t.payload.channels,groups:t.payload.groups,cursor:e.cursor})})),wt.on(dt.type,(function(e){return Et.with(void 0,[$e({category:X.PNDisconnectedCategory})])}));var St=new ye("RECEIVING");St.onEnter((function(e){return Ye(e.channels,e.groups,e.cursor)})),St.onExit((function(){return Ye.cancel})),St.on(at.type,(function(e,t){return St.with({channels:e.channels,groups:e.groups,cursor:t.payload.cursor},[Xe(t.payload.events)])})),St.on(et.type,(function(e,t){return 0===t.payload.channels.length&&0===t.payload.groups.length?Et.with(void 0):St.with({cursor:e.cursor,channels:t.payload.channels,groups:t.payload.groups})})),St.on(tt.type,(function(e,t){return 0===t.payload.channels.length&&0===t.payload.groups.length?Et.with(void 0):St.with({channels:t.payload.channels,groups:t.payload.groups,cursor:{timetoken:t.payload.cursor.timetoken,region:t.payload.cursor.region||e.cursor.region}})})),St.on(ut.type,(function(e,t){return wt.with(n(n({},e),{attempts:0,reason:t.payload}))})),St.on(ht.type,(function(e){return mt.with({channels:e.channels,groups:e.groups,cursor:e.cursor},[$e({category:X.PNDisconnectedCategory})])})),St.on(dt.type,(function(e){return Et.with(void 0,[$e({category:X.PNDisconnectedCategory})])}));var kt=new ye("HANDSHAKE_RECONNECTING");kt.onEnter((function(e){return Qe(e)})),kt.onExit((function(){return Qe.cancel})),kt.on(it.type,(function(e,t){var n,r,i={timetoken:(null===(n=e.cursor)||void 0===n?void 0:n.timetoken)?null===(r=e.cursor)||void 0===r?void 0:r.timetoken:t.payload.cursor.timetoken,region:t.payload.cursor.region};return St.with({channels:e.channels,groups:e.groups,cursor:i},[$e({category:X.PNConnectedCategory})])})),kt.on(ot.type,(function(e,t){return kt.with(n(n({},e),{attempts:e.attempts+1,reason:t.payload}))})),kt.on(st.type,(function(e,t){var n;return gt.with({groups:e.groups,channels:e.channels,cursor:e.cursor,reason:t.payload},[$e({category:X.PNConnectionErrorCategory,error:null===(n=t.payload)||void 0===n?void 0:n.message})])})),kt.on(ht.type,(function(e){return vt.with({channels:e.channels,groups:e.groups,cursor:e.cursor})})),kt.on(et.type,(function(e,t){return Pt.with({channels:t.payload.channels,groups:t.payload.groups,cursor:e.cursor})})),kt.on(tt.type,(function(e,t){var n,r;return Pt.with({channels:t.payload.channels,groups:t.payload.groups,cursor:{timetoken:t.payload.cursor.timetoken,region:(null===(n=t.payload.cursor)||void 0===n?void 0:n.region)||(null===(r=null==e?void 0:e.cursor)||void 0===r?void 0:r.region)||0}})})),kt.on(dt.type,(function(e){return Et.with(void 0)}));var Pt=new ye("HANDSHAKING");Pt.onEnter((function(e){return Je(e.channels,e.groups)})),Pt.onExit((function(){return Je.cancel})),Pt.on(et.type,(function(e,t){return 0===t.payload.channels.length&&0===t.payload.groups.length?Et.with(void 0):Pt.with({channels:t.payload.channels,groups:t.payload.groups,cursor:e.cursor})})),Pt.on(nt.type,(function(e,t){var n,r;return St.with({channels:e.channels,groups:e.groups,cursor:{timetoken:(null===(n=null==e?void 0:e.cursor)||void 0===n?void 0:n.timetoken)?null===(r=null==e?void 0:e.cursor)||void 0===r?void 0:r.timetoken:t.payload.timetoken,region:t.payload.region}},[$e({category:X.PNConnectedCategory})])})),Pt.on(rt.type,(function(e,t){return kt.with({channels:e.channels,groups:e.groups,cursor:e.cursor,attempts:0,reason:t.payload})})),Pt.on(ht.type,(function(e){return vt.with({channels:e.channels,groups:e.groups,cursor:e.cursor})})),Pt.on(tt.type,(function(e,t){var n;return Pt.with({channels:t.payload.channels,groups:t.payload.groups,cursor:{timetoken:t.payload.cursor.timetoken,region:t.payload.cursor.region||(null===(n=null==e?void 0:e.cursor)||void 0===n?void 0:n.region)||0}})})),Pt.on(dt.type,(function(e){return Et.with()}));var Et=new ye("UNSUBSCRIBED");Et.on(et.type,(function(e,t){return Pt.with({channels:t.payload.channels,groups:t.payload.groups})})),Et.on(tt.type,(function(e,t){return Pt.with({channels:t.payload.channels,groups:t.payload.groups,cursor:t.payload.cursor})}));var Ot,Ct=function(){function e(e){var t=this;this.engine=new ge,this.channels=[],this.groups=[],this.dependencies=e,this.dispatcher=new yt(this.engine,e),this._unsubscribeEngine=this.engine.subscribe((function(e){"invocationDispatched"===e.type&&t.dispatcher.dispatch(e.invocation)})),this.engine.start(Et,void 0)}return Object.defineProperty(e.prototype,"_engine",{get:function(){return this.engine},enumerable:!1,configurable:!0}),e.prototype.subscribe=function(e){var t=this,n=e.channels,r=e.channelGroups,i=e.timetoken,o=e.withPresence;this.channels=u(u([],a(this.channels),!1),a(null!=n?n:[]),!1),this.groups=u(u([],a(this.groups),!1),a(null!=r?r:[]),!1),o&&(this.channels.map((function(e){return t.channels.push("".concat(e,"-pnpres"))})),this.groups.map((function(e){return t.groups.push("".concat(e,"-pnpres"))}))),i?this.engine.transition(tt(Array.from(new Set(u(u([],a(this.channels),!1),a(null!=n?n:[]),!1))),Array.from(new Set(u(u([],a(this.groups),!1),a(null!=r?r:[]),!1))),i)):this.engine.transition(et(Array.from(new Set(u(u([],a(this.channels),!1),a(null!=n?n:[]),!1))),Array.from(new Set(u(u([],a(this.groups),!1),a(null!=r?r:[]),!1))))),this.dependencies.join&&this.dependencies.join({channels:Array.from(new Set(this.channels.filter((function(e){return!e.endsWith("-pnpres")})))),groups:Array.from(new Set(this.groups.filter((function(e){return!e.endsWith("-pnpres")}))))})},e.prototype.unsubscribe=function(e){var t=this,n=e.channels,r=void 0===n?[]:n,i=e.channelGroups,o=void 0===i?[]:i,s=z(this.channels,u(u([],a(r),!1),a(r.map((function(e){return"".concat(e,"-pnpres")}))),!1)),c=z(this.groups,u(u([],a(o),!1),a(o.map((function(e){return"".concat(e,"-pnpres")}))),!1));if(new Set(this.channels).size!==new Set(s).size||new Set(this.groups).size!==new Set(c).size){var p=V(this.channels,r),l=V(this.groups,o);this.dependencies.presenceState&&(null==p||p.forEach((function(e){return delete t.dependencies.presenceState[e]})),null==l||l.forEach((function(e){return delete t.dependencies.presenceState[e]}))),this.channels=s,this.groups=c,this.engine.transition(et(Array.from(new Set(this.channels.slice(0))),Array.from(new Set(this.groups.slice(0))))),this.dependencies.leave&&this.dependencies.leave({channels:p.slice(0),groups:l.slice(0)})}},e.prototype.unsubscribeAll=function(){this.channels=[],this.groups=[],this.dependencies.presenceState&&(this.dependencies.presenceState={}),this.engine.transition(et(this.channels.slice(0),this.groups.slice(0))),this.dependencies.leaveAll&&this.dependencies.leaveAll()},e.prototype.reconnect=function(e){var t=e.timetoken,n=e.region;this.engine.transition(ft(t,n))},e.prototype.disconnect=function(){this.engine.transition(ht()),this.dependencies.leaveAll&&this.dependencies.leaveAll()},e.prototype.getSubscribedChannels=function(){return Array.from(new Set(this.channels.slice(0)))},e.prototype.getSubscribedChannelGroups=function(){return Array.from(new Set(this.groups.slice(0)))},e.prototype.dispose=function(){this.disconnect(),this._unsubscribeEngine(),this.dispatcher.dispose()},e}(),_t=function(e){function r(t){var n,r,i,o,s,a,u=e.call(this,{method:t.sendByPost?D.POST:D.GET})||this;return u.parameters=t,null!==(n=(o=u.parameters).storeInHistory)&&void 0!==n||(o.storeInHistory=true),null!==(r=(s=u.parameters).sendByPost)&&void 0!==r||(s.sendByPost=false),null!==(i=(a=u.parameters).replicate)&&void 0!==i||(a.replicate=true),u}return t(r,e),r.prototype.operation=function(){return pe.PNPublishOperation},r.prototype.validate=function(){var e=this.parameters,t=e.message,n=e.channel,r=e.keySet.publishKey;return n?t?r?void 0:"Missing 'publishKey'":"Missing 'message'":"Missing 'channel''"},r.prototype.parse=function(e){return i(this,void 0,void 0,(function(){var t;return o(this,(function(n){if(!(t=this.deserializeResponse(e)))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,{timetoken:t[2]}]}))}))},Object.defineProperty(r.prototype,"path",{get:function(){var e=this.parameters,t=e.message,n=e.channel,r=e.keySet,i=this.prepareMessagePayload(t);return"/publish/".concat(r.publishKey,"/").concat(r.subscribeKey,"/0/").concat(H(n),"/0").concat(this.parameters.sendByPost?"":"/".concat(H(i)))},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"queryParameters",{get:function(){var e=this.parameters,t=e.meta,r=e.replicate,i=e.storeInHistory,o=e.ttl;return n(n(n({store:i?"1":"0"},void 0!==o?{ttl:o}:{}),r?{}:{norep:"true"}),t&&"object"==typeof t?{meta:JSON.stringify(t)}:{})},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"body",{get:function(){return this.prepareMessagePayload(this.parameters.message)},enumerable:!1,configurable:!0}),r.prototype.prepareMessagePayload=function(e){var t=this.parameters.crypto;if(!t)return JSON.stringify(e)||"";var n=t.encrypt(JSON.stringify(e));return JSON.stringify("string"==typeof n?n:g(n))},r}(ue),Nt=function(e){function n(t){var n=e.call(this)||this;return n.parameters=t,n}return t(n,e),n.prototype.operation=function(){return pe.PNSignalOperation},n.prototype.validate=function(){var e=this.parameters,t=e.message,n=e.channel,r=e.keySet.publishKey;return n?t?r?void 0:"Missing 'publishKey'":"Missing 'message'":"Missing 'channel''"},n.prototype.parse=function(e){return i(this,void 0,void 0,(function(){var t;return o(this,(function(n){if(!(t=this.deserializeResponse(e)))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,{timetoken:t[2]}]}))}))},Object.defineProperty(n.prototype,"path",{get:function(){var e=this.parameters,t=e.keySet,n=t.publishKey,r=t.subscribeKey,i=e.channel,o=e.message,s=JSON.stringify(o);return"/signal/".concat(n,"/").concat(r,"/0/").concat(H(i),"/0/").concat(H(s))},enumerable:!1,configurable:!0}),n}(ue),Mt=function(e){function n(){return null!==e&&e.apply(this,arguments)||this}return t(n,e),n.prototype.operation=function(){return pe.PNReceiveMessagesOperation},n.prototype.validate=function(){var t=e.prototype.validate.call(this);return t||(this.parameters.timetoken?this.parameters.region?void 0:"region can not be empty":"timetoken can not be empty")},Object.defineProperty(n.prototype,"path",{get:function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.channels;return"/v2/subscribe/".concat(t,"/").concat(H(n.length>0?n.join(","):","),"/0")},enumerable:!1,configurable:!0}),Object.defineProperty(n.prototype,"queryParameters",{get:function(){var e=this.parameters,t=e.channelGroups,n=e.filterExpression,r=e.timetoken,i=e.region,o={ee:""};return t&&t.length>0&&(o["channel-group"]=t.join(",")),n&&n.length>0&&(o["filter-expr"]=n),"string"==typeof r?r&&r.length>0&&(o.tt=r):r&&r>0&&(o.tt=r),i&&(o.tr=i),o},enumerable:!1,configurable:!0}),n}(le),At=function(e){function n(){return null!==e&&e.apply(this,arguments)||this}return t(n,e),n.prototype.operation=function(){return pe.PNHandshakeOperation},Object.defineProperty(n.prototype,"path",{get:function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.channels;return"/v2/subscribe/".concat(t,"/").concat(H(n.length>0?n.join(","):","),"/0")},enumerable:!1,configurable:!0}),Object.defineProperty(n.prototype,"queryParameters",{get:function(){var e=this.parameters,t=e.channelGroups,n=e.filterExpression,r=e.state,i={tt:0,ee:""};return t&&t.length>0&&(i["channel-group"]=t.join(",")),n&&n.length>0&&(i["filter-expr"]=n),r&&Object.keys(r).length>0&&(i.state=JSON.stringify(r)),i},enumerable:!1,configurable:!0}),n}(le),Rt=function(e){function n(t){var n,r,i,o,s=e.call(this)||this;return s.parameters=t,null!==(n=(i=s.parameters).channels)&&void 0!==n||(i.channels=[]),null!==(r=(o=s.parameters).channelGroups)&&void 0!==r||(o.channelGroups=[]),s}return t(n,e),n.prototype.operation=function(){return pe.PNGetStateOperation},n.prototype.validate=function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.channels,r=e.channelGroups;return t?n&&n.length>0&&r&&r.length>0?"Only `channels` or `channelGroups` can be specified at once.":void 0:"Missing Subscribe Key"},n.prototype.parse=function(e){return i(this,void 0,void 0,(function(){var t,n,r,i,s;return o(this,(function(o){if(!(t=this.deserializeResponse(e)))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return n=this.parameters,r=n.channels,i=n.channelGroups,s={channels:{}},1===(null==r?void 0:r.length)&&0===(null==i?void 0:i.length)?s.channels[r[0]]=t.payload:s.channels=t.payload,[2,s]}))}))},Object.defineProperty(n.prototype,"path",{get:function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.uuid,r=e.channels,i=r&&r.length>0?H(r.join(",")):",";return"/v2/presence/sub-key/".concat(t,"/channel/").concat(i,"/uuid/").concat(n)},enumerable:!1,configurable:!0}),Object.defineProperty(n.prototype,"queryParameters",{get:function(){var e=this.parameters.channelGroups;return e&&0!==e.length?{"channel-group":e.join(",")}:{}},enumerable:!1,configurable:!0}),n}(ue),jt=function(e){function n(t){var n=e.call(this)||this;return n.parameters=t,n}return t(n,e),n.prototype.operation=function(){return pe.PNSetStateOperation},n.prototype.validate=function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.state,r=e.channels,i=e.channelGroups;return t?n?0===(null==r?void 0:r.length)&&0===(null==i?void 0:i.length)?"Please provide a list of channels and/or channel-groups":void 0:"Missing State":"Missing Subscribe Key"},n.prototype.parse=function(e){return i(this,void 0,void 0,(function(){var t;return o(this,(function(n){if(!(t=this.deserializeResponse(e)))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,{state:t.payload}]}))}))},Object.defineProperty(n.prototype,"path",{get:function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.uuid,r=e.channels,i=r&&r.length>0?H(r.join(",")):",";return"/v2/presence/sub-key/".concat(t,"/channel/").concat(i,"/uuid/").concat(n,"/data")},enumerable:!1,configurable:!0}),Object.defineProperty(n.prototype,"queryParameters",{get:function(){var e=this.parameters,t=e.channelGroups,n=e.state,r={state:JSON.stringify(n)};return t&&0===t.length&&(r["channel-group"]=t.join(",")),r},enumerable:!1,configurable:!0}),n}(ue),It=function(e){function n(t){var n=e.call(this)||this;return n.parameters=t,n}return t(n,e),n.prototype.operation=function(){return pe.PNHeartbeatOperation},n.prototype.validate=function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.channels,r=e.channelGroups;return t?0===(null==n?void 0:n.length)&&0===(null==r?void 0:r.length)?"Please provide a list of channels and/or channel-groups":void 0:"Missing Subscribe Key"},n.prototype.parse=function(e){return i(this,void 0,void 0,(function(){return o(this,(function(t){if(!this.deserializeResponse(e))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,{}]}))}))},Object.defineProperty(n.prototype,"path",{get:function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.channels,r=n&&n.length>0?H(n.join(",")):",";return"/v2/presence/sub-key/".concat(t,"/channel/").concat(r,"/heartbeat")},enumerable:!1,configurable:!0}),Object.defineProperty(n.prototype,"queryParameters",{get:function(){var e=this.parameters,t=e.channelGroups,n=e.state,r=e.heartbeat,i={heartbeat:"".concat(r)};return t&&0===t.length&&(i["channel-group"]=t.join(",")),n&&(i.state=JSON.stringify(n)),i},enumerable:!1,configurable:!0}),n}(ue),Tt=function(e){function n(t){var n=e.call(this)||this;return n.parameters=t,n}return t(n,e),n.prototype.operation=function(){return pe.PNUnsubscribeOperation},n.prototype.validate=function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.channels,r=e.channelGroups;return t?0===(null==n?void 0:n.length)&&0===(null==r?void 0:r.length)?"At least one `channel` or `channel group` should be provided.":void 0:"Missing Subscribe Key"},n.prototype.parse=function(e){return i(this,void 0,void 0,(function(){return o(this,(function(t){if(!this.deserializeResponse(e))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,{}]}))}))},Object.defineProperty(n.prototype,"path",{get:function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.channels,r=n&&n.length>0?H(n.join(",")):",";return"/v2/presence/sub-key/".concat(t,"/channel/").concat(r,"/leave")},enumerable:!1,configurable:!0}),Object.defineProperty(n.prototype,"queryParameters",{get:function(){var e=this.parameters.channelGroups;return e&&0!==e.length?{"channel-group":e.join(",")}:{}},enumerable:!1,configurable:!0}),n}(ue),Ut=function(e){function n(t){var n=e.call(this)||this;return n.parameters=t,n}return t(n,e),n.prototype.operation=function(){return pe.PNWhereNowOperation},n.prototype.validate=function(){if(!this.parameters.keySet.subscribeKey)return"Missing Subscribe Key"},n.prototype.parse=function(e){return i(this,void 0,void 0,(function(){var t;return o(this,(function(n){if(!(t=this.deserializeResponse(e)))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return t.payload?[2,{channels:t.payload.channels}]:[2,{channels:[]}]}))}))},Object.defineProperty(n.prototype,"path",{get:function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.uuid;return"/v2/presence/sub-key/".concat(t,"/uuid/").concat(H(n))},enumerable:!1,configurable:!0}),n}(ue),Ft=function(e){function r(t){var n,r,i,o,s,a,u=e.call(this)||this;return u.parameters=t,null!==(n=(o=u.parameters).queryParameters)&&void 0!==n||(o.queryParameters={}),null!==(r=(s=u.parameters).includeUUIDs)&&void 0!==r||(s.includeUUIDs=true),null!==(i=(a=u.parameters).includeState)&&void 0!==i||(a.includeState=false),u}return t(r,e),r.prototype.operation=function(){return pe.PNHereNowOperation},r.prototype.validate=function(){if(!this.parameters.keySet.subscribeKey)return"Missing Subscribe Key"},r.prototype.parse=function(e){return i(this,void 0,void 0,(function(){var t,n,r,i,s,a,u,c;return o(this,(function(o){if(!(t=this.deserializeResponse(e)))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return n="occupancy"in t?1:t.payload.total_channels,r="occupancy"in t?t.occupancy:t.payload.total_channels,i={},s={},"occupancy"in t?(a=this.parameters.channels[0],s[a]={uuids:null!==(u=t.uuids)&&void 0!==u?u:[],occupancy:r}):s=null!==(c=t.payload.channels)&&void 0!==c?c:{},Object.keys(s).forEach((function(e){var t=s[e];i[e]={occupants:t.uuids.map((function(e){return"string"==typeof e?{uuid:e,state:null}:e})),name:e,occupancy:t.occupancy}})),[2,{totalChannels:n,totalOccupancy:r,channels:i}]}))}))},Object.defineProperty(r.prototype,"path",{get:function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.channels,r=e.channelGroups,i="/v2/presence/sub-key/".concat(t);if(n&&n.length>0||r&&r.length>0){var o=n&&n.length>0?H(n.join(",")):",";i+="/channel/".concat(o)}return i},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"queryParameters",{get:function(){var e=this.parameters,t=e.channelGroups,r=e.includeUUIDs,i=e.includeState,o=e.queryParameters;return n(n(n(n({},r?{}:{disable_uuids:"1"}),null!=i&&i?{state:"1"}:{}),t&&t.length>0?{"channel-group":t.join(",")}:{}),o)},enumerable:!1,configurable:!0}),r}(ue),Dt=function(e){function r(t){var n=e.call(this,{method:D.DELETE})||this;return n.parameters=t,n}return t(r,e),r.prototype.operation=function(){return pe.PNDeleteMessagesOperation},r.prototype.validate=function(){return this.parameters.keySet.subscribeKey?this.parameters.channel?void 0:"Missing channel":"Missing Subscribe Key"},r.prototype.parse=function(e){return i(this,void 0,void 0,(function(){return o(this,(function(t){if(!this.deserializeResponse(e))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,{}]}))}))},Object.defineProperty(r.prototype,"path",{get:function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.channel;return"/v3/history/sub-key/".concat(t,"/channel/").concat(H(n))},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"queryParameters",{get:function(){var e=this.parameters,t=e.start,r=e.end;return n(n({},t?{start:t}:{}),r?{end:r}:{})},enumerable:!1,configurable:!0}),r}(ue),xt=function(e){function r(t){var n=e.call(this)||this;return n.parameters=t,n}return t(r,e),r.prototype.operation=function(){return pe.PNMessageCounts},r.prototype.validate=function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.channels,r=e.timetoken,i=e.channelTimetokens;return t?n?r&&i?"`timetoken` and `channelTimetokens` are incompatible together":r||i?i&&i.length&&i.length!==n.length?"Length of `channelTimetokens` and `channels` do not match":void 0:"`timetoken` or `channelTimetokens` need to be set":"Missing channels":"Missing Subscribe Key"},r.prototype.parse=function(e){return i(this,void 0,void 0,(function(){var t;return o(this,(function(n){if(!(t=this.deserializeResponse(e)))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,{channels:t.channels}]}))}))},Object.defineProperty(r.prototype,"path",{get:function(){return"/v3/history/sub-key/".concat(this.parameters.keySet.subscribeKey,"/message-counts/").concat(H(this.parameters.channels.join(",")))},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"queryParameters",{get:function(){var e=this.parameters.channelTimetokens;return this.parameters.timetoken&&(e=[this.parameters.timetoken]),n(n({},1===e.length?{timetoken:e[0]}:{}),e.length>1?{channelsTimetoken:e.join(",")}:{})},enumerable:!1,configurable:!0}),r}(ue),Kt=function(e){function r(t){var n,r,i,o=e.call(this)||this;return o.parameters=t,t.count?t.count=Math.min(t.count,100):t.count=100,null!==(n=t.stringifiedTimeToken)&&void 0!==n||(t.stringifiedTimeToken=false),null!==(r=t.includeMeta)&&void 0!==r||(t.includeMeta=false),null!==(i=t.logVerbosity)&&void 0!==i||(t.logVerbosity=false),o}return t(r,e),r.prototype.operation=function(){return pe.PNHistoryOperation},r.prototype.validate=function(){return this.parameters.keySet.subscribeKey?this.parameters.channel?void 0:"Missing channel":"Missing Subscribe Key"},r.prototype.parse=function(e){return i(this,void 0,void 0,(function(){var t,n,r,i,s=this;return o(this,(function(o){if(!(t=this.deserializeResponse(e)))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return n=t[0],r=t[1],i=t[2],Array.isArray(n)?[2,{messages:n.map((function(e){var t=s.processPayload(e.message),n={entry:t.payload,timetoken:e.timetoken};return t.error&&(n.error=t.error),e.meta&&(n.meta=e.meta),n})),startTimeToken:r,endTimeToken:i}]:[2,{messages:[],startTimeToken:r,endTimeToken:i}]}))}))},Object.defineProperty(r.prototype,"path",{get:function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.channel;return"/v2/history/sub-key/".concat(t,"/channel/").concat(H(n))},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"queryParameters",{get:function(){var e=this.parameters,t=e.start,r=e.end,i=e.reverse,o=e.count,s=e.stringifiedTimeToken,a=e.includeMeta;return n(n(n(n(n({count:o,include_token:"true"},t?{start:t}:{}),r?{end:r}:{}),s?{string_message_token:"true"}:{}),null!=i?{reverse:i.toString()}:{}),a?{include_meta:"true"}:{})},enumerable:!1,configurable:!0}),r.prototype.processPayload=function(e){var t,n,i=this.parameters,o=i.crypto,s=i.logVerbosity;if(!o||"string"!=typeof e)return{payload:e};try{var a=o.decrypt(e);t=a instanceof ArrayBuffer?JSON.parse(r.decoder.decode(a)):a}catch(r){s&&console.log("decryption error",r.message),t=e,n="Error while decrypting message content: ".concat(r.message)}return{payload:t,error:n}},r}(ue);!function(e){e[e.Message=-1]="Message",e[e.Files=4]="Files"}(Ot||(Ot={}));var Gt=function(e){function r(t){var n,r,i,o,s,a,u=e.call(this)||this;u.parameters=t;var c=null!==(n=t.includeMessageActions)&&void 0!==n&&n,p=1===t.channels.length&&c?100:25;return t.count?t.count=Math.min(t.count,p):t.count=p,t.includeUuid?t.includeUUID=t.includeUuid:null!==(r=t.includeUUID)&&void 0!==r||(t.includeUUID=true),null!==(i=t.stringifiedTimeToken)&&void 0!==i||(t.stringifiedTimeToken=false),null!==(o=t.includeMessageType)&&void 0!==o||(t.includeMessageType=true),null!==(s=t.includeMeta)&&void 0!==s||(t.includeMeta=true),null!==(a=t.logVerbosity)&&void 0!==a||(t.logVerbosity=false),u}return t(r,e),r.prototype.operation=function(){return pe.PNFetchMessagesOperation},r.prototype.validate=function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.channels,r=e.includeMessageActions;return t?n?r&&n.length>1?"History can return actions data for a single channel only. Either pass a single channel or disable the includeMessageActions flag.":void 0:"Missing channels":"Missing Subscribe Key"},r.prototype.parse=function(e){return i(this,void 0,void 0,(function(){var t,n,r,i,s=this;return o(this,(function(o){if(!(t=this.deserializeResponse(e)))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return n=null!==(i=t.channels)&&void 0!==i?i:{},r={},Object.keys(n).forEach((function(e){r[e]=n[e].map((function(t){null===t.message_type&&(t.message_type=Ot.Message);var n=s.processPayload(e,t),r={channel:e,timetoken:t.timetoken,message:n.payload,messageType:t.message_type,uuid:t.uuid};if(t.actions){var i=r;i.actions=t.actions,i.data=t.actions}return t.meta&&(r.meta=t.meta),n.error&&(r.error=n.error),r}))})),t.more?[2,{channels:n,more:t.more}]:[2,{channels:n}]}))}))},Object.defineProperty(r.prototype,"path",{get:function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.channels,r=e.includeMessageActions;return"/v3/".concat(r?"history-with-actions":"history","/sub-key/").concat(t,"/channel/").concat(H(n.join(",")))},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"queryParameters",{get:function(){var e=this.parameters,t=e.start,r=e.end,i=e.count,o=e.includeMessageType,s=e.includeMeta,a=e.includeUUID,u=e.stringifiedTimeToken;return n(n(n(n(n(n({max:i},t?{start:t}:{}),r?{end:r}:{}),u?{string_message_token:"true"}:{}),s?{include_meta:"true"}:{}),a?{include_uuid:"true"}:{}),o?{include_message_type:"true"}:{})},enumerable:!1,configurable:!0}),r.prototype.processPayload=function(e,t){var i,o,s=this.parameters,a=s.crypto,u=s.logVerbosity;if(!a||"string"!=typeof t.message)return{payload:t.message};try{var c=a.decrypt(t.message);i=c instanceof ArrayBuffer?JSON.parse(r.decoder.decode(c)):c}catch(e){u&&console.log("decryption error",e.message),i=t.message,o="Error while decrypting message content: ".concat(e.message)}if(!o&&i&&t.message_type==Ot.Files&&"object"==typeof i&&this.isFileMessage(i)){var p=i;return{payload:{message:p.message,file:n(n({},p.file),{url:this.parameters.getFileUrl({channel:e,id:p.file.id,name:p.file.name})})},error:o}}return{payload:i,error:o}},r.prototype.isFileMessage=function(e){return void 0!==e.file},r}(ue),qt=function(e){function r(t){var n=e.call(this)||this;return n.parameters=t,n}return t(r,e),r.prototype.operation=function(){return pe.PNGetMessageActionsOperation},r.prototype.validate=function(){return this.parameters.keySet.subscribeKey?this.parameters.channel?void 0:"Missing message channel":"Missing Subscribe Key"},r.prototype.parse=function(e){return i(this,void 0,void 0,(function(){var t,n,r;return o(this,(function(i){if(!(t=this.deserializeResponse(e)))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return n=null,r=null,t.data.length>0&&(n=t.data[0].actionTimetoken,r=t.data[t.data.length-1].actionTimetoken),[2,{data:t.data,more:t.more,start:n,end:r}]}))}))},Object.defineProperty(r.prototype,"path",{get:function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.channel;return"/v1/message-actions/".concat(t,"/channel/").concat(H(n))},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"queryParameters",{get:function(){var e=this.parameters,t=e.limit,r=e.start,i=e.end;return n(n(n({},r?{start:r}:{}),i?{end:i}:{}),t?{limit:t}:{})},enumerable:!1,configurable:!0}),r}(ue),Lt=function(e){function n(t){var n=e.call(this,{method:D.POST})||this;return n.parameters=t,n}return t(n,e),n.prototype.operation=function(){return pe.PNAddMessageActionOperation},n.prototype.validate=function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.action,r=e.channel,i=e.messageTimetoken;return t?r?i?n&&n.value?n.type?n.type.length>15?"Action.type value exceed maximum length of 15":void 0:"Missing Action.type":"Missing Action.value":"Missing message timetoken":"Missing message channel":"Missing Subscribe Key"},n.prototype.parse=function(e){return i(this,void 0,void 0,(function(){var t;return o(this,(function(n){if(!(t=this.deserializeResponse(e)))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,{data:t.data}]}))}))},Object.defineProperty(n.prototype,"headers",{get:function(){return{"Content-Type":"application/json"}},enumerable:!1,configurable:!0}),Object.defineProperty(n.prototype,"path",{get:function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.channel,r=e.messageTimetoken;return"/v1/message-actions/".concat(t,"/channel/").concat(H(n),"/message/").concat(r)},enumerable:!1,configurable:!0}),Object.defineProperty(n.prototype,"body",{get:function(){return JSON.stringify(this.parameters.action)},enumerable:!1,configurable:!0}),n}(ue),Bt=function(e){function n(t){var n=e.call(this,{method:D.DELETE})||this;return n.parameters=t,n}return t(n,e),n.prototype.operation=function(){return pe.PNRemoveMessageActionOperation},n.prototype.validate=function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.channel,r=e.messageTimetoken,i=e.actionTimetoken;return t?n?r?i?void 0:"Missing action timetoken":"Missing message timetoken":"Missing message action channel":"Missing Subscribe Key"},n.prototype.parse=function(e){return i(this,void 0,void 0,(function(){var t;return o(this,(function(n){if(!(t=this.deserializeResponse(e)))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,{data:t.data}]}))}))},Object.defineProperty(n.prototype,"path",{get:function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.channel,r=e.actionTimetoken,i=e.messageTimetoken;return"/v1/message-actions/".concat(t,"/channel/").concat(H(n),"/message/").concat(i,"/action/").concat(r)},enumerable:!1,configurable:!0}),n}(ue),Ht=function(e){function r(t){var n,r,i=e.call(this)||this;return i.parameters=t,null!==(n=(r=i.parameters).storeInHistory)&&void 0!==n||(r.storeInHistory=true),i}return t(r,e),r.prototype.operation=function(){return pe.PNPublishFileMessageOperation},r.prototype.validate=function(){var e=this.parameters,t=e.channel,n=e.fileId,r=e.fileName;return t?n?r?void 0:"file name can't be empty":"file id can't be empty":"channel can't be empty"},r.prototype.parse=function(e){return i(this,void 0,void 0,(function(){var t;return o(this,(function(n){if(!(t=this.deserializeResponse(e)))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,{timetoken:t[2]}]}))}))},Object.defineProperty(r.prototype,"path",{get:function(){var e=this.parameters,t=e.message,r=e.channel,i=e.keySet,o=i.publishKey,s=i.subscribeKey,a=e.fileId,u=e.fileName,c=n({file:{name:u,id:a}},t?{message:t}:{});return"/v1/files/publish-file/".concat(o,"/").concat(s,"/0/").concat(H(r),"/0/").concat(H(this.prepareMessagePayload(c)))},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"queryParameters",{get:function(){var e=this.parameters,t=e.storeInHistory,r=e.ttl,i=e.meta;return n(n({store:t?"1":"0"},r?{ttl:r}:{}),i&&"object"==typeof i?{meta:JSON.stringify(i)}:{})},enumerable:!1,configurable:!0}),r.prototype.prepareMessagePayload=function(e){var t=this.parameters.crypto;if(!t)return JSON.stringify(e)||"";var n=t.encrypt(JSON.stringify(e));return JSON.stringify("string"==typeof n?n:g(n))},r}(ue),zt=function(e){function n(t){var n=e.call(this,{method:D.LOCAL})||this;return n.parameters=t,n}return t(n,e),n.prototype.operation=function(){return pe.PNGetFileUrlOperation},n.prototype.validate=function(){var e=this.parameters,t=e.channel,n=e.id,r=e.name;return t?n?r?void 0:"file name can't be empty":"file id can't be empty":"channel can't be empty"},n.prototype.parse=function(e){return i(this,void 0,void 0,(function(){return o(this,(function(t){return[2,e.url]}))}))},Object.defineProperty(n.prototype,"path",{get:function(){var e=this.parameters,t=e.channel,n=e.id,r=e.name,i=e.keySet.subscribeKey;return"/v1/files/".concat(i,"/channels/").concat(H(t),"/files/").concat(n,"/").concat(r)},enumerable:!1,configurable:!0}),n}(ue),Vt=function(e){function n(t){var n=e.call(this,{method:D.DELETE})||this;return n.parameters=t,n}return t(n,e),n.prototype.operation=function(){return pe.PNDeleteFileOperation},n.prototype.validate=function(){var e=this.parameters,t=e.channel,n=e.id,r=e.name;return t?n?r?void 0:"file name can't be empty":"file id can't be empty":"channel can't be empty"},n.prototype.parse=function(e){return i(this,void 0,void 0,(function(){var t;return o(this,(function(n){if(!(t=this.deserializeResponse(e)))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,t]}))}))},Object.defineProperty(n.prototype,"path",{get:function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.id,r=e.channel,i=e.name;return"/v1/files/".concat(t,"/channels/").concat(H(r),"/files/").concat(n,"/").concat(i)},enumerable:!1,configurable:!0}),n}(ue),Wt=function(e){function r(t){var n,r,i=e.call(this)||this;return i.parameters=t,null!==(n=(r=i.parameters).limit)&&void 0!==n||(r.limit=100),i}return t(r,e),r.prototype.operation=function(){return pe.PNListFilesOperation},r.prototype.validate=function(){if(!this.parameters.channel)return"channel can't be empty"},r.prototype.parse=function(e){return i(this,void 0,void 0,(function(){var t;return o(this,(function(n){if(!(t=this.deserializeResponse(e)))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,t]}))}))},Object.defineProperty(r.prototype,"path",{get:function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.channel;return"/v1/files/".concat(t,"/channels/").concat(H(n),"/files")},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"queryParameters",{get:function(){var e=this.parameters,t=e.limit,r=e.next;return n({limit:t},r?{next:r}:{})},enumerable:!1,configurable:!0}),r}(ue),Jt=function(e){function n(t){var n=e.call(this,{method:D.POST})||this;return n.parameters=t,n}return t(n,e),n.prototype.operation=function(){return pe.PNGenerateUploadUrlOperation},n.prototype.validate=function(){return this.parameters.channel?this.parameters.name?void 0:"'name' can't be empty":"channel can't be empty"},n.prototype.parse=function(e){return i(this,void 0,void 0,(function(){var t;return o(this,(function(n){if(!(t=this.deserializeResponse(e)))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,{id:t.data.id,name:t.data.name,url:t.file_upload_request.url,formFields:t.file_upload_request.form_fields}]}))}))},Object.defineProperty(n.prototype,"path",{get:function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.channel;return"/v1/files/".concat(t,"/channels/").concat(H(n),"/generate-upload-url")},enumerable:!1,configurable:!0}),Object.defineProperty(n.prototype,"body",{get:function(){return JSON.stringify({name:this.parameters.name})},enumerable:!1,configurable:!0}),n}(ue),Yt=function(e){function r(t){var n=e.call(this)||this;n.parameters=t;var r=t.file.mimeType;return r&&(t.formFields=t.formFields.map((function(e){return"Content-Type"===e.name?{name:e.name,value:r}:e}))),n}return t(r,e),r.prototype.operation=function(){return pe.PNPublishFileOperation},r.prototype.validate=function(){var e=this.parameters,t=e.fileId,n=e.fileName,r=e.file,i=e.uploadUrl;return t?n?r?i?void 0:"Validation failed: file upload 'url' can't be empty":"Validation failed: 'file' can't be empty":"Validation failed: file 'name' can't be empty":"Validation failed: file 'id' can't be empty"},r.prototype.parse=function(e){return i(this,void 0,void 0,(function(){return o(this,(function(t){return[2,{status:e.status,message:e.body?r.decoder.decode(e.body):"OK"}]}))}))},r.prototype.request=function(){return n(n({},e.prototype.request.call(this)),{origin:new URL(this.parameters.uploadUrl).origin})},Object.defineProperty(r.prototype,"path",{get:function(){var e=new URL(this.parameters.uploadUrl),t=e.pathname,n=e.search;return"".concat(t).concat(n)},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"body",{get:function(){return this.parameters.file},enumerable:!1,configurable:!0}),r}(ue),Xt=function(){function e(e){var t;if(this.parameters=e,this.file=null===(t=this.parameters.PubNubFile)||void 0===t?void 0:t.create(e.file),!this.file)throw new Error("File upload error: unable to create File object.")}return e.prototype.process=function(){return i(this,void 0,void 0,(function(){var e,t,n=this;return o(this,(function(r){return[2,this.generateFileUploadUrl().then((function(r){return e=r.name,t=r.id,n.uploadFile(r)})).then((function(){return n.publishFileMessage(t,e)})).catch((function(e){var t=$.create(e).toStatus(pe.PNPublishFileOperation);throw new v("File upload error.",t)}))]}))}))},e.prototype.generateFileUploadUrl=function(){return i(this,void 0,void 0,(function(){var e;return o(this,(function(t){return e=new Jt(n(n({},this.parameters),{name:this.file.name,keySet:this.parameters.keySet})),[2,this.parameters.sendRequest(e)]}))}))},e.prototype.uploadFile=function(e){return i(this,void 0,void 0,(function(){var t,n,r,i,s,a,u,c,p,l,h;return o(this,(function(o){switch(o.label){case 0:return t=this.parameters,n=t.cipherKey,r=t.PubNubFile,i=t.crypto,s=t.cryptography,a=e.id,u=e.name,c=e.url,p=e.formFields,this.parameters.PubNubFile.supportsEncryptFile?n||!i?[3,2]:(l=this,[4,i.encryptFile(this.file,r)]):[3,4];case 1:return l.file=o.sent(),[3,4];case 2:return n&&s?(h=this,[4,s.encryptFile(n,this.file,r)]):[3,4];case 3:h.file=o.sent(),o.label=4;case 4:return[2,this.parameters.sendRequest(new Yt({fileId:a,fileName:u,file:this.file,uploadUrl:c,formFields:p}))]}}))}))},e.prototype.publishFileMessage=function(e,t){return i(this,void 0,void 0,(function(){var r,i,s;return o(this,(function(o){switch(o.label){case 0:r={timetoken:"0"},i=this.parameters.fileUploadPublishRetryLimit,s=!1,o.label=1;case 1:return o.trys.push([1,3,,4]),[4,this.parameters.publishFile(n(n({},this.parameters),{fileId:e,fileName:t}))];case 2:return r=o.sent(),s=!0,[3,4];case 3:return o.sent(),i-=1,[3,4];case 4:if(!s&&i>0)return[3,1];o.label=5;case 5:if(s)return[2,{status:200,timetoken:r.timetoken,id:e,name:t}];throw new v("Publish failed. You may want to execute that operation manually using pubnub.publishFile",{error:!0,channel:this.parameters.channel,id:e,name:t})}}))}))},e}(),$t=function(e){function n(t){var n=e.call(this,{method:D.DELETE})||this;return n.parameters=t,n}return t(n,e),n.prototype.operation=function(){return pe.PNAccessManagerRevokeToken},n.prototype.validate=function(){return this.parameters.keySet.secretKey?this.parameters.token?void 0:"token can't be empty":"Missing Secret Key"},n.prototype.parse=function(e){return i(this,void 0,void 0,(function(){return o(this,(function(t){if(!this.deserializeResponse(e))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,{}]}))}))},Object.defineProperty(n.prototype,"path",{get:function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.token;return"/v3/pam/".concat(t,"/grant/").concat(H(n))},enumerable:!1,configurable:!0}),n}(ue),Zt=function(e){function r(t){var n,r,i,o,s=e.call(this,{method:D.POST})||this;return s.parameters=t,null!==(n=(i=s.parameters).resources)&&void 0!==n||(i.resources={}),null!==(r=(o=s.parameters).patterns)&&void 0!==r||(o.patterns={}),s}return t(r,e),r.prototype.operation=function(){return pe.PNAccessManagerGrantToken},r.prototype.validate=function(){var e,t,n,r,i,o,s=this.parameters,a=s.keySet,u=a.subscribeKey,c=a.publishKey,p=a.secretKey,l=s.resources,h=s.patterns;if(!u)return"Missing Subscribe Key";if(!c)return"Missing Publish Key";if(!p)return"Missing Secret Key";if(!l&&!h)return"Missing either Resources or Patterns";if(this.isVspPermissions(this.parameters)&&("channels"in(null!==(e=this.parameters.resources)&&void 0!==e?e:{})||"uuids"in(null!==(t=this.parameters.resources)&&void 0!==t?t:{})||"groups"in(null!==(n=this.parameters.resources)&&void 0!==n?n:{})||"channels"in(null!==(r=this.parameters.patterns)&&void 0!==r?r:{})||"uuids"in(null!==(i=this.parameters.patterns)&&void 0!==i?i:{})||"groups"in(null!==(o=this.parameters.patterns)&&void 0!==o?o:{})))return"Cannot mix `users`, `spaces` and `authorizedUserId` with `uuids`, `channels`, `groups` and `authorized_uuid`";var f=!0;return[this.parameters.resources,this.parameters.patterns].forEach((function(e){Object.keys(null!=e?e:{}).forEach((function(t){var n;e&&f&&Object.keys(null!==(n=e[t])&&void 0!==n?n:{}).length>0&&(f=!1)}))})),f?"Missing values for either Resources or Patterns":void 0},r.prototype.parse=function(e){return i(this,void 0,void 0,(function(){var t;return o(this,(function(n){if(!(t=this.deserializeResponse(e)))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,t.data.token]}))}))},Object.defineProperty(r.prototype,"path",{get:function(){return"/v3/pam/".concat(this.parameters.keySet.subscribeKey,"/grant")},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"body",{get:function(){var e=this,t=this.parameters,r=t.ttl,i=t.meta,o=n({},r||0===r?{ttl:r}:{}),s=this.isVspPermissions(this.parameters)?this.parameters.authorizedUserId:this.parameters.authorized_uuid,a={},u={},c={},p=function(e,t,n,r){r[n]||(r[n]={}),r[n][e]=t},l=this.parameters;return[l.resources,l.patterns].forEach((function(t,n){var r,i,o,s,a,l=0===n?u:c,h={},f={},d={};t&&("spaces"in t||"users"in t?(h=null!==(r=t.spaces)&&void 0!==r?r:{},d=null!==(i=t.users)&&void 0!==i?i:{}):("channels"in t||"uuids"in t||"groups"in t)&&(h=null!==(o=t.channels)&&void 0!==o?o:{},f=null!==(s=t.groups)&&void 0!==s?s:{},d=null!==(a=t.uuids)&&void 0!==a?a:{})),Object.keys(h).forEach((function(t){return p(t,e.extractPermissions(h[t]),"channels",l)})),Object.keys(f).forEach((function(t){return p(t,e.extractPermissions(f[t]),"groups",l)})),Object.keys(d).forEach((function(t){return p(t,e.extractPermissions(d[t]),"uuids",l)}))})),s&&(a.uuid="".concat(s)),i&&(a.meta=i),o.permissions=a,JSON.stringify(o)},enumerable:!1,configurable:!0}),r.prototype.extractPermissions=function(e){var t=0;return"join"in e&&e.join&&(t|=128),"update"in e&&e.update&&(t|=64),"get"in e&&e.get&&(t|=32),"delete"in e&&e.delete&&(t|=8),"manage"in e&&e.manage&&(t|=4),"write"in e&&e.write&&(t|=2),"read"in e&&e.read&&(t|=1),t},r.prototype.isVspPermissions=function(e){var t,n,r,i;return"authorizedUserId"in e||"spaces"in(null!==(t=e.resources)&&void 0!==t?t:{})||"users"in(null!==(n=e.resources)&&void 0!==n?n:{})||"spaces"in(null!==(r=e.patterns)&&void 0!==r?r:{})||"users"in(null!==(i=e.patterns)&&void 0!==i?i:{})},r}(ue),Qt=function(e){function r(t){var n,r,i,o,s,a,u,c,p,l,h,f,d,y,g,v,b,m,w,S,k=e.call(this)||this;return k.parameters=t,null!==(n=(h=k.parameters).channels)&&void 0!==n||(h.channels=[]),null!==(r=(f=k.parameters).channelGroups)&&void 0!==r||(f.channelGroups=[]),null!==(i=(d=k.parameters).uuids)&&void 0!==i||(d.uuids=[]),null!==(o=(y=k.parameters).read)&&void 0!==o||(y.read=false),null!==(s=(g=k.parameters).write)&&void 0!==s||(g.write=false),null!==(a=(v=k.parameters).delete)&&void 0!==a||(v.delete=false),null!==(u=(b=k.parameters).get)&&void 0!==u||(b.get=false),null!==(c=(m=k.parameters).update)&&void 0!==c||(m.update=false),null!==(p=(w=k.parameters).manage)&&void 0!==p||(w.manage=false),null!==(l=(S=k.parameters).join)&&void 0!==l||(S.join=false),k}return t(r,e),r.prototype.operation=function(){return pe.PNAccessManagerGrant},r.prototype.validate=function(){var e,t=this.parameters,n=t.keySet,r=n.subscribeKey,i=n.publishKey,o=n.secretKey,s=t.uuids,a=t.channels,u=t.channelGroups;return r?i?o?0!==(null==s?void 0:s.length)&&0===(null===(e=this.parameters.authKeys)||void 0===e?void 0:e.length)?"authKeys are required for grant request on uuids":!(null==s?void 0:s.length)||0===(null==a?void 0:a.length)&&0===(null==u?void 0:u.length)?void 0:"Both channel/channel group and uuid cannot be used in the same request":"Missing Secret Key":"Missing Publish Key":"Missing Subscribe Key"},r.prototype.parse=function(e){return i(this,void 0,void 0,(function(){var t;return o(this,(function(n){if(!(t=this.deserializeResponse(e)))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,t.payload]}))}))},Object.defineProperty(r.prototype,"path",{get:function(){return"/v2/auth/grant/sub-key/".concat(this.parameters.keySet.subscribeKey)},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"queryParameters",{get:function(){var e=this.parameters,t=e.channels,r=e.channelGroups,i=e.authKeys,o=e.uuids,s=e.read,a=e.write,u=e.manage,c=e.delete,p=e.get,l=e.join,h=e.update,f=e.ttl;return n(n(n(n(n(n({},t&&(null==t?void 0:t.length)>0?{channel:t.join(",")}:{}),r&&(null==r?void 0:r.length)>0?{"channel-group":r.join(",")}:{}),i&&(null==i?void 0:i.length)>0?{auth:i.join(",")}:{}),o&&(null==o?void 0:o.length)>0?{"target-uuid":o.join(",")}:{}),{r:s?"1":"0",w:a?"1":"0",m:u?"1":"0",d:c?"1":"0",g:p?"1":"0",j:l?"1":"0",u:h?"1":"0"}),f||0===f?{ttl:f}:{})},enumerable:!1,configurable:!0}),r}(ue),en=[],tn=function(e){function r(t){var n,r,i=e.call(this)||this;return i.parameters=t,null!==(n=(r=i.parameters).authKeys)&&void 0!==n||(r.authKeys=en),i}return t(r,e),r.prototype.operation=function(){return pe.PNAccessManagerAudit},r.prototype.validate=function(){if(!this.parameters.keySet.subscribeKey)return"Missing Subscribe Key"},r.prototype.parse=function(e){return i(this,void 0,void 0,(function(){var t;return o(this,(function(n){if(!(t=this.deserializeResponse(e)))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,t.payload]}))}))},Object.defineProperty(r.prototype,"path",{get:function(){return"/v2/auth/audit/sub-key/".concat(this.parameters.keySet.subscribeKey)},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"queryParameters",{get:function(){var e=this.parameters,t=e.channel,r=e.channelGroup,i=e.authKeys;return n(n(n({},t?{channel:t}:{}),r?{"channel-group":r}:{}),i&&i.length?{auth:i.join(",")}:{})},enumerable:!1,configurable:!0}),r}(ue),nn=function(){function e(){}return e.prototype.subscribe=function(){var e,t;this.pubnub.subscribe(n({channels:this.channelNames,channelGroups:this.groupNames},(null===(t=null===(e=this.options)||void 0===e?void 0:e.cursor)||void 0===t?void 0:t.timetoken)&&{timetoken:this.options.cursor.timetoken}))},e.prototype.unsubscribe=function(){this.pubnub.unsubscribe({channels:this.channelNames.filter((function(e){return!e.endsWith("-pnpres")})),channelGroups:this.groupNames.filter((function(e){return!e.endsWith("-pnpres")}))})},Object.defineProperty(e.prototype,"onMessage",{set:function(e){this.listener.message=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"onPresence",{set:function(e){this.listener.presence=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"onSignal",{set:function(e){this.listener.signal=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"onObjects",{set:function(e){this.listener.objects=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"onMessageAction",{set:function(e){this.listener.messageAction=e},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"onFile",{set:function(e){this.listener.file=e},enumerable:!1,configurable:!0}),e.prototype.addListener=function(e){this.eventEmitter.addListener(e,this.channelNames.filter((function(e){return!e.endsWith("-pnpres")})),this.groupNames.filter((function(e){return!e.endsWith("-pnpres")})))},e.prototype.removeListener=function(e){this.eventEmitter.removeListener(e,this.channelNames,this.groupNames)},Object.defineProperty(e.prototype,"channels",{get:function(){return this.channelNames.slice(0)},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"channelGroups",{get:function(){return this.groupNames.slice(0)},enumerable:!1,configurable:!0}),e}(),rn=function(e){function n(t){var n=t.channels,r=void 0===n?[]:n,i=t.channelGroups,o=void 0===i?[]:i,s=t.subscriptionOptions,c=t.eventEmitter,p=t.pubnub,l=e.call(this)||this;return l.channelNames=[],l.groupNames=[],l.subscriptionList=[],l.options=s,l.eventEmitter=c,l.pubnub=p,r.forEach((function(e){var t=l.pubnub.channel(e).subscription(l.options);l.channelNames=u(u([],a(l.channelNames),!1),a(t.channels),!1),l.subscriptionList.push(t)})),o.forEach((function(e){var t=l.pubnub.channelGroup(e).subscription(l.options);l.groupNames=u(u([],a(l.groupNames),!1),a(t.channelGroups),!1),l.subscriptionList.push(t)})),l.listener={},c.addListener(l.listener,l.channelNames.filter((function(e){return!e.endsWith("-pnpres")})),l.groupNames.filter((function(e){return!e.endsWith("-pnpres")}))),l}return t(n,e),n.prototype.addSubscription=function(e){this.subscriptionList.push(e),this.channelNames=u(u([],a(this.channelNames),!1),a(e.channels),!1),this.groupNames=u(u([],a(this.groupNames),!1),a(e.channelGroups),!1)},n.prototype.removeSubscription=function(e){var t=e.channels,n=e.channelGroups;this.channelNames=this.channelNames.filter((function(e){return!t.includes(e)})),this.groupNames=this.groupNames.filter((function(e){return!n.includes(e)})),this.subscriptionList=this.subscriptionList.filter((function(t){return t!==e}))},n.prototype.addSubscriptionSet=function(e){this.subscriptionList=u(u([],a(this.subscriptionList),!1),a(e.subscriptions),!1),this.channelNames=u(u([],a(this.channelNames),!1),a(e.channels),!1),this.groupNames=u(u([],a(this.groupNames),!1),a(e.channelGroups),!1)},n.prototype.removeSubscriptionSet=function(e){var t=e.channels,n=e.channelGroups;this.channelNames=this.channelNames.filter((function(e){return!t.includes(e)})),this.groupNames=this.groupNames.filter((function(e){return!n.includes(e)})),this.subscriptionList=this.subscriptionList.filter((function(t){return!e.subscriptions.includes(t)}))},Object.defineProperty(n.prototype,"subscriptions",{get:function(){return this.subscriptionList.slice(0)},enumerable:!1,configurable:!0}),n}(nn),on=function(e){function r(t){var n=t.channels,r=t.channelGroups,i=t.subscriptionOptions,o=t.eventEmitter,s=t.pubnub,a=e.call(this)||this;return a.channelNames=[],a.groupNames=[],a.channelNames=n,a.groupNames=r,a.options=i,a.pubnub=s,a.eventEmitter=o,a.listener={},o.addListener(a.listener,a.channelNames.filter((function(e){return!e.endsWith("-pnpres")})),a.groupNames.filter((function(e){return!e.endsWith("-pnpres")}))),a}return t(r,e),r.prototype.addSubscription=function(e){return new rn({channels:u(u([],a(this.channelNames),!1),a(e.channels),!1),channelGroups:u(u([],a(this.groupNames),!1),a(e.channelGroups),!1),subscriptionOptions:n(n({},this.options),null==e?void 0:e.options),eventEmitter:this.eventEmitter,pubnub:this.pubnub})},r}(nn),sn=function(){function e(e,t,n){this.id=e,this.eventEmitter=t,this.pubnub=n}return e.prototype.subscription=function(e){return new on({channels:[this.id],channelGroups:[],subscriptionOptions:e,eventEmitter:this.eventEmitter,pubnub:this.pubnub})},e}(),an=function(){function e(e,t,n){this.eventEmitter=t,this.pubnub=n,this.name=e}return e.prototype.subscription=function(e){return new on({channels:[],channelGroups:(null==e?void 0:e.receivePresenceEvents)?[this.name,"".concat(this.name,"-pnpres")]:[this.name],subscriptionOptions:e,eventEmitter:this.eventEmitter,pubnub:this.pubnub})},e}(),un=function(){function e(e,t,n){this.id=e,this.eventEmitter=t,this.pubnub=n}return e.prototype.subscription=function(e){return new on({channels:[this.id],channelGroups:[],subscriptionOptions:e,eventEmitter:this.eventEmitter,pubnub:this.pubnub})},e}(),cn=function(){function e(e,t,n){this.eventEmitter=t,this.pubnub=n,this.name=e}return e.prototype.subscription=function(e){return new on({channels:(null==e?void 0:e.receivePresenceEvents)?[this.name,"".concat(this.name,"-pnpres")]:[this.name],channelGroups:[],subscriptionOptions:e,eventEmitter:this.eventEmitter,pubnub:this.pubnub})},e}(),pn=function(e){function n(t){var n=e.call(this)||this;return n.parameters=t,n}return t(n,e),n.prototype.operation=function(){return pe.PNRemoveChannelsFromGroupOperation},n.prototype.validate=function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.channels,r=e.channelGroup;return t?r?n?void 0:"Missing channels":"Missing Channel Group":"Missing Subscribe Key"},n.prototype.parse=function(e){return i(this,void 0,void 0,(function(){return o(this,(function(t){if(!this.deserializeResponse(e))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,{}]}))}))},Object.defineProperty(n.prototype,"path",{get:function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.channelGroup;return"/v1/channel-registration/sub-key/".concat(t,"/channel-group/").concat(H(n))},enumerable:!1,configurable:!0}),Object.defineProperty(n.prototype,"queryParameters",{get:function(){return{remove:this.parameters.channels.join(",")}},enumerable:!1,configurable:!0}),n}(ue),ln=function(e){function n(t){var n=e.call(this)||this;return n.parameters=t,n}return t(n,e),n.prototype.operation=function(){return pe.PNAddChannelsToGroupOperation},n.prototype.validate=function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.channels,r=e.channelGroup;return t?r?n?void 0:"Missing channels":"Missing Channel Group":"Missing Subscribe Key"},n.prototype.parse=function(e){return i(this,void 0,void 0,(function(){return o(this,(function(t){if(!this.deserializeResponse(e))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,{}]}))}))},Object.defineProperty(n.prototype,"path",{get:function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.channelGroup;return"/v1/channel-registration/sub-key/".concat(t,"/channel-group/").concat(H(n))},enumerable:!1,configurable:!0}),Object.defineProperty(n.prototype,"queryParameters",{get:function(){return{add:this.parameters.channels.join(",")}},enumerable:!1,configurable:!0}),n}(ue),hn=function(e){function n(t){var n=e.call(this)||this;return n.parameters=t,n}return t(n,e),n.prototype.operation=function(){return pe.PNChannelsForGroupOperation},n.prototype.validate=function(){return this.parameters.keySet.subscribeKey?this.parameters.channelGroup?void 0:"Missing Channel Group":"Missing Subscribe Key"},n.prototype.parse=function(e){return i(this,void 0,void 0,(function(){var t;return o(this,(function(n){if(!(t=this.deserializeResponse(e)))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,{channels:t.payload.channels}]}))}))},Object.defineProperty(n.prototype,"path",{get:function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.channelGroup;return"/v1/channel-registration/sub-key/".concat(t,"/channel-group/").concat(H(n))},enumerable:!1,configurable:!0}),n}(ue),fn=function(e){function n(t){var n=e.call(this)||this;return n.parameters=t,n}return t(n,e),n.prototype.operation=function(){return pe.PNRemoveGroupOperation},n.prototype.validate=function(){return this.parameters.keySet.subscribeKey?this.parameters.channelGroup?void 0:"Missing Channel Group":"Missing Subscribe Key"},n.prototype.parse=function(e){return i(this,void 0,void 0,(function(){return o(this,(function(t){if(!this.deserializeResponse(e))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,{}]}))}))},Object.defineProperty(n.prototype,"path",{get:function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.channelGroup;return"/v1/channel-registration/sub-key/".concat(t,"/channel-group/").concat(H(n),"/remove")},enumerable:!1,configurable:!0}),n}(ue),dn=function(e){function n(t){var n=e.call(this)||this;return n.parameters=t,n}return t(n,e),n.prototype.operation=function(){return pe.PNChannelGroupsOperation},n.prototype.validate=function(){if(!this.parameters.keySet.subscribeKey)return"Missing Subscribe Key"},n.prototype.parse=function(e){return i(this,void 0,void 0,(function(){var t;return o(this,(function(n){if(!(t=this.deserializeResponse(e)))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,{groups:t.payload.groups}]}))}))},Object.defineProperty(n.prototype,"path",{get:function(){return"/v1/channel-registration/sub-key/".concat(this.parameters.keySet.subscribeKey,"/channel-group")},enumerable:!1,configurable:!0}),n}(ue),yn=function(){function e(e,t){this.keySet=e,this.sendRequest=t}return e.prototype.listChannels=function(e,t){return i(this,void 0,void 0,(function(){var r;return o(this,(function(i){return r=new hn(n(n({},e),{keySet:this.keySet})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},e.prototype.listGroups=function(e){return i(this,void 0,void 0,(function(){var t;return o(this,(function(n){return t=new dn({keySet:this.keySet}),e?[2,this.sendRequest(t,e)]:[2,this.sendRequest(t)]}))}))},e.prototype.addChannels=function(e,t){return i(this,void 0,void 0,(function(){var r;return o(this,(function(i){return r=new ln(n(n({},e),{keySet:this.keySet})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},e.prototype.removeChannels=function(e,t){return i(this,void 0,void 0,(function(){var r;return o(this,(function(i){return r=new pn(n(n({},e),{keySet:this.keySet})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},e.prototype.deleteGroup=function(e,t){return i(this,void 0,void 0,(function(){var r;return o(this,(function(i){return r=new fn(n(n({},e),{keySet:this.keySet})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},e}(),gn=function(e){function r(t){var n,r,i=e.call(this)||this;return i.parameters=t,"apns2"===i.parameters.pushGateway&&(null!==(n=(r=i.parameters).environment)&&void 0!==n||(r.environment="development")),i.parameters.count&&i.parameters.count>1e3&&(i.parameters.count=1e3),i}return t(r,e),r.prototype.operation=function(){throw Error("Should be implemented in subclass.")},r.prototype.validate=function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.action,r=e.device,i=e.pushGateway;return t?r?"add"!==n&&"remove"!==n||"channels"in this.parameters&&0!==this.parameters.channels.length?i?"apns2"!==this.parameters.pushGateway||this.parameters.topic?void 0:"Missing APNS2 topic":"Missing GW Type (pushGateway: gcm or apns2)":"Missing Channels":"Missing Device ID (device)":"Missing Subscribe Key"},r.prototype.parse=function(e){return i(this,void 0,void 0,(function(){return o(this,(function(e){throw Error("Should be implemented in subclass.")}))}))},Object.defineProperty(r.prototype,"path",{get:function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.action,r=e.device,i="apns2"===e.pushGateway?"/v2/push/sub-key/".concat(t,"/devices-apns2/").concat(r):"/v1/push/sub-key/".concat(t,"/devices/").concat(r);return"remove-device"===n&&(i="".concat(i,"/remove")),i},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"queryParameters",{get:function(){var e=this.parameters,t=e.start,r=e.count,i=n(n({type:this.parameters.pushGateway},t?{start:t}:{}),r&&r>0?{count:r}:{});if("channels"in this.parameters&&(i[this.parameters.action]=this.parameters.channels.join(",")),"apns2"===this.parameters.pushGateway){var o=this.parameters,s=o.environment,a=o.topic;i=n(n({},i),{environment:s,topic:a})}return i},enumerable:!1,configurable:!0}),r}(ue),vn=function(e){function r(t){return e.call(this,n(n({},t),{action:"remove"}))||this}return t(r,e),r.prototype.operation=function(){return pe.PNRemovePushNotificationEnabledChannelsOperation},r.prototype.parse=function(e){return i(this,void 0,void 0,(function(){return o(this,(function(t){if(!this.deserializeResponse(e))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,{}]}))}))},r}(gn),bn=function(e){function r(t){return e.call(this,n(n({},t),{action:"list"}))||this}return t(r,e),r.prototype.operation=function(){return pe.PNPushNotificationEnabledChannelsOperation},r.prototype.parse=function(e){return i(this,void 0,void 0,(function(){var t;return o(this,(function(n){if(!(t=this.deserializeResponse(e)))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,{channels:t}]}))}))},r}(gn),mn=function(e){function r(t){return e.call(this,n(n({},t),{action:"add"}))||this}return t(r,e),r.prototype.operation=function(){return pe.PNAddPushNotificationEnabledChannelsOperation},r.prototype.parse=function(e){return i(this,void 0,void 0,(function(){return o(this,(function(t){if(!this.deserializeResponse(e))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,{}]}))}))},r}(gn),wn=function(e){function r(t){return e.call(this,n(n({},t),{action:"remove-device"}))||this}return t(r,e),r.prototype.operation=function(){return pe.PNRemoveAllPushNotificationsOperation},r.prototype.parse=function(e){return i(this,void 0,void 0,(function(){return o(this,(function(t){if(!this.deserializeResponse(e))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,{}]}))}))},r}(gn),Sn=function(){function e(e,t){this.keySet=e,this.sendRequest=t}return e.prototype.listChannels=function(e,t){return i(this,void 0,void 0,(function(){var r;return o(this,(function(i){return r=new bn(n(n({},e),{keySet:this.keySet})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},e.prototype.addChannels=function(e,t){return i(this,void 0,void 0,(function(){var r;return o(this,(function(i){return r=new mn(n(n({},e),{keySet:this.keySet})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},e.prototype.removeChannels=function(e,t){return i(this,void 0,void 0,(function(){var r;return o(this,(function(i){return r=new vn(n(n({},e),{keySet:this.keySet})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},e.prototype.deleteDevice=function(e,t){return i(this,void 0,void 0,(function(){var r;return o(this,(function(i){return r=new wn(n(n({},e),{keySet:this.keySet})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},e}(),kn=function(e){function r(t){var n,r,i,o,s,a,u=e.call(this)||this;return u.parameters=t,null!==(n=t.include)&&void 0!==n||(t.include={}),null!==(r=(s=t.include).customFields)&&void 0!==r||(s.customFields=false),null!==(i=(a=t.include).totalCount)&&void 0!==i||(a.totalCount=false),null!==(o=t.limit)&&void 0!==o||(t.limit=100),u}return t(r,e),r.prototype.operation=function(){return pe.PNGetAllChannelMetadataOperation},r.prototype.parse=function(e){return i(this,void 0,void 0,(function(){var t;return o(this,(function(n){if(!(t=this.deserializeResponse(e)))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,t]}))}))},Object.defineProperty(r.prototype,"path",{get:function(){return"/v2/objects/".concat(this.parameters.keySet.subscribeKey,"/channels")},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"queryParameters",{get:function(){var e=this.parameters,t=e.include,r=e.page,i=e.filter,o=e.sort,s=e.limit,c=Object.entries(null!=o?o:{}).map((function(e){var t=a(e,2),n=t[0],r=t[1];return null!==r?"".concat(n,":").concat(r):n}));return n(n(n(n(n({include:u(["status","type"],a(t.customFields?["custom"]:[]),!1).join(","),count:"".concat(t.totalCount)},i?{filter:i}:{}),(null==r?void 0:r.next)?{start:r.next}:{}),(null==r?void 0:r.prev)?{end:r.prev}:{}),s?{limit:s}:{}),c.length?{sort:c}:{})},enumerable:!1,configurable:!0}),r}(ue),Pn=function(e){function n(t){var n=e.call(this,{method:D.DELETE})||this;return n.parameters=t,n}return t(n,e),n.prototype.operation=function(){return pe.PNRemoveChannelMetadataOperation},n.prototype.validate=function(){if(!this.parameters.channel)return"Channel cannot be empty"},n.prototype.parse=function(e){return i(this,void 0,void 0,(function(){var t;return o(this,(function(n){if(!(t=this.deserializeResponse(e)))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,t]}))}))},Object.defineProperty(n.prototype,"path",{get:function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.channel;return"/v2/objects/".concat(t,"/channels/").concat(H(n))},enumerable:!1,configurable:!0}),n}(ue),En=function(e){function r(t){var n,r,i,o,s,a,u,c,p,l,h,f,d,y,g,v,b=e.call(this)||this;return b.parameters=t,null!==(n=t.include)&&void 0!==n||(t.include={}),null!==(r=(l=t.include).customFields)&&void 0!==r||(l.customFields=false),null!==(i=(h=t.include).totalCount)&&void 0!==i||(h.totalCount=false),null!==(o=(f=t.include).statusField)&&void 0!==o||(f.statusField=false),null!==(s=(d=t.include).channelFields)&&void 0!==s||(d.channelFields=false),null!==(a=(y=t.include).customChannelFields)&&void 0!==a||(y.customChannelFields=false),null!==(u=(g=t.include).channelStatusField)&&void 0!==u||(g.channelStatusField=false),null!==(c=(v=t.include).channelTypeField)&&void 0!==c||(v.channelTypeField=false),null!==(p=t.limit)&&void 0!==p||(t.limit=100),b.parameters.userId&&(b.parameters.uuid=b.parameters.userId),b}return t(r,e),r.prototype.operation=function(){return pe.PNGetMembershipsOperation},r.prototype.validate=function(){if(!this.parameters.uuid)return"'uuid' cannot be empty"},r.prototype.parse=function(e){return i(this,void 0,void 0,(function(){var t;return o(this,(function(n){if(!(t=this.deserializeResponse(e)))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,t]}))}))},Object.defineProperty(r.prototype,"path",{get:function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.uuid;return"/v2/objects/".concat(t,"/uuids/").concat(H(n),"/channels")},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"queryParameters",{get:function(){var e=this.parameters,t=e.include,r=e.page,i=e.filter,o=e.sort,s=e.limit,u=Object.entries(null!=o?o:{}).map((function(e){var t=a(e,2),n=t[0],r=t[1];return null!==r?"".concat(n,":").concat(r):n})),c=[];return t.statusField&&c.push("status"),t.customFields&&c.push("custom"),t.channelFields&&c.push("channel"),t.channelStatusField&&c.push("channel.status"),t.channelTypeField&&c.push("channel.type"),t.customChannelFields&&c.push("channel.custom"),n(n(n(n(n(n({count:"".concat(t.totalCount)},c.length>0?{include:c.join(",")}:{}),i?{filter:i}:{}),(null==r?void 0:r.next)?{start:r.next}:{}),(null==r?void 0:r.prev)?{end:r.prev}:{}),s?{limit:s}:{}),u.length?{sort:u}:{})},enumerable:!1,configurable:!0}),r}(ue),On=function(e){function r(t){var n,r,i,o,s,a,u,c,p,l,h=e.call(this,{method:D.PATCH})||this;return h.parameters=t,null!==(n=t.include)&&void 0!==n||(t.include={}),null!==(r=(u=t.include).customFields)&&void 0!==r||(u.customFields=false),null!==(i=(c=t.include).totalCount)&&void 0!==i||(c.totalCount=false),null!==(o=(p=t.include).channelFields)&&void 0!==o||(p.channelFields=false),null!==(s=(l=t.include).customChannelFields)&&void 0!==s||(l.customChannelFields=false),null!==(a=t.limit)&&void 0!==a||(t.limit=100),h.parameters.userId&&(h.parameters.uuid=h.parameters.userId),h}return t(r,e),r.prototype.operation=function(){return pe.PNSetMembershipsOperation},r.prototype.validate=function(){var e=this.parameters,t=e.uuid,n=e.channels;return t?n&&0!==n.length?void 0:"Channels cannot be empty":"'uuid' cannot be empty"},r.prototype.parse=function(e){return i(this,void 0,void 0,(function(){var t;return o(this,(function(n){if(!(t=this.deserializeResponse(e)))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,t]}))}))},Object.defineProperty(r.prototype,"path",{get:function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.uuid;return"/v2/objects/".concat(t,"/uuids/").concat(H(n),"/channels")},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"queryParameters",{get:function(){var e=this.parameters,t=e.include,r=e.page,i=e.filter,o=e.sort,s=e.limit,u=Object.entries(null!=o?o:{}).map((function(e){var t=a(e,2),n=t[0],r=t[1];return null!==r?"".concat(n,":").concat(r):n})),c=["channel.status","channel.type","status"];return t.customFields&&c.push("custom"),t.channelFields&&c.push("channel"),t.customChannelFields&&c.push("channel.custom"),n(n(n(n(n(n({count:"".concat(t.totalCount)},c.length>0?{include:c.join(",")}:{}),i?{filter:i}:{}),(null==r?void 0:r.next)?{start:r.next}:{}),(null==r?void 0:r.prev)?{end:r.prev}:{}),s?{limit:s}:{}),u.length?{sort:u}:{})},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"body",{get:function(){var e,t=this.parameters,n=t.channels,r=t.type;return JSON.stringify(((e={})["".concat(r)]=n.map((function(e){return"string"==typeof e?{channel:{id:e}}:{channel:{id:e.id},status:e.status,custom:e.custom}})),e))},enumerable:!1,configurable:!0}),r}(ue),Cn=function(e){function r(t){var n,r,i,o,s,a,u=e.call(this)||this;return u.parameters=t,null!==(n=t.include)&&void 0!==n||(t.include={}),null!==(r=(s=t.include).customFields)&&void 0!==r||(s.customFields=false),null!==(i=(a=t.include).totalCount)&&void 0!==i||(a.totalCount=false),null!==(o=t.limit)&&void 0!==o||(t.limit=100),u}return t(r,e),r.prototype.operation=function(){return pe.PNGetAllUUIDMetadataOperation},r.prototype.parse=function(e){return i(this,void 0,void 0,(function(){var t;return o(this,(function(n){if(!(t=this.deserializeResponse(e)))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,t]}))}))},Object.defineProperty(r.prototype,"path",{get:function(){return"/v2/objects/".concat(this.parameters.keySet.subscribeKey,"/uuids")},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"queryParameters",{get:function(){var e=this.parameters,t=e.include,r=e.page,i=e.filter,o=e.sort,s=e.limit,c=Object.entries(null!=o?o:{}).map((function(e){var t=a(e,2),n=t[0],r=t[1];return null!==r?"".concat(n,":").concat(r):n}));return n(n(n(n(n({include:u(["status","type"],a(t.customFields?["custom"]:[]),!1).join(","),count:"".concat(t.totalCount)},i?{filter:i}:{}),(null==r?void 0:r.next)?{start:r.next}:{}),(null==r?void 0:r.prev)?{end:r.prev}:{}),s?{limit:s}:{}),c.length?{sort:c}:{})},enumerable:!1,configurable:!0}),r}(ue),_n=function(e){function n(t){var n,r,i,o=e.call(this)||this;return o.parameters=t,null!==(n=t.include)&&void 0!==n||(t.include={}),null!==(r=(i=t.include).customFields)&&void 0!==r||(i.customFields=true),o}return t(n,e),n.prototype.operation=function(){return pe.PNGetChannelMetadataOperation},n.prototype.validate=function(){if(!this.parameters.channel)return"Channel cannot be empty"},n.prototype.parse=function(e){return i(this,void 0,void 0,(function(){var t;return o(this,(function(n){if(!(t=this.deserializeResponse(e)))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,t]}))}))},Object.defineProperty(n.prototype,"path",{get:function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.channel;return"/v2/objects/".concat(t,"/channels/").concat(H(n))},enumerable:!1,configurable:!0}),Object.defineProperty(n.prototype,"queryParameters",{get:function(){return{include:u(["status","type"],a(this.parameters.include.customFields?["custom"]:[]),!1).join(",")}},enumerable:!1,configurable:!0}),n}(ue),Nn=function(e){function n(t){var n,r,i,o=e.call(this,{method:D.PATCH})||this;return o.parameters=t,null!==(n=t.include)&&void 0!==n||(t.include={}),null!==(r=(i=t.include).customFields)&&void 0!==r||(i.customFields=true),o}return t(n,e),n.prototype.operation=function(){return pe.PNSetChannelMetadataOperation},n.prototype.validate=function(){return this.parameters.channel?this.parameters.data?void 0:"Data cannot be empty":"Channel cannot be empty"},n.prototype.parse=function(e){return i(this,void 0,void 0,(function(){var t;return o(this,(function(n){if(!(t=this.deserializeResponse(e)))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,t]}))}))},Object.defineProperty(n.prototype,"path",{get:function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.channel;return"/v2/objects/".concat(t,"/channels/").concat(H(n))},enumerable:!1,configurable:!0}),Object.defineProperty(n.prototype,"queryParameters",{get:function(){return{include:u(["status","type"],a(this.parameters.include.customFields?["custom"]:[]),!1).join(",")}},enumerable:!1,configurable:!0}),Object.defineProperty(n.prototype,"body",{get:function(){return JSON.stringify(this.parameters.data)},enumerable:!1,configurable:!0}),n}(ue),Mn=function(e){function n(t){var n=e.call(this,{method:D.DELETE})||this;return n.parameters=t,n.parameters.userId&&(n.parameters.uuid=n.parameters.userId),n}return t(n,e),n.prototype.operation=function(){return pe.PNRemoveUUIDMetadataOperation},n.prototype.validate=function(){if(!this.parameters.uuid)return"'uuid' cannot be empty"},n.prototype.parse=function(e){return i(this,void 0,void 0,(function(){var t;return o(this,(function(n){if(!(t=this.deserializeResponse(e)))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,t]}))}))},Object.defineProperty(n.prototype,"path",{get:function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.uuid;return"/v2/objects/".concat(t,"/uuids/").concat(H(n))},enumerable:!1,configurable:!0}),n}(ue),An=function(e){function r(t){var n,r,i,o,s,a,u,c,p,l,h,f,d,y,g,v,b=e.call(this)||this;return b.parameters=t,null!==(n=t.include)&&void 0!==n||(t.include={}),null!==(r=(l=t.include).customFields)&&void 0!==r||(l.customFields=false),null!==(i=(h=t.include).totalCount)&&void 0!==i||(h.totalCount=false),null!==(o=(f=t.include).statusField)&&void 0!==o||(f.statusField=false),null!==(s=(d=t.include).UUIDFields)&&void 0!==s||(d.UUIDFields=false),null!==(a=(y=t.include).customUUIDFields)&&void 0!==a||(y.customUUIDFields=false),null!==(u=(g=t.include).UUIDStatusField)&&void 0!==u||(g.UUIDStatusField=false),null!==(c=(v=t.include).UUIDTypeField)&&void 0!==c||(v.UUIDTypeField=false),null!==(p=t.limit)&&void 0!==p||(t.limit=100),b}return t(r,e),r.prototype.operation=function(){return pe.PNSetMembersOperation},r.prototype.validate=function(){if(!this.parameters.channel)return"Channel cannot be empty"},r.prototype.parse=function(e){return i(this,void 0,void 0,(function(){var t;return o(this,(function(n){if(!(t=this.deserializeResponse(e)))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,t]}))}))},Object.defineProperty(r.prototype,"path",{get:function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.channel;return"/v2/objects/".concat(t,"/channels/").concat(H(n),"/uuids")},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"queryParameters",{get:function(){var e=this.parameters,t=e.include,r=e.page,i=e.filter,o=e.sort,s=e.limit,u=Object.entries(null!=o?o:{}).map((function(e){var t=a(e,2),n=t[0],r=t[1];return null!==r?"".concat(n,":").concat(r):n})),c=[];return t.statusField&&c.push("status"),t.customFields&&c.push("custom"),t.UUIDFields&&c.push("uuid"),t.UUIDStatusField&&c.push("uuid.status"),t.UUIDTypeField&&c.push("uuid.type"),t.customUUIDFields&&c.push("uuid.custom"),n(n(n(n(n(n({count:"".concat(t.totalCount)},c.length>0?{include:c.join(",")}:{}),i?{filter:i}:{}),(null==r?void 0:r.next)?{start:r.next}:{}),(null==r?void 0:r.prev)?{end:r.prev}:{}),s?{limit:s}:{}),u.length?{sort:u}:{})},enumerable:!1,configurable:!0}),r}(ue),Rn=function(e){function r(t){var n,r,i,o,s,a,u,c,p,l,h=e.call(this,{method:D.PATCH})||this;return h.parameters=t,null!==(n=t.include)&&void 0!==n||(t.include={}),null!==(r=(u=t.include).customFields)&&void 0!==r||(u.customFields=false),null!==(i=(c=t.include).totalCount)&&void 0!==i||(c.totalCount=false),null!==(o=(p=t.include).UUIDFields)&&void 0!==o||(p.UUIDFields=false),null!==(s=(l=t.include).customUUIDFields)&&void 0!==s||(l.customUUIDFields=false),null!==(a=t.limit)&&void 0!==a||(t.limit=100),h}return t(r,e),r.prototype.operation=function(){return pe.PNSetMembersOperation},r.prototype.validate=function(){var e=this.parameters,t=e.channel,n=e.uuids;return t?n&&0!==n.length?void 0:"UUIDs cannot be empty":"Channel cannot be empty"},r.prototype.parse=function(e){return i(this,void 0,void 0,(function(){var t;return o(this,(function(n){if(!(t=this.deserializeResponse(e)))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,t]}))}))},Object.defineProperty(r.prototype,"path",{get:function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.channel;return"/v2/objects/".concat(t,"/channels/").concat(H(n),"/uuids")},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"queryParameters",{get:function(){var e=this.parameters,t=e.include,r=e.page,i=e.filter,o=e.sort,s=e.limit,u=Object.entries(null!=o?o:{}).map((function(e){var t=a(e,2),n=t[0],r=t[1];return null!==r?"".concat(n,":").concat(r):n})),c=["uuid.status","uuid.type","type"];return t.customFields&&c.push("custom"),t.UUIDFields&&c.push("uuid"),t.customUUIDFields&&c.push("uuid.custom"),n(n(n(n(n(n({count:"".concat(t.totalCount)},c.length>0?{include:c.join(",")}:{}),i?{filter:i}:{}),(null==r?void 0:r.next)?{start:r.next}:{}),(null==r?void 0:r.prev)?{end:r.prev}:{}),s?{limit:s}:{}),u.length?{sort:u}:{})},enumerable:!1,configurable:!0}),Object.defineProperty(r.prototype,"body",{get:function(){var e,t=this.parameters,n=t.uuids,r=t.type;return JSON.stringify(((e={})["".concat(r)]=n.map((function(e){return"string"==typeof e?{uuid:{id:e}}:{uuid:{id:e.id},status:e.status,custom:e.custom}})),e))},enumerable:!1,configurable:!0}),r}(ue),jn=function(e){function n(t){var n,r,i,o=e.call(this)||this;return o.parameters=t,null!==(n=t.include)&&void 0!==n||(t.include={}),null!==(r=(i=t.include).customFields)&&void 0!==r||(i.customFields=true),o.parameters.userId&&(o.parameters.uuid=o.parameters.userId),o}return t(n,e),n.prototype.operation=function(){return pe.PNGetUUIDMetadataOperation},n.prototype.validate=function(){if(!this.parameters.uuid)return"'uuid' cannot be empty"},n.prototype.parse=function(e){return i(this,void 0,void 0,(function(){var t;return o(this,(function(n){if(!(t=this.deserializeResponse(e)))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,t]}))}))},Object.defineProperty(n.prototype,"path",{get:function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.uuid;return"/v2/objects/".concat(t,"/uuids/").concat(H(n))},enumerable:!1,configurable:!0}),Object.defineProperty(n.prototype,"queryParameters",{get:function(){var e=this.parameters,t=e.uuid;return e.include,{uuid:t,include:u(["status","type"],a(this.parameters.include.customFields?["custom"]:[]),!1).join(",")}},enumerable:!1,configurable:!0}),n}(ue),In=function(){function e(e,t){this.configuration=e,this.sendRequest=t,this.keySet=e.keySet}return e.prototype.getAllUUIDMetadata=function(e,t){return i(this,void 0,void 0,(function(){return o(this,(function(n){return[2,this._getAllUUIDMetadata(e,t)]}))}))},e.prototype._getAllUUIDMetadata=function(e,t){return i(this,void 0,void 0,(function(){var r;return o(this,(function(i){return null!=t||(t="function"==typeof e?e:void 0),r=new Cn(n(n({},e&&"function"!=typeof e?e:{}),{keySet:this.keySet})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},e.prototype.getUUIDMetadata=function(e,t){return i(this,void 0,void 0,(function(){return o(this,(function(n){return[2,this._getUUIDMetadata(e,t)]}))}))},e.prototype._getUUIDMetadata=function(e,t){return i(this,void 0,void 0,(function(){var r,i,s;return o(this,(function(o){return null!=t||(t="function"==typeof e?e:void 0),(r=e&&"function"!=typeof e?e:{}).userId&&(r.uuid=r.userId),null!==(s=r.uuid)&&void 0!==s||(r.uuid=this.configuration.userId),i=new jn(n(n({},r),{keySet:this.keySet})),t?[2,this.sendRequest(i,t)]:[2,this.sendRequest(i)]}))}))},e.prototype.setUUIDMetadata=function(e,t){return i(this,void 0,void 0,(function(){return o(this,(function(n){return[2,this._setUUIDMetadata(e,t)]}))}))},e.prototype._setUUIDMetadata=function(e,t){return i(this,void 0,void 0,(function(){var r,i;return o(this,(function(o){return e.userId&&(e.uuid=e.userId),null!==(i=e.uuid)&&void 0!==i||(e.uuid=this.configuration.userId),r=new jn(n(n({},e),{keySet:this.keySet})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},e.prototype.removeUUIDMetadata=function(e,t){return i(this,void 0,void 0,(function(){return o(this,(function(n){return[2,this._removeUUIDMetadata(e,t)]}))}))},e.prototype._removeUUIDMetadata=function(e,t){return i(this,void 0,void 0,(function(){var r,i,s;return o(this,(function(o){return null!=t||(t="function"==typeof e?e:void 0),(r=e&&"function"!=typeof e?e:{}).userId&&(r.uuid=r.userId),null!==(s=r.uuid)&&void 0!==s||(r.uuid=this.configuration.userId),i=new Mn(n(n({},r),{keySet:this.keySet})),t?[2,this.sendRequest(i,t)]:[2,this.sendRequest(i)]}))}))},e.prototype.getAllChannelMetadata=function(e,t){return i(this,void 0,void 0,(function(){return o(this,(function(n){return[2,this._getAllChannelMetadata(e,t)]}))}))},e.prototype._getAllChannelMetadata=function(e,t){return i(this,void 0,void 0,(function(){var r;return o(this,(function(i){return null!=t||(t="function"==typeof e?e:void 0),r=new kn(n(n({},e&&"function"!=typeof e?e:{}),{keySet:this.keySet})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},e.prototype.getChannelMetadata=function(e,t){return i(this,void 0,void 0,(function(){return o(this,(function(n){return[2,this._getChannelMetadata(e,t)]}))}))},e.prototype._getChannelMetadata=function(e,t){return i(this,void 0,void 0,(function(){var r;return o(this,(function(i){return r=new _n(n(n({},e),{keySet:this.keySet})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},e.prototype.setChannelMetadata=function(e,t){return i(this,void 0,void 0,(function(){return o(this,(function(n){return[2,this._setChannelMetadata(e,t)]}))}))},e.prototype._setChannelMetadata=function(e,t){return i(this,void 0,void 0,(function(){var r;return o(this,(function(i){return r=new Nn(n(n({},e),{keySet:this.keySet})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},e.prototype.removeChannelMetadata=function(e,t){return i(this,void 0,void 0,(function(){return o(this,(function(n){return[2,this._removeChannelMetadata(e,t)]}))}))},e.prototype._removeChannelMetadata=function(e,t){return i(this,void 0,void 0,(function(){var r;return o(this,(function(i){return r=new Pn(n(n({},e),{keySet:this.keySet})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},e.prototype.getChannelMembers=function(e,t){return i(this,void 0,void 0,(function(){var r;return o(this,(function(i){return r=new An(n(n({},e),{keySet:this.keySet})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},e.prototype.setChannelMembers=function(e,t){return i(this,void 0,void 0,(function(){var r;return o(this,(function(i){return r=new Rn(n(n({},e),{type:"set",keySet:this.keySet})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},e.prototype.removeChannelMembers=function(e,t){return i(this,void 0,void 0,(function(){var r;return o(this,(function(i){return r=new Rn(n(n({},e),{type:"delete",keySet:this.keySet})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},e.prototype.getMemberships=function(e,t){return i(this,void 0,void 0,(function(){var r,i,s;return o(this,(function(o){return null!=t||(t="function"==typeof e?e:void 0),(r=e&&"function"!=typeof e?e:{}).userId&&(r.uuid=r.userId),null!==(s=r.uuid)&&void 0!==s||(r.uuid=this.configuration.userId),i=new En(n(n({},r),{keySet:this.keySet})),t?[2,this.sendRequest(i,t)]:[2,this.sendRequest(i)]}))}))},e.prototype.setMemberships=function(e,t){return i(this,void 0,void 0,(function(){var r,i;return o(this,(function(o){return e.userId&&(e.uuid=e.userId),null!==(i=e.uuid)&&void 0!==i||(e.uuid=this.configuration.userId),r=new On(n(n({},e),{type:"set",keySet:this.keySet})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},e.prototype.removeMemberships=function(e,t){return i(this,void 0,void 0,(function(){var r,i;return o(this,(function(o){return e.userId&&(e.uuid=e.userId),null!==(i=e.uuid)&&void 0!==i||(e.uuid=this.configuration.userId),r=new On(n(n({},e),{type:"delete",keySet:this.keySet})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},e.prototype.fetchMemberships=function(e,t){return i(this,void 0,void 0,(function(){var r,i,s,u,c,p,l,h;return o(this,(function(o){return"spaceId"in e?(i={channel:null!==(l=(r=e).spaceId)&&void 0!==l?l:r.channel,filter:r.filter,limit:r.limit,page:r.page,include:n({},r.include),sort:r.sort?Object.fromEntries(Object.entries(r.sort).map((function(e){var t=a(e,2),n=t[0],r=t[1];return[n.replace("user","uuid"),r]}))):void 0},s=function(e){return{status:e.status,data:e.data.map((function(e){return{user:e.uuid,custom:e.custom,updated:e.updated,eTag:e.eTag}})),totalCount:e.totalCount,next:e.next,prev:e.prev}},t?[2,this.getChannelMembers(i,(function(e,n){t(e,n?s(n):n)}))]:[2,this.getChannelMembers(i).then(s)]):(c={uuid:null!==(h=(u=e).userId)&&void 0!==h?h:u.uuid,filter:u.filter,limit:u.limit,page:u.page,include:n({},u.include),sort:u.sort?Object.fromEntries(Object.entries(u.sort).map((function(e){var t=a(e,2),n=t[0],r=t[1];return[n.replace("space","channel"),r]}))):void 0},p=function(e){return{status:e.status,data:e.data.map((function(e){return{space:e.channel,custom:e.custom,updated:e.updated,eTag:e.eTag}})),totalCount:e.totalCount,next:e.next,prev:e.prev}},t?[2,this.getMemberships(c,(function(e,n){t(e,n?p(n):n)}))]:[2,this.getMemberships(c).then(p)])}))}))},e.prototype.addMemberships=function(e,t){return i(this,void 0,void 0,(function(){var n,r,i,s,a,u,c,p,l,h;return o(this,(function(o){return"spaceId"in e?(r={channel:null!==(a=(n=e).spaceId)&&void 0!==a?a:n.channel,uuids:null!==(c=null===(u=n.users)||void 0===u?void 0:u.map((function(e){return"string"==typeof e?e:(e.userId,{id:e.userId,custom:e.custom})})))&&void 0!==c?c:n.uuids,limit:0},t?[2,this.setChannelMembers(r,t)]:[2,this.setChannelMembers(r)]):(s={uuid:null!==(p=(i=e).userId)&&void 0!==p?p:i.uuid,channels:null!==(h=null===(l=i.spaces)||void 0===l?void 0:l.map((function(e){return"string"==typeof e?e:{id:e.spaceId,custom:e.custom}})))&&void 0!==h?h:i.channels,limit:0},t?[2,this.setMemberships(s,t)]:[2,this.setMemberships(s)])}))}))},e}(),Tn=function(e){function n(){return e.call(this)||this}return t(n,e),n.prototype.operation=function(){return pe.PNTimeOperation},n.prototype.parse=function(e){return i(this,void 0,void 0,(function(){var t;return o(this,(function(n){if(!(t=this.deserializeResponse(e)))throw new v("Service response error, check status for details",b("Unable to deserialize service response"));return[2,{timetoken:t[0]}]}))}))},Object.defineProperty(n.prototype,"path",{get:function(){return"/time/0"},enumerable:!1,configurable:!0}),n}(ue),Un=function(e){function n(t){var n=e.call(this)||this;return n.parameters=t,n}return t(n,e),n.prototype.operation=function(){return pe.PNDownloadFileOperation},n.prototype.validate=function(){var e=this.parameters,t=e.channel,n=e.id,r=e.name;return t?n?r?void 0:"file name can't be empty":"file id can't be empty":"channel can't be empty"},n.prototype.parse=function(e){return i(this,void 0,void 0,(function(){var t,n,r,i,s,a,u,c,p;return o(this,(function(o){switch(o.label){case 0:return t=this.parameters,n=t.cipherKey,r=t.crypto,i=t.cryptography,s=t.name,a=t.PubNubFile,u=e.headers["content-type"],p=e.body,a.supportsEncryptFile&&(n||r)?n&&i?[4,i.decrypt(n,p)]:[3,2]:[3,4];case 1:return p=o.sent(),[3,4];case 2:return n||!r?[3,4]:[4,r.decryptFile(a.create({data:p,name:s,mimeType:u}),a)];case 3:c=o.sent(),o.label=4;case 4:return[2,c||a.create({data:p,name:s,mimeType:u})]}}))}))},Object.defineProperty(n.prototype,"path",{get:function(){var e=this.parameters,t=e.keySet.subscribeKey,n=e.channel,r=e.id,i=e.name;return"/v1/files/".concat(t,"/channels/").concat(H(n),"/files/").concat(r,"/").concat(i)},enumerable:!1,configurable:!0}),n}(ue),Fn=function(){function e(e){var t,n,r,i=this;if(this._configuration=e.configuration,this.cryptography=e.cryptography,this.tokenManager=e.tokenManager,this.transport=e.transport,this.crypto=e.crypto,this._objects=new In(this._configuration,this.sendRequest),this._channelGroups=new yn(this._configuration.keySet,this.sendRequest),this._push=new Sn(this._configuration.keySet,this.sendRequest),this.listenerManager=new Q,this.eventEmitter=new fe(this.listenerManager),this._configuration.enableEventEngine){var o=this._configuration.getHeartbeatInterval();this.presenceState={},o&&(this.presenceEventEngine=new Ve({heartbeat:this.heartbeat,leave:this.unsubscribe,heartbeatDelay:function(){return new Promise((function(e,t){(o=i._configuration.getHeartbeatInterval())?setTimeout(e,1e3*o):t(new v("Heartbeat interval has been reset."))}))},retryDelay:function(e){return new Promise((function(t){return setTimeout(t,e)}))},emitStatus:function(e){return i.listenerManager.announceStatus(e)},config:this._configuration,presenceState:this.presenceState})),this.eventEngine=new Ct({handshake:this.subscribeHandshake,receiveMessages:this.subscribeReceiveMessages,delay:function(e){return new Promise((function(t){return setTimeout(t,e)}))},join:null===(t=this.presenceEventEngine)||void 0===t?void 0:t.join,leave:null===(n=this.presenceEventEngine)||void 0===n?void 0:n.leave,leaveAll:null===(r=this.presenceEventEngine)||void 0===r?void 0:r.leaveAll,presenceState:this.presenceState,config:this._configuration,emitMessages:function(e){return e.forEach((function(e){return i.eventEmitter.emitEvent(e)}))},emitStatus:function(e){return i.listenerManager.announceStatus(e)}})}else this.subscriptionManager=new ne(this._configuration,this.listenerManager,this.eventEmitter,this.makeSubscribe,this.heartbeat,this.makeUnsubscribe,this.time)}return e.notificationPayload=function(e,t){return new ae(e,t)},e.generateUUID=function(){return K()},Object.defineProperty(e.prototype,"configuration",{get:function(){return this._configuration},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"_config",{get:function(){return this.configuration},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"authKey",{get:function(){var e;return null!==(e=this._configuration.authKey)&&void 0!==e?e:void 0},enumerable:!1,configurable:!0}),e.prototype.getAuthKey=function(){return this.authKey},e.prototype.setAuthKey=function(e){this._configuration.setAuthKey(e)},Object.defineProperty(e.prototype,"userId",{get:function(){return this._configuration.userId},set:function(e){this._configuration.userId=e},enumerable:!1,configurable:!0}),e.prototype.getUserId=function(){return this._configuration.userId},e.prototype.setUserId=function(e){this._configuration.userId=e},Object.defineProperty(e.prototype,"filterExpression",{get:function(){var e;return null!==(e=this._configuration.getFilterExpression())&&void 0!==e?e:void 0},set:function(e){this._configuration.setFilterExpression(e)},enumerable:!1,configurable:!0}),e.prototype.getFilterExpression=function(){return this.filterExpression},e.prototype.setFilterExpression=function(e){this.filterExpression=e},Object.defineProperty(e.prototype,"cipherKey",{get:function(){return this._configuration.cipherKey},set:function(e){this._configuration.setCipherKey(e)},enumerable:!1,configurable:!0}),e.prototype.setCipherKey=function(e){this.cipherKey=e},Object.defineProperty(e.prototype,"heartbeatInterval",{set:function(e){this._configuration.setHeartbeatInterval(e)},enumerable:!1,configurable:!0}),e.prototype.setHeartbeatInterval=function(e){this.heartbeatInterval=e},e.prototype.getVersion=function(){return this._configuration.version},e.prototype._addPnsdkSuffix=function(e,t){this._configuration._addPnsdkSuffix(e,t)},e.prototype.getUUID=function(){return this.userId},e.prototype.setUUID=function(e){this.userId=e},Object.defineProperty(e.prototype,"customEncrypt",{get:function(){return this._configuration.customEncrypt},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"customDecrypt",{get:function(){return this._configuration.customDecrypt},enumerable:!1,configurable:!0}),e.prototype.channel=function(e){return new cn(e,this.eventEmitter,this)},e.prototype.channelGroup=function(e){return new an(e,this.eventEmitter,this)},e.prototype.channelMetadata=function(e){return new sn(e,this.eventEmitter,this)},e.prototype.userMetadata=function(e){return new un(e,this.eventEmitter,this)},e.prototype.subscriptionSet=function(e){return new rn(n(n({},e),{eventEmitter:this.eventEmitter,pubnub:this}))},e.prototype.sendRequest=function(e,t){return i(this,void 0,void 0,(function(){var n,r,i,s,u,c;return o(this,(function(o){if(n=e.validate()){if(t)return[2,t(b(n),null)];throw new v("Validation failed, check status for details",b(n))}return(r=e.request()).body&&"object"==typeof r.body&&"toArrayBuffer"in r.body?r.timeout=300:e.operation()===pe.PNSubscribeOperation?r.timeout=this._configuration.getSubscribeTimeout():r.timeout=this._configuration.getTransactionTimeout(),i={error:!1,operation:e.operation(),statusCode:0},s=a(this.transport.makeSendable(r),2),u=s[0],c=s[1],e.cancellationController=c||null,[2,u.then((function(t){return i.statusCode=t.status,e.parse(t)})).then((function(e){return t?t(i,e):e})).catch((function(e){console.log("~~~~~~~> WHAT HERE?:",e),e instanceof v&&(console.log("~~~~~~> OH, WE ARE REGULAR PUBNUB ERROR"),console.log("~~~~~~~~> WHAT IN STATUS?: ",e.status));var n={error:!0};throw t&&t(n,null),new v("REST API request processing error, check status for details",n)}))]}))}))},e.prototype.destroy=function(e){this.subscriptionManager?(this.subscriptionManager.unsubscribeAll(e),this.subscriptionManager.disconnect()):this.eventEngine&&this.eventEngine.dispose()},e.prototype.addListener=function(e){this.listenerManager.addListener(e)},e.prototype.removeListener=function(e){this.listenerManager.removeListener(e)},e.prototype.removeAllListeners=function(){this.listenerManager.removeAllListeners()},e.prototype.publish=function(e,t){return i(this,void 0,void 0,(function(){var r;return o(this,(function(i){return r=new _t(n(n({},e),{keySet:this._configuration.keySet,crypto:this._configuration.cryptoModule})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},e.prototype.signal=function(e,t){return i(this,void 0,void 0,(function(){var r;return o(this,(function(i){return r=new Nt(n(n({},e),{keySet:this._configuration.keySet})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},e.prototype.fire=function(e,t){return i(this,void 0,void 0,(function(){return o(this,(function(r){return null!=t||(t=function(){}),[2,this.publish(n(n({},e),{replicate:!1,storeInHistory:!1}),t)]}))}))},e.prototype.getSubscribedChannels=function(){return this.subscriptionManager?this.subscriptionManager.subscribedChannels:this.eventEngine?this.eventEngine.getSubscribedChannels():[]},e.prototype.getSubscribedChannelGroups=function(){return this.subscriptionManager?this.subscriptionManager.subscribedChannelGroups:this.eventEngine?this.eventEngine.getSubscribedChannelGroups():[]},e.prototype.subscribe=function(e){this.subscriptionManager?this.subscriptionManager.subscribe(e):this.eventEngine&&this.eventEngine.subscribe(e)},e.prototype.makeSubscribe=function(e,t){var r=this,i=new he(n(n({},e),{keySet:this._configuration.keySet,getFileUrl:this.getFileUrl}));this.sendRequest(i,(function(e,n){r.subscriptionManager&&r.subscriptionManager.abort===i.abort&&(r.subscriptionManager.abort=null),t(e,n)})),this.subscriptionManager&&(this.subscriptionManager.abort=i.abort)},e.prototype.unsubscribe=function(e){this.subscriptionManager?this.subscriptionManager.unsubscribe(e):this.eventEngine&&this.eventEngine.unsubscribe(e)},e.prototype.makeUnsubscribe=function(e,t){this.sendRequest(new Tt(n(n({},e),{keySet:this._configuration.keySet})),t)},e.prototype.unsubscribeAll=function(){this.subscriptionManager?this.subscriptionManager.unsubscribeAll():this.eventEngine&&this.eventEngine.unsubscribeAll()},e.prototype.disconnect=function(){this.subscriptionManager?this.subscriptionManager.disconnect():this.eventEngine&&this.eventEngine.disconnect()},e.prototype.reconnect=function(e){this.subscriptionManager?this.subscriptionManager.reconnect():this.eventEngine&&this.eventEngine.reconnect(null!=e?e:{})},e.prototype.subscribeHandshake=function(e){return i(this,void 0,void 0,(function(){var t,r;return o(this,(function(i){return t=new At(n(n({},e),{keySet:this._configuration.keySet,crypto:this._configuration.cryptoModule,getFileUrl:this.getFileUrl})),r=e.abortSignal.subscribe(t.abort),[2,this.sendRequest(t).then((function(e){return r(),e.cursor}))]}))}))},e.prototype.subscribeReceiveMessages=function(e){return i(this,void 0,void 0,(function(){var t,r;return o(this,(function(i){return t=new Mt(n(n({},e),{keySet:this._configuration.keySet,crypto:this._configuration.cryptoModule,getFileUrl:this.getFileUrl})),r=e.abortSignal.subscribe(t.abort),[2,this.sendRequest(t).then((function(e){return r(),e}))]}))}))},e.prototype.getMessageActions=function(e,t){return i(this,void 0,void 0,(function(){var r;return o(this,(function(i){return r=new qt(n(n({},e),{keySet:this._configuration.keySet})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},e.prototype.addMessageAction=function(e,t){return i(this,void 0,void 0,(function(){var r;return o(this,(function(i){return r=new Lt(n(n({},e),{keySet:this._configuration.keySet})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},e.prototype.removeMessageAction=function(e,t){return i(this,void 0,void 0,(function(){var r;return o(this,(function(i){return r=new Bt(n(n({},e),{keySet:this._configuration.keySet})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},e.prototype.fetchMessages=function(e,t){return i(this,void 0,void 0,(function(){var r;return o(this,(function(i){return r=new Gt(n(n({},e),{keySet:this._configuration.keySet,crypto:this._configuration.cryptoModule,getFileUrl:this.getFileUrl})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},e.prototype.deleteMessages=function(e,t){return i(this,void 0,void 0,(function(){var r;return o(this,(function(i){return r=new Dt(n(n({},e),{keySet:this._configuration.keySet})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},e.prototype.messageCounts=function(e,t){return i(this,void 0,void 0,(function(){var r;return o(this,(function(i){return r=new xt(n(n({},e),{keySet:this._configuration.keySet})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},e.prototype.history=function(e,t){return i(this,void 0,void 0,(function(){var r;return o(this,(function(i){return r=new Kt(n(n({},e),{keySet:this._configuration.keySet,crypto:this._configuration.cryptoModule})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},e.prototype.hereNow=function(e,t){return i(this,void 0,void 0,(function(){var r;return o(this,(function(i){return r=new Ft(n(n({},e),{keySet:this._configuration.keySet})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},e.prototype.whereNow=function(e,t){return i(this,void 0,void 0,(function(){var n,r;return o(this,(function(i){return n=new Ut({uuid:null!==(r=e.uuid)&&void 0!==r?r:this._configuration.userId,keySet:this._configuration.keySet}),t?[2,this.sendRequest(n,t)]:[2,this.sendRequest(n)]}))}))},e.prototype.getState=function(e,t){return i(this,void 0,void 0,(function(){var r,i;return o(this,(function(o){return r=new Rt(n(n({},e),{uuid:null!==(i=e.uuid)&&void 0!==i?i:this._configuration.userId,keySet:this._configuration.keySet})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},e.prototype.setState=function(e,t){return i(this,void 0,void 0,(function(){var r,i,s,a,u,c,p,l;return o(this,(function(o){return r=this._configuration,i=r.keySet,s=r.userId,a=this._configuration.getPresenceTimeout(),this._configuration.enableEventEngine&&this.presenceState&&(c=this.presenceState,null===(p=e.channels)||void 0===p||p.forEach((function(t){return c[t]=e.state})),"channelGroups"in e&&(null===(l=e.channelGroups)||void 0===l||l.forEach((function(t){return c[t]=e.state})))),u="withHeartbeat"in e?new It(n(n({},e),{keySet:i,heartbeat:a})):new jt(n(n({},e),{keySet:i,uuid:s})),this.subscriptionManager&&this.subscriptionManager.setState(e),t?[2,this.sendRequest(u,t)]:[2,this.sendRequest(u)]}))}))},e.prototype.presence=function(e){var t;null===(t=this.subscriptionManager)||void 0===t||t.changePresence(e)},e.prototype.heartbeat=function(e){return i(this,void 0,void 0,(function(){var t;return o(this,(function(r){return this.subscriptionManager?(t=new It(n(n({},e),{keySet:this._configuration.keySet})),[2,this.sendRequest(t)]):[2]}))}))},e.prototype.grantToken=function(e,t){return i(this,void 0,void 0,(function(){var r;return o(this,(function(i){return r=new Zt(n(n({},e),{keySet:this._configuration.keySet})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},e.prototype.revokeToken=function(e,t){return i(this,void 0,void 0,(function(){var r;return o(this,(function(i){return r=new $t(n(n({},e),{keySet:this._configuration.keySet})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},Object.defineProperty(e.prototype,"token",{get:function(){return this.tokenManager.getToken()},set:function(e){this.tokenManager.setToken(e)},enumerable:!1,configurable:!0}),e.prototype.getToken=function(){return this.token},e.prototype.setToken=function(e){this.token=e},e.prototype.parseToken=function(e){return this.tokenManager.parseToken(e)},e.prototype.grant=function(e,t){return i(this,void 0,void 0,(function(){var r;return o(this,(function(i){return r=new Qt(n(n({},e),{keySet:this._configuration.keySet})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},e.prototype.audit=function(e,t){return i(this,void 0,void 0,(function(){var r;return o(this,(function(i){return r=new tn(n(n({},e),{keySet:this._configuration.keySet})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},Object.defineProperty(e.prototype,"objects",{get:function(){return this._objects},enumerable:!1,configurable:!0}),e.prototype.fetchUsers=function(e,t){return i(this,void 0,void 0,(function(){return o(this,(function(n){return[2,this.objects._getAllUUIDMetadata(e,t)]}))}))},e.prototype.fetchUser=function(e,t){return i(this,void 0,void 0,(function(){return o(this,(function(n){return[2,this.objects._getUUIDMetadata(e,t)]}))}))},e.prototype.createUser=function(e,t){return i(this,void 0,void 0,(function(){return o(this,(function(n){return[2,this.objects._setUUIDMetadata(e,t)]}))}))},e.prototype.updateUser=function(e,t){return i(this,void 0,void 0,(function(){return o(this,(function(n){return[2,this.objects._setUUIDMetadata(e,t)]}))}))},e.prototype.removeUser=function(e,t){return i(this,void 0,void 0,(function(){return o(this,(function(n){return[2,this.objects._removeUUIDMetadata(e,t)]}))}))},e.prototype.fetchSpaces=function(e,t){return i(this,void 0,void 0,(function(){return o(this,(function(n){return[2,this.objects._getAllChannelMetadata(e,t)]}))}))},e.prototype.fetchSpace=function(e,t){return i(this,void 0,void 0,(function(){return o(this,(function(n){return[2,this.objects._getChannelMetadata(e,t)]}))}))},e.prototype.createSpace=function(e,t){return i(this,void 0,void 0,(function(){return o(this,(function(n){return[2,this.objects._setChannelMetadata(e,t)]}))}))},e.prototype.updateSpace=function(e,t){return i(this,void 0,void 0,(function(){return o(this,(function(n){return[2,this.objects._setChannelMetadata(e,t)]}))}))},e.prototype.removeSpace=function(e,t){return i(this,void 0,void 0,(function(){return o(this,(function(n){return[2,this.objects._removeChannelMetadata(e,t)]}))}))},e.prototype.fetchMemberships=function(e,t){return i(this,void 0,void 0,(function(){return o(this,(function(n){return[2,this.objects.fetchMemberships(e,t)]}))}))},e.prototype.addMemberships=function(e,t){return i(this,void 0,void 0,(function(){return o(this,(function(n){return[2,this.objects.addMemberships(e,t)]}))}))},e.prototype.updateMemberships=function(e,t){return i(this,void 0,void 0,(function(){return o(this,(function(n){return[2,this.objects.addMemberships(e,t)]}))}))},e.prototype.removeMemberships=function(e,t){return i(this,void 0,void 0,(function(){var n,r,i,s,a,u,c;return o(this,(function(o){return"spaceId"in e?(r={channel:null!==(a=(n=e).spaceId)&&void 0!==a?a:n.channel,uuids:null!==(u=n.userIds)&&void 0!==u?u:n.uuids,limit:0},t?[2,this.objects.removeChannelMembers(r,t)]:[2,this.objects.removeChannelMembers(r)]):(s={uuid:(i=e).userId,channels:null!==(c=i.spaceIds)&&void 0!==c?c:i.channels,limit:0},t?[2,this.objects.removeMemberships(s,t)]:[2,this.objects.removeMemberships(s)])}))}))},Object.defineProperty(e.prototype,"channelGroups",{get:function(){return this._channelGroups},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"push",{get:function(){return this._push},enumerable:!1,configurable:!0}),e.prototype.sendFile=function(e,t){return i(this,void 0,void 0,(function(){var r,i,s;return o(this,(function(o){if(!this._configuration.PubNubFile)throw new Error("Validation failed: 'PubNubFile' not configured or file upload not supported by the platform.");return r=new Xt(n(n({},e),{cipherKey:null!==(s=e.cipherKey)&&void 0!==s?s:this._configuration.cipherKey,keySet:this._configuration.keySet,PubNubFile:this._configuration.PubNubFile,fileUploadPublishRetryLimit:this._configuration.fileUploadPublishRetryLimit,file:e.file,sendRequest:this.sendRequest,publishFile:this.publishFile,crypto:this._configuration.cryptoModule,cryptography:this.cryptography?this.cryptography:void 0})),i={error:!1,operation:pe.PNPublishFileOperation,statusCode:0},[2,r.process().then((function(e){return i.statusCode=e.status,t?t(i,e):e})).catch((function(e){var n=e.toStatus(i.operation);throw t&&t(n,null),new v("REST API request processing error, check status for details",n)}))]}))}))},e.prototype.publishFile=function(e,t){return i(this,void 0,void 0,(function(){var r;return o(this,(function(i){if(!this._configuration.PubNubFile)throw new Error("Validation failed: 'PubNubFile' not configured or file upload not supported by the platform.");return r=new Ht(n(n({},e),{keySet:this._configuration.keySet,crypto:this._configuration.cryptoModule})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},e.prototype.listFiles=function(e,t){return i(this,void 0,void 0,(function(){var r;return o(this,(function(i){return r=new Wt(n(n({},e),{keySet:this._configuration.keySet})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},e.prototype.getFileUrl=function(e){var t,r=this.transport.request(new zt(n(n({},e),{keySet:this._configuration.keySet})).request()),i=null!==(t=r.queryParameters)&&void 0!==t?t:{},o=Object.keys(i).map((function(e){var t=i[e];return Array.isArray(t)?t.map((function(t){return"".concat(e,"=").concat(H(t))})).join("&"):"".concat(e,"=").concat(H(t))})).join("&");return"".concat(r.origin).concat(r.path,"?").concat(o)},e.prototype.downloadFile=function(e,t){return i(this,void 0,void 0,(function(){var r,i;return o(this,(function(o){switch(o.label){case 0:if(!this._configuration.PubNubFile)throw new Error("Validation failed: 'PubNubFile' not configured or file upload not supported by the platform.");return r=new Un(n(n({},e),{cipherKey:null!==(i=e.cipherKey)&&void 0!==i?i:this._configuration.cipherKey,keySet:this._configuration.keySet,PubNubFile:this._configuration.PubNubFile,cryptography:this.cryptography?this.cryptography:void 0,crypto:this._configuration.cryptoModule})),t?[2,this.sendRequest(r,t)]:[4,this.sendRequest(r)];case 1:return[2,o.sent()]}}))}))},e.prototype.deleteFile=function(e,t){return i(this,void 0,void 0,(function(){var r;return o(this,(function(i){return r=new Vt(n(n({},e),{keySet:this._configuration.keySet})),t?[2,this.sendRequest(r,t)]:[2,this.sendRequest(r)]}))}))},e.prototype.time=function(e){return i(this,void 0,void 0,(function(){var t;return o(this,(function(n){return t=new Tn,e?[2,this.sendRequest(t,e)]:[2,this.sendRequest(t)]}))}))},e.prototype.encrypt=function(e,t){if(void 0===t&&this._configuration.cryptoModule){var n=this._configuration.cryptoModule.encrypt(e);return"string"==typeof n?n:g(n)}if(!this.crypto)throw new Error("Encryption error: cypher key not set");return this.crypto.encrypt(e,t)},e.prototype.decrypt=function(e,t){if(void 0===t&&this._configuration.cryptoModule){var n=this._configuration.cryptoModule.decrypt(e);return n instanceof ArrayBuffer?JSON.parse((new TextDecoder).decode(n)):n}if(!this.crypto)throw new Error("Decryption error: cypher key not set");return this.crypto.decrypt(e,t)},e.prototype.encryptFile=function(e,t){return i(this,void 0,void 0,(function(){var n;return o(this,(function(r){if("string"!=typeof e&&(t=e),!t)throw new Error("File encryption error. Source file is missing.");if(!this._configuration.PubNubFile)throw new Error("File encryption error. File constructor not configured.");if("string"!=typeof e&&!this._configuration.cryptoModule)throw new Error("File encryption error. Crypto module not configured.");if("string"==typeof e){if(!this.cryptography)throw new Error("File encryption error. File encryption not available");return[2,this.cryptography.encryptFile(e,t,this._configuration.PubNubFile)]}return[2,null===(n=this._configuration.cryptoModule)||void 0===n?void 0:n.encryptFile(t,this._configuration.PubNubFile)]}))}))},e.prototype.decryptFile=function(e,t){return i(this,void 0,void 0,(function(){var n;return o(this,(function(r){if("string"!=typeof e&&(t=e),!t)throw new Error("File encryption error. Source file is missing.");if(!this._configuration.PubNubFile)throw new Error("File decryption error. File constructor not configured.");if("string"==typeof e&&!this._configuration.cryptoModule)throw new Error("File decryption error. Crypto module not configured.");if("string"==typeof e){if(!this.cryptography)throw new Error("File decryption error. File decryption not available");return[2,this.cryptography.decryptFile(e,t,this._configuration.PubNubFile)]}return[2,null===(n=this._configuration.cryptoModule)||void 0===n?void 0:n.decryptFile(t,this._configuration.PubNubFile)]}))}))},e.OPERATIONS=pe,e.CATEGORIES=X,e.ExponentialRetryPolicy=We.ExponentialRetryPolicy,e.LinearRetryPolicy=We.LinearRetryPolicy,e}(),Dn=function(){function e(e,t){this._base64ToBinary=t,this._decode=e}return e.prototype.decodeToken=function(e){var t="";e.length%4==3?t="=":e.length%4==2&&(t="==");var n=e.replace(/-/gi,"+").replace(/_/gi,"/")+t,r=this._decode(this._base64ToBinary(n));if("object"==typeof r)return r},e}();return function(e){function r(t){var r,i,o=this,s=q(t),a=function(e,t){var r,i,o;null===(r=e.retryConfiguration)||void 0===r||r.validate(),null!==(i=e.useRandomIVs)&&void 0!==i||(e.useRandomIVs=!0),e.origin=G(null!==(o=e.ssl)&&void 0!==o&&o,e.origin);var s=n(n({},e),{_pnsdkSuffix:{},_instanceId:"pn-".concat(K()),_cryptoModule:void 0,_cipherKey:void 0,_setupCryptoModule:t,get instanceId(){if(this.useInstanceId)return this._instanceId},getUserId:function(){return this.userId},setUserId:function(e){if(!e||"string"!=typeof e||0===e.trim().length)throw new Error("Missing or invalid userId parameter. Provide a valid string userId");this.userId=e},getAuthKey:function(){return this.authKey},setAuthKey:function(e){this.authKey=e},getFilterExpression:function(){return this.filterExpression},setFilterExpression:function(e){this.filterExpression=e},get cipherKey(){return this._cipherKey},setCipherKey:function(t){this._cipherKey=t,t||!this._cryptoModule?t&&this._setupCryptoModule&&(this._cryptoModule=this._setupCryptoModule({cipherKey:t,useRandomIVs:e.useRandomIVs,customEncrypt:this.customEncrypt,customDecrypt:this.customDecrypt})):this._cryptoModule=void 0},get cryptoModule(){return this._cryptoModule},get useRandomIVs(){return e.useRandomIVs},getPresenceTimeout:function(){return this.presenceTimeout},getHeartbeatInterval:function(){return this.heartbeatInterval},setHeartbeatInterval:function(e){this.heartbeatInterval=e},getTransactionTimeout:function(){return this.transactionalRequestTimeout},getSubscribeTimeout:function(){return this.subscribeRequestTimeout},get PubNubFile(){return e.PubNubFile},get version(){return"7.6.0"},getVersion:function(){return this.version},_addPnsdkSuffix:function(e,t){this._pnsdkSuffix[e]="".concat(t)},_getPnsdkSuffix:function(e){return Object.values(this._pnsdkSuffix).join(e)},getUUID:function(){return this.getUserId()},setUUID:function(e){this.setUserId(e)},get customEncrypt(){return e.customEncrypt},get customDecrypt(){return e.customDecrypt}});return e.cipherKey&&s.setCipherKey(e.cipherKey),s}(n(n({},s),{sdkFamily:"Nodejs",PubNubFile:d}),(function(e){if(e.cipherKey)return new j({default:new R(n({},e)),cryptors:[new C({cipherKey:e.cipherKey})]})})),u=new L(new Dn((function(e){return U(h.decode(e))}),y));if(a.cipherKey||a.secretKey){var c=a.secretKey,p=a.cipherKey,l=a.useRandomIVs,f=a.customEncrypt,g=a.customDecrypt;i=new N({secretKey:c,cipherKey:p,useRandomIVs:l,customEncrypt:f,customDecrypt:g})}var v=new J({clientConfiguration:a,tokenManager:u,transport:new Z(a.keepAlive,a.logVerbosity)});return o=e.call(this,{configuration:a,transport:v,cryptography:new A,tokenManager:u,crypto:i})||this,(null===(r=t.listenToBrowserNetworkEvents)||void 0===r||r)&&(window.addEventListener("offline",(function(){o.networkDownDetected()})),window.addEventListener("online",(function(){o.networkUpDetected()}))),o}return t(r,e),r.prototype.networkDownDetected=function(){this.listenerManager.announceNetworkDown(),this._configuration.restore?this.disconnect():this.destroy(!0)},r.prototype.networkUpDetected=function(){this.listenerManager.announceNetworkUp(),this.reconnect()},r.CryptoModule=j,r}(Fn)})); diff --git a/lib/core/components/abort_signal.js b/lib/core/components/abort_signal.js index acee414dd..1b9ae76d2 100644 --- a/lib/core/components/abort_signal.js +++ b/lib/core/components/abort_signal.js @@ -14,6 +14,31 @@ var __extends = (this && this.__extends) || (function () { d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); +var __read = (this && this.__read) || function (o, n) { + var m = typeof Symbol === "function" && o[Symbol.iterator]; + if (!m) return o; + var i = m.call(o), r, ar = [], e; + try { + while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); + } + catch (error) { e = { error: error }; } + finally { + try { + if (r && !r.done && (m = i["return"])) m.call(i); + } + finally { if (e) throw e.error; } + } + return ar; +}; +var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { + if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { + if (ar || !(i in from)) { + if (!ar) ar = Array.prototype.slice.call(from, 0, i); + ar[i] = from[i]; + } + } + return to.concat(ar || Array.prototype.slice.call(from)); +}; Object.defineProperty(exports, "__esModule", { value: true }); exports.AbortSignal = exports.AbortError = void 0; var subject_1 = require("./subject"); @@ -32,7 +57,7 @@ exports.AbortError = AbortError; var AbortSignal = /** @class */ (function (_super) { __extends(AbortSignal, _super); function AbortSignal() { - var _this = _super !== null && _super.apply(this, arguments) || this; + var _this = _super.apply(this, __spreadArray([], __read(arguments), false)) || this; _this._aborted = false; return _this; } diff --git a/lib/core/components/config.js b/lib/core/components/config.js deleted file mode 100644 index 0b7786537..000000000 --- a/lib/core/components/config.js +++ /dev/null @@ -1,209 +0,0 @@ -"use strict"; -/* */ -/* global location */ -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -var uuid_1 = __importDefault(require("./uuid")); -var PRESENCE_TIMEOUT_MINIMUM = 20; -var PRESENCE_TIMEOUT_DEFAULT = 300; -var makeDefaultOrigins = function () { return Array.from({ length: 20 }, function (_, i) { return "ps".concat(i + 1, ".pndsn.com"); }); }; -var default_1 = /** @class */ (function () { - function default_1(_a) { - var setup = _a.setup; - var _b, _c, _d, _e; - this._PNSDKSuffix = {}; - this.instanceId = "pn-".concat(uuid_1.default.createUUID()); - this.secretKey = setup.secretKey || setup.secret_key; - this.subscribeKey = setup.subscribeKey || setup.subscribe_key; - this.publishKey = setup.publishKey || setup.publish_key; - this.sdkName = setup.sdkName; - this.sdkFamily = setup.sdkFamily; - this.partnerId = setup.partnerId; - this.setAuthKey(setup.authKey); - this.cryptoModule = setup.cryptoModule; - this.setFilterExpression(setup.filterExpression); - if (typeof setup.origin !== 'string' && !Array.isArray(setup.origin) && setup.origin !== undefined) { - throw new Error('Origin must be either undefined, a string or a list of strings.'); - } - this.origin = setup.origin || makeDefaultOrigins(); - this.secure = setup.ssl || false; - this.restore = setup.restore || false; - this.proxy = setup.proxy; - this.keepAlive = setup.keepAlive; - this.keepAliveSettings = setup.keepAliveSettings; - this.autoNetworkDetection = setup.autoNetworkDetection || false; - this.dedupeOnSubscribe = setup.dedupeOnSubscribe || false; - this.maximumCacheSize = setup.maximumCacheSize || 100; - this.customEncrypt = setup.customEncrypt; - this.customDecrypt = setup.customDecrypt; - this.fileUploadPublishRetryLimit = (_b = setup.fileUploadPublishRetryLimit) !== null && _b !== void 0 ? _b : 5; - this.useRandomIVs = (_c = setup.useRandomIVs) !== null && _c !== void 0 ? _c : true; - this.enableEventEngine = (_d = setup.enableEventEngine) !== null && _d !== void 0 ? _d : false; - this.maintainPresenceState = (_e = setup.maintainPresenceState) !== null && _e !== void 0 ? _e : true; - // if location config exist and we are in https, force secure to true. - if (typeof location !== 'undefined' && location.protocol === 'https:') { - this.secure = true; - } - this.logVerbosity = setup.logVerbosity || false; - this.suppressLeaveEvents = setup.suppressLeaveEvents || false; - this.announceFailedHeartbeats = setup.announceFailedHeartbeats || true; - this.announceSuccessfulHeartbeats = setup.announceSuccessfulHeartbeats || false; - this.useInstanceId = setup.useInstanceId || false; - this.useRequestId = setup.useRequestId || false; - this.requestMessageCountThreshold = setup.requestMessageCountThreshold; - if (setup.retryConfiguration) { - this._setRetryConfiguration(setup.retryConfiguration); - } - // set timeout to how long a transaction request will wait for the server (default 15 seconds) - this.setTransactionTimeout(setup.transactionalRequestTimeout || 15 * 1000); - // set timeout to how long a subscribe event loop will run (default 310 seconds) - this.setSubscribeTimeout(setup.subscribeRequestTimeout || 310 * 1000); - // set config on beacon (https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon) usage - this.setSendBeaconConfig(setup.useSendBeacon || true); - // how long the SDK will report the client to be alive before issuing a timeout - if (setup.presenceTimeout) { - this.setPresenceTimeout(setup.presenceTimeout); - } - else { - this._presenceTimeout = PRESENCE_TIMEOUT_DEFAULT; - } - if (setup.heartbeatInterval != null) { - this.setHeartbeatInterval(setup.heartbeatInterval); - } - if (typeof setup.userId === 'string') { - if (typeof setup.uuid === 'string') { - throw new Error('Only one of the following configuration options has to be provided: `uuid` or `userId`'); - } - this.setUserId(setup.userId); - } - else { - if (typeof setup.uuid !== 'string') { - throw new Error('One of the following configuration options has to be provided: `uuid` or `userId`'); - } - this.setUUID(setup.uuid); - } - this.setCipherKey(setup.cipherKey, setup); - } - // exposed setters - default_1.prototype.getAuthKey = function () { - return this.authKey; - }; - default_1.prototype.setAuthKey = function (val) { - this.authKey = val; - return this; - }; - default_1.prototype.setCipherKey = function (val, setup, modules) { - var _a; - this.cipherKey = val; - if (this.cipherKey) { - this.cryptoModule = - (_a = setup.cryptoModule) !== null && _a !== void 0 ? _a : setup.initCryptoModule({ cipherKey: this.cipherKey, useRandomIVs: this.useRandomIVs }); - if (modules) - modules.cryptoModule = this.cryptoModule; - } - return this; - }; - default_1.prototype.getUUID = function () { - return this.UUID; - }; - default_1.prototype.setUUID = function (val) { - if (!val || typeof val !== 'string' || val.trim().length === 0) { - throw new Error('Missing uuid parameter. Provide a valid string uuid'); - } - this.UUID = val; - return this; - }; - default_1.prototype.getUserId = function () { - return this.UUID; - }; - default_1.prototype.setUserId = function (value) { - if (!value || typeof value !== 'string' || value.trim().length === 0) { - throw new Error('Missing or invalid userId parameter. Provide a valid string userId'); - } - this.UUID = value; - return this; - }; - default_1.prototype.getFilterExpression = function () { - return this.filterExpression; - }; - default_1.prototype.setFilterExpression = function (val) { - this.filterExpression = val; - return this; - }; - default_1.prototype.getPresenceTimeout = function () { - return this._presenceTimeout; - }; - default_1.prototype.setPresenceTimeout = function (val) { - if (val >= PRESENCE_TIMEOUT_MINIMUM) { - this._presenceTimeout = val; - } - else { - this._presenceTimeout = PRESENCE_TIMEOUT_MINIMUM; - // eslint-disable-next-line no-console - console.log('WARNING: Presence timeout is less than the minimum. Using minimum value: ', this._presenceTimeout); - } - this.setHeartbeatInterval(this._presenceTimeout / 2 - 1); - return this; - }; - default_1.prototype.setProxy = function (proxy) { - this.proxy = proxy; - }; - default_1.prototype.getHeartbeatInterval = function () { - return this._heartbeatInterval; - }; - default_1.prototype.setHeartbeatInterval = function (val) { - this._heartbeatInterval = val; - return this; - }; - // deprecated setters. - default_1.prototype.getSubscribeTimeout = function () { - return this._subscribeRequestTimeout; - }; - default_1.prototype.setSubscribeTimeout = function (val) { - this._subscribeRequestTimeout = val; - return this; - }; - default_1.prototype.getTransactionTimeout = function () { - return this._transactionalRequestTimeout; - }; - default_1.prototype.setTransactionTimeout = function (val) { - this._transactionalRequestTimeout = val; - return this; - }; - default_1.prototype.isSendBeaconEnabled = function () { - return this._useSendBeacon; - }; - default_1.prototype.setSendBeaconConfig = function (val) { - this._useSendBeacon = val; - return this; - }; - default_1.prototype.getVersion = function () { - return '7.6.0'; - }; - default_1.prototype._setRetryConfiguration = function (configuration) { - if (configuration.minimumdelay < 2) { - throw new Error('Minimum delay can not be set less than 2 seconds for retry'); - } - if (configuration.maximumDelay > 150) { - throw new Error('Maximum delay can not be set more than 150 seconds for retry'); - } - if (configuration.maximumDelay && maximumRetry > 6) { - throw new Error('Maximum retry for exponential retry policy can not be more than 6'); - } - else if (configuration.maximumRetry > 10) { - throw new Error('Maximum retry for linear retry policy can not be more than 10'); - } - this.retryConfiguration = configuration; - }; - default_1.prototype._addPnsdkSuffix = function (name, suffix) { - this._PNSDKSuffix[name] = suffix; - }; - default_1.prototype._getPnsdkSuffix = function (separator) { - var _this = this; - return Object.keys(this._PNSDKSuffix).reduce(function (result, key) { return result + separator + _this._PNSDKSuffix[key]; }, ''); - }; - return default_1; -}()); -exports.default = default_1; diff --git a/lib/core/components/configuration.js b/lib/core/components/configuration.js new file mode 100644 index 000000000..10ad3a915 --- /dev/null +++ b/lib/core/components/configuration.js @@ -0,0 +1,139 @@ +"use strict"; +/** + * {@link PubNub} client configuration module. + */ +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.makeConfiguration = void 0; +var uuid_1 = __importDefault(require("./uuid")); +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults +/** + * Whether encryption (if set) should use random initialization vector or not. + */ +var USE_RANDOM_INITIALIZATION_VECTOR = true; +/** + * Create {@link PubNub} client private configuration object. + * + * @param base - User- and platform-provided configuration. + * @param setupCryptoModule - Platform-provided {@link CryptoModule} configuration block. + * + * @returns `PubNub` client private configuration. + */ +var makeConfiguration = function (base, setupCryptoModule) { + var _a, _b, _c; + // Ensure that retry policy has proper configuration (if has been set). + (_a = base.retryConfiguration) === null || _a === void 0 ? void 0 : _a.validate(); + (_b = base.useRandomIVs) !== null && _b !== void 0 ? _b : (base.useRandomIVs = USE_RANDOM_INITIALIZATION_VECTOR); + // Override origin value. + base.origin = standardOrigin((_c = base.ssl) !== null && _c !== void 0 ? _c : false, base.origin); + var clientConfiguration = __assign(__assign({}, base), { _pnsdkSuffix: {}, _instanceId: "pn-".concat(uuid_1.default.createUUID()), _cryptoModule: undefined, _cipherKey: undefined, _setupCryptoModule: setupCryptoModule, get instanceId() { + if (this.useInstanceId) + return this._instanceId; + return undefined; + }, getUserId: function () { + return this.userId; + }, setUserId: function (value) { + if (!value || typeof value !== 'string' || value.trim().length === 0) + throw new Error('Missing or invalid userId parameter. Provide a valid string userId'); + this.userId = value; + }, getAuthKey: function () { + return this.authKey; + }, setAuthKey: function (authKey) { + this.authKey = authKey; + }, getFilterExpression: function () { + return this.filterExpression; + }, setFilterExpression: function (expression) { + this.filterExpression = expression; + }, get cipherKey() { + return this._cipherKey; + }, setCipherKey: function (key) { + this._cipherKey = key; + if (!key && this._cryptoModule) { + this._cryptoModule = undefined; + return; + } + else if (!key || !this._setupCryptoModule) + return; + this._cryptoModule = this._setupCryptoModule({ + cipherKey: key, + useRandomIVs: base.useRandomIVs, + customEncrypt: this.customEncrypt, + customDecrypt: this.customDecrypt, + }); + }, get cryptoModule() { + return this._cryptoModule; + }, + get useRandomIVs() { + return base.useRandomIVs; + }, getPresenceTimeout: function () { + return this.presenceTimeout; + }, getHeartbeatInterval: function () { + return this.heartbeatInterval; + }, setHeartbeatInterval: function (interval) { + this.heartbeatInterval = interval; + }, getTransactionTimeout: function () { + return this.transactionalRequestTimeout; + }, getSubscribeTimeout: function () { + return this.subscribeRequestTimeout; + }, get PubNubFile() { + return this.PubNubFile; + }, + get version() { + return '7.6.0'; + }, getVersion: function () { + return this.version; + }, _addPnsdkSuffix: function (name, suffix) { + this._pnsdkSuffix[name] = "".concat(suffix); + }, _getPnsdkSuffix: function (separator) { + return Object.values(this._pnsdkSuffix).join(separator); + }, + // -------------------------------------------------------- + // ---------------------- Deprecated ---------------------- + // -------------------------------------------------------- + // region Deprecated + getUUID: function () { + return this.getUserId(); + }, setUUID: function (value) { + this.setUserId(value); + }, get customEncrypt() { + return base.customEncrypt; + }, + get customDecrypt() { + return base.customDecrypt; + } }); + // Setup `CryptoModule` if possible. + if (base.cipherKey) + clientConfiguration.setCipherKey(base.cipherKey); + return clientConfiguration; +}; +exports.makeConfiguration = makeConfiguration; +/** + * Decide {@lin PubNub} service REST API origin. + * + * @param secure - Whether preferred to use secured connection or not. + * @param origin - User-provided or default origin. + * + * @returns `PubNub` REST API endpoints origin. + */ +var standardOrigin = function (secure, origin) { + var protocol = secure ? 'https://' : 'http://'; + if (typeof origin === 'string') + return "".concat(protocol).concat(origin); + return "".concat(protocol).concat(origin[Math.floor(Math.random() * origin.length)]); +}; diff --git a/lib/core/components/cryptography/index.js b/lib/core/components/cryptography/index.js index 19c58e51e..51c54f5f6 100644 --- a/lib/core/components/cryptography/index.js +++ b/lib/core/components/cryptography/index.js @@ -1,151 +1,276 @@ "use strict"; +/** + * Legacy cryptography module. + */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); var base64_codec_1 = require("../base64_codec"); var hmac_sha256_1 = __importDefault(require("./hmac-sha256")); +/** + * Convert bytes array to words array. + * + * @param b - Bytes array (buffer) which should be converted. + * + * @returns Word sized array. + */ +/* eslint-disable @typescript-eslint/no-explicit-any */ function bufferToWordArray(b) { var wa = []; var i; for (i = 0; i < b.length; i += 1) { wa[(i / 4) | 0] |= b[i] << (24 - 8 * i); } + // @ts-expect-error Bundled library without types. return hmac_sha256_1.default.lib.WordArray.create(wa, b.length); } var default_1 = /** @class */ (function () { - function default_1(_a) { - var config = _a.config; - this._config = config; - this._iv = '0123456789012345'; - this._allowedKeyEncodings = ['hex', 'utf8', 'base64', 'binary']; - this._allowedKeyLengths = [128, 256]; - this._allowedModes = ['ecb', 'cbc']; - this._defaultOptions = { + function default_1(configuration) { + this.configuration = configuration; + /** + * Crypto initialization vector. + */ + this.iv = '0123456789012345'; + /** + * List os allowed cipher key encodings. + */ + this.allowedKeyEncodings = ['hex', 'utf8', 'base64', 'binary']; + /** + * Allowed cipher key lengths. + */ + this.allowedKeyLengths = [128, 256]; + /** + * Allowed crypto modes. + */ + this.allowedModes = ['ecb', 'cbc']; + this.defaultOptions = { encryptKey: true, keyEncoding: 'utf8', keyLength: 256, mode: 'cbc', }; } + /** + * Generate HMAC-SHA256 hash from input data. + * + * @param data - Data from which hash should be generated. + * + * @returns HMAC-SHA256 hash from provided `data`. + */ default_1.prototype.HMACSHA256 = function (data) { - var hash = hmac_sha256_1.default.HmacSHA256(data, this._config.secretKey); + // @ts-expect-error Bundled library without types. + var hash = hmac_sha256_1.default.HmacSHA256(data, this.configuration.secretKey); + // @ts-expect-error Bundled library without types. return hash.toString(hmac_sha256_1.default.enc.Base64); }; - default_1.prototype.SHA256 = function (s) { - return hmac_sha256_1.default.SHA256(s).toString(hmac_sha256_1.default.enc.Hex); - }; - default_1.prototype._parseOptions = function (incomingOptions) { - // Defaults - var options = incomingOptions || {}; - if (!options.hasOwnProperty('encryptKey')) - options.encryptKey = this._defaultOptions.encryptKey; - if (!options.hasOwnProperty('keyEncoding')) - options.keyEncoding = this._defaultOptions.keyEncoding; - if (!options.hasOwnProperty('keyLength')) - options.keyLength = this._defaultOptions.keyLength; - if (!options.hasOwnProperty('mode')) - options.mode = this._defaultOptions.mode; - // Validation - if (this._allowedKeyEncodings.indexOf(options.keyEncoding.toLowerCase()) === -1) { - options.keyEncoding = this._defaultOptions.keyEncoding; - } - if (this._allowedKeyLengths.indexOf(parseInt(options.keyLength, 10)) === -1) { - options.keyLength = this._defaultOptions.keyLength; - } - if (this._allowedModes.indexOf(options.mode.toLowerCase()) === -1) { - options.mode = this._defaultOptions.mode; - } - return options; - }; - default_1.prototype._decodeKey = function (key, options) { - if (options.keyEncoding === 'base64') { - return hmac_sha256_1.default.enc.Base64.parse(key); - } - if (options.keyEncoding === 'hex') { - return hmac_sha256_1.default.enc.Hex.parse(key); - } - return key; - }; - default_1.prototype._getPaddedKey = function (key, options) { - key = this._decodeKey(key, options); - if (options.encryptKey) { - return hmac_sha256_1.default.enc.Utf8.parse(this.SHA256(key).slice(0, 32)); - } - return key; - }; - default_1.prototype._getMode = function (options) { - if (options.mode === 'ecb') { - return hmac_sha256_1.default.mode.ECB; - } - return hmac_sha256_1.default.mode.CBC; - }; - default_1.prototype._getIV = function (options) { - return options.mode === 'cbc' ? hmac_sha256_1.default.enc.Utf8.parse(this._iv) : null; - }; - default_1.prototype._getRandomIV = function () { - return hmac_sha256_1.default.lib.WordArray.random(16); + /** + * Generate SHA256 hash from input data. + * + * @param data - Data from which hash should be generated. + * + * @returns SHA256 hash from provided `data`. + */ + default_1.prototype.SHA256 = function (data) { + // @ts-expect-error Bundled library without types. + return hmac_sha256_1.default.SHA256(data).toString(hmac_sha256_1.default.enc.Hex); }; + /** + * Encrypt provided data. + * + * @param data - Source data which should be encrypted. + * @param [customCipherKey] - Custom cipher key (different from defined on client level). + * @param [options] - Specific crypto configuration options. + * + * @returns Encrypted `data`. + */ default_1.prototype.encrypt = function (data, customCipherKey, options) { - if (this._config.customEncrypt) { - return this._config.customEncrypt(data); - } + if (this.configuration.customEncrypt) + return this.configuration.customEncrypt(data); return this.pnEncrypt(data, customCipherKey, options); }; + /** + * Decrypt provided data. + * + * @param data - Encrypted data which should be decrypted. + * @param [customCipherKey] - Custom cipher key (different from defined on client level). + * @param [options] - Specific crypto configuration options. + * + * @returns Decrypted `data`. + */ default_1.prototype.decrypt = function (data, customCipherKey, options) { - if (this._config.customDecrypt) { - return this._config.customDecrypt(data); - } + if (this.configuration.customDecrypt) + return this.configuration.customDecrypt(data); return this.pnDecrypt(data, customCipherKey, options); }; + /** + * Encrypt provided data. + * + * @param data - Source data which should be encrypted. + * @param [customCipherKey] - Custom cipher key (different from defined on client level). + * @param [options] - Specific crypto configuration options. + * + * @returns Encrypted `data` as string. + */ default_1.prototype.pnEncrypt = function (data, customCipherKey, options) { - if (!customCipherKey && !this._config.cipherKey) + var decidedCipherKey = customCipherKey !== null && customCipherKey !== void 0 ? customCipherKey : this.configuration.cipherKey; + if (!decidedCipherKey) return data; - options = this._parseOptions(options); - var mode = this._getMode(options); - var cipherKey = this._getPaddedKey(customCipherKey || this._config.cipherKey, options); - if (this._config.useRandomIVs) { - var waIv = this._getRandomIV(); + options = this.parseOptions(options); + var mode = this.getMode(options); + var cipherKey = this.getPaddedKey(decidedCipherKey, options); + if (this.configuration.useRandomIVs) { + var waIv = this.getRandomIV(); + // @ts-expect-error Bundled library without types. var waPayload = hmac_sha256_1.default.AES.encrypt(data, cipherKey, { iv: waIv, mode: mode }).ciphertext; + // @ts-expect-error Bundled library without types. return waIv.clone().concat(waPayload.clone()).toString(hmac_sha256_1.default.enc.Base64); } - var iv = this._getIV(options); + var iv = this.getIV(options); + // @ts-expect-error Bundled library without types. var encryptedHexArray = hmac_sha256_1.default.AES.encrypt(data, cipherKey, { iv: iv, mode: mode }).ciphertext; + // @ts-expect-error Bundled library without types. var base64Encrypted = encryptedHexArray.toString(hmac_sha256_1.default.enc.Base64); return base64Encrypted || data; }; + /** + * Decrypt provided data. + * + * @param data - Encrypted data which should be decrypted. + * @param [customCipherKey] - Custom cipher key (different from defined on client level). + * @param [options] - Specific crypto configuration options. + * + * @returns Decrypted `data`. + */ default_1.prototype.pnDecrypt = function (data, customCipherKey, options) { - if (!customCipherKey && !this._config.cipherKey) + var decidedCipherKey = customCipherKey !== null && customCipherKey !== void 0 ? customCipherKey : this.configuration.cipherKey; + if (!decidedCipherKey) return data; - options = this._parseOptions(options); - var mode = this._getMode(options); - var cipherKey = this._getPaddedKey(customCipherKey || this._config.cipherKey, options); - if (this._config.useRandomIVs) { + options = this.parseOptions(options); + var mode = this.getMode(options); + var cipherKey = this.getPaddedKey(decidedCipherKey, options); + if (this.configuration.useRandomIVs) { var ciphertext = new Uint8ClampedArray((0, base64_codec_1.decode)(data)); var iv = bufferToWordArray(ciphertext.slice(0, 16)); var payload = bufferToWordArray(ciphertext.slice(16)); try { - var plainJSON = hmac_sha256_1.default.AES.decrypt({ ciphertext: payload }, cipherKey, { iv: iv, mode: mode }).toString(hmac_sha256_1.default.enc.Utf8); - var plaintext = JSON.parse(plainJSON); - return plaintext; + // @ts-expect-error Bundled library without types. + var plainJSON = hmac_sha256_1.default.AES.decrypt({ ciphertext: payload }, cipherKey, { iv: iv, mode: mode }).toString( + // @ts-expect-error Bundled library without types. + hmac_sha256_1.default.enc.Utf8); + return JSON.parse(plainJSON); } catch (e) { return null; } } else { - var iv = this._getIV(options); + var iv = this.getIV(options); try { + // @ts-expect-error Bundled library without types. var ciphertext = hmac_sha256_1.default.enc.Base64.parse(data); + // @ts-expect-error Bundled library without types. var plainJSON = hmac_sha256_1.default.AES.decrypt({ ciphertext: ciphertext }, cipherKey, { iv: iv, mode: mode }).toString(hmac_sha256_1.default.enc.Utf8); - var plaintext = JSON.parse(plainJSON); - return plaintext; + return JSON.parse(plainJSON); } catch (e) { return null; } } }; + /** + * Pre-process provided custom crypto configuration. + * + * @param incomingOptions - Configuration which should be pre-processed before use. + * + * @returns Normalized crypto configuration options. + */ + default_1.prototype.parseOptions = function (incomingOptions) { + var _a, _b, _c, _d; + if (!incomingOptions) + return this.defaultOptions; + // Defaults + var options = { + encryptKey: (_a = incomingOptions.encryptKey) !== null && _a !== void 0 ? _a : this.defaultOptions.encryptKey, + keyEncoding: (_b = incomingOptions.keyEncoding) !== null && _b !== void 0 ? _b : this.defaultOptions.keyEncoding, + keyLength: (_c = incomingOptions.keyLength) !== null && _c !== void 0 ? _c : this.defaultOptions.keyLength, + mode: (_d = incomingOptions.mode) !== null && _d !== void 0 ? _d : this.defaultOptions.mode, + }; + // Validation + if (this.allowedKeyEncodings.indexOf(options.keyEncoding.toLowerCase()) === -1) + options.keyEncoding = this.defaultOptions.keyEncoding; + if (this.allowedKeyLengths.indexOf(options.keyLength) === -1) + options.keyLength = this.defaultOptions.keyLength; + if (this.allowedModes.indexOf(options.mode.toLowerCase()) === -1) + options.mode = this.defaultOptions.mode; + return options; + }; + /** + * Decode provided cipher key. + * + * @param key - Key in `encoding` provided by `options`. + * @param options - Crypto configuration options with cipher key details. + * + * @returns Array buffer with decoded key. + */ + default_1.prototype.decodeKey = function (key, options) { + // @ts-expect-error Bundled library without types. + if (options.keyEncoding === 'base64') + return hmac_sha256_1.default.enc.Base64.parse(key); + // @ts-expect-error Bundled library without types. + if (options.keyEncoding === 'hex') + return hmac_sha256_1.default.enc.Hex.parse(key); + return key; + }; + /** + * Add padding to the cipher key. + * + * @param key - Key which should be padded. + * @param options - Crypto configuration options with cipher key details. + * + * @returns Properly padded cipher key. + */ + default_1.prototype.getPaddedKey = function (key, options) { + key = this.decodeKey(key, options); + // @ts-expect-error Bundled library without types. + if (options.encryptKey) + return hmac_sha256_1.default.enc.Utf8.parse(this.SHA256(key).slice(0, 32)); + return key; + }; + /** + * Cipher mode. + * + * @param options - Crypto configuration with information about cipher mode. + * + * @returns Crypto cipher mode. + */ + default_1.prototype.getMode = function (options) { + // @ts-expect-error Bundled library without types. + if (options.mode === 'ecb') + return hmac_sha256_1.default.mode.ECB; + // @ts-expect-error Bundled library without types. + return hmac_sha256_1.default.mode.CBC; + }; + /** + * Cipher initialization vector. + * + * @param options - Crypto configuration with information about cipher mode. + * + * @returns Initialization vector. + */ + default_1.prototype.getIV = function (options) { + // @ts-expect-error Bundled library without types. + return options.mode === 'cbc' ? hmac_sha256_1.default.enc.Utf8.parse(this.iv) : null; + }; + /** + * Random initialization vector. + * + * @returns Generated random initialization vector. + */ + default_1.prototype.getRandomIV = function () { + // @ts-expect-error Bundled library without types. + return hmac_sha256_1.default.lib.WordArray.random(16); + }; return default_1; }()); exports.default = default_1; diff --git a/lib/core/components/endpoint.js b/lib/core/components/endpoint.js deleted file mode 100644 index 6c837275f..000000000 --- a/lib/core/components/endpoint.js +++ /dev/null @@ -1,282 +0,0 @@ -"use strict"; -var __extends = (this && this.__extends) || (function () { - var extendStatics = function (d, b) { - extendStatics = Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || - function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; - return extendStatics(d, b); - }; - return function (d, b) { - if (typeof b !== "function" && b !== null) - throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); - extendStatics(d, b); - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); - }; -})(); -var __assign = (this && this.__assign) || function () { - __assign = Object.assign || function(t) { - for (var s, i = 1, n = arguments.length; i < n; i++) { - s = arguments[i]; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) - t[p] = s[p]; - } - return t; - }; - return __assign.apply(this, arguments); -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.signRequest = exports.generatePNSDK = exports.createValidationError = exports.PubNubError = void 0; -var uuid_1 = __importDefault(require("./uuid")); -var utils_1 = __importDefault(require("../utils")); -var operations_1 = __importDefault(require("../constants/operations")); -var categories_1 = __importDefault(require("../constants/categories")); -var PubNubError = /** @class */ (function (_super) { - __extends(PubNubError, _super); - function PubNubError(message, status) { - var _newTarget = this.constructor; - var _this = _super.call(this, message) || this; - _this.name = _this.constructor.name; - _this.status = status; - _this.message = message; - Object.setPrototypeOf(_this, _newTarget.prototype); - return _this; - } - return PubNubError; -}(Error)); -exports.PubNubError = PubNubError; -function createError(errorPayload, type) { - errorPayload.type = type; - errorPayload.error = true; - return errorPayload; -} -function createValidationError(message) { - return createError({ message: message }, 'validationError'); -} -exports.createValidationError = createValidationError; -function decideURL(endpoint, modules, incomingParams) { - if (endpoint.usePost && endpoint.usePost(modules, incomingParams)) { - return endpoint.postURL(modules, incomingParams); - } - if (endpoint.usePatch && endpoint.usePatch(modules, incomingParams)) { - return endpoint.patchURL(modules, incomingParams); - } - if (endpoint.useGetFile && endpoint.useGetFile(modules, incomingParams)) { - return endpoint.getFileURL(modules, incomingParams); - } - return endpoint.getURL(modules, incomingParams); -} -function generatePNSDK(config) { - if (config.sdkName) { - return config.sdkName; - } - var base = "PubNub-JS-".concat(config.sdkFamily); - if (config.partnerId) { - base += "-".concat(config.partnerId); - } - base += "/".concat(config.getVersion()); - var pnsdkSuffix = config._getPnsdkSuffix(' '); - if (pnsdkSuffix.length > 0) { - base += pnsdkSuffix; - } - return base; -} -exports.generatePNSDK = generatePNSDK; -function getHttpMethod(modules, endpoint, incomingParams) { - if (endpoint.usePost && endpoint.usePost(modules, incomingParams)) { - return 'POST'; - } - if (endpoint.usePatch && endpoint.usePatch(modules, incomingParams)) { - return 'PATCH'; - } - if (endpoint.useDelete && endpoint.useDelete(modules, incomingParams)) { - return 'DELETE'; - } - if (endpoint.useGetFile && endpoint.useGetFile(modules, incomingParams)) { - return 'GETFILE'; - } - return 'GET'; -} -function signRequest(modules, url, outgoingParams, incomingParams, endpoint) { - var config = modules.config, crypto = modules.crypto; - var httpMethod = getHttpMethod(modules, endpoint, incomingParams); - outgoingParams.timestamp = Math.floor(new Date().getTime() / 1000); - // This is because of a server-side bug, old publish using post should be deprecated - if (endpoint.getOperation() === 'PNPublishOperation' && - endpoint.usePost && - endpoint.usePost(modules, incomingParams)) { - httpMethod = 'GET'; - } - if (httpMethod === 'GETFILE') { - httpMethod = 'GET'; - } - var signInput = "".concat(httpMethod, "\n").concat(config.publishKey, "\n").concat(url, "\n").concat(utils_1.default.signPamFromParams(outgoingParams), "\n"); - if (httpMethod === 'POST') { - var payload = endpoint.postPayload(modules, incomingParams); - if (typeof payload === 'string') { - signInput += payload; - } - else { - signInput += JSON.stringify(payload); - } - } - else if (httpMethod === 'PATCH') { - var payload = endpoint.patchPayload(modules, incomingParams); - if (typeof payload === 'string') { - signInput += payload; - } - else { - signInput += JSON.stringify(payload); - } - } - var signature = "v2.".concat(crypto.HMACSHA256(signInput)); - signature = signature.replace(/\+/g, '-'); - signature = signature.replace(/\//g, '_'); - signature = signature.replace(/=+$/, ''); - outgoingParams.signature = signature; -} -exports.signRequest = signRequest; -function default_1(modules, endpoint) { - var args = []; - for (var _i = 2; _i < arguments.length; _i++) { - args[_i - 2] = arguments[_i]; - } - var networking = modules.networking, config = modules.config, telemetryManager = modules.telemetryManager, tokenManager = modules.tokenManager; - var requestId = uuid_1.default.createUUID(); - var callback = null; - var promiseComponent = null; - var incomingParams = {}; - if (endpoint.getOperation() === operations_1.default.PNTimeOperation || - endpoint.getOperation() === operations_1.default.PNChannelGroupsOperation) { - callback = args[0]; - } - else { - incomingParams = args[0]; - callback = args[1]; - } - // bridge in Promise support. - if (typeof Promise !== 'undefined' && !callback) { - promiseComponent = utils_1.default.createPromise(); - } - var validationResult = endpoint.validateParams(modules, incomingParams); - if (validationResult) { - if (callback) { - return callback(createValidationError(validationResult)); - } - if (promiseComponent) { - promiseComponent.reject(new PubNubError('Validation failed, check status for details', createValidationError(validationResult))); - return promiseComponent.promise; - } - return; - } - var outgoingParams = endpoint.prepareParams(modules, incomingParams); - var url = decideURL(endpoint, modules, incomingParams); - var callInstance; - var networkingParams = { - url: url, - operation: endpoint.getOperation(), - timeout: endpoint.getRequestTimeout(modules), - headers: endpoint.getRequestHeaders ? endpoint.getRequestHeaders() : {}, - ignoreBody: typeof endpoint.ignoreBody === 'function' ? endpoint.ignoreBody(modules) : false, - forceBuffered: typeof endpoint.forceBuffered === 'function' ? endpoint.forceBuffered(modules, incomingParams) : null, - abortSignal: typeof endpoint.getAbortSignal === 'function' ? endpoint.getAbortSignal(modules, incomingParams) : null, - }; - outgoingParams.uuid = config.UUID; - outgoingParams.pnsdk = generatePNSDK(config); - // Add telemetry information (if there is any available). - var telemetryLatencies = telemetryManager.operationsLatencyForRequest(); - if (Object.keys(telemetryLatencies).length) { - outgoingParams = __assign(__assign({}, outgoingParams), telemetryLatencies); - } - if (config.useInstanceId) { - outgoingParams.instanceid = config.instanceId; - } - if (config.useRequestId) { - outgoingParams.requestid = requestId; - } - if (endpoint.isAuthSupported()) { - var tokenOrKey = tokenManager.getToken() || config.getAuthKey(); - if (tokenOrKey) { - outgoingParams.auth = tokenOrKey; - } - } - if (config.secretKey) { - signRequest(modules, url, outgoingParams, incomingParams, endpoint); - } - var onResponse = function (status, payload) { - if (status.error) { - if (endpoint.handleError) { - endpoint.handleError(modules, incomingParams, status); - } - if (callback) { - callback(status); - } - else if (promiseComponent) { - promiseComponent.reject(new PubNubError('PubNub call failed, check status for details', status)); - } - return; - } - // Stop endpoint latency tracking. - telemetryManager.stopLatencyMeasure(endpoint.getOperation(), requestId); - var responseP = endpoint.handleResponse(modules, payload, incomingParams); - if (typeof (responseP === null || responseP === void 0 ? void 0 : responseP.then) !== 'function') { - responseP = Promise.resolve(responseP); - } - responseP - .then(function (result) { - if (callback) { - callback(status, result); - } - else if (promiseComponent) { - promiseComponent.fulfill(result); - } - }) - .catch(function (e) { - if (callback) { - var errorData = e; - if (endpoint.getOperation() === operations_1.default.PNSubscribeOperation) { - errorData = { - statusCode: 400, - error: true, - operation: endpoint.getOperation(), - errorData: e, - category: categories_1.default.PNUnknownCategory, - }; - } - callback(errorData, null); - } - else if (promiseComponent) { - promiseComponent.reject(new PubNubError('PubNub call failed, check status for details', e)); - } - }); - }; - // Start endpoint latency tracking. - telemetryManager.startLatencyMeasure(endpoint.getOperation(), requestId); - if (getHttpMethod(modules, endpoint, incomingParams) === 'POST') { - var payload = endpoint.postPayload(modules, incomingParams); - callInstance = networking.POST(outgoingParams, payload, networkingParams, onResponse); - } - else if (getHttpMethod(modules, endpoint, incomingParams) === 'PATCH') { - var payload = endpoint.patchPayload(modules, incomingParams); - callInstance = networking.PATCH(outgoingParams, payload, networkingParams, onResponse); - } - else if (getHttpMethod(modules, endpoint, incomingParams) === 'DELETE') { - callInstance = networking.DELETE(outgoingParams, networkingParams, onResponse); - } - else if (getHttpMethod(modules, endpoint, incomingParams) === 'GETFILE') { - callInstance = networking.GETFILE(outgoingParams, networkingParams, onResponse); - } - else { - callInstance = networking.GET(outgoingParams, networkingParams, onResponse); - } - if (endpoint.getOperation() === operations_1.default.PNSubscribeOperation) { - return callInstance; - } - if (promiseComponent) { - return promiseComponent.promise; - } -} -exports.default = default_1; diff --git a/lib/core/components/eventEmitter.js b/lib/core/components/eventEmitter.js index 06c8dc8eb..0ab3c270c 100644 --- a/lib/core/components/eventEmitter.js +++ b/lib/core/components/eventEmitter.js @@ -22,262 +22,166 @@ var __rest = (this && this.__rest) || function (s, e) { return t; }; Object.defineProperty(exports, "__esModule", { value: true }); +var subscribe_1 = require("../endpoints/subscribe"); var EventEmitter = /** @class */ (function () { - function EventEmitter(_a) { - var modules = _a.modules, listenerManager = _a.listenerManager, getFileUrl = _a.getFileUrl; - this.modules = modules; + function EventEmitter(listenerManager) { this.listenerManager = listenerManager; - this.getFileUrl = getFileUrl; - this._channelListenerMap = new Map(); - this._groupListenerMap = new Map(); - if (modules.cryptoModule) - this._decoder = new TextDecoder(); + /** + * Map of channels to listener callbacks for them. + */ + this.channelListenerMap = new Map(); + /** + * Map of channel group names to the listener callbacks for them. + */ + this.groupListenerMap = new Map(); } - EventEmitter.prototype.emitEvent = function (e) { - var channel = e.channel, publishMetaData = e.publishMetaData; - var subscriptionMatch = e.subscriptionMatch; - if (channel === subscriptionMatch) { - subscriptionMatch = null; + /** + * Emit specific real-time event. + * + * Proper listener will be notified basing on event `type`. + * + * @param event - Received real-time event. + */ + EventEmitter.prototype.emitEvent = function (event) { + if (event.type === subscribe_1.PubNubEventType.Message) { + this.listenerManager.announceMessage(event.data); + this.announce('message', event.data, event.data.channel, event.data.subscription); } - if (e.channel.endsWith('-pnpres')) { - var announce = {}; - announce.channel = null; - announce.subscription = null; - if (channel) { - announce.channel = channel.substring(0, channel.lastIndexOf('-pnpres')); - } - if (subscriptionMatch) { - announce.subscription = subscriptionMatch.substring(0, subscriptionMatch.lastIndexOf('-pnpres')); - } - announce.action = e.payload.action; - announce.state = e.payload.data; - announce.timetoken = publishMetaData.publishTimetoken; - announce.occupancy = e.payload.occupancy; - announce.uuid = e.payload.uuid; - announce.timestamp = e.payload.timestamp; - if (e.payload.join) { - announce.join = e.payload.join; - } - if (e.payload.leave) { - announce.leave = e.payload.leave; - } - if (e.payload.timeout) { - announce.timeout = e.payload.timeout; - } - // deprecated --> - announce.actualChannel = subscriptionMatch != null ? channel : null; - announce.subscribedChannel = subscriptionMatch != null ? subscriptionMatch : channel; - // <-- deprecated - this.listenerManager.announcePresence(announce); - this._announce('presence', announce, announce.channel, announce.subscription); + else if (event.type === subscribe_1.PubNubEventType.Signal) { + this.listenerManager.announceSignal(event.data); + this.announce('signal', event.data, event.data.channel, event.data.subscription); } - else if (e.messageType === 1) { - var announce = {}; - announce.channel = null; - announce.subscription = null; - announce.channel = channel; - announce.subscription = subscriptionMatch; - announce.timetoken = publishMetaData.publishTimetoken; - announce.publisher = e.issuingClientId; - if (e.userMetadata) { - announce.userMetadata = e.userMetadata; - } - announce.message = e.payload; - this.listenerManager.announceSignal(announce); - this._announce('signal', announce, announce.channel, announce.subscription); + else if (event.type === subscribe_1.PubNubEventType.Presence) { + this.listenerManager.announcePresence(event.data); + this.announce('presence', event.data, event.data.channel, event.data.subscription); } - else if (e.messageType === 2) { - var announce = {}; - announce.channel = null; - announce.subscription = null; - announce.channel = channel; - announce.subscription = subscriptionMatch; - announce.timetoken = publishMetaData.publishTimetoken; - announce.publisher = e.issuingClientId; - if (e.userMetadata) { - announce.userMetadata = e.userMetadata; - } - announce.message = { - event: e.payload.event, - type: e.payload.type, - data: e.payload.data, - }; - this.listenerManager.announceObjects(announce); - this._announce('objects', announce, announce.channel, announce.subscription); - if (e.payload.type === 'uuid') { - var eventData = this._renameChannelField(announce); - var userEvent = __assign(__assign({}, eventData), { message: __assign(__assign({}, eventData.message), { event: this._renameEvent(eventData.message.event), type: 'user' }) }); + else if (event.type === subscribe_1.PubNubEventType.AppContext) { + var objectEvent = event.data; + var object = objectEvent.message; + this.listenerManager.announceObjects(objectEvent); + this.announce('objects', objectEvent, objectEvent.channel, objectEvent.subscription); + if (object.type === 'uuid') { + var message = objectEvent.message, channel = objectEvent.channel, restEvent = __rest(objectEvent, ["message", "channel"]); + var event_1 = object.event, type = object.type, restObject = __rest(object, ["event", "type"]); + var userEvent = __assign(__assign({}, restEvent), { spaceId: channel, message: __assign(__assign({}, restObject), { event: event_1 === 'set' ? 'updated' : 'removed', type: 'user' }) }); this.listenerManager.announceUser(userEvent); - this._announce('user', userEvent, announce.channel, announce.subscription); + this.announce('user', userEvent, userEvent.spaceId, userEvent.subscription); } - else if (message.payload.type === 'channel') { - var eventData = this._renameChannelField(announce); - var spaceEvent = __assign(__assign({}, eventData), { message: __assign(__assign({}, eventData.message), { event: this._renameEvent(eventData.message.event), type: 'space' }) }); + else if (object.type === 'channel') { + var message = objectEvent.message, channel = objectEvent.channel, restEvent = __rest(objectEvent, ["message", "channel"]); + var event_2 = object.event, type = object.type, restObject = __rest(object, ["event", "type"]); + var spaceEvent = __assign(__assign({}, restEvent), { spaceId: channel, message: __assign(__assign({}, restObject), { event: event_2 === 'set' ? 'updated' : 'removed', type: 'space' }) }); this.listenerManager.announceSpace(spaceEvent); - this._announce('space', spaceEvent, announce.channel, announce.subscription); + this.announce('space', spaceEvent, spaceEvent.spaceId, spaceEvent.subscription); } - else if (message.payload.type === 'membership') { - var eventData = this._renameChannelField(announce); - var _a = eventData.message.data, user = _a.uuid, space = _a.channel, membershipData = __rest(_a, ["uuid", "channel"]); - membershipData.user = user; - membershipData.space = space; - var membershipEvent = __assign(__assign({}, eventData), { message: __assign(__assign({}, eventData.message), { event: this._renameEvent(eventData.message.event), data: membershipData }) }); + else if (object.type === 'membership') { + var message = objectEvent.message, channel = objectEvent.channel, restEvent = __rest(objectEvent, ["message", "channel"]); + var event_3 = object.event, data = object.data, restObject = __rest(object, ["event", "data"]); + var uuid = data.uuid, channelMeta = data.channel, restData = __rest(data, ["uuid", "channel"]); + var membershipEvent = __assign(__assign({}, restEvent), { spaceId: channel, message: __assign(__assign({}, restObject), { event: event_3 === 'set' ? 'updated' : 'removed', data: __assign(__assign({}, restData), { user: uuid, space: channelMeta }) }) }); this.listenerManager.announceMembership(membershipEvent); - this._announce('membership', membershipEvent, announce.channel, announce.subscription); + this.announce('membership', membershipEvent, membershipEvent.spaceId, membershipEvent.subscription); } } - else if (e.messageType === 3) { - var announce = {}; - announce.channel = channel; - announce.subscription = subscriptionMatch; - announce.timetoken = publishMetaData.publishTimetoken; - announce.publisher = e.issuingClientId; - announce.data = { - messageTimetoken: e.payload.data.messageTimetoken, - actionTimetoken: e.payload.data.actionTimetoken, - type: e.payload.data.type, - uuid: e.issuingClientId, - value: e.payload.data.value, - }; - announce.event = e.payload.event; - this.listenerManager.announceMessageAction(announce); - this._announce('messageAction', announce, announce.channel, announce.subscription); + else if (event.type === subscribe_1.PubNubEventType.MessageAction) { + this.listenerManager.announceMessageAction(event.data); + this.announce('messageAction', event.data, event.data.channel, event.data.subscription); } - else if (e.messageType === 4) { - var announce = {}; - announce.channel = channel; - announce.subscription = subscriptionMatch; - announce.timetoken = publishMetaData.publishTimetoken; - announce.publisher = e.issuingClientId; - var msgPayload = e.payload; - if (this.modules.cryptoModule) { - var decryptedPayload = void 0; - try { - var decryptedData = this.modules.cryptoModule.decrypt(e.payload); - decryptedPayload = - decryptedData instanceof ArrayBuffer ? JSON.parse(this._decoder.decode(decryptedData)) : decryptedData; - } - catch (e) { - decryptedPayload = null; - announce.error = "Error while decrypting message content: ".concat(e.message); - } - if (decryptedPayload !== null) { - msgPayload = decryptedPayload; - } - } - if (e.userMetadata) { - announce.userMetadata = e.userMetadata; - } - announce.message = msgPayload.message; - announce.file = { - id: msgPayload.file.id, - name: msgPayload.file.name, - url: this.getFileUrl({ - id: msgPayload.file.id, - name: msgPayload.file.name, - channel: channel, - }), - }; - this.listenerManager.announceFile(announce); - this._announce('file', announce, announce.channel, announce.subscription); - } - else { - var announce = {}; - announce.channel = null; - announce.subscription = null; - announce.channel = channel; - announce.subscription = subscriptionMatch; - announce.timetoken = publishMetaData.publishTimetoken; - announce.publisher = e.issuingClientId; - if (e.userMetadata) { - announce.userMetadata = e.userMetadata; - } - if (this.modules.cryptoModule) { - var decryptedPayload = void 0; - try { - var decryptedData = this.modules.cryptoModule.decrypt(e.payload); - decryptedPayload = - decryptedData instanceof ArrayBuffer ? JSON.parse(this._decoder.decode(decryptedData)) : decryptedData; - } - catch (e) { - decryptedPayload = null; - announce.error = "Error while decrypting message content: ".concat(e.message); - } - if (decryptedPayload != null) { - announce.message = decryptedPayload; - } - else { - announce.message = e.payload; - } - } - else { - announce.message = e.payload; - } - // deprecated --> - announce.actualChannel = subscriptionMatch != null ? channel : null; - announce.subscribedChannel = subscriptionMatch != null ? subscriptionMatch : channel; - // <-- deprecated - this.listenerManager.announceMessage(announce); - this._announce('message', announce, announce.channel, announce.subscription); + else if (event.type === subscribe_1.PubNubEventType.Files) { + this.listenerManager.announceFile(event.data); + this.announce('file', event.data, event.data.channel, event.data.subscription); } }; - EventEmitter.prototype.addListener = function (l, channels, groups) { + /** + * Register real-time event listener for specific channels and groups. + * + * @param listener - Listener with event callbacks to handle different types of events. + * @param channels - List of channels for which listener should be registered. + * @param groups - List of channel groups for which listener should be registered. + */ + EventEmitter.prototype.addListener = function (listener, channels, groups) { var _this = this; + // Register event-listener listener globally. if (!(channels && groups)) { - this.listenerManager.addListener(l); + this.listenerManager.addListener(listener); } else { - channels === null || channels === void 0 ? void 0 : channels.forEach(function (c) { - if (_this._channelListenerMap[c]) { - if (!_this._channelListenerMap[c].includes(l)) - _this._channelListenerMap[c].push(l); - } - else { - _this._channelListenerMap[c] = [l]; + channels === null || channels === void 0 ? void 0 : channels.forEach(function (channel) { + if (_this.channelListenerMap.has(channel)) { + var channelListeners = _this.channelListenerMap.get(channel); + if (!channelListeners.includes(listener)) + channelListeners.push(listener); } + else + _this.channelListenerMap.set(channel, [listener]); }); - groups === null || groups === void 0 ? void 0 : groups.forEach(function (g) { - if (_this._groupListenerMap[g]) { - if (!_this._groupListenerMap[g].includes(l)) - _this._groupListenerMap[g].push(l); - } - else { - _this._groupListenerMap[g] = [l]; + groups === null || groups === void 0 ? void 0 : groups.forEach(function (group) { + if (_this.groupListenerMap.has(group)) { + var groupListeners = _this.groupListenerMap.get(group); + if (!groupListeners.includes(listener)) + groupListeners.push(listener); } + else + _this.groupListenerMap.set(group, [listener]); }); } }; + /** + * Remove real-time event listener. + * + * @param listener - Event listeners which should be removed. + * @param channels - List of channels for which listener should be removed. + * @param groups - List of channel groups for which listener should be removed. + */ EventEmitter.prototype.removeListener = function (listener, channels, groups) { var _this = this; if (!(channels && groups)) { this.listenerManager.removeListener(listener); } else { - channels === null || channels === void 0 ? void 0 : channels.forEach(function (c) { - var _a; - _this._channelListenerMap[c] = (_a = _this._channelListenerMap[c]) === null || _a === void 0 ? void 0 : _a.filter(function (l) { return l !== listener; }); + channels === null || channels === void 0 ? void 0 : channels.forEach(function (channel) { + if (_this.channelListenerMap.has(channel)) { + _this.channelListenerMap.set(channel, _this.channelListenerMap.get(channel).filter(function (channelListener) { return channelListener !== listener; })); + } }); - groups === null || groups === void 0 ? void 0 : groups.forEach(function (g) { - var _a; - _this._groupListenerMap[g] = (_a = _this._groupListenerMap[g]) === null || _a === void 0 ? void 0 : _a.filter(function (l) { return l !== listener; }); + groups === null || groups === void 0 ? void 0 : groups.forEach(function (group) { + if (_this.groupListenerMap.has(group)) { + _this.groupListenerMap.set(group, _this.groupListenerMap.get(group).filter(function (groupListener) { return groupListener !== listener; })); + } }); } }; + /** + * Clear all real-time event listeners. + */ EventEmitter.prototype.removeAllListeners = function () { this.listenerManager.removeAllListeners(); + this.channelListenerMap.clear(); + this.groupListenerMap.clear(); }; - EventEmitter.prototype._renameEvent = function (e) { - return e === 'set' ? 'updated' : 'removed'; - }; - EventEmitter.prototype._renameChannelField = function (announce) { - var channel = announce.channel, eventData = __rest(announce, ["channel"]); - eventData.spaceId = channel; - return eventData; - }; - EventEmitter.prototype._announce = function (type, event, channel, group) { - var _a, _b; - (_a = this._channelListenerMap[channel]) === null || _a === void 0 ? void 0 : _a.forEach(function (l) { return l[type] && l[type](event); }); - (_b = this._groupListenerMap[group]) === null || _b === void 0 ? void 0 : _b.forEach(function (l) { return l[type] && l[type](event); }); + /** + * Announce real-time event to all listeners. + * + * @param type - Type of event which should be announced. + * @param event - Announced real-time event payload. + * @param channel - Name of the channel for which registered listeners should be notified. + * @param group - Name of the channel group for which registered listeners should be notified. + */ + EventEmitter.prototype.announce = function (type, event, channel, group) { + if (event && this.channelListenerMap.has(channel)) + this.channelListenerMap.get(channel).forEach(function (listener) { + var typedListener = listener[type]; + // @ts-expect-error Dynamic events mapping. + if (typedListener) + typedListener(event); + }); + if (group && this.groupListenerMap.has(group)) + this.groupListenerMap.get(group).forEach(function (listener) { + var typedListener = listener[type]; + // @ts-expect-error Dynamic events mapping. + if (typedListener) + typedListener(event); + }); }; return EventEmitter; }()); diff --git a/lib/core/components/listener_manager.js b/lib/core/components/listener_manager.js index 9518fb550..548bb0c48 100644 --- a/lib/core/components/listener_manager.js +++ b/lib/core/components/listener_manager.js @@ -1,100 +1,192 @@ "use strict"; +/** + * Events listener manager module. + */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); +exports.ListenerManager = void 0; var categories_1 = __importDefault(require("../constants/categories")); -var default_1 = /** @class */ (function () { - function default_1() { - this._listeners = []; +/** + * Real-time listeners' manager. + */ +var ListenerManager = /** @class */ (function () { + function ListenerManager() { + /** + * List of registered event listeners. + */ + this.listeners = []; + // endregion } - default_1.prototype.addListener = function (newListener) { - if (this._listeners.includes(newListener)) { + /** + * Register new real-time events listener. + * + * @param listener - Listener with event callbacks to handle different types of events. + */ + ListenerManager.prototype.addListener = function (listener) { + if (this.listeners.includes(listener)) return; - } - this._listeners.push(newListener); + this.listeners.push(listener); }; - default_1.prototype.removeListener = function (deprecatedListener) { - var newListeners = []; - this._listeners.forEach(function (listener) { - if (listener !== deprecatedListener) - newListeners.push(listener); - }); - this._listeners = newListeners; + /** + * Remove real-time event listener. + * + * @param listener - Event listeners which should be removed. + */ + ListenerManager.prototype.removeListener = function (listener) { + this.listeners = this.listeners.filter(function (storedListener) { return storedListener !== listener; }); }; - default_1.prototype.removeAllListeners = function () { - this._listeners = []; + /** + * Clear all real-time event listeners. + */ + ListenerManager.prototype.removeAllListeners = function () { + this.listeners = []; }; - default_1.prototype.announcePresence = function (announce) { - this._listeners.forEach(function (listener) { - if (listener.presence) - listener.presence(announce); + /** + * Announce PubNub client status change event. + * + * @param status - PubNub client status. + */ + ListenerManager.prototype.announceStatus = function (status) { + this.listeners.forEach(function (listener) { + if (listener.status) + listener.status(status); }); }; - default_1.prototype.announceStatus = function (announce) { - this._listeners.forEach(function (listener) { - if (listener.status) - listener.status(announce); + /** + * Announce channel presence change event. + * + * @param presence - Channel presence change information. + */ + ListenerManager.prototype.announcePresence = function (presence) { + this.listeners.forEach(function (listener) { + if (listener.presence) + listener.presence(presence); }); }; - default_1.prototype.announceMessage = function (announce) { - this._listeners.forEach(function (listener) { + /** + * Announce real-time message event. + * + * @param message - Received real-time message. + */ + ListenerManager.prototype.announceMessage = function (message) { + this.listeners.forEach(function (listener) { if (listener.message) - listener.message(announce); + listener.message(message); }); }; - default_1.prototype.announceSignal = function (announce) { - this._listeners.forEach(function (listener) { + /** + * Announce real-time signal event. + * + * @param signal - Received real-time signal. + */ + ListenerManager.prototype.announceSignal = function (signal) { + this.listeners.forEach(function (listener) { if (listener.signal) - listener.signal(announce); + listener.signal(signal); }); }; - default_1.prototype.announceMessageAction = function (announce) { - this._listeners.forEach(function (listener) { + /** + * Announce message actions change event. + * + * @param messageAction - Message action change information. + */ + ListenerManager.prototype.announceMessageAction = function (messageAction) { + this.listeners.forEach(function (listener) { if (listener.messageAction) - listener.messageAction(announce); + listener.messageAction(messageAction); }); }; - default_1.prototype.announceFile = function (announce) { - this._listeners.forEach(function (listener) { + /** + * Announce fie share event. + * + * @param file - Shared file information. + */ + ListenerManager.prototype.announceFile = function (file) { + this.listeners.forEach(function (listener) { if (listener.file) - listener.file(announce); + listener.file(file); }); }; - default_1.prototype.announceObjects = function (announce) { - this._listeners.forEach(function (listener) { + /** + * Announce App Context Object change event. + * + * @param object - App Context change information. + */ + ListenerManager.prototype.announceObjects = function (object) { + this.listeners.forEach(function (listener) { if (listener.objects) - listener.objects(announce); + listener.objects(object); }); }; - default_1.prototype.announceUser = function (announce) { - this._listeners.forEach(function (listener) { + /** + * Announce network up status. + */ + ListenerManager.prototype.announceNetworkUp = function () { + this.listeners.forEach(function (listener) { + if (listener.status) { + listener.status({ + category: categories_1.default.PNNetworkUpCategory, + }); + } + }); + }; + /** + * Announce network down status. + */ + ListenerManager.prototype.announceNetworkDown = function () { + this.listeners.forEach(function (listener) { + if (listener.status) { + listener.status({ + category: categories_1.default.PNNetworkDownCategory, + }); + } + }); + }; + // -------------------------------------------------------- + // ---------------------- Deprecated ---------------------- + // -------------------------------------------------------- + // region Deprecated + /** + * Announce User App Context Object change event. + * + * @param user - User App Context change information. + * + * @deprecated Use {@link announceObjects} method instead. + */ + ListenerManager.prototype.announceUser = function (user) { + this.listeners.forEach(function (listener) { if (listener.user) - listener.user(announce); + listener.user(user); }); }; - default_1.prototype.announceSpace = function (announce) { - this._listeners.forEach(function (listener) { + /** + * Announce Space App Context Object change event. + * + * @param space - Space App Context change information. + * + * @deprecated Use {@link announceObjects} method instead. + */ + ListenerManager.prototype.announceSpace = function (space) { + this.listeners.forEach(function (listener) { if (listener.space) - listener.space(announce); + listener.space(space); }); }; - default_1.prototype.announceMembership = function (announce) { - this._listeners.forEach(function (listener) { + /** + * Announce VSP Membership App Context Object change event. + * + * @param membership - VSP Membership App Context change information. + * + * @deprecated Use {@link announceObjects} method instead. + */ + ListenerManager.prototype.announceMembership = function (membership) { + this.listeners.forEach(function (listener) { if (listener.membership) - listener.membership(announce); + listener.membership(membership); }); }; - default_1.prototype.announceNetworkUp = function () { - var networkStatus = {}; - networkStatus.category = categories_1.default.PNNetworkUpCategory; - this.announceStatus(networkStatus); - }; - default_1.prototype.announceNetworkDown = function () { - var networkStatus = {}; - networkStatus.category = categories_1.default.PNNetworkDownCategory; - this.announceStatus(networkStatus); - }; - return default_1; + return ListenerManager; }()); -exports.default = default_1; +exports.ListenerManager = ListenerManager; diff --git a/lib/core/components/reconnection_manager.js b/lib/core/components/reconnection_manager.js index 26d293dc0..118da420a 100644 --- a/lib/core/components/reconnection_manager.js +++ b/lib/core/components/reconnection_manager.js @@ -1,28 +1,48 @@ "use strict"; +/** + * Subscription reconnection-manager. + * + * **Note:** Reconnection manger rely on legacy time-based availability check. + */ Object.defineProperty(exports, "__esModule", { value: true }); -var default_1 = /** @class */ (function () { - function default_1(_a) { - var timeEndpoint = _a.timeEndpoint; - this._timeEndpoint = timeEndpoint; +exports.ReconnectionManager = void 0; +var ReconnectionManager = /** @class */ (function () { + function ReconnectionManager(time) { + this.time = time; } - default_1.prototype.onReconnection = function (reconnectionCallback) { - this._reconnectionCallback = reconnectionCallback; + /** + * Configure reconnection handler. + * + * @param callback - Successful availability check notify callback. + */ + ReconnectionManager.prototype.onReconnect = function (callback) { + this.callback = callback; }; - default_1.prototype.startPolling = function () { - this._timeTimer = setInterval(this._performTimeLoop.bind(this), 3000); + /** + * Start periodic "availability" check. + */ + ReconnectionManager.prototype.startPolling = function () { + var _this = this; + this.timeTimer = setInterval(function () { return _this.callTime(); }, 3000); }; - default_1.prototype.stopPolling = function () { - clearInterval(this._timeTimer); + /** + * Stop periodic "availability" check. + */ + ReconnectionManager.prototype.stopPolling = function () { + if (this.timeTimer) + clearInterval(this.timeTimer); + this.timeTimer = null; }; - default_1.prototype._performTimeLoop = function () { + ReconnectionManager.prototype.callTime = function () { var _this = this; - this._timeEndpoint(function (status) { + this.time(function (status) { if (!status.error) { - clearInterval(_this._timeTimer); - _this._reconnectionCallback(); + _this.stopPolling(); + if (_this.callback) + _this.callback(); } }); }; - return default_1; + return ReconnectionManager; }()); -exports.default = default_1; +exports.ReconnectionManager = ReconnectionManager; diff --git a/lib/core/components/request.js b/lib/core/components/request.js new file mode 100644 index 000000000..d9e65f5c1 --- /dev/null +++ b/lib/core/components/request.js @@ -0,0 +1,243 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +var __read = (this && this.__read) || function (o, n) { + var m = typeof Symbol === "function" && o[Symbol.iterator]; + if (!m) return o; + var i = m.call(o), r, ar = [], e; + try { + while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); + } + catch (error) { e = { error: error }; } + finally { + try { + if (r && !r.done && (m = i["return"])) m.call(i); + } + finally { if (e) throw e.error; } + } + return ar; +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.AbstractRequest = void 0; +var transport_request_1 = require("../types/transport-request"); +var uuid_1 = __importDefault(require("./uuid")); +/** + * Base REST API request class. + */ +var AbstractRequest = /** @class */ (function () { + /** + * Construct base request. + * + * Constructed request by default won't be cancellable and performed using `GET` HTTP method. + * + * @param params - Request configuration parameters. + */ + function AbstractRequest(params) { + this.params = params; + this._cancellationController = null; + } + Object.defineProperty(AbstractRequest.prototype, "cancellationController", { + /** + * Retrieve configured cancellation controller. + * + * @returns Cancellation controller. + */ + get: function () { + return this._cancellationController; + }, + /** + * Update request cancellation controller. + * + * Controller itself provided by transport provider implementation and set only when request + * sending has been scheduled. + * + * @param controller - Cancellation controller or `null` to reset it. + */ + set: function (controller) { + this._cancellationController = controller; + }, + enumerable: false, + configurable: true + }); + /** + * Abort request if possible. + */ + AbstractRequest.prototype.abort = function () { + if (this.cancellationController) + this.cancellationController.abort(); + }; + /** + * Target REST API endpoint operation type. + */ + AbstractRequest.prototype.operation = function () { + throw Error('Should be implemented by subclass.'); + }; + /** + * Validate user-provided data before scheduling request. + * + * @returns Error message if request can't be sent without missing or malformed parameters. + */ + AbstractRequest.prototype.validate = function () { + return undefined; + }; + /** + * Parse service response. + * + * @param _response - Raw service response which should be parsed. + */ + AbstractRequest.prototype.parse = function (_response) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + throw Error('Should be implemented by subclass.'); + }); + }); + }; + /** + * Create platform-agnostic request object. + * + * @returns Request object which can be processed using platform-specific requirements. + */ + AbstractRequest.prototype.request = function () { + var _a, _b, _c, _d; + var request = { + method: (_b = (_a = this.params) === null || _a === void 0 ? void 0 : _a.method) !== null && _b !== void 0 ? _b : transport_request_1.TransportMethod.GET, + path: this.path, + queryParameters: this.queryParameters, + cancellable: (_d = (_c = this.params) === null || _c === void 0 ? void 0 : _c.cancellable) !== null && _d !== void 0 ? _d : false, + timeout: 10000, + identifier: uuid_1.default.createUUID(), + }; + // Attach headers (if required). + var headers = this.headers; + if (headers) + request.headers = headers; + // Attach body (if required). + if (request.method === transport_request_1.TransportMethod.POST || request.method === transport_request_1.TransportMethod.PATCH) { + var _e = __read([this.body, this.formData], 2), body = _e[0], formData = _e[1]; + if (formData) + request.formData = formData; + if (body) + request.body = body; + } + return request; + }; + Object.defineProperty(AbstractRequest.prototype, "headers", { + /** + * Target REST API endpoint request headers getter. + * + * @returns Key/value headers which should be used with request. + */ + get: function () { + return undefined; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(AbstractRequest.prototype, "path", { + /** + * Target REST API endpoint request path getter. + * + * @returns REST API path. + */ + get: function () { + throw Error('`path` getter should be implemented by subclass.'); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(AbstractRequest.prototype, "queryParameters", { + /** + * Target REST API endpoint request query parameters getter. + * + * @returns Key/value pairs which should be appended to the REST API path. + */ + get: function () { + return {}; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(AbstractRequest.prototype, "formData", { + get: function () { + return undefined; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(AbstractRequest.prototype, "body", { + /** + * Target REST API Request body payload getter. + * + * @returns Buffer of stringified data which should be sent with `POST` or `PATCH` request. + */ + get: function () { + return undefined; + }, + enumerable: false, + configurable: true + }); + /** + * Deserialize service response. + * + * @param response - Transparent response object with headers and body information. + * + * @returns Deserialized data or `undefined` in case of `JSON.parse(..)` error. + */ + AbstractRequest.prototype.deserializeResponse = function (response) { + var contentType = response.headers['content-type']; + if (contentType.indexOf('javascript') === -1 || contentType.indexOf('json') === -1) + return undefined; + var json = AbstractRequest.decoder.decode(response.body); + try { + var parsedJson = JSON.parse(json); + return parsedJson; + } + catch (error) { + console.error('Error parsing JSON response:', error); + return undefined; + } + }; + /** + * Service `ArrayBuffer` response decoder. + */ + AbstractRequest.decoder = new TextDecoder(); + return AbstractRequest; +}()); +exports.AbstractRequest = AbstractRequest; diff --git a/lib/core/components/subscription-manager.js b/lib/core/components/subscription-manager.js new file mode 100644 index 000000000..517c3d09b --- /dev/null +++ b/lib/core/components/subscription-manager.js @@ -0,0 +1,411 @@ +"use strict"; +/** + * Subscription manager module. + */ +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __read = (this && this.__read) || function (o, n) { + var m = typeof Symbol === "function" && o[Symbol.iterator]; + if (!m) return o; + var i = m.call(o), r, ar = [], e; + try { + while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); + } + catch (error) { e = { error: error }; } + finally { + try { + if (r && !r.done && (m = i["return"])) m.call(i); + } + finally { if (e) throw e.error; } + } + return ar; +}; +var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { + if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { + if (ar || !(i in from)) { + if (!ar) ar = Array.prototype.slice.call(from, 0, i); + ar[i] = from[i]; + } + } + return to.concat(ar || Array.prototype.slice.call(from)); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.SubscriptionManager = void 0; +var reconnection_manager_1 = require("./reconnection_manager"); +var categories_1 = __importDefault(require("../constants/categories")); +var deduping_manager_1 = __importDefault(require("./deduping_manager")); +var categories_2 = __importDefault(require("../constants/categories")); +/** + * Subscription loop manager. + */ +var SubscriptionManager = /** @class */ (function () { + function SubscriptionManager(configuration, listenerManager, eventEmitter, subscribeCall, heartbeatCall, leaveCall, time) { + this.configuration = configuration; + this.listenerManager = listenerManager; + this.eventEmitter = eventEmitter; + this.subscribeCall = subscribeCall; + this.heartbeatCall = heartbeatCall; + this.leaveCall = leaveCall; + this.reconnectionManager = new reconnection_manager_1.ReconnectionManager(time); + this.dedupingManager = new deduping_manager_1.default({ config: this.configuration }); + this.heartbeatChannelGroups = {}; + this.heartbeatChannels = {}; + this.presenceChannelGroups = {}; + this.presenceChannels = {}; + this.heartbeatTimer = null; + this.presenceState = {}; + this.pendingChannelGroupSubscriptions = []; + this.pendingChannelSubscriptions = []; + this.channelGroups = {}; + this.channels = {}; + this.currentTimetoken = '0'; + this.lastTimetoken = '0'; + this.storedTimetoken = null; + this.subscriptionStatusAnnounced = false; + this.isOnline = true; + } + Object.defineProperty(SubscriptionManager.prototype, "subscribedChannels", { + // region Information + get: function () { + return Object.keys(this.channels); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(SubscriptionManager.prototype, "subscribedChannelGroups", { + get: function () { + return Object.keys(this.channelGroups); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(SubscriptionManager.prototype, "abort", { + set: function (call) { + this._subscribeAbort = call; + }, + enumerable: false, + configurable: true + }); + // endregion + // region Subscription + SubscriptionManager.prototype.disconnect = function () { + this.stopSubscribeLoop(); + this.stopHeartbeatTimer(); + this.reconnectionManager.stopPolling(); + }; + SubscriptionManager.prototype.reconnect = function () { + this.startSubscribeLoop(); + this.startHeartbeatTimer(); + }; + /** + * Update channels and groups used in subscription loop. + * + * @param parameters - Subscribe configuration parameters. + */ + SubscriptionManager.prototype.subscribe = function (parameters) { + var _this = this; + var channels = parameters.channels, channelGroups = parameters.channelGroups, timetoken = parameters.timetoken, _a = parameters.withPresence, withPresence = _a === void 0 ? false : _a, _b = parameters.withHeartbeats, withHeartbeats = _b === void 0 ? false : _b; + if (timetoken) { + this.lastTimetoken = this.currentTimetoken; + this.currentTimetoken = timetoken; + } + if (this.currentTimetoken !== '0' && this.currentTimetoken !== 0) { + this.storedTimetoken = this.currentTimetoken; + this.currentTimetoken = 0; + } + channels === null || channels === void 0 ? void 0 : channels.forEach(function (channel) { + _this.pendingChannelSubscriptions.push(channel); + _this.channels[channel] = {}; + if (withPresence) + _this.presenceChannels[channel] = {}; + if (withHeartbeats || _this.configuration.getHeartbeatInterval()) + _this.heartbeatChannels[channel] = {}; + }); + channelGroups === null || channelGroups === void 0 ? void 0 : channelGroups.forEach(function (group) { + _this.pendingChannelGroupSubscriptions.push(group); + _this.channelGroups[group] = {}; + if (withPresence) + _this.presenceChannelGroups[group] = {}; + if (withHeartbeats || _this.configuration.getHeartbeatInterval()) + _this.heartbeatChannelGroups[group] = {}; + }); + this.subscriptionStatusAnnounced = false; + this.reconnect(); + }; + SubscriptionManager.prototype.unsubscribe = function (parameters, isOffline) { + var _this = this; + var channels = parameters.channels, channelGroups = parameters.channelGroups; + var actualChannelGroups = []; + var actualChannels = []; + channels === null || channels === void 0 ? void 0 : channels.forEach(function (channel) { + if (channel in _this.channels) { + delete _this.channels[channel]; + actualChannels.push(channel); + if (channel in _this.heartbeatChannels) + delete _this.heartbeatChannels[channel]; + } + if (channel in _this.presenceState) + delete _this.presenceState[channel]; + if (channel in _this.presenceChannels) { + delete _this.presenceChannels[channel]; + actualChannels.push(channel); + } + }); + channelGroups === null || channelGroups === void 0 ? void 0 : channelGroups.forEach(function (group) { + if (group in _this.channelGroups) { + delete _this.channelGroups[group]; + actualChannelGroups.push(group); + if (group in _this.heartbeatChannelGroups) + delete _this.heartbeatChannelGroups[group]; + } + if (group in _this.presenceState) + delete _this.presenceState[group]; + if (group in _this.presenceChannelGroups) { + delete _this.presenceChannelGroups[group]; + actualChannelGroups.push(group); + } + }); + // There is no need to unsubscribe to empty list of data sources. + if (actualChannels.length === 0 && actualChannelGroups.length === 0) + return; + if (this.configuration.suppressLeaveEvents === false && !isOffline) { + this.leaveCall({ channels: actualChannels, channelGroups: actualChannelGroups }, function (status) { + _this.listenerManager.announceStatus(__assign(__assign({}, status), { affectedChannels: actualChannels, affectedChannelGroups: actualChannelGroups, currentTimetoken: _this.currentTimetoken, lastTimetoken: _this.lastTimetoken })); + }); + } + if (Object.keys(this.channels).length === 0 && + Object.keys(this.presenceChannels).length === 0 && + Object.keys(this.channelGroups).length === 0 && + Object.keys(this.presenceChannelGroups).length === 0) { + this.lastTimetoken = 0; + this.currentTimetoken = 0; + this.storedTimetoken = null; + this.region = null; + this.reconnectionManager.stopPolling(); + } + this.reconnect(); + }; + SubscriptionManager.prototype.unsubscribeAll = function (isOffline) { + this.unsubscribe({ + channels: this.subscribedChannels, + channelGroups: this.subscribedChannelGroups, + }, isOffline); + }; + SubscriptionManager.prototype.startSubscribeLoop = function () { + var _this = this; + this.stopSubscribeLoop(); + var channelGroups = __spreadArray([], __read(Object.keys(this.channelGroups)), false); + var channels = __spreadArray([], __read(Object.keys(this.channels)), false); + Object.keys(this.presenceChannelGroups).forEach(function (group) { return channelGroups.push("".concat(group, "-pnpres")); }); + Object.keys(this.presenceChannels).forEach(function (channel) { return channels.push("".concat(channel, "-pnpres")); }); + // There is no need to start subscription loop for empty list of data sources. + if (channels.length === 0 && channelGroups.length === 0) + return; + this.subscribeCall({ + channels: channels, + channelGroups: channelGroups, + state: this.presenceState, + timetoken: this.currentTimetoken, + region: this.region !== null ? this.region : undefined, + filterExpression: this.configuration.filterExpression, + }, function (status, result) { + _this.processSubscribeResponse(status, result); + }); + }; + SubscriptionManager.prototype.stopSubscribeLoop = function () { + if (this._subscribeAbort) { + this._subscribeAbort(); + this._subscribeAbort = null; + } + }; + /** + * Process subscribe REST API endpoint response. + */ + SubscriptionManager.prototype.processSubscribeResponse = function (status, result) { + var _this = this; + if (status.error) { + // Ignore aborted request. + if (typeof status.errorData === 'object' && 'name' in status.errorData && status.errorData.name === 'AbortError') + return; + if (status.category === categories_2.default.PNTimeoutCategory) { + this.startSubscribeLoop(); + } + else if (status.category === categories_2.default.PNNetworkIssuesCategory) { + this.disconnect(); + if (status.error && this.configuration.autoNetworkDetection && this.isOnline) { + this.isOnline = false; + this.listenerManager.announceNetworkDown(); + } + this.reconnectionManager.onReconnect(function () { + if (_this.configuration.autoNetworkDetection && !_this.isOnline) { + _this.isOnline = true; + _this.listenerManager.announceNetworkUp(); + } + _this.reconnect(); + _this.subscriptionStatusAnnounced = true; + var reconnectedAnnounce = { + category: categories_2.default.PNReconnectedCategory, + operation: status.operation, + lastTimetoken: _this.lastTimetoken, + currentTimetoken: _this.currentTimetoken, + }; + _this.listenerManager.announceStatus(reconnectedAnnounce); + }); + this.reconnectionManager.startPolling(); + this.listenerManager.announceStatus(status); + } + else if (status.category === categories_2.default.PNBadRequestCategory) { + this.stopHeartbeatTimer(); + this.listenerManager.announceStatus(status); + } + else { + this.listenerManager.announceStatus(status); + } + return; + } + if (this.storedTimetoken) { + this.currentTimetoken = this.storedTimetoken; + this.storedTimetoken = null; + } + else { + this.lastTimetoken = this.currentTimetoken; + this.currentTimetoken = result.cursor.timetoken; + } + if (!this.subscriptionStatusAnnounced) { + var connected = { + category: categories_1.default.PNConnectedCategory, + operation: status.operation, + affectedChannels: this.pendingChannelSubscriptions, + subscribedChannels: this.subscribedChannels, + affectedChannelGroups: this.pendingChannelGroupSubscriptions, + lastTimetoken: this.lastTimetoken, + currentTimetoken: this.currentTimetoken, + }; + this.subscriptionStatusAnnounced = true; + this.listenerManager.announceStatus(connected); + // Clear pending channels and groups. + this.pendingChannelGroupSubscriptions = []; + this.pendingChannelSubscriptions = []; + } + var messages = result.messages; + var _a = this.configuration, requestMessageCountThreshold = _a.requestMessageCountThreshold, dedupeOnSubscribe = _a.dedupeOnSubscribe; + if (requestMessageCountThreshold && messages.length >= requestMessageCountThreshold) { + this.listenerManager.announceStatus({ + category: categories_1.default.PNRequestMessageCountExceededCategory, + operation: status.operation, + }); + } + messages.forEach(function (message) { + if (dedupeOnSubscribe) { + if (_this.dedupingManager.isDuplicate(message)) + return; + _this.dedupingManager.addEntry(message); + } + _this.eventEmitter.emitEvent(message); + }); + this.region = result.cursor.region; + this.startSubscribeLoop(); + }; + // endregion + // region Presence + /** + * Update `uuid` state which should be sent with subscribe request. + * + * @param parameters - Channels and groups with state which should be associated to `uuid`. + */ + SubscriptionManager.prototype.setState = function (parameters) { + var _this = this; + var state = parameters.state, channels = parameters.channels, channelGroups = parameters.channelGroups; + channels === null || channels === void 0 ? void 0 : channels.forEach(function (channel) { return channel in _this.channels && (_this.presenceState[channel] = state); }); + channelGroups === null || channelGroups === void 0 ? void 0 : channelGroups.forEach(function (group) { return group in _this.channelGroups && (_this.presenceState[group] = state); }); + }; + /** + * Manual presence management. + * + * @param parameters - Desired presence state for provided list of channels and groups. + */ + SubscriptionManager.prototype.changePresence = function (parameters) { + var _this = this; + var connected = parameters.connected, channels = parameters.channels, channelGroups = parameters.channelGroups; + if (connected) { + channels === null || channels === void 0 ? void 0 : channels.forEach(function (channel) { return (_this.heartbeatChannels[channel] = {}); }); + channelGroups === null || channelGroups === void 0 ? void 0 : channelGroups.forEach(function (group) { return (_this.heartbeatChannelGroups[group] = {}); }); + } + else { + channels === null || channels === void 0 ? void 0 : channels.forEach(function (channel) { + if (channel in _this.heartbeatChannels) + delete _this.heartbeatChannels[channel]; + }); + channelGroups === null || channelGroups === void 0 ? void 0 : channelGroups.forEach(function (group) { + if (group in _this.heartbeatChannelGroups) + delete _this.heartbeatChannelGroups[group]; + }); + if (this.configuration.suppressLeaveEvents === false) { + this.leaveCall({ channels: channels, channelGroups: channelGroups }, function (status) { return _this.listenerManager.announceStatus(status); }); + } + } + this.reconnect(); + }; + SubscriptionManager.prototype.startHeartbeatTimer = function () { + var _this = this; + this.stopHeartbeatTimer(); + var heartbeatInterval = this.configuration.getHeartbeatInterval(); + if (!heartbeatInterval || heartbeatInterval === 0) + return; + this.sendHeartbeat(); + this.heartbeatTimer = setInterval(function () { return _this.sendHeartbeat(); }, heartbeatInterval * 1000); + }; + /** + * Stop heartbeat. + * + * Stop timer which trigger {@link HeartbeatRequest} sending with configured presence intervals. + */ + SubscriptionManager.prototype.stopHeartbeatTimer = function () { + if (!this.heartbeatTimer) + return; + clearInterval(this.heartbeatTimer); + this.heartbeatTimer = null; + }; + /** + * Send heartbeat request. + */ + SubscriptionManager.prototype.sendHeartbeat = function () { + var _this = this; + var heartbeatChannelGroups = Object.keys(this.heartbeatChannelGroups); + var heartbeatChannels = Object.keys(this.heartbeatChannels); + // There is no need to start heartbeat loop if there is no channels and groups to use. + if (heartbeatChannels.length === 0 && heartbeatChannelGroups.length === 0) + return; + this.heartbeatCall({ + channels: heartbeatChannels, + channelGroups: heartbeatChannelGroups, + heartbeat: this.configuration.getPresenceTimeout(), + state: this.presenceState, + }, function (status) { + if (status.error && _this.configuration.announceFailedHeartbeats) + _this.listenerManager.announceStatus(status); + if (status.error && _this.configuration.autoNetworkDetection && _this.isOnline) { + _this.isOnline = false; + _this.disconnect(); + _this.listenerManager.announceNetworkDown(); + _this.reconnect(); + } + if (!status.error && _this.configuration.announceSuccessfulHeartbeats) + _this.listenerManager.announceNetworkUp(); + }); + }; + return SubscriptionManager; +}()); +exports.SubscriptionManager = SubscriptionManager; diff --git a/lib/core/components/subscription_manager.js b/lib/core/components/subscription_manager.js deleted file mode 100644 index 077bb4a1b..000000000 --- a/lib/core/components/subscription_manager.js +++ /dev/null @@ -1,434 +0,0 @@ -"use strict"; -var __rest = (this && this.__rest) || function (s, e) { - var t = {}; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) - t[p] = s[p]; - if (s != null && typeof Object.getOwnPropertySymbols === "function") - for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { - if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) - t[p[i]] = s[p[i]]; - } - return t; -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -var reconnection_manager_1 = __importDefault(require("./reconnection_manager")); -var deduping_manager_1 = __importDefault(require("./deduping_manager")); -var categories_1 = __importDefault(require("../constants/categories")); -var default_1 = /** @class */ (function () { - function default_1(_a) { - var subscribeEndpoint = _a.subscribeEndpoint, leaveEndpoint = _a.leaveEndpoint, heartbeatEndpoint = _a.heartbeatEndpoint, setStateEndpoint = _a.setStateEndpoint, timeEndpoint = _a.timeEndpoint, getFileUrl = _a.getFileUrl, config = _a.config, crypto = _a.crypto, listenerManager = _a.listenerManager, cryptoModule = _a.cryptoModule, eventEmitter = _a.eventEmitter; - this._listenerManager = listenerManager; - this._config = config; - this._leaveEndpoint = leaveEndpoint; - this._heartbeatEndpoint = heartbeatEndpoint; - this._setStateEndpoint = setStateEndpoint; - this._subscribeEndpoint = subscribeEndpoint; - this._getFileUrl = getFileUrl; - this._crypto = crypto; - this._cryptoModule = cryptoModule; - this._channels = {}; - this._presenceChannels = {}; - this._heartbeatChannels = {}; - this._heartbeatChannelGroups = {}; - this._channelGroups = {}; - this._presenceChannelGroups = {}; - this._pendingChannelSubscriptions = []; - this._pendingChannelGroupSubscriptions = []; - this._currentTimetoken = 0; - this._lastTimetoken = 0; - this._storedTimetoken = null; - this._subscriptionStatusAnnounced = false; - this._isOnline = true; - this._reconnectionManager = new reconnection_manager_1.default({ timeEndpoint: timeEndpoint }); - this._dedupingManager = new deduping_manager_1.default({ config: config }); - if (this._cryptoModule) - this._decoder = new TextDecoder(); - this._eventEmitter = eventEmitter; - } - default_1.prototype.adaptStateChange = function (args, callback) { - var _this = this; - var state = args.state, _a = args.channels, channels = _a === void 0 ? [] : _a, _b = args.channelGroups, channelGroups = _b === void 0 ? [] : _b, _c = args.withHeartbeat, withHeartbeat = _c === void 0 ? false : _c; - channels.forEach(function (channel) { - if (channel in _this._channels) - _this._channels[channel].state = state; - }); - channelGroups.forEach(function (channelGroup) { - if (channelGroup in _this._channelGroups) { - _this._channelGroups[channelGroup].state = state; - } - }); - if (withHeartbeat) { - var presenceState_1 = {}; - channels.forEach(function (channel) { return (presenceState_1[channel] = state); }); - channelGroups.forEach(function (group) { return (presenceState_1[group] = state); }); - return this._heartbeatEndpoint({ channels: channels, channelGroups: channelGroups, state: presenceState_1 }, callback); - } - return this._setStateEndpoint({ state: state, channels: channels, channelGroups: channelGroups }, callback); - }; - default_1.prototype.adaptPresenceChange = function (args) { - var _this = this; - var connected = args.connected, _a = args.channels, channels = _a === void 0 ? [] : _a, _b = args.channelGroups, channelGroups = _b === void 0 ? [] : _b; - if (connected) { - channels.forEach(function (channel) { - _this._heartbeatChannels[channel] = { state: {} }; - }); - channelGroups.forEach(function (channelGroup) { - _this._heartbeatChannelGroups[channelGroup] = { state: {} }; - }); - } - else { - channels.forEach(function (channel) { - if (channel in _this._heartbeatChannels) { - delete _this._heartbeatChannels[channel]; - } - }); - channelGroups.forEach(function (channelGroup) { - if (channelGroup in _this._heartbeatChannelGroups) { - delete _this._heartbeatChannelGroups[channelGroup]; - } - }); - if (this._config.suppressLeaveEvents === false) { - this._leaveEndpoint({ channels: channels, channelGroups: channelGroups }, function (status) { - _this._listenerManager.announceStatus(status); - }); - } - } - this.reconnect(); - }; - default_1.prototype.adaptSubscribeChange = function (args) { - var _this = this; - var timetoken = args.timetoken, _a = args.channels, channels = _a === void 0 ? [] : _a, _b = args.channelGroups, channelGroups = _b === void 0 ? [] : _b, _c = args.withPresence, withPresence = _c === void 0 ? false : _c, _d = args.withHeartbeats, withHeartbeats = _d === void 0 ? false : _d; - if (!this._config.subscribeKey || this._config.subscribeKey === '') { - // eslint-disable-next-line - if (console && console.log) { - console.log('subscribe key missing; aborting subscribe'); //eslint-disable-line - } - return; - } - if (timetoken) { - this._lastTimetoken = this._currentTimetoken; - this._currentTimetoken = timetoken; - } - // reset the current timetoken to get a connect event. - // $FlowFixMe - if (this._currentTimetoken !== '0' && this._currentTimetoken !== 0) { - this._storedTimetoken = this._currentTimetoken; - this._currentTimetoken = 0; - } - channels.forEach(function (channel) { - _this._channels[channel] = { state: {} }; - if (withPresence) - _this._presenceChannels[channel] = {}; - if (withHeartbeats || _this._config.getHeartbeatInterval()) - _this._heartbeatChannels[channel] = {}; - _this._pendingChannelSubscriptions.push(channel); - }); - channelGroups.forEach(function (channelGroup) { - _this._channelGroups[channelGroup] = { state: {} }; - if (withPresence) - _this._presenceChannelGroups[channelGroup] = {}; - if (withHeartbeats || _this._config.getHeartbeatInterval()) - _this._heartbeatChannelGroups[channelGroup] = {}; - _this._pendingChannelGroupSubscriptions.push(channelGroup); - }); - this._subscriptionStatusAnnounced = false; - this.reconnect(); - }; - default_1.prototype.adaptUnsubscribeChange = function (args, isOffline) { - var _this = this; - var _a = args.channels, channels = _a === void 0 ? [] : _a, _b = args.channelGroups, channelGroups = _b === void 0 ? [] : _b; - // keep track of which channels and channel groups - // we are going to unsubscribe from. - var actualChannels = []; - var actualChannelGroups = []; - // - channels.forEach(function (channel) { - if (channel in _this._channels) { - delete _this._channels[channel]; - actualChannels.push(channel); - if (channel in _this._heartbeatChannels) { - delete _this._heartbeatChannels[channel]; - } - } - if (channel in _this._presenceChannels) { - delete _this._presenceChannels[channel]; - actualChannels.push(channel); - } - }); - channelGroups.forEach(function (channelGroup) { - if (channelGroup in _this._channelGroups) { - delete _this._channelGroups[channelGroup]; - actualChannelGroups.push(channelGroup); - if (channelGroup in _this._heartbeatChannelGroups) { - delete _this._heartbeatChannelGroups[channelGroup]; - } - } - if (channelGroup in _this._presenceChannelGroups) { - delete _this._presenceChannelGroups[channelGroup]; - actualChannelGroups.push(channelGroup); - } - }); - // no-op if there are no channels and cg's to unsubscribe from. - if (actualChannels.length === 0 && actualChannelGroups.length === 0) { - return; - } - if (this._config.suppressLeaveEvents === false && !isOffline) { - this._leaveEndpoint({ channels: actualChannels, channelGroups: actualChannelGroups }, function (status) { - status.affectedChannels = actualChannels; - status.affectedChannelGroups = actualChannelGroups; - status.currentTimetoken = _this._currentTimetoken; - status.lastTimetoken = _this._lastTimetoken; - _this._listenerManager.announceStatus(status); - }); - } - // if we have nothing to subscribe to, reset the timetoken. - if (Object.keys(this._channels).length === 0 && - Object.keys(this._presenceChannels).length === 0 && - Object.keys(this._channelGroups).length === 0 && - Object.keys(this._presenceChannelGroups).length === 0) { - this._lastTimetoken = 0; - this._currentTimetoken = 0; - this._storedTimetoken = null; - this._region = null; - this._reconnectionManager.stopPolling(); - } - this.reconnect(); - }; - default_1.prototype.unsubscribeAll = function (isOffline) { - this.adaptUnsubscribeChange({ - channels: this.getSubscribedChannels(), - channelGroups: this.getSubscribedChannelGroups(), - }, isOffline); - }; - default_1.prototype.getHeartbeatChannels = function () { - return Object.keys(this._heartbeatChannels); - }; - default_1.prototype.getHeartbeatChannelGroups = function () { - return Object.keys(this._heartbeatChannelGroups); - }; - default_1.prototype.getSubscribedChannels = function () { - return Object.keys(this._channels); - }; - default_1.prototype.getSubscribedChannelGroups = function () { - return Object.keys(this._channelGroups); - }; - default_1.prototype.reconnect = function () { - this._startSubscribeLoop(); - this._registerHeartbeatTimer(); - }; - default_1.prototype.disconnect = function () { - this._stopSubscribeLoop(); - this._stopHeartbeatTimer(); - this._reconnectionManager.stopPolling(); - }; - default_1.prototype._registerHeartbeatTimer = function () { - this._stopHeartbeatTimer(); - // if the interval is 0 or undefined, do not queue up heartbeating - if (this._config.getHeartbeatInterval() === 0 || this._config.getHeartbeatInterval() === undefined) { - return; - } - this._performHeartbeatLoop(); - // $FlowFixMe - this._heartbeatTimer = setInterval(this._performHeartbeatLoop.bind(this), this._config.getHeartbeatInterval() * 1000); - }; - default_1.prototype._stopHeartbeatTimer = function () { - if (this._heartbeatTimer) { - // $FlowFixMe - clearInterval(this._heartbeatTimer); - this._heartbeatTimer = null; - } - }; - default_1.prototype._performHeartbeatLoop = function () { - var _this = this; - var heartbeatChannels = this.getHeartbeatChannels(); - var heartbeatChannelGroups = this.getHeartbeatChannelGroups(); - var presenceState = {}; - if (heartbeatChannels.length === 0 && heartbeatChannelGroups.length === 0) { - return; - } - this.getSubscribedChannels().forEach(function (channel) { - var channelState = _this._channels[channel].state; - if (Object.keys(channelState).length) { - presenceState[channel] = channelState; - } - }); - this.getSubscribedChannelGroups().forEach(function (channelGroup) { - var channelGroupState = _this._channelGroups[channelGroup].state; - if (Object.keys(channelGroupState).length) { - presenceState[channelGroup] = channelGroupState; - } - }); - var onHeartbeat = function (status) { - if (status.error && _this._config.announceFailedHeartbeats) { - _this._listenerManager.announceStatus(status); - } - if (status.error && _this._config.autoNetworkDetection && _this._isOnline) { - _this._isOnline = false; - _this.disconnect(); - _this._listenerManager.announceNetworkDown(); - _this.reconnect(); - } - if (!status.error && _this._config.announceSuccessfulHeartbeats) { - _this._listenerManager.announceStatus(status); - } - }; - this._heartbeatEndpoint({ - channels: heartbeatChannels, - channelGroups: heartbeatChannelGroups, - state: presenceState, - }, onHeartbeat.bind(this)); - }; - default_1.prototype._startSubscribeLoop = function () { - var _this = this; - this._stopSubscribeLoop(); - var presenceState = {}; - var channels = []; - var channelGroups = []; - Object.keys(this._channels).forEach(function (channel) { - var channelState = _this._channels[channel].state; - if (Object.keys(channelState).length) { - presenceState[channel] = channelState; - } - channels.push(channel); - }); - Object.keys(this._presenceChannels).forEach(function (channel) { - channels.push("".concat(channel, "-pnpres")); - }); - Object.keys(this._channelGroups).forEach(function (channelGroup) { - var channelGroupState = _this._channelGroups[channelGroup].state; - if (Object.keys(channelGroupState).length) { - presenceState[channelGroup] = channelGroupState; - } - channelGroups.push(channelGroup); - }); - Object.keys(this._presenceChannelGroups).forEach(function (channelGroup) { - channelGroups.push("".concat(channelGroup, "-pnpres")); - }); - if (channels.length === 0 && channelGroups.length === 0) { - return; - } - var subscribeArgs = { - channels: channels, - channelGroups: channelGroups, - state: presenceState, - timetoken: this._currentTimetoken, - filterExpression: this._config.filterExpression, - region: this._region, - }; - this._subscribeCall = this._subscribeEndpoint(subscribeArgs, this._processSubscribeResponse.bind(this)); - }; - default_1.prototype._processSubscribeResponse = function (status, payload) { - var _this = this; - if (status.error) { - // if error comes from request abort, ignore - if (status.errorData && status.errorData.message === 'Aborted') { - return; - } - // if we timeout from server, restart the loop. - if (status.category === categories_1.default.PNTimeoutCategory) { - this._startSubscribeLoop(); - } - else if (status.category === categories_1.default.PNNetworkIssuesCategory) { - // we lost internet connection, alert the reconnection manager and terminate all loops - this.disconnect(); - if (status.error && this._config.autoNetworkDetection && this._isOnline) { - this._isOnline = false; - this._listenerManager.announceNetworkDown(); - } - this._reconnectionManager.onReconnection(function () { - if (_this._config.autoNetworkDetection && !_this._isOnline) { - _this._isOnline = true; - _this._listenerManager.announceNetworkUp(); - } - _this.reconnect(); - _this._subscriptionStatusAnnounced = true; - var reconnectedAnnounce = { - category: categories_1.default.PNReconnectedCategory, - operation: status.operation, - lastTimetoken: _this._lastTimetoken, - currentTimetoken: _this._currentTimetoken, - }; - _this._listenerManager.announceStatus(reconnectedAnnounce); - }); - this._reconnectionManager.startPolling(); - this._listenerManager.announceStatus(status); - } - else if (status.category === categories_1.default.PNBadRequestCategory) { - this._stopHeartbeatTimer(); - this._listenerManager.announceStatus(status); - } - else { - this._listenerManager.announceStatus(status); - } - return; - } - if (this._storedTimetoken) { - this._currentTimetoken = this._storedTimetoken; - this._storedTimetoken = null; - } - else { - this._lastTimetoken = this._currentTimetoken; - this._currentTimetoken = payload.metadata.timetoken; - } - if (!this._subscriptionStatusAnnounced) { - var connectedAnnounce = {}; - connectedAnnounce.category = categories_1.default.PNConnectedCategory; - connectedAnnounce.operation = status.operation; - connectedAnnounce.affectedChannels = this._pendingChannelSubscriptions; - connectedAnnounce.subscribedChannels = this.getSubscribedChannels(); - connectedAnnounce.affectedChannelGroups = this._pendingChannelGroupSubscriptions; - connectedAnnounce.lastTimetoken = this._lastTimetoken; - connectedAnnounce.currentTimetoken = this._currentTimetoken; - this._subscriptionStatusAnnounced = true; - this._listenerManager.announceStatus(connectedAnnounce); - // clear the pending connections list - this._pendingChannelSubscriptions = []; - this._pendingChannelGroupSubscriptions = []; - } - var messages = payload.messages || []; - var _a = this._config, requestMessageCountThreshold = _a.requestMessageCountThreshold, dedupeOnSubscribe = _a.dedupeOnSubscribe; - if (requestMessageCountThreshold && messages.length >= requestMessageCountThreshold) { - var countAnnouncement = {}; - countAnnouncement.category = categories_1.default.PNRequestMessageCountExceededCategory; - countAnnouncement.operation = status.operation; - this._listenerManager.announceStatus(countAnnouncement); - } - messages.forEach(function (message) { - var channel = message.channel; - var subscriptionMatch = message.subscriptionMatch; - if (channel === subscriptionMatch) { - subscriptionMatch = null; - } - if (dedupeOnSubscribe) { - if (_this._dedupingManager.isDuplicate(message)) { - return; - } - _this._dedupingManager.addEntry(message); - } - _this._eventEmitter.emitEvent(message); - }); - this._region = payload.metadata.region; - this._startSubscribeLoop(); - }; - default_1.prototype._stopSubscribeLoop = function () { - if (this._subscribeCall) { - if (typeof this._subscribeCall.abort === 'function') { - this._subscribeCall.abort(); - } - this._subscribeCall = null; - } - }; - default_1.prototype._renameEvent = function (e) { - return e === 'set' ? 'updated' : 'removed'; - }; - default_1.prototype._renameChannelField = function (announce) { - var channel = announce.channel, eventData = __rest(announce, ["channel"]); - eventData.spaceId = channel; - return eventData; - }; - return default_1; -}()); -exports.default = default_1; diff --git a/lib/core/components/telemetry_manager.js b/lib/core/components/telemetry_manager.js deleted file mode 100644 index f63405121..000000000 --- a/lib/core/components/telemetry_manager.js +++ /dev/null @@ -1,137 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -/* */ -var operations_1 = __importDefault(require("../constants/operations")); -var default_1 = /** @class */ (function () { - function default_1(configuration) { - this._maximumSamplesCount = 100; - this._trackedLatencies = {}; - this._latencies = {}; - this._telemetryExcludeOperations = [ - operations_1.default.PNSubscribeOperation, - operations_1.default.PNReceiveMessagesOperation, - operations_1.default.PNHandshakeOperation, - ]; - this._maximumSamplesCount = configuration.maximumSamplesCount || this._maximumSamplesCount; - } - /** - * Compose object with latency information of recently used API endpoints. - * - * @return {Object} Object with request query key/value pairs. - */ - default_1.prototype.operationsLatencyForRequest = function () { - var _this = this; - var latencies = {}; - Object.keys(this._latencies).forEach(function (endpointName) { - var operationLatencies = _this._latencies[endpointName]; - var averageLatency = _this._averageLatency(operationLatencies); - if (averageLatency > 0) { - latencies["l_".concat(endpointName)] = averageLatency; - } - }); - return latencies; - }; - default_1.prototype.startLatencyMeasure = function (operationType, identifier) { - if (this._telemetryExcludeOperations.includes(operationType) || !identifier) { - return; - } - this._trackedLatencies[identifier] = Date.now(); - }; - default_1.prototype.stopLatencyMeasure = function (operationType, identifier) { - if (this._telemetryExcludeOperations.includes(operationType) || !identifier) { - return; - } - var endpointName = this._endpointName(operationType); - /** @type Array */ - var endpointLatencies = this._latencies[endpointName]; - var startDate = this._trackedLatencies[identifier]; - if (!endpointLatencies) { - this._latencies[endpointName] = []; - endpointLatencies = this._latencies[endpointName]; - } - endpointLatencies.push(Date.now() - startDate); - // Truncate samples count if there is more then configured. - if (endpointLatencies.length > this._maximumSamplesCount) { - endpointLatencies.splice(0, endpointLatencies.length - this._maximumSamplesCount); - } - delete this._trackedLatencies[identifier]; - }; - default_1.prototype._averageLatency = function (latencies) { - var arrayReduce = function (accumulatedLatency, latency) { return accumulatedLatency + latency; }; - return Math.floor(latencies.reduce(arrayReduce, 0) / latencies.length); - }; - default_1.prototype._endpointName = function (operationType) { - var operation = null; - switch (operationType) { - case operations_1.default.PNPublishOperation: - operation = 'pub'; - break; - case operations_1.default.PNSignalOperation: - operation = 'sig'; - break; - case operations_1.default.PNHistoryOperation: - case operations_1.default.PNFetchMessagesOperation: - case operations_1.default.PNDeleteMessagesOperation: - case operations_1.default.PNMessageCounts: - operation = 'hist'; - break; - case operations_1.default.PNUnsubscribeOperation: - case operations_1.default.PNWhereNowOperation: - case operations_1.default.PNHereNowOperation: - case operations_1.default.PNHeartbeatOperation: - case operations_1.default.PNSetStateOperation: - case operations_1.default.PNGetStateOperation: - operation = 'pres'; - break; - case operations_1.default.PNAddChannelsToGroupOperation: - case operations_1.default.PNRemoveChannelsFromGroupOperation: - case operations_1.default.PNChannelGroupsOperation: - case operations_1.default.PNRemoveGroupOperation: - case operations_1.default.PNChannelsForGroupOperation: - operation = 'cg'; - break; - case operations_1.default.PNPushNotificationEnabledChannelsOperation: - case operations_1.default.PNRemoveAllPushNotificationsOperation: - operation = 'push'; - break; - case operations_1.default.PNCreateUserOperation: - case operations_1.default.PNUpdateUserOperation: - case operations_1.default.PNDeleteUserOperation: - case operations_1.default.PNGetUserOperation: - case operations_1.default.PNGetUsersOperation: - case operations_1.default.PNCreateSpaceOperation: - case operations_1.default.PNUpdateSpaceOperation: - case operations_1.default.PNDeleteSpaceOperation: - case operations_1.default.PNGetSpaceOperation: - case operations_1.default.PNGetSpacesOperation: - case operations_1.default.PNGetMembersOperation: - case operations_1.default.PNUpdateMembersOperation: - case operations_1.default.PNGetMembershipsOperation: - case operations_1.default.PNUpdateMembershipsOperation: - operation = 'obj'; - break; - case operations_1.default.PNAddMessageActionOperation: - case operations_1.default.PNRemoveMessageActionOperation: - case operations_1.default.PNGetMessageActionsOperation: - operation = 'msga'; - break; - case operations_1.default.PNAccessManagerGrant: - case operations_1.default.PNAccessManagerAudit: - operation = 'pam'; - break; - case operations_1.default.PNAccessManagerGrantToken: - case operations_1.default.PNAccessManagerRevokeToken: - operation = 'pamv3'; - break; - default: - operation = 'time'; - break; - } - return operation; - }; - return default_1; -}()); -exports.default = default_1; diff --git a/lib/core/components/token_manager.js b/lib/core/components/token_manager.js index e41ef77a1..53e334b1a 100644 --- a/lib/core/components/token_manager.js +++ b/lib/core/components/token_manager.js @@ -1,8 +1,7 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var default_1 = /** @class */ (function () { - function default_1(config, cbor) { - this._config = config; + function default_1(cbor) { this._cbor = cbor; } default_1.prototype.setToken = function (token) { diff --git a/lib/core/constants/categories.js b/lib/core/constants/categories.js index c976cd42a..1898cf9c3 100644 --- a/lib/core/constants/categories.js +++ b/lib/core/constants/categories.js @@ -1,26 +1,74 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -/* */ -exports.default = { - // SDK will announce when the network appears to be connected again. - PNNetworkUpCategory: 'PNNetworkUpCategory', - // SDK will announce when the network appears to down. - PNNetworkDownCategory: 'PNNetworkDownCategory', - // call failed when network was unable to complete the call. - PNNetworkIssuesCategory: 'PNNetworkIssuesCategory', - // network call timed out - PNTimeoutCategory: 'PNTimeoutCategory', - // server responded with bad response - PNBadRequestCategory: 'PNBadRequestCategory', - // server responded with access denied - PNAccessDeniedCategory: 'PNAccessDeniedCategory', - // something strange happened; please check the logs. - PNUnknownCategory: 'PNUnknownCategory', - // on reconnection - PNReconnectedCategory: 'PNReconnectedCategory', - PNConnectedCategory: 'PNConnectedCategory', - PNRequestMessageCountExceededCategory: 'PNRequestMessageCountExceededCategory', - PNDisconnectedCategory: 'PNDisconnectedCategory', - PNConnectionErrorCategory: 'PNConnectionErrorCategory', - PNDisconnectedUnexpectedlyCategory: 'PNDisconnectedUnexpectedlyCategory', -}; +/** + * Request processing status categories. + */ +var StatusCategory; +(function (StatusCategory) { + /** + * Call failed when network was unable to complete the call. + */ + StatusCategory["PNNetworkIssuesCategory"] = "PNNetworkIssuesCategory"; + /** + * Network call timed out. + */ + StatusCategory["PNTimeoutCategory"] = "PNTimeoutCategory"; + /** + * Request has been cancelled. + */ + StatusCategory["PNCancelledCategory"] = "PNCancelledCategory"; + /** + * Server responded with bad response. + */ + StatusCategory["PNBadRequestCategory"] = "PNBadRequestCategory"; + /** + * Server responded with access denied. + */ + StatusCategory["PNAccessDeniedCategory"] = "PNAccessDeniedCategory"; + /** + * Something strange happened; please check the logs. + */ + StatusCategory["PNUnknownCategory"] = "PNUnknownCategory"; + // -------------------------------------------------------- + // --------------------- Network status ------------------- + // -------------------------------------------------------- + /** + * SDK will announce when the network appears to be connected again. + */ + StatusCategory["PNNetworkUpCategory"] = "PNNetworkUpCategory"; + /** + * SDK will announce when the network appears to down. + */ + StatusCategory["PNNetworkDownCategory"] = "PNNetworkDownCategory"; + // -------------------------------------------------------- + // -------------------- Real-time events ------------------ + // -------------------------------------------------------- + /** + * PubNub client reconnected to the real-time updates stream. + */ + StatusCategory["PNReconnectedCategory"] = "PNReconnectedCategory"; + /** + * PubNub client connected to the real-time updates stream. + */ + StatusCategory["PNConnectedCategory"] = "PNConnectedCategory"; + /** + * Received real-time updates exceed specified threshold. + * + * After temporary disconnection and catchup, this category means that potentially some + * real-time updates have been pushed into `storage` and need to be requested separately. + */ + StatusCategory["PNRequestMessageCountExceededCategory"] = "PNRequestMessageCountExceededCategory"; + /** + * PubNub client disconnected from the real-time updates streams. + */ + StatusCategory["PNDisconnectedCategory"] = "PNDisconnectedCategory"; + /** + * PubNub client wasn't able to connect to the real-time updates streams. + */ + StatusCategory["PNConnectionErrorCategory"] = "PNConnectionErrorCategory"; + /** + * PubNub client unexpectedly disconnected from the real-time updates streams. + */ + StatusCategory["PNDisconnectedUnexpectedlyCategory"] = "PNDisconnectedUnexpectedlyCategory"; +})(StatusCategory || (StatusCategory = {})); +exports.default = StatusCategory; diff --git a/lib/core/constants/operations.js b/lib/core/constants/operations.js index 5a934e464..6741c1cfe 100644 --- a/lib/core/constants/operations.js +++ b/lib/core/constants/operations.js @@ -1,83 +1,237 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); /* */ -exports.default = { - PNTimeOperation: 'PNTimeOperation', - PNHistoryOperation: 'PNHistoryOperation', - PNDeleteMessagesOperation: 'PNDeleteMessagesOperation', - PNFetchMessagesOperation: 'PNFetchMessagesOperation', - PNMessageCounts: 'PNMessageCountsOperation', - // pubsub - PNSubscribeOperation: 'PNSubscribeOperation', - PNUnsubscribeOperation: 'PNUnsubscribeOperation', - PNPublishOperation: 'PNPublishOperation', - PNSignalOperation: 'PNSignalOperation', - // Actions API - PNAddMessageActionOperation: 'PNAddActionOperation', - PNRemoveMessageActionOperation: 'PNRemoveMessageActionOperation', - PNGetMessageActionsOperation: 'PNGetMessageActionsOperation', - // Objects API - PNCreateUserOperation: 'PNCreateUserOperation', - PNUpdateUserOperation: 'PNUpdateUserOperation', - PNDeleteUserOperation: 'PNDeleteUserOperation', - PNGetUserOperation: 'PNGetUsersOperation', - PNGetUsersOperation: 'PNGetUsersOperation', - PNCreateSpaceOperation: 'PNCreateSpaceOperation', - PNUpdateSpaceOperation: 'PNUpdateSpaceOperation', - PNDeleteSpaceOperation: 'PNDeleteSpaceOperation', - PNGetSpaceOperation: 'PNGetSpacesOperation', - PNGetSpacesOperation: 'PNGetSpacesOperation', - PNGetMembersOperation: 'PNGetMembersOperation', - PNUpdateMembersOperation: 'PNUpdateMembersOperation', - PNGetMembershipsOperation: 'PNGetMembershipsOperation', - PNUpdateMembershipsOperation: 'PNUpdateMembershipsOperation', - // File Upload API v1 - PNListFilesOperation: 'PNListFilesOperation', - PNGenerateUploadUrlOperation: 'PNGenerateUploadUrlOperation', - PNPublishFileOperation: 'PNPublishFileOperation', - PNGetFileUrlOperation: 'PNGetFileUrlOperation', - PNDownloadFileOperation: 'PNDownloadFileOperation', - // Objects API v2 - // UUID - PNGetAllUUIDMetadataOperation: 'PNGetAllUUIDMetadataOperation', - PNGetUUIDMetadataOperation: 'PNGetUUIDMetadataOperation', - PNSetUUIDMetadataOperation: 'PNSetUUIDMetadataOperation', - PNRemoveUUIDMetadataOperation: 'PNRemoveUUIDMetadataOperation', - // channel - PNGetAllChannelMetadataOperation: 'PNGetAllChannelMetadataOperation', - PNGetChannelMetadataOperation: 'PNGetChannelMetadataOperation', - PNSetChannelMetadataOperation: 'PNSetChannelMetadataOperation', - PNRemoveChannelMetadataOperation: 'PNRemoveChannelMetadataOperation', - // member - // PNGetMembersOperation: 'PNGetMembersOperation', - PNSetMembersOperation: 'PNSetMembersOperation', - // PNGetMembershipsOperation: 'PNGetMembersOperation', - PNSetMembershipsOperation: 'PNSetMembershipsOperation', - // push - PNPushNotificationEnabledChannelsOperation: 'PNPushNotificationEnabledChannelsOperation', - PNRemoveAllPushNotificationsOperation: 'PNRemoveAllPushNotificationsOperation', +var RequestOperation; +(function (RequestOperation) { + // -------------------------------------------------------- + // ---------------------- Publish API --------------------- + // -------------------------------------------------------- + /** + * Data publish REST API operation. + */ + RequestOperation["PNPublishOperation"] = "PNPublishOperation"; + /** + * Signal sending REST API operation. + */ + RequestOperation["PNSignalOperation"] = "PNSignalOperation"; + // -------------------------------------------------------- + // --------------------- Subscribe API -------------------- + // -------------------------------------------------------- + /** + * Subscribe for real-time updates REST API operation. + * + * User's presence change on specified entities will trigger `join` event. + */ + RequestOperation["PNSubscribeOperation"] = "PNSubscribeOperation"; + /** + * Unsubscribe from real-time updates REST API operation. + * + * User's presence change on specified entities will trigger `leave` event. + */ + RequestOperation["PNUnsubscribeOperation"] = "PNUnsubscribeOperation"; + // -------------------------------------------------------- + // --------------------- Presence API --------------------- + // -------------------------------------------------------- + /** + * Fetch user's presence information REST API operation. + */ + RequestOperation["PNWhereNowOperation"] = "PNWhereNowOperation"; + /** + * Fetch channel's presence information REST API operation. + */ + RequestOperation["PNHereNowOperation"] = "PNHereNowOperation"; + /** + * Update user's information associated with specified channel REST API operation. + */ + RequestOperation["PNSetStateOperation"] = "PNSetStateOperation"; + /** + * Fetch user's information associated with the specified channel REST API operation. + */ + RequestOperation["PNGetStateOperation"] = "PNGetStateOperation"; + /** + * Announce presence on managed channels REST API operation. + */ + RequestOperation["PNHeartbeatOperation"] = "PNHeartbeatOperation"; + // -------------------------------------------------------- + // ----------------- Message Reaction API ----------------- + // -------------------------------------------------------- + /** + * Add a reaction to the specified message REST API operation. + */ + RequestOperation["PNAddMessageActionOperation"] = "PNAddActionOperation"; + /** + * Remove reaction from the specified message REST API operation. + */ + RequestOperation["PNRemoveMessageActionOperation"] = "PNRemoveMessageActionOperation"; + /** + * Fetch reactions for specific message REST API operation. + */ + RequestOperation["PNGetMessageActionsOperation"] = "PNGetMessageActionsOperation"; + RequestOperation["PNTimeOperation"] = "PNTimeOperation"; + // -------------------------------------------------------- + // ---------------------- Storage API --------------------- + // -------------------------------------------------------- + /** + * Channel history REST API operation. + */ + RequestOperation["PNHistoryOperation"] = "PNHistoryOperation"; + /** + * Delete messages from channel history REST API operation. + */ + RequestOperation["PNDeleteMessagesOperation"] = "PNDeleteMessagesOperation"; + /** + * History for channels REST API operation. + */ + RequestOperation["PNFetchMessagesOperation"] = "PNFetchMessagesOperation"; + /** + * Number of messages for channels in specified time frame REST API operation. + */ + RequestOperation["PNMessageCounts"] = "PNMessageCountsOperation"; + // -------------------------------------------------------- + // -------------------- App Context API ------------------- + // -------------------------------------------------------- + /** + * Fetch users metadata REST API operation. + */ + RequestOperation["PNGetAllUUIDMetadataOperation"] = "PNGetAllUUIDMetadataOperation"; + /** + * Fetch user metadata REST API operation. + */ + RequestOperation["PNGetUUIDMetadataOperation"] = "PNGetUUIDMetadataOperation"; + /** + * Set user metadata REST API operation. + */ + RequestOperation["PNSetUUIDMetadataOperation"] = "PNSetUUIDMetadataOperation"; + /** + * Remove user metadata REST API operation. + */ + RequestOperation["PNRemoveUUIDMetadataOperation"] = "PNRemoveUUIDMetadataOperation"; + /** + * Fetch channels metadata REST API operation. + */ + RequestOperation["PNGetAllChannelMetadataOperation"] = "PNGetAllChannelMetadataOperation"; + /** + * Fetch channel metadata REST API operation. + */ + RequestOperation["PNGetChannelMetadataOperation"] = "PNGetChannelMetadataOperation"; + /** + * Set channel metadata REST API operation. + */ + RequestOperation["PNSetChannelMetadataOperation"] = "PNSetChannelMetadataOperation"; + /** + * Remove channel metadata REST API operation. + */ + RequestOperation["PNRemoveChannelMetadataOperation"] = "PNRemoveChannelMetadataOperation"; + /** + * Fetch channel members REST API operation. + */ + RequestOperation["PNGetMembersOperation"] = "PNGetMembersOperation"; + /** + * Update channel members REST API operation. + */ + RequestOperation["PNSetMembersOperation"] = "PNSetMembersOperation"; + /** + * Fetch channel memberships REST API operation. + */ + RequestOperation["PNGetMembershipsOperation"] = "PNGetMembershipsOperation"; + /** + * Update channel memberships REST API operation. + */ + RequestOperation["PNSetMembershipsOperation"] = "PNSetMembershipsOperation"; + // -------------------------------------------------------- + // -------------------- File Upload API ------------------- + // -------------------------------------------------------- + /** + * Fetch list of files sent to the channel REST API operation. + */ + RequestOperation["PNListFilesOperation"] = "PNListFilesOperation"; + /** + * Retrieve file upload URL REST API operation. + */ + RequestOperation["PNGenerateUploadUrlOperation"] = "PNGenerateUploadUrlOperation"; + /** + * Upload file to the channel REST API operation. + */ + RequestOperation["PNPublishFileOperation"] = "PNPublishFileOperation"; + /** + * Publish File Message to the channel REST API operation. + */ + RequestOperation["PNPublishFileMessageOperation"] = "PNPublishFileMessageOperation"; + /** + * Retrieve file download URL REST API operation. + */ + RequestOperation["PNGetFileUrlOperation"] = "PNGetFileUrlOperation"; + /** + * Download file from the channel REST API operation. + */ + RequestOperation["PNDownloadFileOperation"] = "PNDownloadFileOperation"; + /** + * Delete file sent to the channel REST API operation. + */ + RequestOperation["PNDeleteFileOperation"] = "PNDeleteFileOperation"; + // -------------------------------------------------------- + // -------------------- Mobile Push API ------------------- + // -------------------------------------------------------- + /** + * Register channels with device push notifications REST API operation. + */ + RequestOperation["PNAddPushNotificationEnabledChannelsOperation"] = "PNAddPushNotificationEnabledChannelsOperation"; + /** + * Unregister channels with device push notifications REST API operation. + */ + RequestOperation["PNRemovePushNotificationEnabledChannelsOperation"] = "PNRemovePushNotificationEnabledChannelsOperation"; + /** + * Fetch list of channels with enabled push notifications for device REST API operation. + */ + RequestOperation["PNPushNotificationEnabledChannelsOperation"] = "PNPushNotificationEnabledChannelsOperation"; + /** + * Disable push notifications for device REST API operation. + */ + RequestOperation["PNRemoveAllPushNotificationsOperation"] = "PNRemoveAllPushNotificationsOperation"; + // -------------------------------------------------------- + // ------------------ Channel Groups API ------------------ + // -------------------------------------------------------- + /** + * Fetch channels groups list REST API operation. + */ + RequestOperation["PNChannelGroupsOperation"] = "PNChannelGroupsOperation"; + /** + * Remove specified channel group REST API operation. + */ + RequestOperation["PNRemoveGroupOperation"] = "PNRemoveGroupOperation"; + /** + * Fetch list of channels for the specified channel group REST API operation. + */ + RequestOperation["PNChannelsForGroupOperation"] = "PNChannelsForGroupOperation"; + /** + * Add list of channels to the specified channel group REST API operation. + */ + RequestOperation["PNAddChannelsToGroupOperation"] = "PNAddChannelsToGroupOperation"; + /** + * Remove list of channels from the specified channel group REST API operation. + */ + RequestOperation["PNRemoveChannelsFromGroupOperation"] = "PNRemoveChannelsFromGroupOperation"; + // -------------------------------------------------------- + // ----------------------- PAM API ------------------------ + // -------------------------------------------------------- + /** + * Generate authorized token REST API operation. + */ + RequestOperation["PNAccessManagerGrant"] = "PNAccessManagerGrant"; + /** + * Generate authorized token REST API operation. + */ + RequestOperation["PNAccessManagerGrantToken"] = "PNAccessManagerGrantToken"; + RequestOperation["PNAccessManagerAudit"] = "PNAccessManagerAudit"; + /** + * Revoke authorized token REST API operation. + */ + RequestOperation["PNAccessManagerRevokeToken"] = "PNAccessManagerRevokeToken"; // - // presence - PNWhereNowOperation: 'PNWhereNowOperation', - PNSetStateOperation: 'PNSetStateOperation', - PNHereNowOperation: 'PNHereNowOperation', - PNGetStateOperation: 'PNGetStateOperation', - PNHeartbeatOperation: 'PNHeartbeatOperation', - // - // channel group - PNChannelGroupsOperation: 'PNChannelGroupsOperation', - PNRemoveGroupOperation: 'PNRemoveGroupOperation', - PNChannelsForGroupOperation: 'PNChannelsForGroupOperation', - PNAddChannelsToGroupOperation: 'PNAddChannelsToGroupOperation', - PNRemoveChannelsFromGroupOperation: 'PNRemoveChannelsFromGroupOperation', - // - // PAM - PNAccessManagerGrant: 'PNAccessManagerGrant', - PNAccessManagerGrantToken: 'PNAccessManagerGrantToken', - PNAccessManagerAudit: 'PNAccessManagerAudit', - PNAccessManagerRevokeToken: 'PNAccessManagerRevokeToken', - // - // subscription utilities - PNHandshakeOperation: 'PNHandshakeOperation', - PNReceiveMessagesOperation: 'PNReceiveMessagesOperation', -}; + // -------------------------------------------------------- + // ---------------- Subscription Utility ------------------ + // -------------------------------------------------------- + RequestOperation["PNHandshakeOperation"] = "PNHandshakeOperation"; + RequestOperation["PNReceiveMessagesOperation"] = "PNReceiveMessagesOperation"; +})(RequestOperation || (RequestOperation = {})); +exports.default = RequestOperation; diff --git a/lib/core/endpoints/access_manager/audit.js b/lib/core/endpoints/access_manager/audit.js index 2cdd17c8e..3a210fab2 100644 --- a/lib/core/endpoints/access_manager/audit.js +++ b/lib/core/endpoints/access_manager/audit.js @@ -1,51 +1,133 @@ "use strict"; -/* */ +/** + * PAM Audit REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; +exports.AuditRequest = void 0; +var PubNubError_1 = require("../../../models/PubNubError"); +var request_1 = require("../../components/request"); var operations_1 = __importDefault(require("../../constants/operations")); -function getOperation() { - return operations_1.default.PNAccessManagerAudit; -} -exports.getOperation = getOperation; -function validateParams(modules) { - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules) { - var config = modules.config; - return "/v2/auth/audit/sub-key/".concat(config.subscribeKey); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return false; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams(modules, incomingParams) { - var channel = incomingParams.channel, channelGroup = incomingParams.channelGroup, _a = incomingParams.authKeys, authKeys = _a === void 0 ? [] : _a; - var params = {}; - if (channel) { - params.channel = channel; - } - if (channelGroup) { - params['channel-group'] = channelGroup; - } - if (authKeys.length > 0) { - params.auth = authKeys.join(','); +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults +/** + * Auth keys for which permissions should be audited. + */ +var AUTH_KEYS = []; +// endregion +/** + * Permissions audit request. + */ +var AuditRequest = /** @class */ (function (_super) { + __extends(AuditRequest, _super); + function AuditRequest(parameters) { + var _a; + var _b; + var _this = _super.call(this) || this; + _this.parameters = parameters; + // Apply default request parameters. + (_a = (_b = _this.parameters).authKeys) !== null && _a !== void 0 ? _a : (_b.authKeys = AUTH_KEYS); + return _this; } - return params; -} -exports.prepareParams = prepareParams; -function handleResponse(modules, serverResponse) { - return serverResponse.payload; -} -exports.handleResponse = handleResponse; + AuditRequest.prototype.operation = function () { + return operations_1.default.PNAccessManagerAudit; + }; + AuditRequest.prototype.validate = function () { + if (!this.parameters.keySet.subscribeKey) + return 'Missing Subscribe Key'; + }; + AuditRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, serviceResponse.payload]; + }); + }); + }; + Object.defineProperty(AuditRequest.prototype, "path", { + get: function () { + return "/v2/auth/audit/sub-key/".concat(this.parameters.keySet.subscribeKey); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(AuditRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, channel = _a.channel, channelGroup = _a.channelGroup, authKeys = _a.authKeys; + return __assign(__assign(__assign({}, (channel ? { channel: channel } : {})), (channelGroup ? { 'channel-group': channelGroup } : {})), (authKeys && authKeys.length ? { auth: authKeys.join(',') } : {})); + }, + enumerable: false, + configurable: true + }); + return AuditRequest; +}(request_1.AbstractRequest)); +exports.AuditRequest = AuditRequest; diff --git a/lib/core/endpoints/access_manager/grant.js b/lib/core/endpoints/access_manager/grant.js index e65a390b5..78866ddf4 100644 --- a/lib/core/endpoints/access_manager/grant.js +++ b/lib/core/endpoints/access_manager/grant.js @@ -1,75 +1,176 @@ "use strict"; +/** + * PAM Grant REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; -/* */ +exports.GrantRequest = void 0; +var PubNubError_1 = require("../../../models/PubNubError"); +var request_1 = require("../../components/request"); var operations_1 = __importDefault(require("../../constants/operations")); -function getOperation() { - return operations_1.default.PNAccessManagerGrant; -} -exports.getOperation = getOperation; -function validateParams(modules, incomingParams) { - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - if (!config.publishKey) - return 'Missing Publish Key'; - if (!config.secretKey) - return 'Missing Secret Key'; - if (incomingParams.uuids != null && !incomingParams.authKeys) { - return 'authKeys are required for grant request on uuids'; - } - if (incomingParams.uuids != null && (incomingParams.channels != null || incomingParams.channelGroups != null)) { - return 'Both channel/channelgroup and uuid cannot be used in the same request'; - } -} -exports.validateParams = validateParams; -function getURL(modules) { - var config = modules.config; - return "/v2/auth/grant/sub-key/".concat(config.subscribeKey); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return false; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams(modules, incomingParams) { - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a, _b = incomingParams.channelGroups, channelGroups = _b === void 0 ? [] : _b, _c = incomingParams.uuids, uuids = _c === void 0 ? [] : _c, ttl = incomingParams.ttl, _d = incomingParams.read, read = _d === void 0 ? false : _d, _e = incomingParams.write, write = _e === void 0 ? false : _e, _f = incomingParams.manage, manage = _f === void 0 ? false : _f, _g = incomingParams.get, get = _g === void 0 ? false : _g, _h = incomingParams.join, join = _h === void 0 ? false : _h, _j = incomingParams.update, update = _j === void 0 ? false : _j, _k = incomingParams.authKeys, authKeys = _k === void 0 ? [] : _k; - var deleteParam = incomingParams.delete; - var params = {}; - params.r = read ? '1' : '0'; - params.w = write ? '1' : '0'; - params.m = manage ? '1' : '0'; - params.d = deleteParam ? '1' : '0'; - params.g = get ? '1' : '0'; - params.j = join ? '1' : '0'; - params.u = update ? '1' : '0'; - if (channels.length > 0) { - params.channel = channels.join(','); - } - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); - } - if (authKeys.length > 0) { - params.auth = authKeys.join(','); - } - if (uuids.length > 0) { - params['target-uuid'] = uuids.join(','); - } - if (ttl || ttl === 0) { - params.ttl = ttl; +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults +/** + * Resources `read` permission. + */ +var READ_PERMISSION = false; +/** + * Resources `write` permission. + */ +var WRITE_PERMISSION = false; +/** + * Resources `delete` permission. + */ +var DELETE_PERMISSION = false; +/** + * Resources `get` permission. + */ +var GET_PERMISSION = false; +/** + * Resources `update` permission. + */ +var UPDATE_PERMISSION = false; +/** + * Resources `manage` permission. + */ +var MANAGE_PERMISSION = false; +/** + * Resources `join` permission. + */ +var JOIN_PERMISSION = false; +// endregion +/** + * Grant permissions request. + */ +var GrantRequest = /** @class */ (function (_super) { + __extends(GrantRequest, _super); + function GrantRequest(parameters) { + var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k; + var _l, _m, _o, _p, _q, _r, _s, _t, _u, _v; + var _this = _super.call(this) || this; + _this.parameters = parameters; + // Apply defaults. + (_a = (_l = _this.parameters).channels) !== null && _a !== void 0 ? _a : (_l.channels = []); + (_b = (_m = _this.parameters).channelGroups) !== null && _b !== void 0 ? _b : (_m.channelGroups = []); + (_c = (_o = _this.parameters).uuids) !== null && _c !== void 0 ? _c : (_o.uuids = []); + (_d = (_p = _this.parameters).read) !== null && _d !== void 0 ? _d : (_p.read = READ_PERMISSION); + (_e = (_q = _this.parameters).write) !== null && _e !== void 0 ? _e : (_q.write = WRITE_PERMISSION); + (_f = (_r = _this.parameters).delete) !== null && _f !== void 0 ? _f : (_r.delete = DELETE_PERMISSION); + (_g = (_s = _this.parameters).get) !== null && _g !== void 0 ? _g : (_s.get = GET_PERMISSION); + (_h = (_t = _this.parameters).update) !== null && _h !== void 0 ? _h : (_t.update = UPDATE_PERMISSION); + (_j = (_u = _this.parameters).manage) !== null && _j !== void 0 ? _j : (_u.manage = MANAGE_PERMISSION); + (_k = (_v = _this.parameters).join) !== null && _k !== void 0 ? _k : (_v.join = JOIN_PERMISSION); + return _this; } - return params; -} -exports.prepareParams = prepareParams; -function handleResponse() { - return {}; -} -exports.handleResponse = handleResponse; + GrantRequest.prototype.operation = function () { + return operations_1.default.PNAccessManagerGrant; + }; + GrantRequest.prototype.validate = function () { + var _a; + var _b = this.parameters, _c = _b.keySet, subscribeKey = _c.subscribeKey, publishKey = _c.publishKey, secretKey = _c.secretKey, uuids = _b.uuids, channels = _b.channels, channelGroups = _b.channelGroups; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!publishKey) + return 'Missing Publish Key'; + if (!secretKey) + return 'Missing Secret Key'; + if ((uuids === null || uuids === void 0 ? void 0 : uuids.length) !== 0 && ((_a = this.parameters.authKeys) === null || _a === void 0 ? void 0 : _a.length) === 0) + return 'authKeys are required for grant request on uuids'; + if ((uuids === null || uuids === void 0 ? void 0 : uuids.length) && ((channels === null || channels === void 0 ? void 0 : channels.length) !== 0 || (channelGroups === null || channelGroups === void 0 ? void 0 : channelGroups.length) !== 0)) + return 'Both channel/channel group and uuid cannot be used in the same request'; + }; + GrantRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, serviceResponse.payload]; + }); + }); + }; + Object.defineProperty(GrantRequest.prototype, "path", { + get: function () { + return "/v2/auth/grant/sub-key/".concat(this.parameters.keySet.subscribeKey); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(GrantRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, channels = _a.channels, channelGroups = _a.channelGroups, authKeys = _a.authKeys, uuids = _a.uuids, read = _a.read, write = _a.write, manage = _a.manage, del = _a.delete, get = _a.get, join = _a.join, update = _a.update, ttl = _a.ttl; + return __assign(__assign(__assign(__assign(__assign(__assign({}, (channels && (channels === null || channels === void 0 ? void 0 : channels.length) > 0 ? { channel: channels.join(',') } : {})), (channelGroups && (channelGroups === null || channelGroups === void 0 ? void 0 : channelGroups.length) > 0 ? { 'channel-group': channelGroups.join(',') } : {})), (authKeys && (authKeys === null || authKeys === void 0 ? void 0 : authKeys.length) > 0 ? { auth: authKeys.join(',') } : {})), (uuids && (uuids === null || uuids === void 0 ? void 0 : uuids.length) > 0 ? { 'target-uuid': uuids.join(',') } : {})), { r: read ? '1' : '0', w: write ? '1' : '0', m: manage ? '1' : '0', d: del ? '1' : '0', g: get ? '1' : '0', j: join ? '1' : '0', u: update ? '1' : '0' }), (ttl || ttl === 0 ? { ttl: ttl } : {})); + }, + enumerable: false, + configurable: true + }); + return GrantRequest; +}(request_1.AbstractRequest)); +exports.GrantRequest = GrantRequest; diff --git a/lib/core/endpoints/access_manager/grant_token.js b/lib/core/endpoints/access_manager/grant_token.js index 8c9f0b974..f08769bc4 100644 --- a/lib/core/endpoints/access_manager/grant_token.js +++ b/lib/core/endpoints/access_manager/grant_token.js @@ -1,263 +1,243 @@ "use strict"; +/** + * PAM Grant Token REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.postPayload = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.usePost = exports.postURL = exports.validateParams = exports.extractPermissions = exports.getOperation = void 0; +exports.GrantTokenRequest = void 0; +var PubNubError_1 = require("../../../models/PubNubError"); +var transport_request_1 = require("../../types/transport-request"); +var request_1 = require("../../components/request"); var operations_1 = __importDefault(require("../../constants/operations")); -function getOperation() { - return operations_1.default.PNAccessManagerGrantToken; -} -exports.getOperation = getOperation; -function hasVspTerms(incomingParams) { - var _a, _b, _c, _d; - var hasAuthorizedUserId = (incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.authorizedUserId) !== undefined; - var hasUserResources = ((_a = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.resources) === null || _a === void 0 ? void 0 : _a.users) !== undefined; - var hasSpaceResources = ((_b = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.resources) === null || _b === void 0 ? void 0 : _b.spaces) !== undefined; - var hasUserPatterns = ((_c = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.patterns) === null || _c === void 0 ? void 0 : _c.users) !== undefined; - var hasSpacePatterns = ((_d = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.patterns) === null || _d === void 0 ? void 0 : _d.spaces) !== undefined; - return hasUserPatterns || hasUserResources || hasSpacePatterns || hasSpaceResources || hasAuthorizedUserId; -} -function extractPermissions(permissions) { - var permissionsResult = 0; - if (permissions.join) { - permissionsResult |= 128; - } - if (permissions.update) { - permissionsResult |= 64; - } - if (permissions.get) { - permissionsResult |= 32; - } - if (permissions.delete) { - permissionsResult |= 8; - } - if (permissions.manage) { - permissionsResult |= 4; - } - if (permissions.write) { - permissionsResult |= 2; - } - if (permissions.read) { - permissionsResult |= 1; - } - return permissionsResult; -} -exports.extractPermissions = extractPermissions; -function prepareMessagePayloadVsp(_modules, _a) { - var ttl = _a.ttl, resources = _a.resources, patterns = _a.patterns, meta = _a.meta, authorizedUserId = _a.authorizedUserId; - var params = { - ttl: 0, - permissions: { - resources: { - channels: {}, - groups: {}, - uuids: {}, - users: {}, - spaces: {}, // not used, needed for api backward compatibility - }, - patterns: { - channels: {}, - groups: {}, - uuids: {}, - users: {}, - spaces: {}, // not used, needed for api backward compatibility - }, - meta: {}, - }, +// endregion +/** + * Grant token permissions request. + */ +var GrantTokenRequest = /** @class */ (function (_super) { + __extends(GrantTokenRequest, _super); + function GrantTokenRequest(parameters) { + var _a, _b; + var _c, _d; + var _this = _super.call(this, { method: transport_request_1.TransportMethod.POST }) || this; + _this.parameters = parameters; + // Apply defaults. + (_a = (_c = _this.parameters).resources) !== null && _a !== void 0 ? _a : (_c.resources = {}); + (_b = (_d = _this.parameters).patterns) !== null && _b !== void 0 ? _b : (_d.patterns = {}); + return _this; + } + GrantTokenRequest.prototype.operation = function () { + return operations_1.default.PNAccessManagerGrantToken; }; - if (resources) { - var users_1 = resources.users, spaces_1 = resources.spaces, groups_1 = resources.groups; - if (users_1) { - Object.keys(users_1).forEach(function (userID) { - params.permissions.resources.uuids[userID] = extractPermissions(users_1[userID]); - }); - } - if (spaces_1) { - Object.keys(spaces_1).forEach(function (spaceId) { - params.permissions.resources.channels[spaceId] = extractPermissions(spaces_1[spaceId]); + GrantTokenRequest.prototype.validate = function () { + var _a, _b, _c, _d, _e, _f; + var _g = this.parameters, _h = _g.keySet, subscribeKey = _h.subscribeKey, publishKey = _h.publishKey, secretKey = _h.secretKey, resources = _g.resources, patterns = _g.patterns; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!publishKey) + return 'Missing Publish Key'; + if (!secretKey) + return 'Missing Secret Key'; + if (!resources && !patterns) + return 'Missing either Resources or Patterns'; + if (this.isVspPermissions(this.parameters) && + ('channels' in ((_a = this.parameters.resources) !== null && _a !== void 0 ? _a : {}) || + 'uuids' in ((_b = this.parameters.resources) !== null && _b !== void 0 ? _b : {}) || + 'groups' in ((_c = this.parameters.resources) !== null && _c !== void 0 ? _c : {}) || + 'channels' in ((_d = this.parameters.patterns) !== null && _d !== void 0 ? _d : {}) || + 'uuids' in ((_e = this.parameters.patterns) !== null && _e !== void 0 ? _e : {}) || + 'groups' in ((_f = this.parameters.patterns) !== null && _f !== void 0 ? _f : {}))) + return ('Cannot mix `users`, `spaces` and `authorizedUserId` with `uuids`, `channels`,' + + ' `groups` and `authorized_uuid`'); + var permissionsEmpty = true; + [this.parameters.resources, this.parameters.patterns].forEach(function (refPerm) { + Object.keys(refPerm !== null && refPerm !== void 0 ? refPerm : {}).forEach(function (scope) { + var _a; + // @ts-expect-error Permissions with backward compatibility. + if (refPerm && permissionsEmpty && Object.keys((_a = refPerm[scope]) !== null && _a !== void 0 ? _a : {}).length > 0) { + permissionsEmpty = false; + } }); - } - if (groups_1) { - Object.keys(groups_1).forEach(function (group) { - params.permissions.resources.groups[group] = extractPermissions(groups_1[group]); - }); - } - } - if (patterns) { - var users_2 = patterns.users, spaces_2 = patterns.spaces, groups_2 = patterns.groups; - if (users_2) { - Object.keys(users_2).forEach(function (userId) { - params.permissions.patterns.uuids[userId] = extractPermissions(users_2[userId]); - }); - } - if (spaces_2) { - Object.keys(spaces_2).forEach(function (spaceId) { - params.permissions.patterns.channels[spaceId] = extractPermissions(spaces_2[spaceId]); + }); + if (permissionsEmpty) + return 'Missing values for either Resources or Patterns'; + }; + GrantTokenRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, serviceResponse.data.token]; }); - } - if (groups_2) { - Object.keys(groups_2).forEach(function (group) { - params.permissions.patterns.groups[group] = extractPermissions(groups_2[group]); + }); + }; + Object.defineProperty(GrantTokenRequest.prototype, "path", { + get: function () { + return "/v3/pam/".concat(this.parameters.keySet.subscribeKey, "/grant"); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(GrantTokenRequest.prototype, "body", { + get: function () { + var _this = this; + var _a = this.parameters, ttl = _a.ttl, meta = _a.meta; + var body = __assign({}, (ttl || ttl === 0 ? { ttl: ttl } : {})); + var uuid = this.isVspPermissions(this.parameters) + ? this.parameters.authorizedUserId + : this.parameters.authorized_uuid; + var permissions = {}; + var resourcePermissions = {}; + var patternPermissions = {}; + var mapPermissions = function (name, permissionBit, type, permissions) { + if (!permissions[type]) + permissions[type] = {}; + permissions[type][name] = permissionBit; + }; + var _b = this.parameters, resources = _b.resources, patterns = _b.patterns; + [resources, patterns].forEach(function (refPerm, idx) { + var _a, _b, _c, _d, _e; + var target = idx === 0 ? resourcePermissions : patternPermissions; + var channelsPermissions = {}; + var channelGroupsPermissions = {}; + var uuidsPermissions = {}; + if (refPerm) { + // Check whether working with legacy Objects permissions. + if ('spaces' in refPerm || 'users' in refPerm) { + channelsPermissions = (_a = refPerm.spaces) !== null && _a !== void 0 ? _a : {}; + uuidsPermissions = (_b = refPerm.users) !== null && _b !== void 0 ? _b : {}; + } + else if ('channels' in refPerm || 'uuids' in refPerm || 'groups' in refPerm) { + channelsPermissions = (_c = refPerm.channels) !== null && _c !== void 0 ? _c : {}; + channelGroupsPermissions = (_d = refPerm.groups) !== null && _d !== void 0 ? _d : {}; + uuidsPermissions = (_e = refPerm.uuids) !== null && _e !== void 0 ? _e : {}; + } + } + Object.keys(channelsPermissions).forEach(function (channel) { + return mapPermissions(channel, _this.extractPermissions(channelsPermissions[channel]), 'channels', target); + }); + Object.keys(channelGroupsPermissions).forEach(function (groups) { + return mapPermissions(groups, _this.extractPermissions(channelGroupsPermissions[groups]), 'groups', target); + }); + Object.keys(uuidsPermissions).forEach(function (uuids) { + return mapPermissions(uuids, _this.extractPermissions(uuidsPermissions[uuids]), 'uuids', target); + }); }); - } - } - if (ttl || ttl === 0) { - params.ttl = ttl; - } - if (meta) { - params.permissions.meta = meta; - } - if (authorizedUserId) { - params.permissions.uuid = "".concat(authorizedUserId); // ensure this is a string - } - return params; -} -function prepareMessagePayload(_modules, incomingParams) { - if (hasVspTerms(incomingParams)) { - return prepareMessagePayloadVsp(_modules, incomingParams); - } - var ttl = incomingParams.ttl, resources = incomingParams.resources, patterns = incomingParams.patterns, meta = incomingParams.meta, authorized_uuid = incomingParams.authorized_uuid; - var params = { - ttl: 0, - permissions: { - resources: { - channels: {}, - groups: {}, - uuids: {}, - users: {}, - spaces: {}, // not used, needed for api backward compatibility - }, - patterns: { - channels: {}, - groups: {}, - uuids: {}, - users: {}, - spaces: {}, // not used, needed for api backward compatibility - }, - meta: {}, + if (uuid) + permissions.uuid = "".concat(uuid); + if (meta) + permissions.meta = meta; + body.permissions = permissions; + return JSON.stringify(body); }, + enumerable: false, + configurable: true + }); + /** + * Extract permissions bit from permission configuration object. + * + * @param permissions - User provided scope-based permissions. + * + * @returns Permissions bit. + */ + GrantTokenRequest.prototype.extractPermissions = function (permissions) { + var permissionsResult = 0; + if ('join' in permissions && permissions.join) + permissionsResult |= 128; + if ('update' in permissions && permissions.update) + permissionsResult |= 64; + if ('get' in permissions && permissions.get) + permissionsResult |= 32; + if ('delete' in permissions && permissions.delete) + permissionsResult |= 8; + if ('manage' in permissions && permissions.manage) + permissionsResult |= 4; + if ('write' in permissions && permissions.write) + permissionsResult |= 2; + if ('read' in permissions && permissions.read) + permissionsResult |= 1; + return permissionsResult; }; - if (resources) { - var uuids_1 = resources.uuids, channels_1 = resources.channels, groups_3 = resources.groups; - if (uuids_1) { - Object.keys(uuids_1).forEach(function (uuid) { - params.permissions.resources.uuids[uuid] = extractPermissions(uuids_1[uuid]); - }); - } - if (channels_1) { - Object.keys(channels_1).forEach(function (channel) { - params.permissions.resources.channels[channel] = extractPermissions(channels_1[channel]); - }); - } - if (groups_3) { - Object.keys(groups_3).forEach(function (group) { - params.permissions.resources.groups[group] = extractPermissions(groups_3[group]); - }); - } - } - if (patterns) { - var uuids_2 = patterns.uuids, channels_2 = patterns.channels, groups_4 = patterns.groups; - if (uuids_2) { - Object.keys(uuids_2).forEach(function (uuid) { - params.permissions.patterns.uuids[uuid] = extractPermissions(uuids_2[uuid]); - }); - } - if (channels_2) { - Object.keys(channels_2).forEach(function (channel) { - params.permissions.patterns.channels[channel] = extractPermissions(channels_2[channel]); - }); - } - if (groups_4) { - Object.keys(groups_4).forEach(function (group) { - params.permissions.patterns.groups[group] = extractPermissions(groups_4[group]); - }); - } - } - if (ttl || ttl === 0) { - params.ttl = ttl; - } - if (meta) { - params.permissions.meta = meta; - } - if (authorized_uuid) { - params.permissions.uuid = "".concat(authorized_uuid); // ensure this is a string - } - return params; -} -function validateParams(modules, incomingParams) { - var _a, _b, _c, _d, _e, _f; - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - if (!config.publishKey) - return 'Missing Publish Key'; - if (!config.secretKey) - return 'Missing Secret Key'; - if (!incomingParams.resources && !incomingParams.patterns) - return 'Missing either Resources or Patterns.'; - var hasAuthorizedUuid = (incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.authorized_uuid) !== undefined; - var hasUuidResources = ((_a = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.resources) === null || _a === void 0 ? void 0 : _a.uuids) !== undefined; - var hasChannelResources = ((_b = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.resources) === null || _b === void 0 ? void 0 : _b.channels) !== undefined; - var hasGroupResources = ((_c = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.resources) === null || _c === void 0 ? void 0 : _c.groups) !== undefined; - var hasUuidPatterns = ((_d = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.patterns) === null || _d === void 0 ? void 0 : _d.uuids) !== undefined; - var hasChannelPatterns = ((_e = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.patterns) === null || _e === void 0 ? void 0 : _e.channels) !== undefined; - var hasGroupPatterns = ((_f = incomingParams === null || incomingParams === void 0 ? void 0 : incomingParams.patterns) === null || _f === void 0 ? void 0 : _f.groups) !== undefined; - var hasLegacyTerms = hasAuthorizedUuid || - hasUuidResources || - hasUuidPatterns || - hasChannelResources || - hasChannelPatterns || - hasGroupResources || - hasGroupPatterns; - if (hasVspTerms(incomingParams) && hasLegacyTerms) { - return ('Cannot mix `users`, `spaces` and `authorizedUserId` ' + - 'with `uuids`, `channels`, `groups` and `authorized_uuid`'); - } - if ((incomingParams.resources && - (!incomingParams.resources.uuids || Object.keys(incomingParams.resources.uuids).length === 0) && - (!incomingParams.resources.channels || Object.keys(incomingParams.resources.channels).length === 0) && - (!incomingParams.resources.groups || Object.keys(incomingParams.resources.groups).length === 0) && - (!incomingParams.resources.users || Object.keys(incomingParams.resources.users).length === 0) && - (!incomingParams.resources.spaces || Object.keys(incomingParams.resources.spaces).length === 0)) || - (incomingParams.patterns && - (!incomingParams.patterns.uuids || Object.keys(incomingParams.patterns.uuids).length === 0) && - (!incomingParams.patterns.channels || Object.keys(incomingParams.patterns.channels).length === 0) && - (!incomingParams.patterns.groups || Object.keys(incomingParams.patterns.groups).length === 0) && - (!incomingParams.patterns.users || Object.keys(incomingParams.patterns.users).length === 0) && - (!incomingParams.patterns.spaces || Object.keys(incomingParams.patterns.spaces).length === 0))) { - return 'Missing values for either Resources or Patterns.'; - } -} -exports.validateParams = validateParams; -function postURL(modules) { - var config = modules.config; - return "/v3/pam/".concat(config.subscribeKey, "/grant"); -} -exports.postURL = postURL; -function usePost() { - return true; -} -exports.usePost = usePost; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return false; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams() { - return {}; -} -exports.prepareParams = prepareParams; -function postPayload(modules, incomingParams) { - return prepareMessagePayload(modules, incomingParams); -} -exports.postPayload = postPayload; -function handleResponse(modules, response) { - var token = response.data.token; - return token; -} -exports.handleResponse = handleResponse; + /** + * Check whether provided parameters is part of legacy VSP access token configuration. + * + * @param parameters - Parameters which should be checked. + * + * @returns VSP request parameters if it is legacy configuration. + */ + GrantTokenRequest.prototype.isVspPermissions = function (parameters) { + var _a, _b, _c, _d; + return ('authorizedUserId' in parameters || + 'spaces' in ((_a = parameters.resources) !== null && _a !== void 0 ? _a : {}) || + 'users' in ((_b = parameters.resources) !== null && _b !== void 0 ? _b : {}) || + 'spaces' in ((_c = parameters.patterns) !== null && _c !== void 0 ? _c : {}) || + 'users' in ((_d = parameters.patterns) !== null && _d !== void 0 ? _d : {})); + }; + return GrantTokenRequest; +}(request_1.AbstractRequest)); +exports.GrantTokenRequest = GrantTokenRequest; diff --git a/lib/core/endpoints/access_manager/revoke_token.js b/lib/core/endpoints/access_manager/revoke_token.js index 81f04e9e5..c2ea2c25b 100644 --- a/lib/core/endpoints/access_manager/revoke_token.js +++ b/lib/core/endpoints/access_manager/revoke_token.js @@ -1,41 +1,109 @@ "use strict"; -/** */ +/** + * PAM Revoke Token REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); +exports.RevokeTokenRequest = void 0; +var PubNubError_1 = require("../../../models/PubNubError"); +var transport_request_1 = require("../../types/transport-request"); +var request_1 = require("../../components/request"); var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNAccessManagerRevokeToken; }, - validateParams: function (modules, token) { - var secretKey = modules.config.secretKey; - if (!secretKey) { +var utils_1 = require("../../utils"); +// endregion +/** + * Access token revoke request. + * + * Invalidate token and permissions which has been granted for it. + */ +var RevokeTokenRequest = /** @class */ (function (_super) { + __extends(RevokeTokenRequest, _super); + function RevokeTokenRequest(parameters) { + var _this = _super.call(this, { method: transport_request_1.TransportMethod.DELETE }) || this; + _this.parameters = parameters; + return _this; + } + RevokeTokenRequest.prototype.operation = function () { + return operations_1.default.PNAccessManagerRevokeToken; + }; + RevokeTokenRequest.prototype.validate = function () { + if (!this.parameters.keySet.secretKey) return 'Missing Secret Key'; - } - if (!token) { + if (!this.parameters.token) return "token can't be empty"; - } - }, - getURL: function (_a, token) { - var config = _a.config; - return "/v3/pam/".concat(config.subscribeKey, "/grant/").concat(utils_1.default.encodeString(token)); - }, - useDelete: function () { return true; }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return false; }, - prepareParams: function (_a) { - var config = _a.config; - return ({ - uuid: config.getUUID(), + }; + RevokeTokenRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, {}]; + }); }); - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - }); }, -}; -exports.default = endpoint; + }; + Object.defineProperty(RevokeTokenRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, token = _a.token; + return "/v3/pam/".concat(subscribeKey, "/grant/").concat((0, utils_1.encodeString)(token)); + }, + enumerable: false, + configurable: true + }); + return RevokeTokenRequest; +}(request_1.AbstractRequest)); +exports.RevokeTokenRequest = RevokeTokenRequest; diff --git a/lib/core/endpoints/actions/add_message_action.js b/lib/core/endpoints/actions/add_message_action.js index fef7705ba..433a602aa 100644 --- a/lib/core/endpoints/actions/add_message_action.js +++ b/lib/core/endpoints/actions/add_message_action.js @@ -1,67 +1,132 @@ "use strict"; -/* */ +/** + * Add Message Action REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.postPayload = exports.prepareParams = exports.isAuthSupported = exports.getRequestHeaders = exports.getRequestTimeout = exports.postURL = exports.usePost = exports.validateParams = exports.getOperation = void 0; +exports.AddMessageActionRequest = void 0; +var PubNubError_1 = require("../../../models/PubNubError"); +var transport_request_1 = require("../../types/transport-request"); +var request_1 = require("../../components/request"); var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -function getOperation() { - return operations_1.default.PNAddMessageActionOperation; -} -exports.getOperation = getOperation; -function validateParams(_a, incomingParams) { - var config = _a.config; - var action = incomingParams.action, channel = incomingParams.channel, messageTimetoken = incomingParams.messageTimetoken; - if (!messageTimetoken) - return 'Missing message timetoken'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - if (!channel) - return 'Missing message channel'; - if (!action) - return 'Missing Action'; - if (!action.value) - return 'Missing Action.value'; - if (!action.type) - return 'Missing Action.type'; - if (action.type.length > 15) - return 'Action.type value exceed maximum length of 15'; -} -exports.validateParams = validateParams; -function usePost() { - return true; -} -exports.usePost = usePost; -function postURL(_a, incomingParams) { - var config = _a.config; - var channel = incomingParams.channel, messageTimetoken = incomingParams.messageTimetoken; - return "/v1/message-actions/".concat(config.subscribeKey, "/channel/").concat(utils_1.default.encodeString(channel), "/message/").concat(messageTimetoken); -} -exports.postURL = postURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function getRequestHeaders() { - return { 'Content-Type': 'application/json' }; -} -exports.getRequestHeaders = getRequestHeaders; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams() { - return {}; -} -exports.prepareParams = prepareParams; -function postPayload(modules, incomingParams) { - return incomingParams.action; -} -exports.postPayload = postPayload; -function handleResponse(modules, addMessageActionResponse) { - return { data: addMessageActionResponse.data }; -} -exports.handleResponse = handleResponse; +var utils_1 = require("../../utils"); +// endregion +/** + * Add Message Reaction request. + */ +var AddMessageActionRequest = /** @class */ (function (_super) { + __extends(AddMessageActionRequest, _super); + function AddMessageActionRequest(parameters) { + var _this = _super.call(this, { method: transport_request_1.TransportMethod.POST }) || this; + _this.parameters = parameters; + return _this; + } + AddMessageActionRequest.prototype.operation = function () { + return operations_1.default.PNAddMessageActionOperation; + }; + AddMessageActionRequest.prototype.validate = function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, action = _a.action, channel = _a.channel, messageTimetoken = _a.messageTimetoken; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!channel) + return 'Missing message channel'; + if (!messageTimetoken) + return 'Missing message timetoken'; + if (!action) + return 'Missing Action.value'; + if (!action.value) + return 'Missing Action.value'; + if (!action.type) + return 'Missing Action.type'; + if (action.type.length > 15) + return 'Action.type value exceed maximum length of 15'; + }; + AddMessageActionRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, { data: serviceResponse.data }]; + }); + }); + }; + Object.defineProperty(AddMessageActionRequest.prototype, "headers", { + get: function () { + return { 'Content-Type': 'application/json' }; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(AddMessageActionRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channel = _a.channel, messageTimetoken = _a.messageTimetoken; + return "/v1/message-actions/".concat(subscribeKey, "/channel/").concat((0, utils_1.encodeString)(channel), "/message/").concat(messageTimetoken); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(AddMessageActionRequest.prototype, "body", { + get: function () { + return JSON.stringify(this.parameters.action); + }, + enumerable: false, + configurable: true + }); + return AddMessageActionRequest; +}(request_1.AbstractRequest)); +exports.AddMessageActionRequest = AddMessageActionRequest; diff --git a/lib/core/endpoints/actions/get_message_actions.js b/lib/core/endpoints/actions/get_message_actions.js index 669face9a..0b8e97e36 100644 --- a/lib/core/endpoints/actions/get_message_actions.js +++ b/lib/core/endpoints/actions/get_message_actions.js @@ -1,59 +1,136 @@ "use strict"; +/** + * Get Message Actions REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; -/* */ +exports.GetMessageActionsRequest = void 0; +var PubNubError_1 = require("../../../models/PubNubError"); +var request_1 = require("../../components/request"); var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -function getOperation() { - return operations_1.default.PNGetMessageActionsOperation; -} -exports.getOperation = getOperation; -function validateParams(_a, incomingParams) { - var config = _a.config; - var channel = incomingParams.channel; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - if (!channel) - return 'Missing message channel'; -} -exports.validateParams = validateParams; -function getURL(_a, incomingParams) { - var config = _a.config; - var channel = incomingParams.channel; - return "/v1/message-actions/".concat(config.subscribeKey, "/channel/").concat(utils_1.default.encodeString(channel)); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams(modules, incomingParams) { - var limit = incomingParams.limit, start = incomingParams.start, end = incomingParams.end; - var outgoingParams = {}; - if (limit) - outgoingParams.limit = limit; - if (start) - outgoingParams.start = start; - if (end) - outgoingParams.end = end; - return outgoingParams; -} -exports.prepareParams = prepareParams; -function handleResponse(modules, getMessageActionsResponse) { - /** @type GetMessageActionsResponse */ - var response = { data: getMessageActionsResponse.data, start: null, end: null }; - if (response.data.length) { - response.end = response.data[response.data.length - 1].actionTimetoken; - response.start = response.data[0].actionTimetoken; +var utils_1 = require("../../utils"); +// endregion +/** + * Fetch channel message actions request. + */ +var GetMessageActionsRequest = /** @class */ (function (_super) { + __extends(GetMessageActionsRequest, _super); + function GetMessageActionsRequest(parameters) { + var _this = _super.call(this) || this; + _this.parameters = parameters; + return _this; } - return response; -} -exports.handleResponse = handleResponse; + GetMessageActionsRequest.prototype.operation = function () { + return operations_1.default.PNGetMessageActionsOperation; + }; + GetMessageActionsRequest.prototype.validate = function () { + if (!this.parameters.keySet.subscribeKey) + return 'Missing Subscribe Key'; + if (!this.parameters.channel) + return 'Missing message channel'; + }; + GetMessageActionsRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse, start, end; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + start = null; + end = null; + if (serviceResponse.data.length > 0) { + start = serviceResponse.data[0].actionTimetoken; + end = serviceResponse.data[serviceResponse.data.length - 1].actionTimetoken; + } + return [2 /*return*/, { + data: serviceResponse.data, + more: serviceResponse.more, + start: start, + end: end, + }]; + }); + }); + }; + Object.defineProperty(GetMessageActionsRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channel = _a.channel; + return "/v1/message-actions/".concat(subscribeKey, "/channel/").concat((0, utils_1.encodeString)(channel)); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(GetMessageActionsRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, limit = _a.limit, start = _a.start, end = _a.end; + return __assign(__assign(__assign({}, (start ? { start: start } : {})), (end ? { end: end } : {})), (limit ? { limit: limit } : {})); + }, + enumerable: false, + configurable: true + }); + return GetMessageActionsRequest; +}(request_1.AbstractRequest)); +exports.GetMessageActionsRequest = GetMessageActionsRequest; diff --git a/lib/core/endpoints/actions/remove_message_action.js b/lib/core/endpoints/actions/remove_message_action.js index b70bc0a18..9651d09fc 100644 --- a/lib/core/endpoints/actions/remove_message_action.js +++ b/lib/core/endpoints/actions/remove_message_action.js @@ -1,53 +1,112 @@ "use strict"; -/* */ +/** + * Remove Message Action REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.useDelete = exports.validateParams = exports.getOperation = void 0; +exports.RemoveMessageAction = void 0; +var PubNubError_1 = require("../../../models/PubNubError"); +var transport_request_1 = require("../../types/transport-request"); +var request_1 = require("../../components/request"); var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -function getOperation() { - return operations_1.default.PNRemoveMessageActionOperation; -} -exports.getOperation = getOperation; -function validateParams(_a, incomingParams) { - var config = _a.config; - var channel = incomingParams.channel, actionTimetoken = incomingParams.actionTimetoken, messageTimetoken = incomingParams.messageTimetoken; - if (!messageTimetoken) - return 'Missing message timetoken'; - if (!actionTimetoken) - return 'Missing action timetoken'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - if (!channel) - return 'Missing message channel'; -} -exports.validateParams = validateParams; -function useDelete() { - return true; -} -exports.useDelete = useDelete; -function getURL(_a, incomingParams) { - var config = _a.config; - var channel = incomingParams.channel, actionTimetoken = incomingParams.actionTimetoken, messageTimetoken = incomingParams.messageTimetoken; - return "/v1/message-actions/".concat(config.subscribeKey, "/channel/").concat(utils_1.default.encodeString(channel), "/message/").concat(messageTimetoken, "/action/").concat(actionTimetoken); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams() { - return {}; -} -exports.prepareParams = prepareParams; -function handleResponse(modules, removeMessageActionResponse) { - return { data: removeMessageActionResponse.data }; -} -exports.handleResponse = handleResponse; +var utils_1 = require("../../utils"); +// endregion +/** + * Remove specific message action request. + */ +var RemoveMessageAction = /** @class */ (function (_super) { + __extends(RemoveMessageAction, _super); + function RemoveMessageAction(parameters) { + var _this = _super.call(this, { method: transport_request_1.TransportMethod.DELETE }) || this; + _this.parameters = parameters; + return _this; + } + RemoveMessageAction.prototype.operation = function () { + return operations_1.default.PNRemoveMessageActionOperation; + }; + RemoveMessageAction.prototype.validate = function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channel = _a.channel, messageTimetoken = _a.messageTimetoken, actionTimetoken = _a.actionTimetoken; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!channel) + return 'Missing message action channel'; + if (!messageTimetoken) + return 'Missing message timetoken'; + if (!actionTimetoken) + return 'Missing action timetoken'; + }; + RemoveMessageAction.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, { data: serviceResponse.data }]; + }); + }); + }; + Object.defineProperty(RemoveMessageAction.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channel = _a.channel, actionTimetoken = _a.actionTimetoken, messageTimetoken = _a.messageTimetoken; + return "/v1/message-actions/".concat(subscribeKey, "/channel/").concat((0, utils_1.encodeString)(channel), "/message/").concat(messageTimetoken, "/action/").concat(actionTimetoken); + }, + enumerable: false, + configurable: true + }); + return RemoveMessageAction; +}(request_1.AbstractRequest)); +exports.RemoveMessageAction = RemoveMessageAction; diff --git a/lib/core/endpoints/channel_groups/add_channels.js b/lib/core/endpoints/channel_groups/add_channels.js index 7c7426e5b..37fa873e7 100644 --- a/lib/core/endpoints/channel_groups/add_channels.js +++ b/lib/core/endpoints/channel_groups/add_channels.js @@ -1,50 +1,116 @@ "use strict"; +/** + * Add channel group channels REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; -/* */ +exports.AddChannelGroupChannelsRequest = void 0; +var PubNubError_1 = require("../../../models/PubNubError"); +var request_1 = require("../../components/request"); var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -function getOperation() { - return operations_1.default.PNAddChannelsToGroupOperation; -} -exports.getOperation = getOperation; -function validateParams(modules, incomingParams) { - var channels = incomingParams.channels, channelGroup = incomingParams.channelGroup; - var config = modules.config; - if (!channelGroup) - return 'Missing Channel Group'; - if (!channels || channels.length === 0) - return 'Missing Channels'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var channelGroup = incomingParams.channelGroup; - var config = modules.config; - return "/v1/channel-registration/sub-key/".concat(config.subscribeKey, "/channel-group/").concat(utils_1.default.encodeString(channelGroup)); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams(modules, incomingParams) { - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a; - return { - add: channels.join(','), +var utils_1 = require("../../utils"); +// endregion +/** + * Add channel group channels request. + */ +var AddChannelGroupChannelsRequest = /** @class */ (function (_super) { + __extends(AddChannelGroupChannelsRequest, _super); + function AddChannelGroupChannelsRequest(parameters) { + var _this = _super.call(this) || this; + _this.parameters = parameters; + return _this; + } + AddChannelGroupChannelsRequest.prototype.operation = function () { + return operations_1.default.PNAddChannelsToGroupOperation; + }; + AddChannelGroupChannelsRequest.prototype.validate = function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channels = _a.channels, channelGroup = _a.channelGroup; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!channelGroup) + return 'Missing Channel Group'; + if (!channels) + return 'Missing channels'; + }; + AddChannelGroupChannelsRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, {}]; + }); + }); }; -} -exports.prepareParams = prepareParams; -function handleResponse() { - return {}; -} -exports.handleResponse = handleResponse; + Object.defineProperty(AddChannelGroupChannelsRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channelGroup = _a.channelGroup; + return "/v1/channel-registration/sub-key/".concat(subscribeKey, "/channel-group/").concat((0, utils_1.encodeString)(channelGroup)); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(AddChannelGroupChannelsRequest.prototype, "queryParameters", { + get: function () { + return { add: this.parameters.channels.join(',') }; + }, + enumerable: false, + configurable: true + }); + return AddChannelGroupChannelsRequest; +}(request_1.AbstractRequest)); +exports.AddChannelGroupChannelsRequest = AddChannelGroupChannelsRequest; diff --git a/lib/core/endpoints/channel_groups/delete_group.js b/lib/core/endpoints/channel_groups/delete_group.js index 4ee651809..dcde9a4c3 100644 --- a/lib/core/endpoints/channel_groups/delete_group.js +++ b/lib/core/endpoints/channel_groups/delete_group.js @@ -1,45 +1,106 @@ "use strict"; -/* */ +/** + * Delete channel group REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.getRequestTimeout = exports.isAuthSupported = exports.getURL = exports.validateParams = exports.getOperation = void 0; +exports.DeleteChannelGroupRequest = void 0; +var PubNubError_1 = require("../../../models/PubNubError"); +var request_1 = require("../../components/request"); var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -function getOperation() { - return operations_1.default.PNRemoveGroupOperation; -} -exports.getOperation = getOperation; -function validateParams(modules, incomingParams) { - var channelGroup = incomingParams.channelGroup; - var config = modules.config; - if (!channelGroup) - return 'Missing Channel Group'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var channelGroup = incomingParams.channelGroup; - var config = modules.config; - return "/v1/channel-registration/sub-key/".concat(config.subscribeKey, "/channel-group/").concat(utils_1.default.encodeString(channelGroup), "/remove"); -} -exports.getURL = getURL; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function prepareParams() { - return {}; -} -exports.prepareParams = prepareParams; -function handleResponse() { - return {}; -} -exports.handleResponse = handleResponse; +var utils_1 = require("../../utils"); +// endregion +/** + * Channel group delete request. + */ +var DeleteChannelGroupRequest = /** @class */ (function (_super) { + __extends(DeleteChannelGroupRequest, _super); + function DeleteChannelGroupRequest(parameters) { + var _this = _super.call(this) || this; + _this.parameters = parameters; + return _this; + } + DeleteChannelGroupRequest.prototype.operation = function () { + return operations_1.default.PNRemoveGroupOperation; + }; + DeleteChannelGroupRequest.prototype.validate = function () { + if (!this.parameters.keySet.subscribeKey) + return 'Missing Subscribe Key'; + if (!this.parameters.channelGroup) + return 'Missing Channel Group'; + }; + DeleteChannelGroupRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, {}]; + }); + }); + }; + Object.defineProperty(DeleteChannelGroupRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channelGroup = _a.channelGroup; + return "/v1/channel-registration/sub-key/".concat(subscribeKey, "/channel-group/").concat((0, utils_1.encodeString)(channelGroup), "/remove"); + }, + enumerable: false, + configurable: true + }); + return DeleteChannelGroupRequest; +}(request_1.AbstractRequest)); +exports.DeleteChannelGroupRequest = DeleteChannelGroupRequest; diff --git a/lib/core/endpoints/channel_groups/list_channels.js b/lib/core/endpoints/channel_groups/list_channels.js index 6e385eec4..d18dc66c2 100644 --- a/lib/core/endpoints/channel_groups/list_channels.js +++ b/lib/core/endpoints/channel_groups/list_channels.js @@ -1,47 +1,106 @@ "use strict"; +/** + * List channel group channels REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; -/* */ +exports.ListChannelGroupChannels = void 0; +var PubNubError_1 = require("../../../models/PubNubError"); +var request_1 = require("../../components/request"); var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -function getOperation() { - return operations_1.default.PNChannelsForGroupOperation; -} -exports.getOperation = getOperation; -function validateParams(modules, incomingParams) { - var channelGroup = incomingParams.channelGroup; - var config = modules.config; - if (!channelGroup) - return 'Missing Channel Group'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var channelGroup = incomingParams.channelGroup; - var config = modules.config; - return "/v1/channel-registration/sub-key/".concat(config.subscribeKey, "/channel-group/").concat(utils_1.default.encodeString(channelGroup)); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams() { - return {}; -} -exports.prepareParams = prepareParams; -function handleResponse(modules, serverResponse) { - return { - channels: serverResponse.payload.channels, +var utils_1 = require("../../utils"); +// endregion +/** + * List Channel Group Channels request. + */ +var ListChannelGroupChannels = /** @class */ (function (_super) { + __extends(ListChannelGroupChannels, _super); + function ListChannelGroupChannels(parameters) { + var _this = _super.call(this) || this; + _this.parameters = parameters; + return _this; + } + ListChannelGroupChannels.prototype.operation = function () { + return operations_1.default.PNChannelsForGroupOperation; + }; + ListChannelGroupChannels.prototype.validate = function () { + if (!this.parameters.keySet.subscribeKey) + return 'Missing Subscribe Key'; + if (!this.parameters.channelGroup) + return 'Missing Channel Group'; + }; + ListChannelGroupChannels.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, { channels: serviceResponse.payload.channels }]; + }); + }); }; -} -exports.handleResponse = handleResponse; + Object.defineProperty(ListChannelGroupChannels.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channelGroup = _a.channelGroup; + return "/v1/channel-registration/sub-key/".concat(subscribeKey, "/channel-group/").concat((0, utils_1.encodeString)(channelGroup)); + }, + enumerable: false, + configurable: true + }); + return ListChannelGroupChannels; +}(request_1.AbstractRequest)); +exports.ListChannelGroupChannels = ListChannelGroupChannels; diff --git a/lib/core/endpoints/channel_groups/list_groups.js b/lib/core/endpoints/channel_groups/list_groups.js index e97da0540..66537f0c9 100644 --- a/lib/core/endpoints/channel_groups/list_groups.js +++ b/lib/core/endpoints/channel_groups/list_groups.js @@ -1,42 +1,102 @@ "use strict"; -/* */ +/** + * List All Channel Groups REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; +exports.ListChannelGroupsRequest = void 0; +var PubNubError_1 = require("../../../models/PubNubError"); +var request_1 = require("../../components/request"); var operations_1 = __importDefault(require("../../constants/operations")); -function getOperation() { - return operations_1.default.PNChannelGroupsOperation; -} -exports.getOperation = getOperation; -function validateParams(modules) { - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules) { - var config = modules.config; - return "/v1/channel-registration/sub-key/".concat(config.subscribeKey, "/channel-group"); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams() { - return {}; -} -exports.prepareParams = prepareParams; -function handleResponse(modules, serverResponse) { - return { - groups: serverResponse.payload.groups, +// endregion +/** + * List all channel groups request. + */ +var ListChannelGroupsRequest = /** @class */ (function (_super) { + __extends(ListChannelGroupsRequest, _super); + function ListChannelGroupsRequest(parameters) { + var _this = _super.call(this) || this; + _this.parameters = parameters; + return _this; + } + ListChannelGroupsRequest.prototype.operation = function () { + return operations_1.default.PNChannelGroupsOperation; + }; + ListChannelGroupsRequest.prototype.validate = function () { + if (!this.parameters.keySet.subscribeKey) + return 'Missing Subscribe Key'; + }; + ListChannelGroupsRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, { groups: serviceResponse.payload.groups }]; + }); + }); }; -} -exports.handleResponse = handleResponse; + Object.defineProperty(ListChannelGroupsRequest.prototype, "path", { + get: function () { + return "/v1/channel-registration/sub-key/".concat(this.parameters.keySet.subscribeKey, "/channel-group"); + }, + enumerable: false, + configurable: true + }); + return ListChannelGroupsRequest; +}(request_1.AbstractRequest)); +exports.ListChannelGroupsRequest = ListChannelGroupsRequest; diff --git a/lib/core/endpoints/channel_groups/remove_channels.js b/lib/core/endpoints/channel_groups/remove_channels.js index 74aa55bcf..f863d5864 100644 --- a/lib/core/endpoints/channel_groups/remove_channels.js +++ b/lib/core/endpoints/channel_groups/remove_channels.js @@ -1,50 +1,117 @@ "use strict"; +/** + * Remove channel group channels REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; -/* */ +exports.RemoveChannelGroupChannelsRequest = void 0; +var PubNubError_1 = require("../../../models/PubNubError"); +var request_1 = require("../../components/request"); var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -function getOperation() { - return operations_1.default.PNRemoveChannelsFromGroupOperation; -} -exports.getOperation = getOperation; -function validateParams(modules, incomingParams) { - var channels = incomingParams.channels, channelGroup = incomingParams.channelGroup; - var config = modules.config; - if (!channelGroup) - return 'Missing Channel Group'; - if (!channels || channels.length === 0) - return 'Missing Channels'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var channelGroup = incomingParams.channelGroup; - var config = modules.config; - return "/v1/channel-registration/sub-key/".concat(config.subscribeKey, "/channel-group/").concat(utils_1.default.encodeString(channelGroup)); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams(modules, incomingParams) { - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a; - return { - remove: channels.join(','), +var utils_1 = require("../../utils"); +// endregion +/** + * Remove channel group channels request. + */ +// prettier-ignore +var RemoveChannelGroupChannelsRequest = /** @class */ (function (_super) { + __extends(RemoveChannelGroupChannelsRequest, _super); + function RemoveChannelGroupChannelsRequest(parameters) { + var _this = _super.call(this) || this; + _this.parameters = parameters; + return _this; + } + RemoveChannelGroupChannelsRequest.prototype.operation = function () { + return operations_1.default.PNRemoveChannelsFromGroupOperation; + }; + RemoveChannelGroupChannelsRequest.prototype.validate = function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channels = _a.channels, channelGroup = _a.channelGroup; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!channelGroup) + return 'Missing Channel Group'; + if (!channels) + return 'Missing channels'; + }; + RemoveChannelGroupChannelsRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, {}]; + }); + }); }; -} -exports.prepareParams = prepareParams; -function handleResponse() { - return {}; -} -exports.handleResponse = handleResponse; + Object.defineProperty(RemoveChannelGroupChannelsRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channelGroup = _a.channelGroup; + return "/v1/channel-registration/sub-key/".concat(subscribeKey, "/channel-group/").concat((0, utils_1.encodeString)(channelGroup)); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(RemoveChannelGroupChannelsRequest.prototype, "queryParameters", { + get: function () { + return { remove: this.parameters.channels.join(',') }; + }, + enumerable: false, + configurable: true + }); + return RemoveChannelGroupChannelsRequest; +}(request_1.AbstractRequest)); +exports.RemoveChannelGroupChannelsRequest = RemoveChannelGroupChannelsRequest; diff --git a/lib/core/endpoints/endpoint.js b/lib/core/endpoints/endpoint.js deleted file mode 100644 index 9fa8a127e..000000000 --- a/lib/core/endpoints/endpoint.js +++ /dev/null @@ -1,3 +0,0 @@ -"use strict"; -/** */ -// endpoint definition structure diff --git a/lib/core/endpoints/fetch_messages.js b/lib/core/endpoints/fetch_messages.js index ba1c5e7ec..cd41a0a32 100644 --- a/lib/core/endpoints/fetch_messages.js +++ b/lib/core/endpoints/fetch_messages.js @@ -1,120 +1,292 @@ "use strict"; +/** + * Fetch messages REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; -/* */ +exports.FetchMessagesRequest = void 0; +var PubNubError_1 = require("../../models/PubNubError"); +var request_1 = require("../components/request"); var operations_1 = __importDefault(require("../constants/operations")); -var utils_1 = __importDefault(require("../utils")); -function __processMessage(modules, message) { - var result = {}; - if (!modules.cryptoModule) { - result.payload = message; - return result; +var History = __importStar(require("../types/api/history")); +var utils_1 = require("../utils"); +// -------------------------------------------------------- +// ---------------------- Defaults ------------------------ +// -------------------------------------------------------- +// region Defaults +/** + * Whether verbose logging enabled or not. + */ +var LOG_VERBOSITY = false; +/** + * Whether associated message metadata should be returned or not. + */ +var INCLUDE_METADATA = true; +/** + * Whether message type should be returned or not. + */ +var INCLUDE_MESSAGE_TYPE = true; +/** + * Whether timetokens should be returned as strings by default or not. + */ +var STRINGIFY_TIMETOKENS = false; +/** + * Whether message publisher `uuid` should be returned or not. + */ +var INCLUDE_UUID = true; +/** + * Default number of messages which can be returned for single channel, and it is maximum as well. + */ +var SINGLE_CHANNEL_MESSAGES_COUNT = 100; +/** + * Default number of messages which can be returned for multiple channels or when fetched + * message actions. + */ +var MULTIPLE_CHANNELS_MESSAGES_COUNT = 25; +// endregion +/** + * Fetch messages from channels request. + */ +var FetchMessagesRequest = /** @class */ (function (_super) { + __extends(FetchMessagesRequest, _super); + function FetchMessagesRequest(parameters) { + var _a, _b, _c, _d, _e, _f; + var _this = _super.call(this) || this; + _this.parameters = parameters; + // Apply defaults. + var includeMessageActions = (_a = parameters.includeMessageActions) !== null && _a !== void 0 ? _a : false; + var defaultCount = parameters.channels.length === 1 && includeMessageActions + ? SINGLE_CHANNEL_MESSAGES_COUNT + : MULTIPLE_CHANNELS_MESSAGES_COUNT; + if (!parameters.count) + parameters.count = defaultCount; + else + parameters.count = Math.min(parameters.count, defaultCount); + if (parameters.includeUuid) + parameters.includeUUID = parameters.includeUuid; + else + (_b = parameters.includeUUID) !== null && _b !== void 0 ? _b : (parameters.includeUUID = INCLUDE_UUID); + (_c = parameters.stringifiedTimeToken) !== null && _c !== void 0 ? _c : (parameters.stringifiedTimeToken = STRINGIFY_TIMETOKENS); + (_d = parameters.includeMessageType) !== null && _d !== void 0 ? _d : (parameters.includeMessageType = INCLUDE_MESSAGE_TYPE); + (_e = parameters.includeMeta) !== null && _e !== void 0 ? _e : (parameters.includeMeta = INCLUDE_METADATA); + (_f = parameters.logVerbosity) !== null && _f !== void 0 ? _f : (parameters.logVerbosity = LOG_VERBOSITY); + return _this; } - try { - var decryptedData = modules.cryptoModule.decrypt(message); - var decryptedPayload = decryptedData instanceof ArrayBuffer ? JSON.parse(new TextDecoder().decode(decryptedData)) : decryptedData; - result.payload = decryptedPayload; - return result; - } - catch (e) { - if (modules.config.logVerbosity && console && console.log) - console.log('decryption error', e.message); - result.payload = message; - result.error = "Error while decrypting message content: ".concat(e.message); - } - return result; -} -function getOperation() { - return operations_1.default.PNFetchMessagesOperation; -} -exports.getOperation = getOperation; -function validateParams(modules, incomingParams) { - var channels = incomingParams.channels, _a = incomingParams.includeMessageActions, includeMessageActions = _a === void 0 ? false : _a; - var config = modules.config; - if (!channels || channels.length === 0) - return 'Missing channels'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - if (includeMessageActions && channels.length > 1) { - throw new TypeError('History can return actions data for a single channel only. ' + - 'Either pass a single channel or disable the includeMessageActions flag.'); - } -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a, _b = incomingParams.includeMessageActions, includeMessageActions = _b === void 0 ? false : _b; - var config = modules.config; - var endpoint = !includeMessageActions ? 'history' : 'history-with-actions'; - var stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return "/v3/".concat(endpoint, "/sub-key/").concat(config.subscribeKey, "/channel/").concat(utils_1.default.encodeString(stringifiedChannels)); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams(modules, incomingParams) { - var channels = incomingParams.channels, start = incomingParams.start, end = incomingParams.end, includeMessageActions = incomingParams.includeMessageActions, count = incomingParams.count, _a = incomingParams.stringifiedTimeToken, stringifiedTimeToken = _a === void 0 ? false : _a, _b = incomingParams.includeMeta, includeMeta = _b === void 0 ? false : _b, includeUuid = incomingParams.includeUuid, _c = incomingParams.includeUUID, includeUUID = _c === void 0 ? true : _c, _d = incomingParams.includeMessageType, includeMessageType = _d === void 0 ? true : _d; - var outgoingParams = {}; - if (count) { - outgoingParams.max = count; - } - else { - outgoingParams.max = channels.length > 1 || includeMessageActions === true ? 25 : 100; - } - if (start) - outgoingParams.start = start; - if (end) - outgoingParams.end = end; - if (stringifiedTimeToken) - outgoingParams.string_message_token = 'true'; - if (includeMeta) - outgoingParams.include_meta = 'true'; - if (includeUUID && includeUuid !== false) - outgoingParams.include_uuid = 'true'; - if (includeMessageType) - outgoingParams.include_message_type = 'true'; - return outgoingParams; -} -exports.prepareParams = prepareParams; -function handleResponse(modules, serverResponse) { - var response = { - channels: {}, + FetchMessagesRequest.prototype.operation = function () { + return operations_1.default.PNFetchMessagesOperation; }; - Object.keys(serverResponse.channels || {}).forEach(function (channelName) { - response.channels[channelName] = []; - (serverResponse.channels[channelName] || []).forEach(function (messageEnvelope) { - var announce = {}; - var processedMessgeResult = __processMessage(modules, messageEnvelope.message); - announce.channel = channelName; - announce.timetoken = messageEnvelope.timetoken; - announce.message = processedMessgeResult.payload; - announce.messageType = messageEnvelope.message_type; - announce.uuid = messageEnvelope.uuid; - if (messageEnvelope.actions) { - announce.actions = messageEnvelope.actions; - // This should be kept for few updates for existing clients consistency. - announce.data = messageEnvelope.actions; - } - if (messageEnvelope.meta) { - announce.meta = messageEnvelope.meta; - } - if (processedMessgeResult.error) - announce.error = processedMessgeResult.error; - response.channels[channelName].push(announce); + FetchMessagesRequest.prototype.validate = function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channels = _a.channels, includeMessageActions = _a.includeMessageActions; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!channels) + return 'Missing channels'; + if (includeMessageActions && channels.length > 1) + return ('History can return actions data for a single channel only. Either pass a single channel ' + + 'or disable the includeMessageActions flag.'); + }; + FetchMessagesRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse, responseChannels, channels; + var _this = this; + var _a; + return __generator(this, function (_b) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + responseChannels = (_a = serviceResponse.channels) !== null && _a !== void 0 ? _a : {}; + channels = {}; + Object.keys(responseChannels).forEach(function (channel) { + // Map service response to expected data object type structure. + channels[channel] = responseChannels[channel].map(function (payload) { + // `null` message type means regular message. + if (payload.message_type === null) + payload.message_type = History.PubNubMessageType.Message; + var processedPayload = _this.processPayload(channel, payload); + var item = { + channel: channel, + timetoken: payload.timetoken, + message: processedPayload.payload, + messageType: payload.message_type, + uuid: payload.uuid, + }; + if (payload.actions) { + var itemWithActions = item; + itemWithActions.actions = payload.actions; + // Backward compatibility for existing users. + // TODO: Remove in next release. + itemWithActions.data = payload.actions; + } + if (payload.meta) + item.meta = payload.meta; + if (processedPayload.error) + item.error = processedPayload.error; + return item; + }); + }); + if (serviceResponse.more) + return [2 /*return*/, { channels: responseChannels, more: serviceResponse.more }]; + return [2 /*return*/, { channels: responseChannels }]; + }); }); + }; + Object.defineProperty(FetchMessagesRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channels = _a.channels, includeMessageActions = _a.includeMessageActions; + var endpoint = !includeMessageActions ? 'history' : 'history-with-actions'; + return "/v3/".concat(endpoint, "/sub-key/").concat(subscribeKey, "/channel/").concat((0, utils_1.encodeString)(channels.join(','))); + }, + enumerable: false, + configurable: true }); - if (serverResponse.more) { - response.more = serverResponse.more; - } - return response; -} -exports.handleResponse = handleResponse; + Object.defineProperty(FetchMessagesRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, start = _a.start, end = _a.end, count = _a.count, includeMessageType = _a.includeMessageType, includeMeta = _a.includeMeta, includeUUID = _a.includeUUID, stringifiedTimeToken = _a.stringifiedTimeToken; + return __assign(__assign(__assign(__assign(__assign(__assign({ max: count }, (start ? { start: start } : {})), (end ? { end: end } : {})), (stringifiedTimeToken ? { string_message_token: 'true' } : {})), (includeMeta ? { include_meta: 'true' } : {})), (includeUUID ? { include_uuid: 'true' } : {})), (includeMessageType ? { include_message_type: 'true' } : {})); + }, + enumerable: false, + configurable: true + }); + /** + * Parse single channel data entry. + * + * @param channel - Channel for which {@link payload} should be processed. + * @param payload - Source payload which should be processed and parsed to expected type. + * + * @returns + */ + FetchMessagesRequest.prototype.processPayload = function (channel, payload) { + var _a = this.parameters, crypto = _a.crypto, logVerbosity = _a.logVerbosity; + if (!crypto || typeof payload.message !== 'string') + return { payload: payload.message }; + var decryptedPayload; + var error; + try { + var decryptedData = crypto.decrypt(payload.message); + decryptedPayload = + decryptedData instanceof ArrayBuffer + ? JSON.parse(FetchMessagesRequest.decoder.decode(decryptedData)) + : decryptedData; + } + catch (err) { + if (logVerbosity) + console.log("decryption error", err.message); + decryptedPayload = payload.message; + error = "Error while decrypting message content: ".concat(err.message); + } + if (!error && + decryptedPayload && + payload.message_type == History.PubNubMessageType.Files && + typeof decryptedPayload === 'object' && + this.isFileMessage(decryptedPayload)) { + var fileMessage = decryptedPayload; + return { + payload: { + message: fileMessage.message, + file: __assign(__assign({}, fileMessage.file), { url: this.parameters.getFileUrl({ channel: channel, id: fileMessage.file.id, name: fileMessage.file.name }) }), + }, + error: error, + }; + } + return { payload: decryptedPayload, error: error }; + }; + /** + * Check whether `payload` potentially represents file message. + * + * @param payload - Fetched message payload. + * + * @returns `true` if payload can be {@link History#FileMessage|FileMessage}. + */ + FetchMessagesRequest.prototype.isFileMessage = function (payload) { + return payload.file !== undefined; + }; + return FetchMessagesRequest; +}(request_1.AbstractRequest)); +exports.FetchMessagesRequest = FetchMessagesRequest; diff --git a/lib/core/endpoints/file_upload/delete_file.js b/lib/core/endpoints/file_upload/delete_file.js index 1e9529932..5d7a5ee89 100644 --- a/lib/core/endpoints/file_upload/delete_file.js +++ b/lib/core/endpoints/file_upload/delete_file.js @@ -1,37 +1,110 @@ "use strict"; -/** */ +/** + * Delete file REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); +exports.DeleteFileRequest = void 0; +var PubNubError_1 = require("../../../models/PubNubError"); +var transport_request_1 = require("../../types/transport-request"); +var request_1 = require("../../components/request"); var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNListFilesOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { +var utils_1 = require("../../utils"); +// endregion +/** + * Delete File request. + */ +var DeleteFileRequest = /** @class */ (function (_super) { + __extends(DeleteFileRequest, _super); + function DeleteFileRequest(parameters) { + var _this = _super.call(this, { method: transport_request_1.TransportMethod.DELETE }) || this; + _this.parameters = parameters; + return _this; + } + DeleteFileRequest.prototype.operation = function () { + return operations_1.default.PNDeleteFileOperation; + }; + DeleteFileRequest.prototype.validate = function () { + var _a = this.parameters, channel = _a.channel, id = _a.id, name = _a.name; + if (!channel) return "channel can't be empty"; - } - if (!(params === null || params === void 0 ? void 0 : params.id)) { + if (!id) return "file id can't be empty"; - } - if (!(params === null || params === void 0 ? void 0 : params.name)) { + if (!name) return "file name can't be empty"; - } - }, - useDelete: function () { return true; }, - getURL: function (_a, params) { - var config = _a.config; - return "/v1/files/".concat(config.subscribeKey, "/channels/").concat(utils_1.default.encodeString(params.channel), "/files/").concat(params.id, "/").concat(params.name); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function () { return ({}); }, - handleResponse: function (_, response) { return ({ - status: response.status, - }); }, -}; -exports.default = endpoint; + }; + DeleteFileRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, serviceResponse]; + }); + }); + }; + Object.defineProperty(DeleteFileRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, id = _a.id, channel = _a.channel, name = _a.name; + return "/v1/files/".concat(subscribeKey, "/channels/").concat((0, utils_1.encodeString)(channel), "/files/").concat(id, "/").concat(name); + }, + enumerable: false, + configurable: true + }); + return DeleteFileRequest; +}(request_1.AbstractRequest)); +exports.DeleteFileRequest = DeleteFileRequest; diff --git a/lib/core/endpoints/file_upload/download_file.js b/lib/core/endpoints/file_upload/download_file.js index 65d4c6ee4..f96e9f10b 100644 --- a/lib/core/endpoints/file_upload/download_file.js +++ b/lib/core/endpoints/file_upload/download_file.js @@ -1,5 +1,22 @@ "use strict"; -// Download_file.js +/** + * Download File REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { @@ -15,7 +32,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) { function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); - while (_) try { + while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { @@ -40,65 +57,73 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -/** */ +exports.DownloadFileRequest = void 0; +var request_1 = require("../../components/request"); var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNDownloadFileOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { +var utils_1 = require("../../utils"); +// endregion +/** + * Download File request. + */ +var DownloadFileRequest = /** @class */ (function (_super) { + __extends(DownloadFileRequest, _super); + function DownloadFileRequest(parameters) { + var _this = _super.call(this) || this; + _this.parameters = parameters; + return _this; + } + DownloadFileRequest.prototype.operation = function () { + return operations_1.default.PNDownloadFileOperation; + }; + DownloadFileRequest.prototype.validate = function () { + var _a = this.parameters, channel = _a.channel, id = _a.id, name = _a.name; + if (!channel) return "channel can't be empty"; - } - if (!(params === null || params === void 0 ? void 0 : params.name)) { - return "name can't be empty"; - } - if (!(params === null || params === void 0 ? void 0 : params.id)) { - return "id can't be empty"; - } - }, - useGetFile: function () { return true; }, - getFileURL: function (_a, params) { - var config = _a.config; - return "/v1/files/".concat(config.subscribeKey, "/channels/").concat(utils_1.default.encodeString(params.channel), "/files/").concat(params.id, "/").concat(params.name); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - ignoreBody: function () { return true; }, - forceBuffered: function () { return true; }, - prepareParams: function () { return ({}); }, - handleResponse: function (_a, res, params) { - var PubNubFile = _a.PubNubFile, config = _a.config, cryptography = _a.cryptography, cryptoModule = _a.cryptoModule; - return __awaiter(void 0, void 0, void 0, function () { - var body, _b; - var _c, _d; - return __generator(this, function (_e) { - switch (_e.label) { + if (!id) + return "file id can't be empty"; + if (!name) + return "file name can't be empty"; + }; + DownloadFileRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var _a, cipherKey, crypto, cryptography, name, PubNubFile, mimeType, decryptedFile, body; + return __generator(this, function (_b) { + switch (_b.label) { case 0: - body = res.response.body; - if (!(PubNubFile.supportsEncryptFile && (params.cipherKey || cryptoModule))) return [3 /*break*/, 5]; - if (!(params.cipherKey == null)) return [3 /*break*/, 2]; - return [4 /*yield*/, cryptoModule.decryptFile(PubNubFile.create({ data: body, name: params.name }), PubNubFile)]; + _a = this.parameters, cipherKey = _a.cipherKey, crypto = _a.crypto, cryptography = _a.cryptography, name = _a.name, PubNubFile = _a.PubNubFile; + mimeType = response.headers['content-type']; + body = response.body; + if (!(PubNubFile.supportsEncryptFile && (cipherKey || crypto))) return [3 /*break*/, 4]; + if (!(cipherKey && cryptography)) return [3 /*break*/, 2]; + return [4 /*yield*/, cryptography.decrypt(cipherKey, body)]; case 1: - _b = (_e.sent()).data; + body = _b.sent(); return [3 /*break*/, 4]; - case 2: return [4 /*yield*/, cryptography.decrypt((_c = params.cipherKey) !== null && _c !== void 0 ? _c : config.cipherKey, body)]; + case 2: + if (!(!cipherKey && crypto)) return [3 /*break*/, 4]; + return [4 /*yield*/, crypto.decryptFile(PubNubFile.create({ data: body, name: name, mimeType: mimeType }), PubNubFile)]; case 3: - _b = _e.sent(); - _e.label = 4; - case 4: - body = _b; - _e.label = 5; - case 5: return [2 /*return*/, PubNubFile.create({ - data: body, - name: (_d = res.response.name) !== null && _d !== void 0 ? _d : params.name, - mimeType: res.response.type, - })]; + decryptedFile = _b.sent(); + _b.label = 4; + case 4: return [2 /*return*/, (decryptedFile + ? decryptedFile + : PubNubFile.create({ + data: body, + name: name, + mimeType: mimeType, + }))]; } }); }); - }, -}; -exports.default = endpoint; + }; + Object.defineProperty(DownloadFileRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channel = _a.channel, id = _a.id, name = _a.name; + return "/v1/files/".concat(subscribeKey, "/channels/").concat((0, utils_1.encodeString)(channel), "/files/").concat(id, "/").concat(name); + }, + enumerable: false, + configurable: true + }); + return DownloadFileRequest; +}(request_1.AbstractRequest)); +exports.DownloadFileRequest = DownloadFileRequest; diff --git a/lib/core/endpoints/file_upload/generate_upload_url.js b/lib/core/endpoints/file_upload/generate_upload_url.js index c35b508b4..a7df92705 100644 --- a/lib/core/endpoints/file_upload/generate_upload_url.js +++ b/lib/core/endpoints/file_upload/generate_upload_url.js @@ -1,39 +1,119 @@ "use strict"; -/** */ +/** + * Generate file upload URL REST API request. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); +exports.GenerateFileUploadUrlRequest = void 0; +var PubNubError_1 = require("../../../models/PubNubError"); +var transport_request_1 = require("../../types/transport-request"); +var request_1 = require("../../components/request"); var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNGenerateUploadUrlOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { +var utils_1 = require("../../utils"); +// endregion +/** + * Generate File Upload Url request. + */ +var GenerateFileUploadUrlRequest = /** @class */ (function (_super) { + __extends(GenerateFileUploadUrlRequest, _super); + function GenerateFileUploadUrlRequest(parameters) { + var _this = _super.call(this, { method: transport_request_1.TransportMethod.POST }) || this; + _this.parameters = parameters; + return _this; + } + GenerateFileUploadUrlRequest.prototype.operation = function () { + return operations_1.default.PNGenerateUploadUrlOperation; + }; + GenerateFileUploadUrlRequest.prototype.validate = function () { + if (!this.parameters.channel) return "channel can't be empty"; - } - if (!(params === null || params === void 0 ? void 0 : params.name)) { - return "name can't be empty"; - } - }, - usePost: function () { return true; }, - postURL: function (_a, params) { - var config = _a.config; - return "/v1/files/".concat(config.subscribeKey, "/channels/").concat(utils_1.default.encodeString(params.channel), "/generate-upload-url"); - }, - postPayload: function (_, params) { return ({ - name: params.name, - }); }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function () { return ({}); }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - file_upload_request: response.file_upload_request, - }); }, -}; -exports.default = endpoint; + if (!this.parameters.name) + return "'name' can't be empty"; + }; + GenerateFileUploadUrlRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, { + id: serviceResponse.data.id, + name: serviceResponse.data.name, + url: serviceResponse.file_upload_request.url, + formFields: serviceResponse.file_upload_request.form_fields, + }]; + }); + }); + }; + Object.defineProperty(GenerateFileUploadUrlRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channel = _a.channel; + return "/v1/files/".concat(subscribeKey, "/channels/").concat((0, utils_1.encodeString)(channel), "/generate-upload-url"); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(GenerateFileUploadUrlRequest.prototype, "body", { + get: function () { + return JSON.stringify({ name: this.parameters.name }); + }, + enumerable: false, + configurable: true + }); + return GenerateFileUploadUrlRequest; +}(request_1.AbstractRequest)); +exports.GenerateFileUploadUrlRequest = GenerateFileUploadUrlRequest; diff --git a/lib/core/endpoints/file_upload/get_file_url.js b/lib/core/endpoints/file_upload/get_file_url.js index e7cb0e33e..40916a10a 100644 --- a/lib/core/endpoints/file_upload/get_file_url.js +++ b/lib/core/endpoints/file_upload/get_file_url.js @@ -1,41 +1,112 @@ "use strict"; -/** */ +/** + * File sharing REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -var endpoint_1 = require("../../components/endpoint"); -var utils_1 = __importDefault(require("../../utils")); -exports.default = (function (modules, _a) { - var channel = _a.channel, id = _a.id, name = _a.name; - var config = modules.config, networking = modules.networking, tokenManager = modules.tokenManager; - if (!channel) { - throw new endpoint_1.PubNubError('Validation failed, check status for details', (0, endpoint_1.createValidationError)("channel can't be empty")); - } - if (!id) { - throw new endpoint_1.PubNubError('Validation failed, check status for details', (0, endpoint_1.createValidationError)("file id can't be empty")); +exports.GetFileDownloadUrlRequest = void 0; +var transport_request_1 = require("../../types/transport-request"); +var request_1 = require("../../components/request"); +var operations_1 = __importDefault(require("../../constants/operations")); +var utils_1 = require("../../utils"); +// endregion +/** + * File download Url generation request. + * + * Local request which generates Url to download shared file from the specific channel. + */ +var GetFileDownloadUrlRequest = /** @class */ (function (_super) { + __extends(GetFileDownloadUrlRequest, _super); + /** + * Construct file download Url generation request. + * + * @param parameters - Request configuration. + */ + function GetFileDownloadUrlRequest(parameters) { + var _this = _super.call(this, { method: transport_request_1.TransportMethod.LOCAL }) || this; + _this.parameters = parameters; + return _this; } - if (!name) { - throw new endpoint_1.PubNubError('Validation failed, check status for details', (0, endpoint_1.createValidationError)("file name can't be empty")); - } - var url = "/v1/files/".concat(config.subscribeKey, "/channels/").concat(utils_1.default.encodeString(channel), "/files/").concat(id, "/").concat(name); - var params = {}; - params.uuid = config.getUUID(); - params.pnsdk = (0, endpoint_1.generatePNSDK)(config); - var tokenOrKey = tokenManager.getToken() || config.getAuthKey(); - if (tokenOrKey) { - params.auth = tokenOrKey; - } - if (config.secretKey) { - (0, endpoint_1.signRequest)(modules, url, params, {}, { - getOperation: function () { return 'PubNubGetFileUrlOperation'; }, + GetFileDownloadUrlRequest.prototype.operation = function () { + return operations_1.default.PNGetFileUrlOperation; + }; + GetFileDownloadUrlRequest.prototype.validate = function () { + var _a = this.parameters, channel = _a.channel, id = _a.id, name = _a.name; + if (!channel) + return "channel can't be empty"; + if (!id) + return "file id can't be empty"; + if (!name) + return "file name can't be empty"; + }; + GetFileDownloadUrlRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, response.url]; + }); }); - } - var queryParams = Object.keys(params) - .map(function (key) { return "".concat(encodeURIComponent(key), "=").concat(encodeURIComponent(params[key])); }) - .join('&'); - if (queryParams !== '') { - return "".concat(networking.getStandardOrigin()).concat(url, "?").concat(queryParams); - } - return "".concat(networking.getStandardOrigin()).concat(url); -}); + }; + Object.defineProperty(GetFileDownloadUrlRequest.prototype, "path", { + get: function () { + var _a = this.parameters, channel = _a.channel, id = _a.id, name = _a.name, subscribeKey = _a.keySet.subscribeKey; + return "/v1/files/".concat(subscribeKey, "/channels/").concat((0, utils_1.encodeString)(channel), "/files/").concat(id, "/").concat(name); + }, + enumerable: false, + configurable: true + }); + return GetFileDownloadUrlRequest; +}(request_1.AbstractRequest)); +exports.GetFileDownloadUrlRequest = GetFileDownloadUrlRequest; diff --git a/lib/core/endpoints/file_upload/list_files.js b/lib/core/endpoints/file_upload/list_files.js index 64b8f28f0..c86dabcea 100644 --- a/lib/core/endpoints/file_upload/list_files.js +++ b/lib/core/endpoints/file_upload/list_files.js @@ -1,42 +1,135 @@ "use strict"; -/** */ +/** + * List Files REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); +exports.FilesListRequest = void 0; +var PubNubError_1 = require("../../../models/PubNubError"); +var request_1 = require("../../components/request"); var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNListFilesOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { +var utils_1 = require("../../utils"); +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults +/** + * Number of files to return in response. + */ +var LIMIT = 100; +// endregion +/** + * Files List request. + */ +var FilesListRequest = /** @class */ (function (_super) { + __extends(FilesListRequest, _super); + function FilesListRequest(parameters) { + var _a; + var _b; + var _this = _super.call(this) || this; + _this.parameters = parameters; + // Apply default request parameters. + (_a = (_b = _this.parameters).limit) !== null && _a !== void 0 ? _a : (_b.limit = LIMIT); + return _this; + } + FilesListRequest.prototype.operation = function () { + return operations_1.default.PNListFilesOperation; + }; + FilesListRequest.prototype.validate = function () { + if (!this.parameters.channel) return "channel can't be empty"; - } - }, - getURL: function (_a, params) { - var config = _a.config; - return "/v1/files/".concat(config.subscribeKey, "/channels/").concat(utils_1.default.encodeString(params.channel), "/files"); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_, params) { - var outParams = {}; - if (params.limit) { - outParams.limit = params.limit; - } - if (params.next) { - outParams.next = params.next; - } - return outParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - next: response.next, - count: response.count, - }); }, -}; -exports.default = endpoint; + }; + FilesListRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, serviceResponse]; + }); + }); + }; + Object.defineProperty(FilesListRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channel = _a.channel; + return "/v1/files/".concat(subscribeKey, "/channels/").concat((0, utils_1.encodeString)(channel), "/files"); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(FilesListRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, limit = _a.limit, next = _a.next; + return __assign({ limit: limit }, (next ? { next: next } : {})); + }, + enumerable: false, + configurable: true + }); + return FilesListRequest; +}(request_1.AbstractRequest)); +exports.FilesListRequest = FilesListRequest; diff --git a/lib/core/endpoints/file_upload/publish_file.js b/lib/core/endpoints/file_upload/publish_file.js index 9a0a5584a..b6822bdb4 100644 --- a/lib/core/endpoints/file_upload/publish_file.js +++ b/lib/core/endpoints/file_upload/publish_file.js @@ -1,66 +1,160 @@ "use strict"; -/** */ +/** + * Publish File Message REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); +exports.PublishFileMessageRequest = void 0; +var PubNubError_1 = require("../../../models/PubNubError"); +var request_1 = require("../../components/request"); var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); var base64_codec_1 = require("../../components/base64_codec"); -var preparePayload = function (modules, payload) { - var stringifiedPayload = JSON.stringify(payload); - if (modules.cryptoModule) { - var encrypted = modules.cryptoModule.encrypt(stringifiedPayload); - stringifiedPayload = typeof encrypted === 'string' ? encrypted : (0, base64_codec_1.encode)(encrypted); - stringifiedPayload = JSON.stringify(stringifiedPayload); +var utils_1 = require("../../utils"); +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults +/** + * Whether published file messages should be stored in the channel's history. + */ +var STORE_IN_HISTORY = true; +// endregion +var PublishFileMessageRequest = /** @class */ (function (_super) { + __extends(PublishFileMessageRequest, _super); + function PublishFileMessageRequest(parameters) { + var _a; + var _b; + var _this = _super.call(this) || this; + _this.parameters = parameters; + // Apply default request parameters. + (_a = (_b = _this.parameters).storeInHistory) !== null && _a !== void 0 ? _a : (_b.storeInHistory = STORE_IN_HISTORY); + return _this; } - return stringifiedPayload || ''; -}; -var endpoint = { - getOperation: function () { return operations_1.default.PNPublishFileOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { + PublishFileMessageRequest.prototype.operation = function () { + return operations_1.default.PNPublishFileMessageOperation; + }; + PublishFileMessageRequest.prototype.validate = function () { + var _a = this.parameters, channel = _a.channel, fileId = _a.fileId, fileName = _a.fileName; + if (!channel) return "channel can't be empty"; - } - if (!(params === null || params === void 0 ? void 0 : params.fileId)) { + if (!fileId) return "file id can't be empty"; - } - if (!(params === null || params === void 0 ? void 0 : params.fileName)) { + if (!fileName) return "file name can't be empty"; - } - }, - getURL: function (modules, params) { - var _a = modules.config, publishKey = _a.publishKey, subscribeKey = _a.subscribeKey; - var message = { - message: params.message, - file: { - name: params.fileName, - id: params.fileId, - }, - }; - var payload = preparePayload(modules, message); - return "/v1/files/publish-file/".concat(publishKey, "/").concat(subscribeKey, "/0/").concat(utils_1.default.encodeString(params.channel), "/0/").concat(utils_1.default.encodeString(payload)); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_, params) { - var outParams = {}; - if (params.ttl) { - outParams.ttl = params.ttl; - } - if (params.storeInHistory !== undefined) { - outParams.store = params.storeInHistory ? '1' : '0'; - } - if (params.meta && typeof params.meta === 'object') { - outParams.meta = JSON.stringify(params.meta); - } - return outParams; - }, - handleResponse: function (_, response) { return ({ - timetoken: response['2'], - }); }, -}; -exports.default = endpoint; + }; + PublishFileMessageRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, { timetoken: serviceResponse[2] }]; + }); + }); + }; + Object.defineProperty(PublishFileMessageRequest.prototype, "path", { + get: function () { + var _a = this.parameters, message = _a.message, channel = _a.channel, _b = _a.keySet, publishKey = _b.publishKey, subscribeKey = _b.subscribeKey, fileId = _a.fileId, fileName = _a.fileName; + var fileMessage = __assign({ file: { + name: fileName, + id: fileId, + } }, (message ? { message: message } : {})); + return "/v1/files/publish-file/".concat(publishKey, "/").concat(subscribeKey, "/0/").concat((0, utils_1.encodeString)(channel), "/0/").concat((0, utils_1.encodeString)(this.prepareMessagePayload(fileMessage))); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(PublishFileMessageRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, storeInHistory = _a.storeInHistory, ttl = _a.ttl, meta = _a.meta; + return __assign(__assign({ store: storeInHistory ? '1' : '0' }, (ttl ? { ttl: ttl } : {})), (meta && typeof meta === 'object' ? { meta: JSON.stringify(meta) } : {})); + }, + enumerable: false, + configurable: true + }); + /** + * Pre-process provided data. + * + * Data will be "normalized" and encrypted if `cryptoModule` has been provided. + * + * @param payload - User-provided data which should be pre-processed before use. + * + * @returns Payload which can be used as part of request URL or body. + * + * @throws {Error} in case if provided `payload` or results of `encryption` can't be stringified. + */ + PublishFileMessageRequest.prototype.prepareMessagePayload = function (payload) { + var crypto = this.parameters.crypto; + if (!crypto) + return JSON.stringify(payload) || ''; + var encrypted = crypto.encrypt(JSON.stringify(payload)); + return JSON.stringify(typeof encrypted === 'string' ? encrypted : (0, base64_codec_1.encode)(encrypted)); + }; + return PublishFileMessageRequest; +}(request_1.AbstractRequest)); +exports.PublishFileMessageRequest = PublishFileMessageRequest; diff --git a/lib/core/endpoints/file_upload/send_file.js b/lib/core/endpoints/file_upload/send_file.js index 34aba2be1..bc00bf30a 100644 --- a/lib/core/endpoints/file_upload/send_file.js +++ b/lib/core/endpoints/file_upload/send_file.js @@ -1,4 +1,15 @@ "use strict"; +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { @@ -14,7 +25,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) { function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); - while (_) try { + while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { @@ -35,161 +46,141 @@ var __generator = (this && this.__generator) || function (thisArg, body) { if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; Object.defineProperty(exports, "__esModule", { value: true }); -var endpoint_1 = require("../../components/endpoint"); -var sendFile = function (_a) { - var _this = this; - var generateUploadUrl = _a.generateUploadUrl, publishFile = _a.publishFile, _b = _a.modules, PubNubFile = _b.PubNubFile, config = _b.config, cryptography = _b.cryptography, cryptoModule = _b.cryptoModule, networking = _b.networking; - return function (_a) { - var channel = _a.channel, input = _a.file, message = _a.message, cipherKey = _a.cipherKey, meta = _a.meta, ttl = _a.ttl, storeInHistory = _a.storeInHistory; - return __awaiter(_this, void 0, void 0, function () { - var file, _b, _c, url, formFields, _d, id, name, _e, formFieldsWithMimeType, result, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, e_1, errorBody, reason, retries, wasSuccessful, publishResult, e_2; - return __generator(this, function (_t) { - switch (_t.label) { +exports.SendFileRequest = void 0; +var generate_upload_url_1 = require("./generate_upload_url"); +var PubNubError_1 = require("../../../models/PubNubError"); +var operations_1 = __importDefault(require("../../constants/operations")); +var api_1 = require("../../types/api"); +var upload_file_1 = require("./upload-file"); +// endregion +/** + * Send file composed request. + */ +var SendFileRequest = /** @class */ (function () { + function SendFileRequest(parameters) { + var _a; + this.parameters = parameters; + this.file = (_a = this.parameters.PubNubFile) === null || _a === void 0 ? void 0 : _a.create(parameters.file); + if (!this.file) + throw new Error('File upload error: unable to create File object.'); + } + /** + * Process user-input and upload file. + * + * @returns File upload request response. + */ + SendFileRequest.prototype.process = function () { + return __awaiter(this, void 0, void 0, function () { + var fileName, fileId; + var _this = this; + return __generator(this, function (_a) { + return [2 /*return*/, this.generateFileUploadUrl() + .then(function (result) { + fileName = result.name; + fileId = result.id; + return _this.uploadFile(result); + }) + .then(function () { return _this.publishFileMessage(fileId, fileName); }) + .catch(function (error) { + var errorStatus = api_1.PubNubAPIError.create(error).toStatus(operations_1.default.PNPublishFileOperation); + throw new PubNubError_1.PubNubError('File upload error.', errorStatus); + })]; + }); + }); + }; + /** + * Generate pre-signed file upload Url. + * + * @returns File upload credentials. + */ + SendFileRequest.prototype.generateFileUploadUrl = function () { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new generate_upload_url_1.GenerateFileUploadUrlRequest(__assign(__assign({}, this.parameters), { name: this.file.name, keySet: this.parameters.keySet })); + return [2 /*return*/, this.parameters.sendRequest(request)]; + }); + }); + }; + /** + * Prepare and upload {@link PubNub} File object to remote storage. + * + * @param uploadParameters - File upload request parameters. + * + * @returns + */ + SendFileRequest.prototype.uploadFile = function (uploadParameters) { + return __awaiter(this, void 0, void 0, function () { + var _a, cipherKey, PubNubFile, crypto, cryptography, id, name, url, formFields, _b, _c; + return __generator(this, function (_d) { + switch (_d.label) { case 0: - if (!channel) { - throw new endpoint_1.PubNubError('Validation failed, check status for details', (0, endpoint_1.createValidationError)("channel can't be empty")); - } - if (!input) { - throw new endpoint_1.PubNubError('Validation failed, check status for details', (0, endpoint_1.createValidationError)("file can't be empty")); - } - file = PubNubFile.create(input); - return [4 /*yield*/, generateUploadUrl({ channel: channel, name: file.name })]; + _a = this.parameters, cipherKey = _a.cipherKey, PubNubFile = _a.PubNubFile, crypto = _a.crypto, cryptography = _a.cryptography; + id = uploadParameters.id, name = uploadParameters.name, url = uploadParameters.url, formFields = uploadParameters.formFields; + if (!this.parameters.PubNubFile.supportsEncryptFile) return [3 /*break*/, 4]; + if (!(!cipherKey && crypto)) return [3 /*break*/, 2]; + _b = this; + return [4 /*yield*/, crypto.encryptFile(this.file, PubNubFile)]; case 1: - _b = _t.sent(), _c = _b.file_upload_request, url = _c.url, formFields = _c.form_fields, _d = _b.data, id = _d.id, name = _d.name; - if (!(PubNubFile.supportsEncryptFile && (cipherKey || cryptoModule))) return [3 /*break*/, 6]; - if (!(cipherKey == null)) return [3 /*break*/, 3]; - return [4 /*yield*/, cryptoModule.encryptFile(file, PubNubFile)]; + _b.file = (_d.sent()); + return [3 /*break*/, 4]; case 2: - _e = _t.sent(); - return [3 /*break*/, 5]; - case 3: return [4 /*yield*/, cryptography.encryptFile(cipherKey, file, PubNubFile)]; - case 4: - _e = _t.sent(); - _t.label = 5; - case 5: - file = _e; - _t.label = 6; - case 6: - formFieldsWithMimeType = formFields; - if (file.mimeType) { - formFieldsWithMimeType = formFields.map(function (entry) { - if (entry.key === 'Content-Type') - return { key: entry.key, value: file.mimeType }; - return entry; - }); - } - _t.label = 7; - case 7: - _t.trys.push([7, 21, , 22]); - if (!(PubNubFile.supportsFileUri && input.uri)) return [3 /*break*/, 10]; - _g = (_f = networking).POSTFILE; - _h = [url, formFieldsWithMimeType]; - return [4 /*yield*/, file.toFileUri()]; - case 8: return [4 /*yield*/, _g.apply(_f, _h.concat([_t.sent()]))]; - case 9: - result = _t.sent(); - return [3 /*break*/, 20]; - case 10: - if (!PubNubFile.supportsFile) return [3 /*break*/, 13]; - _k = (_j = networking).POSTFILE; - _l = [url, formFieldsWithMimeType]; - return [4 /*yield*/, file.toFile()]; - case 11: return [4 /*yield*/, _k.apply(_j, _l.concat([_t.sent()]))]; - case 12: - result = _t.sent(); - return [3 /*break*/, 20]; - case 13: - if (!PubNubFile.supportsBuffer) return [3 /*break*/, 16]; - _o = (_m = networking).POSTFILE; - _p = [url, formFieldsWithMimeType]; - return [4 /*yield*/, file.toBuffer()]; - case 14: return [4 /*yield*/, _o.apply(_m, _p.concat([_t.sent()]))]; - case 15: - result = _t.sent(); - return [3 /*break*/, 20]; - case 16: - if (!PubNubFile.supportsBlob) return [3 /*break*/, 19]; - _r = (_q = networking).POSTFILE; - _s = [url, formFieldsWithMimeType]; - return [4 /*yield*/, file.toBlob()]; - case 17: return [4 /*yield*/, _r.apply(_q, _s.concat([_t.sent()]))]; - case 18: - result = _t.sent(); - return [3 /*break*/, 20]; - case 19: throw new Error('Unsupported environment'); - case 20: return [3 /*break*/, 22]; - case 21: - e_1 = _t.sent(); - if (e_1.response && typeof e_1.response.text === 'string') { - errorBody = e_1.response.text; - reason = /(.*)<\/Message>/gi.exec(errorBody); - throw new endpoint_1.PubNubError(reason ? "Upload to bucket failed: ".concat(reason[1]) : 'Upload to bucket failed.', e_1); - } - else { - throw new endpoint_1.PubNubError('Upload to bucket failed.', e_1); - } - return [3 /*break*/, 22]; - case 22: - if (result.status !== 204) { - throw new endpoint_1.PubNubError('Upload to bucket was unsuccessful', result); - } - retries = config.fileUploadPublishRetryLimit; + if (!(cipherKey && cryptography)) return [3 /*break*/, 4]; + _c = this; + return [4 /*yield*/, cryptography.encryptFile(cipherKey, this.file, PubNubFile)]; + case 3: + _c.file = (_d.sent()); + _d.label = 4; + case 4: return [2 /*return*/, this.parameters.sendRequest(new upload_file_1.UploadFileRequest({ + fileId: id, + fileName: name, + file: this.file, + uploadUrl: url, + formFields: formFields, + }))]; + } + }); + }); + }; + SendFileRequest.prototype.publishFileMessage = function (fileId, fileName) { + return __awaiter(this, void 0, void 0, function () { + var result, retries, wasSuccessful, _1; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + result = { timetoken: '0' }; + retries = this.parameters.fileUploadPublishRetryLimit; wasSuccessful = false; - publishResult = { timetoken: '0' }; - _t.label = 23; - case 23: - _t.trys.push([23, 25, , 26]); - return [4 /*yield*/, publishFile({ - channel: channel, - message: message, - fileId: id, - fileName: name, - meta: meta, - storeInHistory: storeInHistory, - ttl: ttl, - })]; - case 24: - /* eslint-disable-next-line no-await-in-loop */ - publishResult = _t.sent(); + _a.label = 1; + case 1: + _a.trys.push([1, 3, , 4]); + return [4 /*yield*/, this.parameters.publishFile(__assign(__assign({}, this.parameters), { fileId: fileId, fileName: fileName }))]; + case 2: + result = _a.sent(); wasSuccessful = true; - return [3 /*break*/, 26]; - case 25: - e_2 = _t.sent(); + return [3 /*break*/, 4]; + case 3: + _1 = _a.sent(); retries -= 1; - return [3 /*break*/, 26]; - case 26: - if (!wasSuccessful && retries > 0) return [3 /*break*/, 23]; - _t.label = 27; - case 27: + return [3 /*break*/, 4]; + case 4: + if (!wasSuccessful && retries > 0) return [3 /*break*/, 1]; + _a.label = 5; + case 5: if (!wasSuccessful) { - throw new endpoint_1.PubNubError('Publish failed. You may want to execute that operation manually using pubnub.publishFile', { - channel: channel, - id: id, - name: name, - }); - } - else { - return [2 /*return*/, { - timetoken: publishResult.timetoken, - id: id, - name: name, - }]; + throw new PubNubError_1.PubNubError('Publish failed. You may want to execute that operation manually using pubnub.publishFile', { error: true, channel: this.parameters.channel, id: fileId, name: fileName }); } + else + return [2 /*return*/, { status: 200, timetoken: result.timetoken, id: fileId, name: fileName }]; return [2 /*return*/]; } }); }); }; -}; -exports.default = (function (deps) { - var f = sendFile(deps); - return function (params, cb) { - var resultP = f(params); - if (typeof cb === 'function') { - resultP.then(function (result) { return cb(null, result); }).catch(function (error) { return cb(error, null); }); - return resultP; - } - return resultP; - }; -}); + return SendFileRequest; +}()); +exports.SendFileRequest = SendFileRequest; diff --git a/lib/core/endpoints/file_upload/types.js b/lib/core/endpoints/file_upload/types.js deleted file mode 100644 index 1e44d895d..000000000 --- a/lib/core/endpoints/file_upload/types.js +++ /dev/null @@ -1,2 +0,0 @@ -"use strict"; -/** */ diff --git a/lib/core/endpoints/file_upload/upload-file.js b/lib/core/endpoints/file_upload/upload-file.js new file mode 100644 index 000000000..0ac8de96a --- /dev/null +++ b/lib/core/endpoints/file_upload/upload-file.js @@ -0,0 +1,137 @@ +"use strict"; +/** + * Upload file REST API request. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.UploadFileRequest = void 0; +var request_1 = require("../../components/request"); +var operations_1 = __importDefault(require("../../constants/operations")); +/** + * File Upload request. + */ +var UploadFileRequest = /** @class */ (function (_super) { + __extends(UploadFileRequest, _super); + function UploadFileRequest(parameters) { + var _this = _super.call(this) || this; + _this.parameters = parameters; + // Use file's actual mime type if available. + var mimeType = parameters.file.mimeType; + if (mimeType) { + parameters.formFields = parameters.formFields.map(function (entry) { + if (entry.name === 'Content-Type') + return { name: entry.name, value: mimeType }; + return entry; + }); + } + return _this; + } + UploadFileRequest.prototype.operation = function () { + return operations_1.default.PNPublishFileOperation; + }; + UploadFileRequest.prototype.validate = function () { + var _a = this.parameters, fileId = _a.fileId, fileName = _a.fileName, file = _a.file, uploadUrl = _a.uploadUrl; + if (!fileId) + return "Validation failed: file 'id' can't be empty"; + if (!fileName) + return "Validation failed: file 'name' can't be empty"; + if (!file) + return "Validation failed: 'file' can't be empty"; + if (!uploadUrl) + return "Validation failed: file upload 'url' can't be empty"; + }; + UploadFileRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, { + status: response.status, + message: response.body ? UploadFileRequest.decoder.decode(response.body) : 'OK', + }]; + }); + }); + }; + UploadFileRequest.prototype.request = function () { + return __assign(__assign({}, _super.prototype.request.call(this)), { origin: new URL(this.parameters.uploadUrl).origin }); + }; + Object.defineProperty(UploadFileRequest.prototype, "path", { + get: function () { + var _a = new URL(this.parameters.uploadUrl), pathname = _a.pathname, search = _a.search; + return "".concat(pathname).concat(search); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(UploadFileRequest.prototype, "body", { + get: function () { + return this.parameters.file; + }, + enumerable: false, + configurable: true + }); + return UploadFileRequest; +}(request_1.AbstractRequest)); +exports.UploadFileRequest = UploadFileRequest; diff --git a/lib/core/endpoints/history/delete_messages.js b/lib/core/endpoints/history/delete_messages.js index 7a0e4df4a..9c0093bf0 100644 --- a/lib/core/endpoints/history/delete_messages.js +++ b/lib/core/endpoints/history/delete_messages.js @@ -1,55 +1,126 @@ "use strict"; -/* */ +/** + * Delete messages REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.useDelete = exports.validateParams = exports.getOperation = void 0; +exports.DeleteMessageRequest = void 0; +var PubNubError_1 = require("../../../models/PubNubError"); +var transport_request_1 = require("../../types/transport-request"); +var request_1 = require("../../components/request"); var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -function getOperation() { - return operations_1.default.PNDeleteMessagesOperation; -} -exports.getOperation = getOperation; -function validateParams(modules, incomingParams) { - var channel = incomingParams.channel; - var config = modules.config; - if (!channel) - return 'Missing channel'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function useDelete() { - return true; -} -exports.useDelete = useDelete; -function getURL(modules, incomingParams) { - var channel = incomingParams.channel; - var config = modules.config; - return "/v3/history/sub-key/".concat(config.subscribeKey, "/channel/").concat(utils_1.default.encodeString(channel)); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams(modules, incomingParams) { - var start = incomingParams.start, end = incomingParams.end; - var outgoingParams = {}; - if (start) - outgoingParams.start = start; - if (end) - outgoingParams.end = end; - return outgoingParams; -} -exports.prepareParams = prepareParams; -function handleResponse(modules, serverResponse) { - return serverResponse.payload; -} -exports.handleResponse = handleResponse; +var utils_1 = require("../../utils"); +// endregion +/** + * Delete messages from channel history. + */ +var DeleteMessageRequest = /** @class */ (function (_super) { + __extends(DeleteMessageRequest, _super); + function DeleteMessageRequest(parameters) { + var _this = _super.call(this, { method: transport_request_1.TransportMethod.DELETE }) || this; + _this.parameters = parameters; + return _this; + } + DeleteMessageRequest.prototype.operation = function () { + return operations_1.default.PNDeleteMessagesOperation; + }; + DeleteMessageRequest.prototype.validate = function () { + if (!this.parameters.keySet.subscribeKey) + return 'Missing Subscribe Key'; + if (!this.parameters.channel) + return 'Missing channel'; + }; + DeleteMessageRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, {}]; + }); + }); + }; + Object.defineProperty(DeleteMessageRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channel = _a.channel; + return "/v3/history/sub-key/".concat(subscribeKey, "/channel/").concat((0, utils_1.encodeString)(channel)); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(DeleteMessageRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, start = _a.start, end = _a.end; + return __assign(__assign({}, (start ? { start: start } : {})), (end ? { end: end } : {})); + }, + enumerable: false, + configurable: true + }); + return DeleteMessageRequest; +}(request_1.AbstractRequest)); +exports.DeleteMessageRequest = DeleteMessageRequest; diff --git a/lib/core/endpoints/history/get_history.js b/lib/core/endpoints/history/get_history.js index 5cbc72ad3..75843b523 100644 --- a/lib/core/endpoints/history/get_history.js +++ b/lib/core/endpoints/history/get_history.js @@ -1,100 +1,200 @@ "use strict"; +/** + * Get history REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; -/* */ +exports.GetHistoryRequest = void 0; +var PubNubError_1 = require("../../../models/PubNubError"); +var request_1 = require("../../components/request"); var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -function __processMessage(modules, message) { - var result = {}; - if (!modules.cryptoModule) { - result.payload = message; - return result; - } - try { - var decryptedData = modules.cryptoModule.decrypt(message); - var decryptedPayload = decryptedData instanceof ArrayBuffer ? JSON.parse(new TextDecoder().decode(decryptedData)) : decryptedData; - result.payload = decryptedPayload; - return result; +var utils_1 = require("../../utils"); +// -------------------------------------------------------- +// ---------------------- Defaults ------------------------ +// -------------------------------------------------------- +// region Defaults +/** + * Whether verbose logging enabled or not. + */ +var LOG_VERBOSITY = false; +/** + * Whether associated message metadata should be returned or not. + */ +var INCLUDE_METADATA = false; +/** + * Whether timetokens should be returned as strings by default or not. + */ +var STRINGIFY_TIMETOKENS = false; +/** + * Default and maximum number of messages which should be returned. + */ +var MESSAGES_COUNT = 100; +// endregion +/** + * Get single channel messages request. + */ +var GetHistoryRequest = /** @class */ (function (_super) { + __extends(GetHistoryRequest, _super); + function GetHistoryRequest(parameters) { + var _a, _b, _c; + var _this = _super.call(this) || this; + _this.parameters = parameters; + // Apply defaults. + if (parameters.count) + parameters.count = Math.min(parameters.count, MESSAGES_COUNT); + else + parameters.count = MESSAGES_COUNT; + (_a = parameters.stringifiedTimeToken) !== null && _a !== void 0 ? _a : (parameters.stringifiedTimeToken = STRINGIFY_TIMETOKENS); + (_b = parameters.includeMeta) !== null && _b !== void 0 ? _b : (parameters.includeMeta = INCLUDE_METADATA); + (_c = parameters.logVerbosity) !== null && _c !== void 0 ? _c : (parameters.logVerbosity = LOG_VERBOSITY); + return _this; } - catch (e) { - if (modules.config.logVerbosity && console && console.log) - console.log('decryption error', e.message); - result.payload = message; - result.error = "Error while decrypting message content: ".concat(e.message); - } - return result; -} -function getOperation() { - return operations_1.default.PNHistoryOperation; -} -exports.getOperation = getOperation; -function validateParams(modules, incomingParams) { - var channel = incomingParams.channel; - var config = modules.config; - if (!channel) - return 'Missing channel'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var channel = incomingParams.channel; - var config = modules.config; - return "/v2/history/sub-key/".concat(config.subscribeKey, "/channel/").concat(utils_1.default.encodeString(channel)); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams(modules, incomingParams) { - var start = incomingParams.start, end = incomingParams.end, reverse = incomingParams.reverse, _a = incomingParams.count, count = _a === void 0 ? 100 : _a, _b = incomingParams.stringifiedTimeToken, stringifiedTimeToken = _b === void 0 ? false : _b, _c = incomingParams.includeMeta, includeMeta = _c === void 0 ? false : _c; - var outgoingParams = { - include_token: 'true', + GetHistoryRequest.prototype.operation = function () { + return operations_1.default.PNHistoryOperation; }; - outgoingParams.count = count; - if (start) - outgoingParams.start = start; - if (end) - outgoingParams.end = end; - if (stringifiedTimeToken) - outgoingParams.string_message_token = 'true'; - if (reverse != null) - outgoingParams.reverse = reverse.toString(); - if (includeMeta) - outgoingParams.include_meta = 'true'; - return outgoingParams; -} -exports.prepareParams = prepareParams; -function handleResponse(modules, serverResponse) { - var response = { - messages: [], - startTimeToken: serverResponse[1], - endTimeToken: serverResponse[2], + GetHistoryRequest.prototype.validate = function () { + if (!this.parameters.keySet.subscribeKey) + return 'Missing Subscribe Key'; + if (!this.parameters.channel) + return 'Missing channel'; }; - if (Array.isArray(serverResponse[0])) { - serverResponse[0].forEach(function (serverHistoryItem) { - var processedMessgeResult = __processMessage(modules, serverHistoryItem.message); - var item = { - timetoken: serverHistoryItem.timetoken, - entry: processedMessgeResult.payload, - }; - if (serverHistoryItem.meta) { - item.meta = serverHistoryItem.meta; - } - if (processedMessgeResult.error) - item.error = processedMessgeResult.error; - response.messages.push(item); + GetHistoryRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse, messages, startTimeToken, endTimeToken; + var _this = this; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + messages = serviceResponse[0]; + startTimeToken = serviceResponse[1]; + endTimeToken = serviceResponse[2]; + // Handle malformed get history response. + if (!Array.isArray(messages)) + return [2 /*return*/, { messages: [], startTimeToken: startTimeToken, endTimeToken: endTimeToken }]; + return [2 /*return*/, { + messages: messages.map(function (payload) { + var processedPayload = _this.processPayload(payload.message); + var item = { + entry: processedPayload.payload, + timetoken: payload.timetoken, + }; + if (processedPayload.error) + item.error = processedPayload.error; + if (payload.meta) + item.meta = payload.meta; + return item; + }), + startTimeToken: startTimeToken, + endTimeToken: endTimeToken, + }]; + }); }); - } - return response; -} -exports.handleResponse = handleResponse; + }; + Object.defineProperty(GetHistoryRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channel = _a.channel; + return "/v2/history/sub-key/".concat(subscribeKey, "/channel/").concat((0, utils_1.encodeString)(channel)); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(GetHistoryRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, start = _a.start, end = _a.end, reverse = _a.reverse, count = _a.count, stringifiedTimeToken = _a.stringifiedTimeToken, includeMeta = _a.includeMeta; + return __assign(__assign(__assign(__assign(__assign({ count: count, include_token: 'true' }, (start ? { start: start } : {})), (end ? { end: end } : {})), (stringifiedTimeToken ? { string_message_token: 'true' } : {})), (reverse !== undefined && reverse !== null ? { reverse: reverse.toString() } : {})), (includeMeta ? { include_meta: 'true' } : {})); + }, + enumerable: false, + configurable: true + }); + GetHistoryRequest.prototype.processPayload = function (payload) { + var _a = this.parameters, crypto = _a.crypto, logVerbosity = _a.logVerbosity; + if (!crypto || typeof payload !== 'string') + return { payload: payload }; + var decryptedPayload; + var error; + try { + var decryptedData = crypto.decrypt(payload); + decryptedPayload = + decryptedData instanceof ArrayBuffer + ? JSON.parse(GetHistoryRequest.decoder.decode(decryptedData)) + : decryptedData; + } + catch (err) { + if (logVerbosity) + console.log("decryption error", err.message); + decryptedPayload = payload; + error = "Error while decrypting message content: ".concat(err.message); + } + return { + payload: decryptedPayload, + error: error, + }; + }; + return GetHistoryRequest; +}(request_1.AbstractRequest)); +exports.GetHistoryRequest = GetHistoryRequest; diff --git a/lib/core/endpoints/history/message_counts.js b/lib/core/endpoints/history/message_counts.js index 7beb84974..5f9010f21 100644 --- a/lib/core/endpoints/history/message_counts.js +++ b/lib/core/endpoints/history/message_counts.js @@ -1,78 +1,130 @@ "use strict"; -var __read = (this && this.__read) || function (o, n) { - var m = typeof Symbol === "function" && o[Symbol.iterator]; - if (!m) return o; - var i = m.call(o), r, ar = [], e; - try { - while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); - } - catch (error) { e = { error: error }; } - finally { - try { - if (r && !r.done && (m = i["return"])) m.call(i); +/** + * Messages count REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; } - finally { if (e) throw e.error; } + return t; + }; + return __assign.apply(this, arguments); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } - return ar; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; +exports.MessageCountRequest = void 0; +var PubNubError_1 = require("../../../models/PubNubError"); +var request_1 = require("../../components/request"); var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -function getOperation() { - return operations_1.default.PNMessageCounts; -} -exports.getOperation = getOperation; -function validateParams(modules, incomingParams) { - var channels = incomingParams.channels, timetoken = incomingParams.timetoken, channelTimetokens = incomingParams.channelTimetokens; - var config = modules.config; - if (!channels) - return 'Missing channel'; - if (timetoken && channelTimetokens) - return 'timetoken and channelTimetokens are incompatible together'; - if (channelTimetokens && channelTimetokens.length > 1 && channels.length !== channelTimetokens.length) { - return 'Length of channelTimetokens and channels do not match'; - } - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var channels = incomingParams.channels; - var config = modules.config; - var stringifiedChannels = channels.join(','); - return "/v3/history/sub-key/".concat(config.subscribeKey, "/message-counts/").concat(utils_1.default.encodeString(stringifiedChannels)); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams(modules, incomingParams) { - var timetoken = incomingParams.timetoken, channelTimetokens = incomingParams.channelTimetokens; - var outgoingParams = {}; - if (channelTimetokens && channelTimetokens.length === 1) { - var _a = __read(channelTimetokens, 1), tt = _a[0]; - outgoingParams.timetoken = tt; - } - else if (channelTimetokens) { - outgoingParams.channelsTimetoken = channelTimetokens.join(','); - } - else if (timetoken) { - outgoingParams.timetoken = timetoken; +var utils_1 = require("../../utils"); +// endregion +var MessageCountRequest = /** @class */ (function (_super) { + __extends(MessageCountRequest, _super); + function MessageCountRequest(parameters) { + var _this = _super.call(this) || this; + _this.parameters = parameters; + return _this; } - return outgoingParams; -} -exports.prepareParams = prepareParams; -function handleResponse(modules, serverResponse) { - return { channels: serverResponse.channels }; -} -exports.handleResponse = handleResponse; + MessageCountRequest.prototype.operation = function () { + return operations_1.default.PNMessageCounts; + }; + MessageCountRequest.prototype.validate = function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channels = _a.channels, timetoken = _a.timetoken, channelTimetokens = _a.channelTimetokens; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!channels) + return 'Missing channels'; + if (timetoken && channelTimetokens) + return '`timetoken` and `channelTimetokens` are incompatible together'; + if (!timetoken && !channelTimetokens) + return '`timetoken` or `channelTimetokens` need to be set'; + if (channelTimetokens && channelTimetokens.length && channelTimetokens.length !== channels.length) + return 'Length of `channelTimetokens` and `channels` do not match'; + }; + MessageCountRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, { channels: serviceResponse.channels }]; + }); + }); + }; + Object.defineProperty(MessageCountRequest.prototype, "path", { + get: function () { + return "/v3/history/sub-key/".concat(this.parameters.keySet.subscribeKey, "/message-counts/").concat((0, utils_1.encodeString)(this.parameters.channels.join(','))); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(MessageCountRequest.prototype, "queryParameters", { + get: function () { + var channelTimetokens = this.parameters.channelTimetokens; + if (this.parameters.timetoken) + channelTimetokens = [this.parameters.timetoken]; + return __assign(__assign({}, (channelTimetokens.length === 1 ? { timetoken: channelTimetokens[0] } : {})), (channelTimetokens.length > 1 ? { channelsTimetoken: channelTimetokens.join(',') } : {})); + }, + enumerable: false, + configurable: true + }); + return MessageCountRequest; +}(request_1.AbstractRequest)); +exports.MessageCountRequest = MessageCountRequest; diff --git a/lib/core/endpoints/objects/channel/get.js b/lib/core/endpoints/objects/channel/get.js index b482749af..f574de86b 100644 --- a/lib/core/endpoints/objects/channel/get.js +++ b/lib/core/endpoints/objects/channel/get.js @@ -1,41 +1,151 @@ "use strict"; +/** + * Get Channel Metadata REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +var __read = (this && this.__read) || function (o, n) { + var m = typeof Symbol === "function" && o[Symbol.iterator]; + if (!m) return o; + var i = m.call(o), r, ar = [], e; + try { + while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); + } + catch (error) { e = { error: error }; } + finally { + try { + if (r && !r.done && (m = i["return"])) m.call(i); + } + finally { if (e) throw e.error; } + } + return ar; +}; +var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { + if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { + if (ar || !(i in from)) { + if (!ar) ar = Array.prototype.slice.call(from, 0, i); + ar[i] = from[i]; + } + } + return to.concat(ar || Array.prototype.slice.call(from)); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); +exports.GetChannelMetadataRequest = void 0; +var PubNubError_1 = require("../../../../models/PubNubError"); +var request_1 = require("../../../components/request"); var operations_1 = __importDefault(require("../../../constants/operations")); -var utils_1 = __importDefault(require("../../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNGetChannelMetadataOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { +var utils_1 = require("../../../utils"); +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults +/** + * Whether `Channel` custom field should be included by default or not. + */ +var INCLUDE_CUSTOM_FIELDS = true; +// endregion +/** + * Get Channel Metadata request. + */ +var GetChannelMetadataRequest = /** @class */ (function (_super) { + __extends(GetChannelMetadataRequest, _super); + function GetChannelMetadataRequest(parameters) { + var _a, _b; + var _c; + var _this = _super.call(this) || this; + _this.parameters = parameters; + // Apply default request parameters. + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_c = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_c.customFields = INCLUDE_CUSTOM_FIELDS); + return _this; + } + GetChannelMetadataRequest.prototype.operation = function () { + return operations_1.default.PNGetChannelMetadataOperation; + }; + GetChannelMetadataRequest.prototype.validate = function () { + if (!this.parameters.channel) return 'Channel cannot be empty'; - } - }, - getURL: function (_a, params) { - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/channels/").concat(utils_1.default.encodeString(params.channel)); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_, params) { - var _a; - var queryParams = {}; - queryParams.include = ['status', 'type', 'custom']; - if (params === null || params === void 0 ? void 0 : params.include) { - if (((_a = params.include) === null || _a === void 0 ? void 0 : _a.customFields) === false) { - queryParams.include.pop(); - } - } - queryParams.include = queryParams.include.join(','); - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - }); }, -}; -exports.default = endpoint; + }; + GetChannelMetadataRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, serviceResponse]; + }); + }); + }; + Object.defineProperty(GetChannelMetadataRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channel = _a.channel; + return "/v2/objects/".concat(subscribeKey, "/channels/").concat((0, utils_1.encodeString)(channel)); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(GetChannelMetadataRequest.prototype, "queryParameters", { + get: function () { + return { + include: __spreadArray(['status', 'type'], __read((this.parameters.include.customFields ? ['custom'] : [])), false).join(','), + }; + }, + enumerable: false, + configurable: true + }); + return GetChannelMetadataRequest; +}(request_1.AbstractRequest)); +exports.GetChannelMetadataRequest = GetChannelMetadataRequest; diff --git a/lib/core/endpoints/objects/channel/get_all.js b/lib/core/endpoints/objects/channel/get_all.js index a4e35acd2..472682030 100644 --- a/lib/core/endpoints/objects/channel/get_all.js +++ b/lib/core/endpoints/objects/channel/get_all.js @@ -1,4 +1,69 @@ "use strict"; +/** + * Get All Channel Metadata REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; @@ -15,65 +80,90 @@ var __read = (this && this.__read) || function (o, n) { } return ar; }; +var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { + if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { + if (ar || !(i in from)) { + if (!ar) ar = Array.prototype.slice.call(from, 0, i); + ar[i] = from[i]; + } + } + return to.concat(ar || Array.prototype.slice.call(from)); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); +exports.GetAllChannelsMetadataRequest = void 0; +var PubNubError_1 = require("../../../../models/PubNubError"); +var request_1 = require("../../../components/request"); var operations_1 = __importDefault(require("../../../constants/operations")); -var endpoint = { - getOperation: function () { return operations_1.default.PNGetAllChannelMetadataOperation; }, - validateParams: function () { - // No required parameters. - }, - getURL: function (_a) { - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/channels"); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_modules, params) { - var _a, _b, _c, _d, _e, _f, _g, _h, _j; - var queryParams = {}; - queryParams.include = ['status', 'type']; - if (params === null || params === void 0 ? void 0 : params.include) { - if ((_a = params.include) === null || _a === void 0 ? void 0 : _a.customFields) { - queryParams.include.push('custom'); - } - } - queryParams.include = queryParams.include.join(','); - if ((_b = params === null || params === void 0 ? void 0 : params.include) === null || _b === void 0 ? void 0 : _b.totalCount) { - queryParams.count = (_c = params.include) === null || _c === void 0 ? void 0 : _c.totalCount; - } - if ((_d = params === null || params === void 0 ? void 0 : params.page) === null || _d === void 0 ? void 0 : _d.next) { - queryParams.start = (_e = params.page) === null || _e === void 0 ? void 0 : _e.next; - } - if ((_f = params === null || params === void 0 ? void 0 : params.page) === null || _f === void 0 ? void 0 : _f.prev) { - queryParams.end = (_g = params.page) === null || _g === void 0 ? void 0 : _g.prev; - } - if (params === null || params === void 0 ? void 0 : params.filter) { - queryParams.filter = params.filter; - } - queryParams.limit = (_h = params === null || params === void 0 ? void 0 : params.limit) !== null && _h !== void 0 ? _h : 100; - if (params === null || params === void 0 ? void 0 : params.sort) { - queryParams.sort = Object.entries((_j = params.sort) !== null && _j !== void 0 ? _j : {}).map(function (_a) { - var _b = __read(_a, 2), key = _b[0], value = _b[1]; - if (value === 'asc' || value === 'desc') { - return "".concat(key, ":").concat(value); - } - return key; +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults +/** + * Whether `Channel` custom fields should be included in response or not. + */ +var INCLUDE_CUSTOM_FIELDS = false; +/** + * Whether total number of channels should be included in response or not. + */ +var INCLUDE_TOTAL_COUNT = false; +/** + * Number of objects to return in response. + */ +var LIMIT = 100; +// endregion +/** + * Get All Channels Metadata request. + */ +var GetAllChannelsMetadataRequest = /** @class */ (function (_super) { + __extends(GetAllChannelsMetadataRequest, _super); + function GetAllChannelsMetadataRequest(parameters) { + var _a, _b, _c, _d; + var _e, _f; + var _this = _super.call(this) || this; + _this.parameters = parameters; + // Apply default request parameters. + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_e = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_e.customFields = INCLUDE_CUSTOM_FIELDS); + (_c = (_f = parameters.include).totalCount) !== null && _c !== void 0 ? _c : (_f.totalCount = INCLUDE_TOTAL_COUNT); + (_d = parameters.limit) !== null && _d !== void 0 ? _d : (parameters.limit = LIMIT); + return _this; + } + GetAllChannelsMetadataRequest.prototype.operation = function () { + return operations_1.default.PNGetAllChannelMetadataOperation; + }; + GetAllChannelsMetadataRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, serviceResponse]; }); - } - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - totalCount: response.totalCount, - prev: response.prev, - next: response.next, - }); }, -}; -exports.default = endpoint; + }); + }; + Object.defineProperty(GetAllChannelsMetadataRequest.prototype, "path", { + get: function () { + return "/v2/objects/".concat(this.parameters.keySet.subscribeKey, "/channels"); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(GetAllChannelsMetadataRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, include = _a.include, page = _a.page, filter = _a.filter, sort = _a.sort, limit = _a.limit; + var sorting = Object.entries(sort !== null && sort !== void 0 ? sort : {}).map(function (_a) { + var _b = __read(_a, 2), option = _b[0], order = _b[1]; + return order !== null ? "".concat(option, ":").concat(order) : option; + }); + return __assign(__assign(__assign(__assign(__assign({ include: __spreadArray(['status', 'type'], __read((include.customFields ? ['custom'] : [])), false).join(','), count: "".concat(include.totalCount) }, (filter ? { filter: filter } : {})), ((page === null || page === void 0 ? void 0 : page.next) ? { start: page.next } : {})), ((page === null || page === void 0 ? void 0 : page.prev) ? { end: page.prev } : {})), (limit ? { limit: limit } : {})), (sorting.length ? { sort: sorting } : {})); + }, + enumerable: false, + configurable: true + }); + return GetAllChannelsMetadataRequest; +}(request_1.AbstractRequest)); +exports.GetAllChannelsMetadataRequest = GetAllChannelsMetadataRequest; diff --git a/lib/core/endpoints/objects/channel/remove.js b/lib/core/endpoints/objects/channel/remove.js index 9942abc80..56dfcf502 100644 --- a/lib/core/endpoints/objects/channel/remove.js +++ b/lib/core/endpoints/objects/channel/remove.js @@ -1,32 +1,105 @@ "use strict"; -/** */ +/** + * Remove Channel Metadata REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); +exports.RemoveChannelMetadataRequest = void 0; +var PubNubError_1 = require("../../../../models/PubNubError"); +var transport_request_1 = require("../../../types/transport-request"); +var request_1 = require("../../../components/request"); var operations_1 = __importDefault(require("../../../constants/operations")); -var utils_1 = __importDefault(require("../../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNRemoveChannelMetadataOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { +var utils_1 = require("../../../utils"); +// endregion +/** + * Remove Channel Metadata request. + */ +var RemoveChannelMetadataRequest = /** @class */ (function (_super) { + __extends(RemoveChannelMetadataRequest, _super); + function RemoveChannelMetadataRequest(parameters) { + var _this = _super.call(this, { method: transport_request_1.TransportMethod.DELETE }) || this; + _this.parameters = parameters; + return _this; + } + RemoveChannelMetadataRequest.prototype.operation = function () { + return operations_1.default.PNRemoveChannelMetadataOperation; + }; + RemoveChannelMetadataRequest.prototype.validate = function () { + if (!this.parameters.channel) return 'Channel cannot be empty'; - } - }, - getURL: function (_a, params) { - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/channels/").concat(utils_1.default.encodeString(params.channel)); - }, - useDelete: function () { return true; }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function () { return ({}); }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - }); }, -}; -exports.default = endpoint; + }; + RemoveChannelMetadataRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, serviceResponse]; + }); + }); + }; + Object.defineProperty(RemoveChannelMetadataRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channel = _a.channel; + return "/v2/objects/".concat(subscribeKey, "/channels/").concat((0, utils_1.encodeString)(channel)); + }, + enumerable: false, + configurable: true + }); + return RemoveChannelMetadataRequest; +}(request_1.AbstractRequest)); +exports.RemoveChannelMetadataRequest = RemoveChannelMetadataRequest; diff --git a/lib/core/endpoints/objects/channel/set.js b/lib/core/endpoints/objects/channel/set.js index 881bf48d1..633f1b879 100644 --- a/lib/core/endpoints/objects/channel/set.js +++ b/lib/core/endpoints/objects/channel/set.js @@ -1,47 +1,161 @@ "use strict"; -/** */ +/** + * Set Channel Metadata REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +var __read = (this && this.__read) || function (o, n) { + var m = typeof Symbol === "function" && o[Symbol.iterator]; + if (!m) return o; + var i = m.call(o), r, ar = [], e; + try { + while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); + } + catch (error) { e = { error: error }; } + finally { + try { + if (r && !r.done && (m = i["return"])) m.call(i); + } + finally { if (e) throw e.error; } + } + return ar; +}; +var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { + if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { + if (ar || !(i in from)) { + if (!ar) ar = Array.prototype.slice.call(from, 0, i); + ar[i] = from[i]; + } + } + return to.concat(ar || Array.prototype.slice.call(from)); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); +exports.SetChannelMetadataRequest = void 0; +var PubNubError_1 = require("../../../../models/PubNubError"); +var transport_request_1 = require("../../../types/transport-request"); +var request_1 = require("../../../components/request"); var operations_1 = __importDefault(require("../../../constants/operations")); -var utils_1 = __importDefault(require("../../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNSetChannelMetadataOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { +var utils_1 = require("../../../utils"); +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults +/** + * Whether `Channel` custom field should be included by default or not. + */ +var INCLUDE_CUSTOM_FIELDS = true; +// endregion +/** + * Set Channel Metadata request. + */ +var SetChannelMetadataRequest = /** @class */ (function (_super) { + __extends(SetChannelMetadataRequest, _super); + function SetChannelMetadataRequest(parameters) { + var _a, _b; + var _c; + var _this = _super.call(this, { method: transport_request_1.TransportMethod.PATCH }) || this; + _this.parameters = parameters; + // Apply default request parameters. + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_c = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_c.customFields = INCLUDE_CUSTOM_FIELDS); + return _this; + } + SetChannelMetadataRequest.prototype.operation = function () { + return operations_1.default.PNSetChannelMetadataOperation; + }; + SetChannelMetadataRequest.prototype.validate = function () { + if (!this.parameters.channel) return 'Channel cannot be empty'; - } - if (!(params === null || params === void 0 ? void 0 : params.data)) { + if (!this.parameters.data) return 'Data cannot be empty'; - } - }, - usePatch: function () { return true; }, - patchURL: function (_a, params) { - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/channels/").concat(utils_1.default.encodeString(params.channel)); - }, - patchPayload: function (_, params) { return params.data; }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_, params) { - var _a; - var queryParams = {}; - queryParams.include = ['status', 'type', 'custom']; - if (params === null || params === void 0 ? void 0 : params.include) { - if (((_a = params.include) === null || _a === void 0 ? void 0 : _a.customFields) === false) { - queryParams.include.pop(); - } - } - queryParams.include = queryParams.include.join(','); - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - }); }, -}; -exports.default = endpoint; + }; + SetChannelMetadataRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, serviceResponse]; + }); + }); + }; + Object.defineProperty(SetChannelMetadataRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channel = _a.channel; + return "/v2/objects/".concat(subscribeKey, "/channels/").concat((0, utils_1.encodeString)(channel)); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(SetChannelMetadataRequest.prototype, "queryParameters", { + get: function () { + return { + include: __spreadArray(['status', 'type'], __read((this.parameters.include.customFields ? ['custom'] : [])), false).join(','), + }; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(SetChannelMetadataRequest.prototype, "body", { + get: function () { + return JSON.stringify(this.parameters.data); + }, + enumerable: false, + configurable: true + }); + return SetChannelMetadataRequest; +}(request_1.AbstractRequest)); +exports.SetChannelMetadataRequest = SetChannelMetadataRequest; diff --git a/lib/core/endpoints/objects/member/get.js b/lib/core/endpoints/objects/member/get.js index e24405856..2f9686a90 100644 --- a/lib/core/endpoints/objects/member/get.js +++ b/lib/core/endpoints/objects/member/get.js @@ -1,5 +1,69 @@ "use strict"; -/** */ +/** + * Get Channel Members REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; @@ -20,79 +84,121 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); +exports.GetChannelMembersRequest = void 0; +var PubNubError_1 = require("../../../../models/PubNubError"); +var request_1 = require("../../../components/request"); var operations_1 = __importDefault(require("../../../constants/operations")); -var utils_1 = __importDefault(require("../../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNGetMembersOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { - return 'channel cannot be empty'; - } - }, - getURL: function (_a, params) { - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/channels/").concat(utils_1.default.encodeString(params.channel), "/uuids"); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_modules, params) { - var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p; - var queryParams = {}; - queryParams.include = []; - if (params === null || params === void 0 ? void 0 : params.include) { - if ((_a = params.include) === null || _a === void 0 ? void 0 : _a.statusField) { - queryParams.include.push('status'); - } - if ((_b = params.include) === null || _b === void 0 ? void 0 : _b.customFields) { - queryParams.include.push('custom'); - } - if ((_c = params.include) === null || _c === void 0 ? void 0 : _c.UUIDFields) { - queryParams.include.push('uuid'); - } - if ((_d = params.include) === null || _d === void 0 ? void 0 : _d.customUUIDFields) { - queryParams.include.push('uuid.custom'); - } - if ((_e = params.include) === null || _e === void 0 ? void 0 : _e.UUIDStatusField) { - queryParams.include.push('uuid.status'); - } - if ((_f = params.include) === null || _f === void 0 ? void 0 : _f.UUIDTypeField) { - queryParams.include.push('uuid.type'); - } - } - queryParams.include = queryParams.include.join(','); - if ((_g = params === null || params === void 0 ? void 0 : params.include) === null || _g === void 0 ? void 0 : _g.totalCount) { - queryParams.count = (_h = params.include) === null || _h === void 0 ? void 0 : _h.totalCount; - } - if ((_j = params === null || params === void 0 ? void 0 : params.page) === null || _j === void 0 ? void 0 : _j.next) { - queryParams.start = (_k = params.page) === null || _k === void 0 ? void 0 : _k.next; - } - if ((_l = params === null || params === void 0 ? void 0 : params.page) === null || _l === void 0 ? void 0 : _l.prev) { - queryParams.end = (_m = params.page) === null || _m === void 0 ? void 0 : _m.prev; - } - if (params === null || params === void 0 ? void 0 : params.filter) { - queryParams.filter = params.filter; - } - queryParams.limit = (_o = params === null || params === void 0 ? void 0 : params.limit) !== null && _o !== void 0 ? _o : 100; - if (params === null || params === void 0 ? void 0 : params.sort) { - queryParams.sort = Object.entries((_p = params.sort) !== null && _p !== void 0 ? _p : {}).map(function (_a) { - var _b = __read(_a, 2), key = _b[0], value = _b[1]; - if (value === 'asc' || value === 'desc') { - return "".concat(key, ":").concat(value); - } - return key; +var utils_1 = require("../../../utils"); +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults +/** + * Whether `Member` custom field should be included in response or not. + */ +var INCLUDE_CUSTOM_FIELDS = false; +/** + * Whether member's status field should be included in response or not. + */ +var INCLUDE_STATUS = false; +/** + * Whether total number of members should be included in response or not. + */ +var INCLUDE_TOTAL_COUNT = false; +/** + * Whether `UUID` fields should be included in response or not. + */ +var INCLUDE_UUID_FIELDS = false; +/** + * Whether `UUID` status field should be included in response or not. + */ +var INCLUDE_UUID_STATUS_FIELD = false; +/** + * Whether `UUID` type field should be included in response or not. + */ +var INCLUDE_UUID_TYPE_FIELD = false; +/** + * Whether `UUID` custom field should be included in response or not. + */ +var INCLUDE_UUID_CUSTOM_FIELDS = false; +/** + * Number of objects to return in response. + */ +var LIMIT = 100; +// endregion +/** + * Get Channel Members request. + */ +var GetChannelMembersRequest = /** @class */ (function (_super) { + __extends(GetChannelMembersRequest, _super); + function GetChannelMembersRequest(parameters) { + var _a, _b, _c, _d, _e, _f, _g, _h, _j; + var _k, _l, _m, _o, _p, _q, _r; + var _this = _super.call(this) || this; + _this.parameters = parameters; + // Apply default request parameters. + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_k = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_k.customFields = INCLUDE_CUSTOM_FIELDS); + (_c = (_l = parameters.include).totalCount) !== null && _c !== void 0 ? _c : (_l.totalCount = INCLUDE_TOTAL_COUNT); + (_d = (_m = parameters.include).statusField) !== null && _d !== void 0 ? _d : (_m.statusField = INCLUDE_STATUS); + (_e = (_o = parameters.include).UUIDFields) !== null && _e !== void 0 ? _e : (_o.UUIDFields = INCLUDE_UUID_FIELDS); + (_f = (_p = parameters.include).customUUIDFields) !== null && _f !== void 0 ? _f : (_p.customUUIDFields = INCLUDE_UUID_CUSTOM_FIELDS); + (_g = (_q = parameters.include).UUIDStatusField) !== null && _g !== void 0 ? _g : (_q.UUIDStatusField = INCLUDE_UUID_STATUS_FIELD); + (_h = (_r = parameters.include).UUIDTypeField) !== null && _h !== void 0 ? _h : (_r.UUIDTypeField = INCLUDE_UUID_TYPE_FIELD); + (_j = parameters.limit) !== null && _j !== void 0 ? _j : (parameters.limit = LIMIT); + return _this; + } + GetChannelMembersRequest.prototype.operation = function () { + return operations_1.default.PNSetMembersOperation; + }; + GetChannelMembersRequest.prototype.validate = function () { + if (!this.parameters.channel) + return 'Channel cannot be empty'; + }; + GetChannelMembersRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, serviceResponse]; }); - } - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - totalCount: response.totalCount, - prev: response.prev, - next: response.next, - }); }, -}; -exports.default = endpoint; + }); + }; + Object.defineProperty(GetChannelMembersRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channel = _a.channel; + return "/v2/objects/".concat(subscribeKey, "/channels/").concat((0, utils_1.encodeString)(channel), "/uuids"); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(GetChannelMembersRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, include = _a.include, page = _a.page, filter = _a.filter, sort = _a.sort, limit = _a.limit; + var sorting = Object.entries(sort !== null && sort !== void 0 ? sort : {}).map(function (_a) { + var _b = __read(_a, 2), option = _b[0], order = _b[1]; + return order !== null ? "".concat(option, ":").concat(order) : option; + }); + var includeFlags = []; + if (include.statusField) + includeFlags.push('status'); + if (include.customFields) + includeFlags.push('custom'); + if (include.UUIDFields) + includeFlags.push('uuid'); + if (include.UUIDStatusField) + includeFlags.push('uuid.status'); + if (include.UUIDTypeField) + includeFlags.push('uuid.type'); + if (include.customUUIDFields) + includeFlags.push('uuid.custom'); + return __assign(__assign(__assign(__assign(__assign(__assign({ count: "".concat(include.totalCount) }, (includeFlags.length > 0 ? { include: includeFlags.join(',') } : {})), (filter ? { filter: filter } : {})), ((page === null || page === void 0 ? void 0 : page.next) ? { start: page.next } : {})), ((page === null || page === void 0 ? void 0 : page.prev) ? { end: page.prev } : {})), (limit ? { limit: limit } : {})), (sorting.length ? { sort: sorting } : {})); + }, + enumerable: false, + configurable: true + }); + return GetChannelMembersRequest; +}(request_1.AbstractRequest)); +exports.GetChannelMembersRequest = GetChannelMembersRequest; diff --git a/lib/core/endpoints/objects/member/set.js b/lib/core/endpoints/objects/member/set.js index 2aa211f29..45d167e5b 100644 --- a/lib/core/endpoints/objects/member/set.js +++ b/lib/core/endpoints/objects/member/set.js @@ -1,4 +1,69 @@ "use strict"; +/** + * Set Channel Members REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; @@ -19,98 +84,122 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); +exports.SetChannelMembersRequest = void 0; +var PubNubError_1 = require("../../../../models/PubNubError"); +var transport_request_1 = require("../../../types/transport-request"); +var request_1 = require("../../../components/request"); var operations_1 = __importDefault(require("../../../constants/operations")); -var utils_1 = __importDefault(require("../../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNSetMembersOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channel)) { +var utils_1 = require("../../../utils"); +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults +/** + * Whether `Member` custom field should be included in response or not. + */ +var INCLUDE_CUSTOM_FIELDS = false; +/** + * Whether total number of members should be included in response or not. + */ +var INCLUDE_TOTAL_COUNT = false; +/** + * Whether `UUID` fields should be included in response or not. + */ +var INCLUDE_UUID_FIELDS = false; +/** + * Whether `UUID` custom field should be included in response or not. + */ +var INCLUDE_UUID_CUSTOM_FIELDS = false; +/** + * Number of objects to return in response. + */ +var LIMIT = 100; +// endregion +/** + * Set Channel Members request. + */ +var SetChannelMembersRequest = /** @class */ (function (_super) { + __extends(SetChannelMembersRequest, _super); + function SetChannelMembersRequest(parameters) { + var _a, _b, _c, _d, _e, _f; + var _g, _h, _j, _k; + var _this = _super.call(this, { method: transport_request_1.TransportMethod.PATCH }) || this; + _this.parameters = parameters; + // Apply default request parameters. + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_g = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_g.customFields = INCLUDE_CUSTOM_FIELDS); + (_c = (_h = parameters.include).totalCount) !== null && _c !== void 0 ? _c : (_h.totalCount = INCLUDE_TOTAL_COUNT); + (_d = (_j = parameters.include).UUIDFields) !== null && _d !== void 0 ? _d : (_j.UUIDFields = INCLUDE_UUID_FIELDS); + (_e = (_k = parameters.include).customUUIDFields) !== null && _e !== void 0 ? _e : (_k.customUUIDFields = INCLUDE_UUID_CUSTOM_FIELDS); + (_f = parameters.limit) !== null && _f !== void 0 ? _f : (parameters.limit = LIMIT); + return _this; + } + SetChannelMembersRequest.prototype.operation = function () { + return operations_1.default.PNSetMembersOperation; + }; + SetChannelMembersRequest.prototype.validate = function () { + var _a = this.parameters, channel = _a.channel, uuids = _a.uuids; + if (!channel) return 'Channel cannot be empty'; - } - if (!(params === null || params === void 0 ? void 0 : params.uuids) || (params === null || params === void 0 ? void 0 : params.uuids.length) === 0) { + if (!uuids || uuids.length === 0) return 'UUIDs cannot be empty'; - } - }, - usePatch: function () { return true; }, - patchURL: function (_a, params) { - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/channels/").concat(utils_1.default.encodeString(params.channel), "/uuids"); - }, - patchPayload: function (_, params) { - var _a; - return (_a = { - set: [], - delete: [] - }, - _a[params.type] = params.uuids.map(function (uuid) { - if (typeof uuid === 'string') { - return { - uuid: { - id: uuid, - }, - }; - } - return { - uuid: { id: uuid.id }, - custom: uuid.custom, - status: uuid.status, - }; - }), - _a); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_modules, params) { - var _a, _b, _c, _d, _e, _f, _g, _h, _j; - var queryParams = {}; - queryParams.include = ['uuid.status', 'uuid.type', 'type']; - if (params === null || params === void 0 ? void 0 : params.include) { - if ((_a = params.include) === null || _a === void 0 ? void 0 : _a.customFields) { - queryParams.include.push('custom'); - } - if ((_b = params.include) === null || _b === void 0 ? void 0 : _b.customUUIDFields) { - queryParams.include.push('uuid.custom'); - } - if ((_c = params.include) === null || _c === void 0 ? void 0 : _c.UUIDFields) { - queryParams.include.push('uuid'); - } - } - queryParams.include = queryParams.include.join(','); - if ((_d = params === null || params === void 0 ? void 0 : params.include) === null || _d === void 0 ? void 0 : _d.totalCount) { - queryParams.count = true; - } - if ((_e = params === null || params === void 0 ? void 0 : params.page) === null || _e === void 0 ? void 0 : _e.next) { - queryParams.start = (_f = params.page) === null || _f === void 0 ? void 0 : _f.next; - } - if ((_g = params === null || params === void 0 ? void 0 : params.page) === null || _g === void 0 ? void 0 : _g.prev) { - queryParams.end = (_h = params.page) === null || _h === void 0 ? void 0 : _h.prev; - } - if (params === null || params === void 0 ? void 0 : params.filter) { - queryParams.filter = params.filter; - } - if (params.limit != null) { - queryParams.limit = params.limit; - } - if (params === null || params === void 0 ? void 0 : params.sort) { - queryParams.sort = Object.entries((_j = params.sort) !== null && _j !== void 0 ? _j : {}).map(function (_a) { - var _b = __read(_a, 2), key = _b[0], value = _b[1]; - if (value === 'asc' || value === 'desc') { - return "".concat(key, ":").concat(value); - } - return key; + }; + SetChannelMembersRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, serviceResponse]; }); - } - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - totalCount: response.totalCount, - prev: response.prev, - next: response.next, - }); }, -}; -exports.default = endpoint; + }); + }; + Object.defineProperty(SetChannelMembersRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channel = _a.channel; + return "/v2/objects/".concat(subscribeKey, "/channels/").concat((0, utils_1.encodeString)(channel), "/uuids"); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(SetChannelMembersRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, include = _a.include, page = _a.page, filter = _a.filter, sort = _a.sort, limit = _a.limit; + var sorting = Object.entries(sort !== null && sort !== void 0 ? sort : {}).map(function (_a) { + var _b = __read(_a, 2), option = _b[0], order = _b[1]; + return order !== null ? "".concat(option, ":").concat(order) : option; + }); + var includeFlags = ['uuid.status', 'uuid.type', 'type']; + if (include.customFields) + includeFlags.push('custom'); + if (include.UUIDFields) + includeFlags.push('uuid'); + if (include.customUUIDFields) + includeFlags.push('uuid.custom'); + return __assign(__assign(__assign(__assign(__assign(__assign({ count: "".concat(include.totalCount) }, (includeFlags.length > 0 ? { include: includeFlags.join(',') } : {})), (filter ? { filter: filter } : {})), ((page === null || page === void 0 ? void 0 : page.next) ? { start: page.next } : {})), ((page === null || page === void 0 ? void 0 : page.prev) ? { end: page.prev } : {})), (limit ? { limit: limit } : {})), (sorting.length ? { sort: sorting } : {})); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(SetChannelMembersRequest.prototype, "body", { + get: function () { + var _a; + var _b = this.parameters, uuids = _b.uuids, type = _b.type; + return JSON.stringify((_a = {}, + _a["".concat(type)] = uuids.map(function (uuid) { + if (typeof uuid === 'string') { + return { uuid: { id: uuid } }; + } + else { + return { uuid: { id: uuid.id }, status: uuid.status, custom: uuid.custom }; + } + }), + _a)); + }, + enumerable: false, + configurable: true + }); + return SetChannelMembersRequest; +}(request_1.AbstractRequest)); +exports.SetChannelMembersRequest = SetChannelMembersRequest; diff --git a/lib/core/endpoints/objects/membership/get.js b/lib/core/endpoints/objects/membership/get.js index 0e674260f..68034dd0f 100644 --- a/lib/core/endpoints/objects/membership/get.js +++ b/lib/core/endpoints/objects/membership/get.js @@ -1,4 +1,69 @@ "use strict"; +/** + * Get UUID Memberships REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; @@ -19,78 +84,124 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); +exports.GetUUIDMembershipsRequest = void 0; +var PubNubError_1 = require("../../../../models/PubNubError"); +var request_1 = require("../../../components/request"); var operations_1 = __importDefault(require("../../../constants/operations")); -var utils_1 = __importDefault(require("../../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNGetMembershipsOperation; }, - validateParams: function () { - // No required parameters. - }, - getURL: function (_a, params) { - var _b; - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/uuids/").concat(utils_1.default.encodeString((_b = params === null || params === void 0 ? void 0 : params.uuid) !== null && _b !== void 0 ? _b : config.getUUID()), "/channels"); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_modules, params) { - var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p; - var queryParams = {}; - queryParams.include = []; - if (params === null || params === void 0 ? void 0 : params.include) { - if ((_a = params.include) === null || _a === void 0 ? void 0 : _a.statusField) { - queryParams.include.push('status'); - } - if ((_b = params.include) === null || _b === void 0 ? void 0 : _b.customFields) { - queryParams.include.push('custom'); - } - if ((_c = params.include) === null || _c === void 0 ? void 0 : _c.channelFields) { - queryParams.include.push('channel'); - } - if ((_d = params.include) === null || _d === void 0 ? void 0 : _d.customChannelFields) { - queryParams.include.push('channel.custom'); - } - if ((_e = params.include) === null || _e === void 0 ? void 0 : _e.channelStatusField) { - queryParams.include.push('channel.status'); - } - if ((_f = params.include) === null || _f === void 0 ? void 0 : _f.channelTypeField) { - queryParams.include.push('channel.type'); - } - } - queryParams.include = queryParams.include.join(','); - if ((_g = params === null || params === void 0 ? void 0 : params.include) === null || _g === void 0 ? void 0 : _g.totalCount) { - queryParams.count = (_h = params.include) === null || _h === void 0 ? void 0 : _h.totalCount; - } - if ((_j = params === null || params === void 0 ? void 0 : params.page) === null || _j === void 0 ? void 0 : _j.next) { - queryParams.start = (_k = params.page) === null || _k === void 0 ? void 0 : _k.next; - } - if ((_l = params === null || params === void 0 ? void 0 : params.page) === null || _l === void 0 ? void 0 : _l.prev) { - queryParams.end = (_m = params.page) === null || _m === void 0 ? void 0 : _m.prev; - } - if (params === null || params === void 0 ? void 0 : params.filter) { - queryParams.filter = params.filter; - } - queryParams.limit = (_o = params === null || params === void 0 ? void 0 : params.limit) !== null && _o !== void 0 ? _o : 100; - if (params === null || params === void 0 ? void 0 : params.sort) { - queryParams.sort = Object.entries((_p = params.sort) !== null && _p !== void 0 ? _p : {}).map(function (_a) { - var _b = __read(_a, 2), key = _b[0], value = _b[1]; - if (value === 'asc' || value === 'desc') { - return "".concat(key, ":").concat(value); - } - return key; +var utils_1 = require("../../../utils"); +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults +/** + * Whether `Membership` custom field should be included in response or not. + */ +var INCLUDE_CUSTOM_FIELDS = false; +/** + * Whether membership's status field should be included in response or not. + */ +var INCLUDE_STATUS = false; +/** + * Whether total number of memberships should be included in response or not. + */ +var INCLUDE_TOTAL_COUNT = false; +/** + * Whether `Channel` fields should be included in response or not. + */ +var INCLUDE_CHANNEL_FIELDS = false; +/** + * Whether `Channel` status field should be included in response or not. + */ +var INCLUDE_CHANNEL_STATUS_FIELD = false; +/** + * Whether `Channel` type field should be included in response or not. + */ +var INCLUDE_CHANNEL_TYPE_FIELD = false; +/** + * Whether `Channel` custom field should be included in response or not. + */ +var INCLUDE_CHANNEL_CUSTOM_FIELDS = false; +/** + * Number of objects to return in response. + */ +var LIMIT = 100; +// endregion +/** + * Get UUID Memberships request. + */ +var GetUUIDMembershipsRequest = /** @class */ (function (_super) { + __extends(GetUUIDMembershipsRequest, _super); + function GetUUIDMembershipsRequest(parameters) { + var _a, _b, _c, _d, _e, _f, _g, _h, _j; + var _k, _l, _m, _o, _p, _q, _r; + var _this = _super.call(this) || this; + _this.parameters = parameters; + // Apply default request parameters. + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_k = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_k.customFields = INCLUDE_CUSTOM_FIELDS); + (_c = (_l = parameters.include).totalCount) !== null && _c !== void 0 ? _c : (_l.totalCount = INCLUDE_TOTAL_COUNT); + (_d = (_m = parameters.include).statusField) !== null && _d !== void 0 ? _d : (_m.statusField = INCLUDE_STATUS); + (_e = (_o = parameters.include).channelFields) !== null && _e !== void 0 ? _e : (_o.channelFields = INCLUDE_CHANNEL_FIELDS); + (_f = (_p = parameters.include).customChannelFields) !== null && _f !== void 0 ? _f : (_p.customChannelFields = INCLUDE_CHANNEL_CUSTOM_FIELDS); + (_g = (_q = parameters.include).channelStatusField) !== null && _g !== void 0 ? _g : (_q.channelStatusField = INCLUDE_CHANNEL_STATUS_FIELD); + (_h = (_r = parameters.include).channelTypeField) !== null && _h !== void 0 ? _h : (_r.channelTypeField = INCLUDE_CHANNEL_TYPE_FIELD); + (_j = parameters.limit) !== null && _j !== void 0 ? _j : (parameters.limit = LIMIT); + // Remap for backward compatibility. + if (_this.parameters.userId) + _this.parameters.uuid = _this.parameters.userId; + return _this; + } + GetUUIDMembershipsRequest.prototype.operation = function () { + return operations_1.default.PNGetMembershipsOperation; + }; + GetUUIDMembershipsRequest.prototype.validate = function () { + if (!this.parameters.uuid) + return "'uuid' cannot be empty"; + }; + GetUUIDMembershipsRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, serviceResponse]; }); - } - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - totalCount: response.totalCount, - prev: response.prev, - next: response.next, - }); }, -}; -exports.default = endpoint; + }); + }; + Object.defineProperty(GetUUIDMembershipsRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, uuid = _a.uuid; + return "/v2/objects/".concat(subscribeKey, "/uuids/").concat((0, utils_1.encodeString)(uuid), "/channels"); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(GetUUIDMembershipsRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, include = _a.include, page = _a.page, filter = _a.filter, sort = _a.sort, limit = _a.limit; + var sorting = Object.entries(sort !== null && sort !== void 0 ? sort : {}).map(function (_a) { + var _b = __read(_a, 2), option = _b[0], order = _b[1]; + return order !== null ? "".concat(option, ":").concat(order) : option; + }); + var includeFlags = []; + if (include.statusField) + includeFlags.push('status'); + if (include.customFields) + includeFlags.push('custom'); + if (include.channelFields) + includeFlags.push('channel'); + if (include.channelStatusField) + includeFlags.push('channel.status'); + if (include.channelTypeField) + includeFlags.push('channel.type'); + if (include.customChannelFields) + includeFlags.push('channel.custom'); + return __assign(__assign(__assign(__assign(__assign(__assign({ count: "".concat(include.totalCount) }, (includeFlags.length > 0 ? { include: includeFlags.join(',') } : {})), (filter ? { filter: filter } : {})), ((page === null || page === void 0 ? void 0 : page.next) ? { start: page.next } : {})), ((page === null || page === void 0 ? void 0 : page.prev) ? { end: page.prev } : {})), (limit ? { limit: limit } : {})), (sorting.length ? { sort: sorting } : {})); + }, + enumerable: false, + configurable: true + }); + return GetUUIDMembershipsRequest; +}(request_1.AbstractRequest)); +exports.GetUUIDMembershipsRequest = GetUUIDMembershipsRequest; diff --git a/lib/core/endpoints/objects/membership/set.js b/lib/core/endpoints/objects/membership/set.js index 13ea36ef5..864fb4e34 100644 --- a/lib/core/endpoints/objects/membership/set.js +++ b/lib/core/endpoints/objects/membership/set.js @@ -1,5 +1,69 @@ "use strict"; -/** */ +/** + * Set UUID Memberships REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; @@ -20,96 +84,125 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); +exports.SetUUIDMembershipsRequest = void 0; +var PubNubError_1 = require("../../../../models/PubNubError"); +var transport_request_1 = require("../../../types/transport-request"); +var request_1 = require("../../../components/request"); var operations_1 = __importDefault(require("../../../constants/operations")); -var utils_1 = __importDefault(require("../../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNSetMembershipsOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channels) || (params === null || params === void 0 ? void 0 : params.channels.length) === 0) { +var utils_1 = require("../../../utils"); +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults +/** + * Whether `Membership` custom field should be included in response or not. + */ +var INCLUDE_CUSTOM_FIELDS = false; +/** + * Whether total number of memberships should be included in response or not. + */ +var INCLUDE_TOTAL_COUNT = false; +/** + * Whether `Channel` fields should be included in response or not. + */ +var INCLUDE_CHANNEL_FIELDS = false; +/** + * Whether `Channel` custom field should be included in response or not. + */ +var INCLUDE_CHANNEL_CUSTOM_FIELDS = false; +/** + * Number of objects to return in response. + */ +var LIMIT = 100; +// endregion +/** + * Set UUID Memberships request. + */ +var SetUUIDMembershipsRequest = /** @class */ (function (_super) { + __extends(SetUUIDMembershipsRequest, _super); + function SetUUIDMembershipsRequest(parameters) { + var _a, _b, _c, _d, _e, _f; + var _g, _h, _j, _k; + var _this = _super.call(this, { method: transport_request_1.TransportMethod.PATCH }) || this; + _this.parameters = parameters; + // Apply default request parameters. + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_g = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_g.customFields = INCLUDE_CUSTOM_FIELDS); + (_c = (_h = parameters.include).totalCount) !== null && _c !== void 0 ? _c : (_h.totalCount = INCLUDE_TOTAL_COUNT); + (_d = (_j = parameters.include).channelFields) !== null && _d !== void 0 ? _d : (_j.channelFields = INCLUDE_CHANNEL_FIELDS); + (_e = (_k = parameters.include).customChannelFields) !== null && _e !== void 0 ? _e : (_k.customChannelFields = INCLUDE_CHANNEL_CUSTOM_FIELDS); + (_f = parameters.limit) !== null && _f !== void 0 ? _f : (parameters.limit = LIMIT); + // Remap for backward compatibility. + if (_this.parameters.userId) + _this.parameters.uuid = _this.parameters.userId; + return _this; + } + SetUUIDMembershipsRequest.prototype.operation = function () { + return operations_1.default.PNSetMembershipsOperation; + }; + SetUUIDMembershipsRequest.prototype.validate = function () { + var _a = this.parameters, uuid = _a.uuid, channels = _a.channels; + if (!uuid) + return "'uuid' cannot be empty"; + if (!channels || channels.length === 0) return 'Channels cannot be empty'; - } - }, - usePatch: function () { return true; }, - patchURL: function (_a, params) { - var _b; - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/uuids/").concat(utils_1.default.encodeString((_b = params.uuid) !== null && _b !== void 0 ? _b : config.getUUID()), "/channels"); - }, - patchPayload: function (_, params) { - var _a; - return (_a = { - set: [], - delete: [] - }, - _a[params.type] = params.channels.map(function (channel) { - if (typeof channel === 'string') { - return { - channel: { - id: channel, - }, - }; - } - return { - channel: { id: channel.id }, - custom: channel.custom, - status: channel.status, - }; - }), - _a); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_modules, params) { - var _a, _b, _c, _d, _e, _f, _g, _h, _j; - var queryParams = {}; - queryParams.include = ['channel.status', 'channel.type', 'status']; - if (params === null || params === void 0 ? void 0 : params.include) { - if ((_a = params.include) === null || _a === void 0 ? void 0 : _a.customFields) { - queryParams.include.push('custom'); - } - if ((_b = params.include) === null || _b === void 0 ? void 0 : _b.customChannelFields) { - queryParams.include.push('channel.custom'); - } - if ((_c = params.include) === null || _c === void 0 ? void 0 : _c.channelFields) { - queryParams.include.push('channel'); - } - } - queryParams.include = queryParams.include.join(','); - if ((_d = params === null || params === void 0 ? void 0 : params.include) === null || _d === void 0 ? void 0 : _d.totalCount) { - queryParams.count = true; - } - if ((_e = params === null || params === void 0 ? void 0 : params.page) === null || _e === void 0 ? void 0 : _e.next) { - queryParams.start = (_f = params.page) === null || _f === void 0 ? void 0 : _f.next; - } - if ((_g = params === null || params === void 0 ? void 0 : params.page) === null || _g === void 0 ? void 0 : _g.prev) { - queryParams.end = (_h = params.page) === null || _h === void 0 ? void 0 : _h.prev; - } - if (params === null || params === void 0 ? void 0 : params.filter) { - queryParams.filter = params.filter; - } - if (params.limit != null) { - queryParams.limit = params.limit; - } - if (params === null || params === void 0 ? void 0 : params.sort) { - queryParams.sort = Object.entries((_j = params.sort) !== null && _j !== void 0 ? _j : {}).map(function (_a) { - var _b = __read(_a, 2), key = _b[0], value = _b[1]; - if (value === 'asc' || value === 'desc') { - return "".concat(key, ":").concat(value); - } - return key; + }; + SetUUIDMembershipsRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, serviceResponse]; }); - } - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - totalCount: response.totalCount, - prev: response.prev, - next: response.next, - }); }, -}; -exports.default = endpoint; + }); + }; + Object.defineProperty(SetUUIDMembershipsRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, uuid = _a.uuid; + return "/v2/objects/".concat(subscribeKey, "/uuids/").concat((0, utils_1.encodeString)(uuid), "/channels"); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(SetUUIDMembershipsRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, include = _a.include, page = _a.page, filter = _a.filter, sort = _a.sort, limit = _a.limit; + var sorting = Object.entries(sort !== null && sort !== void 0 ? sort : {}).map(function (_a) { + var _b = __read(_a, 2), option = _b[0], order = _b[1]; + return order !== null ? "".concat(option, ":").concat(order) : option; + }); + var includeFlags = ['channel.status', 'channel.type', 'status']; + if (include.customFields) + includeFlags.push('custom'); + if (include.channelFields) + includeFlags.push('channel'); + if (include.customChannelFields) + includeFlags.push('channel.custom'); + return __assign(__assign(__assign(__assign(__assign(__assign({ count: "".concat(include.totalCount) }, (includeFlags.length > 0 ? { include: includeFlags.join(',') } : {})), (filter ? { filter: filter } : {})), ((page === null || page === void 0 ? void 0 : page.next) ? { start: page.next } : {})), ((page === null || page === void 0 ? void 0 : page.prev) ? { end: page.prev } : {})), (limit ? { limit: limit } : {})), (sorting.length ? { sort: sorting } : {})); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(SetUUIDMembershipsRequest.prototype, "body", { + get: function () { + var _a; + var _b = this.parameters, channels = _b.channels, type = _b.type; + return JSON.stringify((_a = {}, + _a["".concat(type)] = channels.map(function (channel) { + if (typeof channel === 'string') { + return { channel: { id: channel } }; + } + else { + return { channel: { id: channel.id }, status: channel.status, custom: channel.custom }; + } + }), + _a)); + }, + enumerable: false, + configurable: true + }); + return SetUUIDMembershipsRequest; +}(request_1.AbstractRequest)); +exports.SetUUIDMembershipsRequest = SetUUIDMembershipsRequest; diff --git a/lib/core/endpoints/objects/uuid/get.js b/lib/core/endpoints/objects/uuid/get.js index 36e1293d6..b0bbde29f 100644 --- a/lib/core/endpoints/objects/uuid/get.js +++ b/lib/core/endpoints/objects/uuid/get.js @@ -1,43 +1,156 @@ "use strict"; -/** */ +/** + * Get UUID Metadata REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +var __read = (this && this.__read) || function (o, n) { + var m = typeof Symbol === "function" && o[Symbol.iterator]; + if (!m) return o; + var i = m.call(o), r, ar = [], e; + try { + while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); + } + catch (error) { e = { error: error }; } + finally { + try { + if (r && !r.done && (m = i["return"])) m.call(i); + } + finally { if (e) throw e.error; } + } + return ar; +}; +var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { + if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { + if (ar || !(i in from)) { + if (!ar) ar = Array.prototype.slice.call(from, 0, i); + ar[i] = from[i]; + } + } + return to.concat(ar || Array.prototype.slice.call(from)); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); +exports.GetUUIDMetadataRequest = void 0; +var PubNubError_1 = require("../../../../models/PubNubError"); +var request_1 = require("../../../components/request"); var operations_1 = __importDefault(require("../../../constants/operations")); -var utils_1 = __importDefault(require("../../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNGetUUIDMetadataOperation; }, - validateParams: function () { - // No required parameters. - }, - getURL: function (_a, params) { - var _b; - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/uuids/").concat(utils_1.default.encodeString((_b = params === null || params === void 0 ? void 0 : params.uuid) !== null && _b !== void 0 ? _b : config.getUUID())); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_a, params) { - var _b, _c; - var config = _a.config; - var queryParams = {}; - queryParams.uuid = (_b = params === null || params === void 0 ? void 0 : params.uuid) !== null && _b !== void 0 ? _b : config.getUUID(); - queryParams.include = ['status', 'type', 'custom']; - if (params === null || params === void 0 ? void 0 : params.include) { - if (((_c = params.include) === null || _c === void 0 ? void 0 : _c.customFields) === false) { - queryParams.include.pop(); - } - } - queryParams.include = queryParams.include.join(','); - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - }); }, -}; -exports.default = endpoint; +var utils_1 = require("../../../utils"); +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults +/** + * Whether UUID custom field should be included by default or not. + */ +var INCLUDE_CUSTOM_FIELDS = true; +// endregion +/** + * Get UUID Metadata request. + */ +var GetUUIDMetadataRequest = /** @class */ (function (_super) { + __extends(GetUUIDMetadataRequest, _super); + function GetUUIDMetadataRequest(parameters) { + var _a, _b; + var _c; + var _this = _super.call(this) || this; + _this.parameters = parameters; + // Apply default request parameters. + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_c = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_c.customFields = INCLUDE_CUSTOM_FIELDS); + // Remap for backward compatibility. + if (_this.parameters.userId) + _this.parameters.uuid = _this.parameters.userId; + return _this; + } + GetUUIDMetadataRequest.prototype.operation = function () { + return operations_1.default.PNGetUUIDMetadataOperation; + }; + GetUUIDMetadataRequest.prototype.validate = function () { + if (!this.parameters.uuid) + return "'uuid' cannot be empty"; + }; + GetUUIDMetadataRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, serviceResponse]; + }); + }); + }; + Object.defineProperty(GetUUIDMetadataRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, uuid = _a.uuid; + return "/v2/objects/".concat(subscribeKey, "/uuids/").concat((0, utils_1.encodeString)(uuid)); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(GetUUIDMetadataRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, uuid = _a.uuid, include = _a.include; + return { + uuid: uuid, + include: __spreadArray(['status', 'type'], __read((this.parameters.include.customFields ? ['custom'] : [])), false).join(','), + }; + }, + enumerable: false, + configurable: true + }); + return GetUUIDMetadataRequest; +}(request_1.AbstractRequest)); +exports.GetUUIDMetadataRequest = GetUUIDMetadataRequest; diff --git a/lib/core/endpoints/objects/uuid/get_all.js b/lib/core/endpoints/objects/uuid/get_all.js index f82c8e893..5cb5ae31b 100644 --- a/lib/core/endpoints/objects/uuid/get_all.js +++ b/lib/core/endpoints/objects/uuid/get_all.js @@ -1,4 +1,69 @@ "use strict"; +/** + * Get All UUID Metadata REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; @@ -15,65 +80,87 @@ var __read = (this && this.__read) || function (o, n) { } return ar; }; +var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { + if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { + if (ar || !(i in from)) { + if (!ar) ar = Array.prototype.slice.call(from, 0, i); + ar[i] = from[i]; + } + } + return to.concat(ar || Array.prototype.slice.call(from)); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); +exports.GetAllUUIDMetadataRequest = void 0; +var PubNubError_1 = require("../../../../models/PubNubError"); +var request_1 = require("../../../components/request"); var operations_1 = __importDefault(require("../../../constants/operations")); -var endpoint = { - getOperation: function () { return operations_1.default.PNGetAllUUIDMetadataOperation; }, - validateParams: function () { - // No required parameters. - }, - getURL: function (_a) { - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/uuids"); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_modules, params) { - var _a, _b, _c, _d, _e, _f, _g, _h, _j; - var queryParams = {}; - queryParams.include = ['status', 'type']; - if (params === null || params === void 0 ? void 0 : params.include) { - if ((_a = params.include) === null || _a === void 0 ? void 0 : _a.customFields) { - queryParams.include.push('custom'); - } - } - queryParams.include = queryParams.include.join(','); - if ((_b = params === null || params === void 0 ? void 0 : params.include) === null || _b === void 0 ? void 0 : _b.totalCount) { - queryParams.count = (_c = params.include) === null || _c === void 0 ? void 0 : _c.totalCount; - } - if ((_d = params === null || params === void 0 ? void 0 : params.page) === null || _d === void 0 ? void 0 : _d.next) { - queryParams.start = (_e = params.page) === null || _e === void 0 ? void 0 : _e.next; - } - if ((_f = params === null || params === void 0 ? void 0 : params.page) === null || _f === void 0 ? void 0 : _f.prev) { - queryParams.end = (_g = params.page) === null || _g === void 0 ? void 0 : _g.prev; - } - if (params === null || params === void 0 ? void 0 : params.filter) { - queryParams.filter = params.filter; - } - queryParams.limit = (_h = params === null || params === void 0 ? void 0 : params.limit) !== null && _h !== void 0 ? _h : 100; - if (params === null || params === void 0 ? void 0 : params.sort) { - queryParams.sort = Object.entries((_j = params.sort) !== null && _j !== void 0 ? _j : {}).map(function (_a) { - var _b = __read(_a, 2), key = _b[0], value = _b[1]; - if (value === 'asc' || value === 'desc') { - return "".concat(key, ":").concat(value); - } - return key; +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults +/** + * Whether `Channel` custom field should be included by default or not. + */ +var INCLUDE_CUSTOM_FIELDS = false; +/** + * Whether to fetch total count or not. + */ +var INCLUDE_TOTAL_COUNT = false; +/** + * Number of objects to return in response. + */ +var LIMIT = 100; +// endregion +var GetAllUUIDMetadataRequest = /** @class */ (function (_super) { + __extends(GetAllUUIDMetadataRequest, _super); + function GetAllUUIDMetadataRequest(parameters) { + var _a, _b, _c, _d; + var _e, _f; + var _this = _super.call(this) || this; + _this.parameters = parameters; + // Apply default request parameters. + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_e = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_e.customFields = INCLUDE_CUSTOM_FIELDS); + (_c = (_f = parameters.include).totalCount) !== null && _c !== void 0 ? _c : (_f.totalCount = INCLUDE_TOTAL_COUNT); + (_d = parameters.limit) !== null && _d !== void 0 ? _d : (parameters.limit = LIMIT); + return _this; + } + GetAllUUIDMetadataRequest.prototype.operation = function () { + return operations_1.default.PNGetAllUUIDMetadataOperation; + }; + GetAllUUIDMetadataRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, serviceResponse]; }); - } - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - totalCount: response.totalCount, - next: response.next, - prev: response.prev, - }); }, -}; -exports.default = endpoint; + }); + }; + Object.defineProperty(GetAllUUIDMetadataRequest.prototype, "path", { + get: function () { + return "/v2/objects/".concat(this.parameters.keySet.subscribeKey, "/uuids"); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(GetAllUUIDMetadataRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, include = _a.include, page = _a.page, filter = _a.filter, sort = _a.sort, limit = _a.limit; + var sorting = Object.entries(sort !== null && sort !== void 0 ? sort : {}).map(function (_a) { + var _b = __read(_a, 2), option = _b[0], order = _b[1]; + return order !== null ? "".concat(option, ":").concat(order) : option; + }); + return __assign(__assign(__assign(__assign(__assign({ include: __spreadArray(['status', 'type'], __read((include.customFields ? ['custom'] : [])), false).join(','), count: "".concat(include.totalCount) }, (filter ? { filter: filter } : {})), ((page === null || page === void 0 ? void 0 : page.next) ? { start: page.next } : {})), ((page === null || page === void 0 ? void 0 : page.prev) ? { end: page.prev } : {})), (limit ? { limit: limit } : {})), (sorting.length ? { sort: sorting } : {})); + }, + enumerable: false, + configurable: true + }); + return GetAllUUIDMetadataRequest; +}(request_1.AbstractRequest)); +exports.GetAllUUIDMetadataRequest = GetAllUUIDMetadataRequest; diff --git a/lib/core/endpoints/objects/uuid/remove.js b/lib/core/endpoints/objects/uuid/remove.js index 5ad9a0599..4b60b689a 100644 --- a/lib/core/endpoints/objects/uuid/remove.js +++ b/lib/core/endpoints/objects/uuid/remove.js @@ -1,37 +1,108 @@ "use strict"; -/** */ +/** + * Remove UUID Metadata REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); +exports.RemoveUUIDMetadataRequest = void 0; +var PubNubError_1 = require("../../../../models/PubNubError"); +var transport_request_1 = require("../../../types/transport-request"); +var request_1 = require("../../../components/request"); var operations_1 = __importDefault(require("../../../constants/operations")); -var utils_1 = __importDefault(require("../../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNRemoveUUIDMetadataOperation; }, - validateParams: function () { - // No required parameters. - }, - getURL: function (_a, params) { - var _b; - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/uuids/").concat(utils_1.default.encodeString((_b = params === null || params === void 0 ? void 0 : params.uuid) !== null && _b !== void 0 ? _b : config.getUUID())); - }, - useDelete: function () { return true; }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_a, params) { - var _b; - var config = _a.config; - return ({ - uuid: (_b = params === null || params === void 0 ? void 0 : params.uuid) !== null && _b !== void 0 ? _b : config.getUUID(), +var utils_1 = require("../../../utils"); +// endregion +/** + * Remove UUID Metadata request. + */ +var RemoveUUIDMetadataRequest = /** @class */ (function (_super) { + __extends(RemoveUUIDMetadataRequest, _super); + function RemoveUUIDMetadataRequest(parameters) { + var _this = _super.call(this, { method: transport_request_1.TransportMethod.DELETE }) || this; + _this.parameters = parameters; + // Remap for backward compatibility. + if (_this.parameters.userId) + _this.parameters.uuid = _this.parameters.userId; + return _this; + } + RemoveUUIDMetadataRequest.prototype.operation = function () { + return operations_1.default.PNRemoveUUIDMetadataOperation; + }; + RemoveUUIDMetadataRequest.prototype.validate = function () { + if (!this.parameters.uuid) + return "'uuid' cannot be empty"; + }; + RemoveUUIDMetadataRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, serviceResponse]; + }); }); - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - }); }, -}; -exports.default = endpoint; + }; + Object.defineProperty(RemoveUUIDMetadataRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, uuid = _a.uuid; + return "/v2/objects/".concat(subscribeKey, "/uuids/").concat((0, utils_1.encodeString)(uuid)); + }, + enumerable: false, + configurable: true + }); + return RemoveUUIDMetadataRequest; +}(request_1.AbstractRequest)); +exports.RemoveUUIDMetadataRequest = RemoveUUIDMetadataRequest; diff --git a/lib/core/endpoints/objects/uuid/set.js b/lib/core/endpoints/objects/uuid/set.js index 0f6f4e6e8..80ad8f95d 100644 --- a/lib/core/endpoints/objects/uuid/set.js +++ b/lib/core/endpoints/objects/uuid/set.js @@ -1,47 +1,164 @@ "use strict"; -/** */ +/** + * Set UUID Metadata REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +var __read = (this && this.__read) || function (o, n) { + var m = typeof Symbol === "function" && o[Symbol.iterator]; + if (!m) return o; + var i = m.call(o), r, ar = [], e; + try { + while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); + } + catch (error) { e = { error: error }; } + finally { + try { + if (r && !r.done && (m = i["return"])) m.call(i); + } + finally { if (e) throw e.error; } + } + return ar; +}; +var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { + if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { + if (ar || !(i in from)) { + if (!ar) ar = Array.prototype.slice.call(from, 0, i); + ar[i] = from[i]; + } + } + return to.concat(ar || Array.prototype.slice.call(from)); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); +exports.SetUUIDMetadataRequest = void 0; +var PubNubError_1 = require("../../../../models/PubNubError"); +var transport_request_1 = require("../../../types/transport-request"); +var request_1 = require("../../../components/request"); var operations_1 = __importDefault(require("../../../constants/operations")); -var utils_1 = __importDefault(require("../../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNSetUUIDMetadataOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.data)) { +var utils_1 = require("../../../utils"); +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults +/** + * Whether `Channel` custom field should be included by default or not. + */ +var INCLUDE_CUSTOM_FIELDS = true; +// endregion +/** + * Set UUID Metadata request. + */ +var SetUUIDMetadataRequest = /** @class */ (function (_super) { + __extends(SetUUIDMetadataRequest, _super); + function SetUUIDMetadataRequest(parameters) { + var _a, _b; + var _c; + var _this = _super.call(this, { method: transport_request_1.TransportMethod.PATCH }) || this; + _this.parameters = parameters; + // Apply default request parameters. + (_a = parameters.include) !== null && _a !== void 0 ? _a : (parameters.include = {}); + (_b = (_c = parameters.include).customFields) !== null && _b !== void 0 ? _b : (_c.customFields = INCLUDE_CUSTOM_FIELDS); + // Remap for backward compatibility. + if (_this.parameters.userId) + _this.parameters.uuid = _this.parameters.userId; + return _this; + } + SetUUIDMetadataRequest.prototype.operation = function () { + return operations_1.default.PNSetUUIDMetadataOperation; + }; + SetUUIDMetadataRequest.prototype.validate = function () { + if (!this.parameters.uuid) + return "'uuid' cannot be empty"; + if (!this.parameters.data) return 'Data cannot be empty'; - } - }, - usePatch: function () { return true; }, - patchURL: function (_a, params) { - var _b; - var config = _a.config; - return "/v2/objects/".concat(config.subscribeKey, "/uuids/").concat(utils_1.default.encodeString((_b = params.uuid) !== null && _b !== void 0 ? _b : config.getUUID())); - }, - patchPayload: function (_, params) { return params.data; }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_a, params) { - var _b, _c; - var config = _a.config; - var queryParams = {}; - queryParams.uuid = (_b = params === null || params === void 0 ? void 0 : params.uuid) !== null && _b !== void 0 ? _b : config.getUUID(); - queryParams.include = ['status', 'type', 'custom']; - if (params === null || params === void 0 ? void 0 : params.include) { - if (((_c = params.include) === null || _c === void 0 ? void 0 : _c.customFields) === false) { - queryParams.include.pop(); - } - } - queryParams.include = queryParams.include.join(','); - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - }); }, -}; -exports.default = endpoint; + }; + SetUUIDMetadataRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, serviceResponse]; + }); + }); + }; + Object.defineProperty(SetUUIDMetadataRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, uuid = _a.uuid; + return "/v2/objects/".concat(subscribeKey, "/uuids/").concat((0, utils_1.encodeString)(uuid)); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(SetUUIDMetadataRequest.prototype, "queryParameters", { + get: function () { + return { + include: __spreadArray(['status', 'type'], __read((this.parameters.include.customFields ? ['custom'] : [])), false).join(','), + }; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(SetUUIDMetadataRequest.prototype, "body", { + get: function () { + return JSON.stringify(this.parameters.data); + }, + enumerable: false, + configurable: true + }); + return SetUUIDMetadataRequest; +}(request_1.AbstractRequest)); +exports.SetUUIDMetadataRequest = SetUUIDMetadataRequest; diff --git a/lib/core/endpoints/presence/get_state.js b/lib/core/endpoints/presence/get_state.js index 030ad9f8d..034fb5084 100644 --- a/lib/core/endpoints/presence/get_state.js +++ b/lib/core/endpoints/presence/get_state.js @@ -1,56 +1,129 @@ "use strict"; -/* */ +/** + * Get Presence State REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; +exports.GetPresenceStateRequest = void 0; +var PubNubError_1 = require("../../../models/PubNubError"); +var request_1 = require("../../components/request"); var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -function getOperation() { - return operations_1.default.PNGetStateOperation; -} -exports.getOperation = getOperation; -function validateParams(modules) { - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var config = modules.config; - var _a = incomingParams.uuid, uuid = _a === void 0 ? config.UUID : _a, _b = incomingParams.channels, channels = _b === void 0 ? [] : _b; - var stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return "/v2/presence/sub-key/".concat(config.subscribeKey, "/channel/").concat(utils_1.default.encodeString(stringifiedChannels), "/uuid/").concat(uuid); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams(modules, incomingParams) { - var _a = incomingParams.channelGroups, channelGroups = _a === void 0 ? [] : _a; - var params = {}; - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); - } - return params; -} -exports.prepareParams = prepareParams; -function handleResponse(modules, serverResponse, incomingParams) { - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a, _b = incomingParams.channelGroups, channelGroups = _b === void 0 ? [] : _b; - var channelsResponse = {}; - if (channels.length === 1 && channelGroups.length === 0) { - channelsResponse[channels[0]] = serverResponse.payload; - } - else { - channelsResponse = serverResponse.payload; +var utils_1 = require("../../utils"); +// endregion +/** + * Get `uuid` presence state request. + */ +var GetPresenceStateRequest = /** @class */ (function (_super) { + __extends(GetPresenceStateRequest, _super); + function GetPresenceStateRequest(parameters) { + var _a, _b; + var _c, _d; + var _this = _super.call(this) || this; + _this.parameters = parameters; + // Apply defaults. + (_a = (_c = _this.parameters).channels) !== null && _a !== void 0 ? _a : (_c.channels = []); + (_b = (_d = _this.parameters).channelGroups) !== null && _b !== void 0 ? _b : (_d.channelGroups = []); + return _this; } - return { channels: channelsResponse }; -} -exports.handleResponse = handleResponse; + GetPresenceStateRequest.prototype.operation = function () { + return operations_1.default.PNGetStateOperation; + }; + GetPresenceStateRequest.prototype.validate = function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channels = _a.channels, channelGroups = _a.channelGroups; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (channels && channels.length > 0 && channelGroups && channelGroups.length > 0) + return 'Only `channels` or `channelGroups` can be specified at once.'; + }; + GetPresenceStateRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse, _a, channels, channelGroups, state; + return __generator(this, function (_b) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + _a = this.parameters, channels = _a.channels, channelGroups = _a.channelGroups; + state = { channels: {} }; + if ((channels === null || channels === void 0 ? void 0 : channels.length) === 1 && (channelGroups === null || channelGroups === void 0 ? void 0 : channelGroups.length) === 0) + state.channels[channels[0]] = serviceResponse.payload; + else + state.channels = serviceResponse.payload; + return [2 /*return*/, state]; + }); + }); + }; + Object.defineProperty(GetPresenceStateRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, uuid = _a.uuid, channels = _a.channels; + var stringifiedChannels = channels && channels.length > 0 ? (0, utils_1.encodeString)(channels.join(',')) : ','; + return "/v2/presence/sub-key/".concat(subscribeKey, "/channel/").concat(stringifiedChannels, "/uuid/").concat(uuid); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(GetPresenceStateRequest.prototype, "queryParameters", { + get: function () { + var channelGroups = this.parameters.channelGroups; + if (!channelGroups || channelGroups.length === 0) + return {}; + return { 'channel-group': channelGroups.join(',') }; + }, + enumerable: false, + configurable: true + }); + return GetPresenceStateRequest; +}(request_1.AbstractRequest)); +exports.GetPresenceStateRequest = GetPresenceStateRequest; diff --git a/lib/core/endpoints/presence/heartbeat.js b/lib/core/endpoints/presence/heartbeat.js index 137bfad1a..a5fb4971d 100644 --- a/lib/core/endpoints/presence/heartbeat.js +++ b/lib/core/endpoints/presence/heartbeat.js @@ -1,53 +1,118 @@ "use strict"; -/* */ +/** + * Announce heartbeat REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.getRequestTimeout = exports.isAuthSupported = exports.getURL = exports.validateParams = exports.getOperation = void 0; +exports.HeartbeatRequest = void 0; +var PubNubError_1 = require("../../../models/PubNubError"); +var request_1 = require("../../components/request"); var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -function getOperation() { - return operations_1.default.PNHeartbeatOperation; -} -exports.getOperation = getOperation; -function validateParams(modules) { - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var config = modules.config; - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a; - var stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return "/v2/presence/sub-key/".concat(config.subscribeKey, "/channel/").concat(utils_1.default.encodeString(stringifiedChannels), "/heartbeat"); -} -exports.getURL = getURL; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function prepareParams(modules, incomingParams) { - var _a = incomingParams.channelGroups, channelGroups = _a === void 0 ? [] : _a, state = incomingParams.state; - var config = modules.config; - var params = {}; - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); - } - if (state) { - params.state = JSON.stringify(state); +var utils_1 = require("../../utils"); +// endregion +var HeartbeatRequest = /** @class */ (function (_super) { + __extends(HeartbeatRequest, _super); + function HeartbeatRequest(parameters) { + var _this = _super.call(this) || this; + _this.parameters = parameters; + return _this; } - params.heartbeat = config.getPresenceTimeout(); - return params; -} -exports.prepareParams = prepareParams; -function handleResponse() { - return {}; -} -exports.handleResponse = handleResponse; + HeartbeatRequest.prototype.operation = function () { + return operations_1.default.PNHeartbeatOperation; + }; + HeartbeatRequest.prototype.validate = function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channels = _a.channels, channelGroups = _a.channelGroups; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if ((channels === null || channels === void 0 ? void 0 : channels.length) === 0 && (channelGroups === null || channelGroups === void 0 ? void 0 : channelGroups.length) === 0) + return 'Please provide a list of channels and/or channel-groups'; + }; + HeartbeatRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, {}]; + }); + }); + }; + Object.defineProperty(HeartbeatRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channels = _a.channels; + var stringifiedChannels = channels && channels.length > 0 ? (0, utils_1.encodeString)(channels.join(',')) : ','; + return "/v2/presence/sub-key/".concat(subscribeKey, "/channel/").concat(stringifiedChannels, "/heartbeat"); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(HeartbeatRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, channelGroups = _a.channelGroups, state = _a.state, heartbeat = _a.heartbeat; + var query = { heartbeat: "".concat(heartbeat) }; + if (channelGroups && channelGroups.length === 0) + query['channel-group'] = channelGroups.join(','); + if (state) + query.state = JSON.stringify(state); + return query; + }, + enumerable: false, + configurable: true + }); + return HeartbeatRequest; +}(request_1.AbstractRequest)); +exports.HeartbeatRequest = HeartbeatRequest; diff --git a/lib/core/endpoints/presence/here_now.js b/lib/core/endpoints/presence/here_now.js index 87cbd46e4..18fc244d6 100644 --- a/lib/core/endpoints/presence/here_now.js +++ b/lib/core/endpoints/presence/here_now.js @@ -1,4 +1,22 @@ "use strict"; +/** + * Channels / channel groups presence REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { @@ -10,131 +28,144 @@ var __assign = (this && this.__assign) || function () { }; return __assign.apply(this, arguments); }; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleError = exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; -/* */ +exports.HereNowRequest = void 0; +var PubNubError_1 = require("../../../models/PubNubError"); +var request_1 = require("../../components/request"); var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -function getOperation() { - return operations_1.default.PNHereNowOperation; -} -exports.getOperation = getOperation; -function validateParams(modules) { - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var config = modules.config; - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a, _b = incomingParams.channelGroups, channelGroups = _b === void 0 ? [] : _b; - var baseURL = "/v2/presence/sub-key/".concat(config.subscribeKey); - if (channels.length > 0 || channelGroups.length > 0) { - var stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - baseURL += "/channel/".concat(utils_1.default.encodeString(stringifiedChannels)); - } - return baseURL; -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams(modules, incomingParams) { - var _a = incomingParams.channelGroups, channelGroups = _a === void 0 ? [] : _a, _b = incomingParams.includeUUIDs, includeUUIDs = _b === void 0 ? true : _b, _c = incomingParams.includeState, includeState = _c === void 0 ? false : _c, _d = incomingParams.queryParameters, queryParameters = _d === void 0 ? {} : _d; - var params = {}; - if (!includeUUIDs) - params.disable_uuids = 1; - if (includeState) - params.state = 1; - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); +var utils_1 = require("../../utils"); +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults +/** + * Whether `uuid` should be included in response or not. + */ +var INCLUDE_UUID = true; +/** + * Whether state associated with `uuid` should be included in response or not. + */ +var INCLUDE_STATE = false; +// endregion +var HereNowRequest = /** @class */ (function (_super) { + __extends(HereNowRequest, _super); + function HereNowRequest(parameters) { + var _a, _b, _c; + var _d, _e, _f; + var _this = _super.call(this) || this; + _this.parameters = parameters; + // Apply defaults. + (_a = (_d = _this.parameters).queryParameters) !== null && _a !== void 0 ? _a : (_d.queryParameters = {}); + (_b = (_e = _this.parameters).includeUUIDs) !== null && _b !== void 0 ? _b : (_e.includeUUIDs = INCLUDE_UUID); + (_c = (_f = _this.parameters).includeState) !== null && _c !== void 0 ? _c : (_f.includeState = INCLUDE_STATE); + return _this; } - params = __assign(__assign({}, params), queryParameters); - return params; -} -exports.prepareParams = prepareParams; -function handleResponse(modules, serverResponse, incomingParams) { - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a, _b = incomingParams.channelGroups, channelGroups = _b === void 0 ? [] : _b, _c = incomingParams.includeUUIDs, includeUUIDs = _c === void 0 ? true : _c, _d = incomingParams.includeState, includeState = _d === void 0 ? false : _d; - var prepareSingularChannel = function () { - var response = {}; - var occupantsList = []; - response.totalChannels = 1; - response.totalOccupancy = serverResponse.occupancy; - response.channels = {}; - response.channels[channels[0]] = { - occupants: occupantsList, - name: channels[0], - occupancy: serverResponse.occupancy, - }; - // We have had issues in the past with server returning responses - // that contain no uuids array - if (includeUUIDs && serverResponse.uuids) { - serverResponse.uuids.forEach(function (uuidEntry) { - if (includeState) { - occupantsList.push({ state: uuidEntry.state, uuid: uuidEntry.uuid }); - } - else { - occupantsList.push({ state: null, uuid: uuidEntry }); - } - }); - } - return response; + HereNowRequest.prototype.operation = function () { + return operations_1.default.PNHereNowOperation; + }; + HereNowRequest.prototype.validate = function () { + if (!this.parameters.keySet.subscribeKey) + return 'Missing Subscribe Key'; }; - var prepareMultipleChannel = function () { - var response = {}; - response.totalChannels = serverResponse.payload.total_channels; - response.totalOccupancy = serverResponse.payload.total_occupancy; - response.channels = {}; - Object.keys(serverResponse.payload.channels).forEach(function (channelName) { - var channelEntry = serverResponse.payload.channels[channelName]; - var occupantsList = []; - response.channels[channelName] = { - occupants: occupantsList, - name: channelName, - occupancy: channelEntry.occupancy, - }; - if (includeUUIDs) { - channelEntry.uuids.forEach(function (uuidEntry) { - if (includeState) { - occupantsList.push({ - state: uuidEntry.state, - uuid: uuidEntry.uuid, - }); - } - else { - occupantsList.push({ state: null, uuid: uuidEntry }); - } + HereNowRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse, totalChannels, totalOccupancy, channelsPresence, channels, channel; + var _a, _b; + return __generator(this, function (_c) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + totalChannels = 'occupancy' in serviceResponse ? 1 : serviceResponse.payload.total_channels; + totalOccupancy = 'occupancy' in serviceResponse ? serviceResponse.occupancy : serviceResponse.payload.total_channels; + channelsPresence = {}; + channels = {}; + // Remap single channel presence to multiple channels presence response. + if ('occupancy' in serviceResponse) { + channel = this.parameters.channels[0]; + channels[channel] = { uuids: (_a = serviceResponse.uuids) !== null && _a !== void 0 ? _a : [], occupancy: totalOccupancy }; + } + else + channels = (_b = serviceResponse.payload.channels) !== null && _b !== void 0 ? _b : {}; + Object.keys(channels).forEach(function (channel) { + var channelEntry = channels[channel]; + channelsPresence[channel] = { + occupants: channelEntry.uuids.map(function (uuid) { + if (typeof uuid === 'string') + return { uuid: uuid, state: null }; + return uuid; + }), + name: channel, + occupancy: channelEntry.occupancy, + }; }); - } - return response; + return [2 /*return*/, { + totalChannels: totalChannels, + totalOccupancy: totalOccupancy, + channels: channelsPresence, + }]; + }); }); - return response; }; - var response; - if (channels.length > 1 || channelGroups.length > 0 || (channelGroups.length === 0 && channels.length === 0)) { - response = prepareMultipleChannel(); - } - else { - response = prepareSingularChannel(); - } - return response; -} -exports.handleResponse = handleResponse; -function handleError(modules, params, status) { - if (status.statusCode === 402 && !this.getURL(modules, params).includes('channel')) { - status.errorData.message = - 'You have tried to perform a Global Here Now operation, ' + - 'your keyset configuration does not support that. Please provide a channel, ' + - 'or enable the Global Here Now feature from the Portal.'; - } -} -exports.handleError = handleError; + Object.defineProperty(HereNowRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channels = _a.channels, channelGroups = _a.channelGroups; + var path = "/v2/presence/sub-key/".concat(subscribeKey); + if ((channels && channels.length > 0) || (channelGroups && channelGroups.length > 0)) { + var stringifiedChannels = channels && channels.length > 0 ? (0, utils_1.encodeString)(channels.join(',')) : ','; + path += "/channel/".concat(stringifiedChannels); + } + return path; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(HereNowRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, channelGroups = _a.channelGroups, includeUUIDs = _a.includeUUIDs, includeState = _a.includeState, queryParameters = _a.queryParameters; + return __assign(__assign(__assign(__assign({}, (!includeUUIDs ? { disable_uuids: '1' } : {})), ((includeState !== null && includeState !== void 0 ? includeState : false) ? { state: '1' } : {})), (channelGroups && channelGroups.length > 0 ? { 'channel-group': channelGroups.join(',') } : {})), queryParameters); + }, + enumerable: false, + configurable: true + }); + return HereNowRequest; +}(request_1.AbstractRequest)); +exports.HereNowRequest = HereNowRequest; diff --git a/lib/core/endpoints/presence/leave.js b/lib/core/endpoints/presence/leave.js index be63c00dd..0bceda8c1 100644 --- a/lib/core/endpoints/presence/leave.js +++ b/lib/core/endpoints/presence/leave.js @@ -1,48 +1,115 @@ "use strict"; -/* */ +/** + * Announce leave REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; +exports.PresenceLeaveRequest = void 0; +var PubNubError_1 = require("../../../models/PubNubError"); +var request_1 = require("../../components/request"); var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -function getOperation() { - return operations_1.default.PNUnsubscribeOperation; -} -exports.getOperation = getOperation; -function validateParams(modules) { - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var config = modules.config; - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a; - var stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return "/v2/presence/sub-key/".concat(config.subscribeKey, "/channel/").concat(utils_1.default.encodeString(stringifiedChannels), "/leave"); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams(modules, incomingParams) { - var _a = incomingParams.channelGroups, channelGroups = _a === void 0 ? [] : _a; - var params = {}; - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); +var utils_1 = require("../../utils"); +// endregion +var PresenceLeaveRequest = /** @class */ (function (_super) { + __extends(PresenceLeaveRequest, _super); + function PresenceLeaveRequest(parameters) { + var _this = _super.call(this) || this; + _this.parameters = parameters; + return _this; } - return params; -} -exports.prepareParams = prepareParams; -function handleResponse() { - return {}; -} -exports.handleResponse = handleResponse; + PresenceLeaveRequest.prototype.operation = function () { + return operations_1.default.PNUnsubscribeOperation; + }; + PresenceLeaveRequest.prototype.validate = function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channels = _a.channels, channelGroups = _a.channelGroups; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if ((channels === null || channels === void 0 ? void 0 : channels.length) === 0 && (channelGroups === null || channelGroups === void 0 ? void 0 : channelGroups.length) === 0) + return 'At least one `channel` or `channel group` should be provided.'; + }; + PresenceLeaveRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, {}]; + }); + }); + }; + Object.defineProperty(PresenceLeaveRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channels = _a.channels; + var stringifiedChannels = channels && channels.length > 0 ? (0, utils_1.encodeString)(channels.join(',')) : ','; + return "/v2/presence/sub-key/".concat(subscribeKey, "/channel/").concat(stringifiedChannels, "/leave"); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(PresenceLeaveRequest.prototype, "queryParameters", { + get: function () { + var channelGroups = this.parameters.channelGroups; + if (!channelGroups || channelGroups.length === 0) + return {}; + return { 'channel-group': channelGroups.join(',') }; + }, + enumerable: false, + configurable: true + }); + return PresenceLeaveRequest; +}(request_1.AbstractRequest)); +exports.PresenceLeaveRequest = PresenceLeaveRequest; diff --git a/lib/core/endpoints/presence/set_state.js b/lib/core/endpoints/presence/set_state.js index daf813524..972aedb82 100644 --- a/lib/core/endpoints/presence/set_state.js +++ b/lib/core/endpoints/presence/set_state.js @@ -1,54 +1,121 @@ "use strict"; +/** + * Set Presence State REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; +exports.SetPresenceStateRequest = void 0; +var PubNubError_1 = require("../../../models/PubNubError"); +var request_1 = require("../../components/request"); var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -function getOperation() { - return operations_1.default.PNSetStateOperation; -} -exports.getOperation = getOperation; -function validateParams(modules, incomingParams) { - var config = modules.config; - var state = incomingParams.state, _a = incomingParams.channels, channels = _a === void 0 ? [] : _a, _b = incomingParams.channelGroups, channelGroups = _b === void 0 ? [] : _b; - if (!state) - return 'Missing State'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; - if (channels.length === 0 && channelGroups.length === 0) { - return 'Please provide a list of channels and/or channel-groups'; - } -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var config = modules.config; - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a; - var stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return "/v2/presence/sub-key/".concat(config.subscribeKey, "/channel/").concat(utils_1.default.encodeString(stringifiedChannels), "/uuid/").concat(utils_1.default.encodeString(config.UUID), "/data"); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams(modules, incomingParams) { - var state = incomingParams.state, _a = incomingParams.channelGroups, channelGroups = _a === void 0 ? [] : _a; - var params = {}; - params.state = JSON.stringify(state); - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); +var utils_1 = require("../../utils"); +// endregion +/** + * Set `uuid` presence state request. + */ +var SetPresenceStateRequest = /** @class */ (function (_super) { + __extends(SetPresenceStateRequest, _super); + function SetPresenceStateRequest(parameters) { + var _this = _super.call(this) || this; + _this.parameters = parameters; + return _this; } - return params; -} -exports.prepareParams = prepareParams; -function handleResponse(modules, serverResponse) { - return { state: serverResponse.payload }; -} -exports.handleResponse = handleResponse; + SetPresenceStateRequest.prototype.operation = function () { + return operations_1.default.PNSetStateOperation; + }; + SetPresenceStateRequest.prototype.validate = function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, state = _a.state, channels = _a.channels, channelGroups = _a.channelGroups; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!state) + return 'Missing State'; + if ((channels === null || channels === void 0 ? void 0 : channels.length) === 0 && (channelGroups === null || channelGroups === void 0 ? void 0 : channelGroups.length) === 0) + return 'Please provide a list of channels and/or channel-groups'; + }; + SetPresenceStateRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, { state: serviceResponse.payload }]; + }); + }); + }; + Object.defineProperty(SetPresenceStateRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, uuid = _a.uuid, channels = _a.channels; + var stringifiedChannels = channels && channels.length > 0 ? (0, utils_1.encodeString)(channels.join(',')) : ','; + return "/v2/presence/sub-key/".concat(subscribeKey, "/channel/").concat(stringifiedChannels, "/uuid/").concat(uuid, "/data"); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(SetPresenceStateRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, channelGroups = _a.channelGroups, state = _a.state; + var query = { state: JSON.stringify(state) }; + if (channelGroups && channelGroups.length === 0) + query['channel-group'] = channelGroups.join(','); + return query; + }, + enumerable: false, + configurable: true + }); + return SetPresenceStateRequest; +}(request_1.AbstractRequest)); +exports.SetPresenceStateRequest = SetPresenceStateRequest; diff --git a/lib/core/endpoints/presence/where_now.js b/lib/core/endpoints/presence/where_now.js index 05c069125..90ad57207 100644 --- a/lib/core/endpoints/presence/where_now.js +++ b/lib/core/endpoints/presence/where_now.js @@ -1,47 +1,103 @@ "use strict"; +/** + * `uuid` presence REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; -/* */ +exports.WhereNowRequest = void 0; +var PubNubError_1 = require("../../../models/PubNubError"); +var request_1 = require("../../components/request"); var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -function getOperation() { - return operations_1.default.PNWhereNowOperation; -} -exports.getOperation = getOperation; -function validateParams(modules) { - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var config = modules.config; - var _a = incomingParams.uuid, uuid = _a === void 0 ? config.UUID : _a; - return "/v2/presence/sub-key/".concat(config.subscribeKey, "/uuid/").concat(utils_1.default.encodeString(uuid)); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams() { - return {}; -} -exports.prepareParams = prepareParams; -function handleResponse(modules, serverResponse) { - // This is a quick fix for when the server does not include a payload - // in where now responses - if (!serverResponse.payload) { - return { channels: [] }; +var utils_1 = require("../../utils"); +// endregion +var WhereNowRequest = /** @class */ (function (_super) { + __extends(WhereNowRequest, _super); + function WhereNowRequest(parameters) { + var _this = _super.call(this) || this; + _this.parameters = parameters; + return _this; } - return { channels: serverResponse.payload.channels }; -} -exports.handleResponse = handleResponse; + WhereNowRequest.prototype.operation = function () { + return operations_1.default.PNWhereNowOperation; + }; + WhereNowRequest.prototype.validate = function () { + if (!this.parameters.keySet.subscribeKey) + return 'Missing Subscribe Key'; + }; + WhereNowRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + if (!serviceResponse.payload) + return [2 /*return*/, { channels: [] }]; + return [2 /*return*/, { channels: serviceResponse.payload.channels }]; + }); + }); + }; + Object.defineProperty(WhereNowRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, uuid = _a.uuid; + return "/v2/presence/sub-key/".concat(subscribeKey, "/uuid/").concat((0, utils_1.encodeString)(uuid)); + }, + enumerable: false, + configurable: true + }); + return WhereNowRequest; +}(request_1.AbstractRequest)); +exports.WhereNowRequest = WhereNowRequest; diff --git a/lib/core/endpoints/publish.js b/lib/core/endpoints/publish.js index f4d3dbafc..3ae0d0442 100644 --- a/lib/core/endpoints/publish.js +++ b/lib/core/endpoints/publish.js @@ -1,93 +1,187 @@ "use strict"; +/** + * Publish REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.postPayload = exports.isAuthSupported = exports.getRequestTimeout = exports.postURL = exports.getURL = exports.usePost = exports.validateParams = exports.getOperation = void 0; -/* */ +exports.PublishRequest = void 0; +var PubNubError_1 = require("../../models/PubNubError"); +var transport_request_1 = require("../types/transport-request"); +var request_1 = require("../components/request"); var operations_1 = __importDefault(require("../constants/operations")); -var utils_1 = __importDefault(require("../utils")); var base64_codec_1 = require("../components/base64_codec"); -function prepareMessagePayload(modules, messagePayload) { - var stringifiedPayload = JSON.stringify(messagePayload); - if (modules.cryptoModule) { - var encrypted = modules.cryptoModule.encrypt(stringifiedPayload); - stringifiedPayload = typeof encrypted === 'string' ? encrypted : (0, base64_codec_1.encode)(encrypted); - stringifiedPayload = JSON.stringify(stringifiedPayload); - } - return stringifiedPayload || ''; -} -function getOperation() { - return operations_1.default.PNPublishOperation; -} -exports.getOperation = getOperation; -function validateParams(_a, incomingParams) { - var config = _a.config; - var message = incomingParams.message, channel = incomingParams.channel; - if (!channel) - return 'Missing Channel'; - if (!message) - return 'Missing Message'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function usePost(modules, incomingParams) { - var _a = incomingParams.sendByPost, sendByPost = _a === void 0 ? false : _a; - return sendByPost; -} -exports.usePost = usePost; -function getURL(modules, incomingParams) { - var config = modules.config; - var channel = incomingParams.channel, message = incomingParams.message; - var stringifiedPayload = prepareMessagePayload(modules, message); - return "/publish/".concat(config.publishKey, "/").concat(config.subscribeKey, "/0/").concat(utils_1.default.encodeString(channel), "/0/").concat(utils_1.default.encodeString(stringifiedPayload)); -} -exports.getURL = getURL; -function postURL(modules, incomingParams) { - var config = modules.config; - var channel = incomingParams.channel; - return "/publish/".concat(config.publishKey, "/").concat(config.subscribeKey, "/0/").concat(utils_1.default.encodeString(channel), "/0"); -} -exports.postURL = postURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function postPayload(modules, incomingParams) { - var message = incomingParams.message; - return prepareMessagePayload(modules, message); -} -exports.postPayload = postPayload; -function prepareParams(modules, incomingParams) { - var meta = incomingParams.meta, _a = incomingParams.replicate, replicate = _a === void 0 ? true : _a, storeInHistory = incomingParams.storeInHistory, ttl = incomingParams.ttl; - var params = {}; - if (storeInHistory != null) { - if (storeInHistory) { - params.store = '1'; - } - else { - params.store = '0'; - } - } - if (ttl) { - params.ttl = ttl; - } - if (replicate === false) { - params.norep = 'true'; - } - if (meta && typeof meta === 'object') { - params.meta = JSON.stringify(meta); +var utils_1 = require("../utils"); +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults +/** + * Whether published data should be stored in history or not. + */ +var STORE_IN_HISTORY = true; +/** + * Whether data is published used `POST` body or not. + */ +var SEND_BY_POST = false; +/** + * Whether published data should be replicated across all data centers or not. + */ +var SHOULD_REPLICATE = true; +// endregion +/** + * Data publish request. + * + * Request will normalize and encrypt (if required) provided data and push it to the specified + * channel. + */ +var PublishRequest = /** @class */ (function (_super) { + __extends(PublishRequest, _super); + /** + * Construct data publish request. + * + * @param parameters - Request configuration. + */ + function PublishRequest(parameters) { + var _a, _b, _c; + var _d, _e, _f; + var _this = _super.call(this, { method: parameters.sendByPost ? transport_request_1.TransportMethod.POST : transport_request_1.TransportMethod.GET }) || this; + _this.parameters = parameters; + // Apply default request parameters. + (_a = (_d = _this.parameters).storeInHistory) !== null && _a !== void 0 ? _a : (_d.storeInHistory = STORE_IN_HISTORY); + (_b = (_e = _this.parameters).sendByPost) !== null && _b !== void 0 ? _b : (_e.sendByPost = SEND_BY_POST); + // Apply defaults to the deprecated parameter. + (_c = (_f = _this.parameters).replicate) !== null && _c !== void 0 ? _c : (_f.replicate = SHOULD_REPLICATE); + return _this; } - return params; -} -exports.prepareParams = prepareParams; -function handleResponse(modules, serverResponse) { - return { timetoken: serverResponse[2] }; -} -exports.handleResponse = handleResponse; + PublishRequest.prototype.operation = function () { + return operations_1.default.PNPublishOperation; + }; + PublishRequest.prototype.validate = function () { + var _a = this.parameters, message = _a.message, channel = _a.channel, publishKey = _a.keySet.publishKey; + if (!channel) + return "Missing 'channel''"; + if (!message) + return "Missing 'message'"; + if (!publishKey) + return "Missing 'publishKey'"; + }; + PublishRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, { timetoken: serviceResponse[2] }]; + }); + }); + }; + Object.defineProperty(PublishRequest.prototype, "path", { + get: function () { + var _a = this.parameters, message = _a.message, channel = _a.channel, keySet = _a.keySet; + var stringifiedPayload = this.prepareMessagePayload(message); + return "/publish/".concat(keySet.publishKey, "/").concat(keySet.subscribeKey, "/0/").concat((0, utils_1.encodeString)(channel), "/0").concat(!this.parameters.sendByPost ? "/".concat((0, utils_1.encodeString)(stringifiedPayload)) : ''); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(PublishRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, meta = _a.meta, replicate = _a.replicate, storeInHistory = _a.storeInHistory, ttl = _a.ttl; + return __assign(__assign(__assign({ store: storeInHistory ? '1' : '0' }, (ttl !== undefined ? { ttl: ttl } : {})), (!replicate ? { norep: 'true' } : {})), (meta && typeof meta === 'object' ? { meta: JSON.stringify(meta) } : {})); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(PublishRequest.prototype, "body", { + get: function () { + return this.prepareMessagePayload(this.parameters.message); + }, + enumerable: false, + configurable: true + }); + /** + * Pre-process provided data. + * + * Data will be "normalized" and encrypted if `cryptoModule` has been provided. + * + * @param payload - User-provided data which should be pre-processed before use. + * + * @returns Payload which can be used as part of request URL or body. + * + * @throws {Error} in case if provided `payload` or results of `encryption` can't be stringified. + */ + PublishRequest.prototype.prepareMessagePayload = function (payload) { + var crypto = this.parameters.crypto; + if (!crypto) + return JSON.stringify(payload) || ''; + var encrypted = crypto.encrypt(JSON.stringify(payload)); + return JSON.stringify(typeof encrypted === 'string' ? encrypted : (0, base64_codec_1.encode)(encrypted)); + }; + return PublishRequest; +}(request_1.AbstractRequest)); +exports.PublishRequest = PublishRequest; diff --git a/lib/core/endpoints/push/add_push_channels.js b/lib/core/endpoints/push/add_push_channels.js index 8912132ba..9facf39b2 100644 --- a/lib/core/endpoints/push/add_push_channels.js +++ b/lib/core/endpoints/push/add_push_channels.js @@ -1,5 +1,22 @@ "use strict"; -/* */ +/** + * Register Channels with Device push REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { @@ -11,60 +28,74 @@ var __assign = (this && this.__assign) || function () { }; return __assign.apply(this, arguments); }; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; +exports.AddDevicePushNotificationChannelsRequest = void 0; +var PubNubError_1 = require("../../../models/PubNubError"); +var push_1 = require("./push"); var operations_1 = __importDefault(require("../../constants/operations")); -function getOperation() { - return operations_1.default.PNPushNotificationEnabledChannelsOperation; -} -exports.getOperation = getOperation; -function validateParams(modules, incomingParams) { - var device = incomingParams.device, pushGateway = incomingParams.pushGateway, channels = incomingParams.channels, topic = incomingParams.topic; - var config = modules.config; - if (!device) - return 'Missing Device ID (device)'; - if (!pushGateway) - return 'Missing GW Type (pushGateway: gcm, apns or apns2)'; - if (pushGateway === 'apns2' && !topic) - return 'Missing APNS2 topic'; - if (!channels || channels.length === 0) - return 'Missing Channels'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var device = incomingParams.device, pushGateway = incomingParams.pushGateway; - var config = modules.config; - if (pushGateway === 'apns2') { - return "/v2/push/sub-key/".concat(config.subscribeKey, "/devices-apns2/").concat(device); - } - return "/v1/push/sub-key/".concat(config.subscribeKey, "/devices/").concat(device); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams(modules, incomingParams) { - var pushGateway = incomingParams.pushGateway, _a = incomingParams.channels, channels = _a === void 0 ? [] : _a, _b = incomingParams.environment, environment = _b === void 0 ? 'development' : _b, topic = incomingParams.topic; - var parameters = { type: pushGateway, add: channels.join(',') }; - if (pushGateway === 'apns2') { - parameters = __assign(__assign({}, parameters), { environment: environment, topic: topic }); - delete parameters.type; +// endregion +/** + * Register channels with device push request. + */ +// prettier-ignore +var AddDevicePushNotificationChannelsRequest = /** @class */ (function (_super) { + __extends(AddDevicePushNotificationChannelsRequest, _super); + function AddDevicePushNotificationChannelsRequest(parameters) { + return _super.call(this, __assign(__assign({}, parameters), { action: 'add' })) || this; } - return parameters; -} -exports.prepareParams = prepareParams; -function handleResponse() { - return {}; -} -exports.handleResponse = handleResponse; + AddDevicePushNotificationChannelsRequest.prototype.operation = function () { + return operations_1.default.PNAddPushNotificationEnabledChannelsOperation; + }; + AddDevicePushNotificationChannelsRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, {}]; + }); + }); + }; + return AddDevicePushNotificationChannelsRequest; +}(push_1.BasePushNotificationChannelsRequest)); +exports.AddDevicePushNotificationChannelsRequest = AddDevicePushNotificationChannelsRequest; diff --git a/lib/core/endpoints/push/list_push_channels.js b/lib/core/endpoints/push/list_push_channels.js index 304662c2c..cd647fae1 100644 --- a/lib/core/endpoints/push/list_push_channels.js +++ b/lib/core/endpoints/push/list_push_channels.js @@ -1,4 +1,22 @@ "use strict"; +/** + * List Device push enabled channels REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { @@ -10,59 +28,74 @@ var __assign = (this && this.__assign) || function () { }; return __assign.apply(this, arguments); }; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; -/* */ +exports.ListDevicePushNotificationChannelsRequest = void 0; +var PubNubError_1 = require("../../../models/PubNubError"); +var push_1 = require("./push"); var operations_1 = __importDefault(require("../../constants/operations")); -function getOperation() { - return operations_1.default.PNPushNotificationEnabledChannelsOperation; -} -exports.getOperation = getOperation; -function validateParams(modules, incomingParams) { - var device = incomingParams.device, pushGateway = incomingParams.pushGateway, topic = incomingParams.topic; - var config = modules.config; - if (!device) - return 'Missing Device ID (device)'; - if (!pushGateway) - return 'Missing GW Type (pushGateway: gcm, apns or apns2)'; - if (pushGateway === 'apns2' && !topic) - return 'Missing APNS2 topic'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var device = incomingParams.device, pushGateway = incomingParams.pushGateway; - var config = modules.config; - if (pushGateway === 'apns2') { - return "/v2/push/sub-key/".concat(config.subscribeKey, "/devices-apns2/").concat(device); - } - return "/v1/push/sub-key/".concat(config.subscribeKey, "/devices/").concat(device); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams(modules, incomingParams) { - var pushGateway = incomingParams.pushGateway, _a = incomingParams.environment, environment = _a === void 0 ? 'development' : _a, topic = incomingParams.topic; - var parameters = { type: pushGateway }; - if (pushGateway === 'apns2') { - parameters = __assign(__assign({}, parameters), { environment: environment, topic: topic }); - delete parameters.type; +// endregion +/** + * List device push enabled channels request. + */ +// prettier-ignore +var ListDevicePushNotificationChannelsRequest = /** @class */ (function (_super) { + __extends(ListDevicePushNotificationChannelsRequest, _super); + function ListDevicePushNotificationChannelsRequest(parameters) { + return _super.call(this, __assign(__assign({}, parameters), { action: 'list' })) || this; } - return parameters; -} -exports.prepareParams = prepareParams; -function handleResponse(modules, serverResponse) { - return { channels: serverResponse }; -} -exports.handleResponse = handleResponse; + ListDevicePushNotificationChannelsRequest.prototype.operation = function () { + return operations_1.default.PNPushNotificationEnabledChannelsOperation; + }; + ListDevicePushNotificationChannelsRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, { channels: serviceResponse }]; + }); + }); + }; + return ListDevicePushNotificationChannelsRequest; +}(push_1.BasePushNotificationChannelsRequest)); +exports.ListDevicePushNotificationChannelsRequest = ListDevicePushNotificationChannelsRequest; diff --git a/lib/core/endpoints/push/push.js b/lib/core/endpoints/push/push.js new file mode 100644 index 000000000..7a176b4a7 --- /dev/null +++ b/lib/core/endpoints/push/push.js @@ -0,0 +1,154 @@ +"use strict"; +/** + * Manage channels enabled for device push REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.BasePushNotificationChannelsRequest = void 0; +var request_1 = require("../../components/request"); +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults +/** + * Environment for which APNS2 notifications + */ +var ENVIRONMENT = 'development'; +/** + * Maximum number of channels in `list` response. + */ +var MAX_COUNT = 1000; +// endregion +/** + * Base push notification request. + */ +var BasePushNotificationChannelsRequest = /** @class */ (function (_super) { + __extends(BasePushNotificationChannelsRequest, _super); + function BasePushNotificationChannelsRequest(parameters) { + var _a; + var _b; + var _this = _super.call(this) || this; + _this.parameters = parameters; + // Apply request defaults + if (_this.parameters.pushGateway === 'apns2') + (_a = (_b = _this.parameters).environment) !== null && _a !== void 0 ? _a : (_b.environment = ENVIRONMENT); + if (_this.parameters.count && _this.parameters.count > MAX_COUNT) + _this.parameters.count = MAX_COUNT; + return _this; + } + BasePushNotificationChannelsRequest.prototype.operation = function () { + throw Error('Should be implemented in subclass.'); + }; + BasePushNotificationChannelsRequest.prototype.validate = function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, action = _a.action, device = _a.device, pushGateway = _a.pushGateway; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!device) + return 'Missing Device ID (device)'; + if ((action === 'add' || action === 'remove') && + (!('channels' in this.parameters) || this.parameters.channels.length === 0)) + return 'Missing Channels'; + if (!pushGateway) + return 'Missing GW Type (pushGateway: gcm or apns2)'; + if (this.parameters.pushGateway === 'apns2' && !this.parameters.topic) + return 'Missing APNS2 topic'; + }; + BasePushNotificationChannelsRequest.prototype.parse = function (_response) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + throw Error('Should be implemented in subclass.'); + }); + }); + }; + Object.defineProperty(BasePushNotificationChannelsRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, action = _a.action, device = _a.device, pushGateway = _a.pushGateway; + var path = pushGateway === 'apns2' + ? "/v2/push/sub-key/".concat(subscribeKey, "/devices-apns2/").concat(device) + : "/v1/push/sub-key/".concat(subscribeKey, "/devices/").concat(device); + if (action === 'remove-device') + path = "".concat(path, "/remove"); + return path; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(BasePushNotificationChannelsRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, start = _a.start, count = _a.count; + var query = __assign(__assign({ type: this.parameters.pushGateway }, (start ? { start: start } : {})), (count && count > 0 ? { count: count } : {})); + if ('channels' in this.parameters) + query[this.parameters.action] = this.parameters.channels.join(','); + if (this.parameters.pushGateway === 'apns2') { + var _b = this.parameters, environment = _b.environment, topic = _b.topic; + query = __assign(__assign({}, query), { environment: environment, topic: topic }); + } + return query; + }, + enumerable: false, + configurable: true + }); + return BasePushNotificationChannelsRequest; +}(request_1.AbstractRequest)); +exports.BasePushNotificationChannelsRequest = BasePushNotificationChannelsRequest; diff --git a/lib/core/endpoints/push/remove_device.js b/lib/core/endpoints/push/remove_device.js index 80abf1028..5648800bb 100644 --- a/lib/core/endpoints/push/remove_device.js +++ b/lib/core/endpoints/push/remove_device.js @@ -1,5 +1,22 @@ "use strict"; -/* */ +/** + * Unregister Device push REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { @@ -11,58 +28,74 @@ var __assign = (this && this.__assign) || function () { }; return __assign.apply(this, arguments); }; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; +exports.RemoveDevicePushNotificationRequest = void 0; +var PubNubError_1 = require("../../../models/PubNubError"); +var push_1 = require("./push"); var operations_1 = __importDefault(require("../../constants/operations")); -function getOperation() { - return operations_1.default.PNRemoveAllPushNotificationsOperation; -} -exports.getOperation = getOperation; -function validateParams(modules, incomingParams) { - var device = incomingParams.device, pushGateway = incomingParams.pushGateway, topic = incomingParams.topic; - var config = modules.config; - if (!device) - return 'Missing Device ID (device)'; - if (!pushGateway) - return 'Missing GW Type (pushGateway: gcm, apns or apns2)'; - if (pushGateway === 'apns2' && !topic) - return 'Missing APNS2 topic'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var device = incomingParams.device, pushGateway = incomingParams.pushGateway; - var config = modules.config; - if (pushGateway === 'apns2') { - return "/v2/push/sub-key/".concat(config.subscribeKey, "/devices-apns2/").concat(device, "/remove"); - } - return "/v1/push/sub-key/".concat(config.subscribeKey, "/devices/").concat(device, "/remove"); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams(modules, incomingParams) { - var pushGateway = incomingParams.pushGateway, _a = incomingParams.environment, environment = _a === void 0 ? 'development' : _a, topic = incomingParams.topic; - var parameters = { type: pushGateway }; - if (pushGateway === 'apns2') { - parameters = __assign(__assign({}, parameters), { environment: environment, topic: topic }); - delete parameters.type; +// endregion +/** + * Unregister device push notifications request. + */ +// prettier-ignore +var RemoveDevicePushNotificationRequest = /** @class */ (function (_super) { + __extends(RemoveDevicePushNotificationRequest, _super); + function RemoveDevicePushNotificationRequest(parameters) { + return _super.call(this, __assign(__assign({}, parameters), { action: 'remove-device' })) || this; } - return parameters; -} -exports.prepareParams = prepareParams; -function handleResponse() { - return {}; -} -exports.handleResponse = handleResponse; + RemoveDevicePushNotificationRequest.prototype.operation = function () { + return operations_1.default.PNRemoveAllPushNotificationsOperation; + }; + RemoveDevicePushNotificationRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, {}]; + }); + }); + }; + return RemoveDevicePushNotificationRequest; +}(push_1.BasePushNotificationChannelsRequest)); +exports.RemoveDevicePushNotificationRequest = RemoveDevicePushNotificationRequest; diff --git a/lib/core/endpoints/push/remove_push_channels.js b/lib/core/endpoints/push/remove_push_channels.js index a6256a9f3..1f5740bc6 100644 --- a/lib/core/endpoints/push/remove_push_channels.js +++ b/lib/core/endpoints/push/remove_push_channels.js @@ -1,5 +1,22 @@ "use strict"; -/* */ +/** + * Unregister Channels from Device push REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { @@ -11,60 +28,74 @@ var __assign = (this && this.__assign) || function () { }; return __assign.apply(this, arguments); }; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; +exports.RemoveDevicePushNotificationChannelsRequest = void 0; +var PubNubError_1 = require("../../../models/PubNubError"); +var push_1 = require("./push"); var operations_1 = __importDefault(require("../../constants/operations")); -function getOperation() { - return operations_1.default.PNPushNotificationEnabledChannelsOperation; -} -exports.getOperation = getOperation; -function validateParams(modules, incomingParams) { - var device = incomingParams.device, pushGateway = incomingParams.pushGateway, channels = incomingParams.channels, topic = incomingParams.topic; - var config = modules.config; - if (!device) - return 'Missing Device ID (device)'; - if (!pushGateway) - return 'Missing GW Type (pushGateway: gcm, apns or apns2)'; - if (pushGateway === 'apns2' && !topic) - return 'Missing APNS2 topic'; - if (!channels || channels.length === 0) - return 'Missing Channels'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var device = incomingParams.device, pushGateway = incomingParams.pushGateway; - var config = modules.config; - if (pushGateway === 'apns2') { - return "/v2/push/sub-key/".concat(config.subscribeKey, "/devices-apns2/").concat(device); - } - return "/v1/push/sub-key/".concat(config.subscribeKey, "/devices/").concat(device); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams(modules, incomingParams) { - var pushGateway = incomingParams.pushGateway, _a = incomingParams.channels, channels = _a === void 0 ? [] : _a, _b = incomingParams.environment, environment = _b === void 0 ? 'development' : _b, topic = incomingParams.topic; - var parameters = { type: pushGateway, remove: channels.join(',') }; - if (pushGateway === 'apns2') { - parameters = __assign(__assign({}, parameters), { environment: environment, topic: topic }); - delete parameters.type; +// endregion +/** + * Unregister channels from device push request. + */ +// prettier-ignore +var RemoveDevicePushNotificationChannelsRequest = /** @class */ (function (_super) { + __extends(RemoveDevicePushNotificationChannelsRequest, _super); + function RemoveDevicePushNotificationChannelsRequest(parameters) { + return _super.call(this, __assign(__assign({}, parameters), { action: 'remove' })) || this; } - return parameters; -} -exports.prepareParams = prepareParams; -function handleResponse() { - return {}; -} -exports.handleResponse = handleResponse; + RemoveDevicePushNotificationChannelsRequest.prototype.operation = function () { + return operations_1.default.PNRemovePushNotificationEnabledChannelsOperation; + }; + RemoveDevicePushNotificationChannelsRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, {}]; + }); + }); + }; + return RemoveDevicePushNotificationChannelsRequest; +}(push_1.BasePushNotificationChannelsRequest)); +exports.RemoveDevicePushNotificationChannelsRequest = RemoveDevicePushNotificationChannelsRequest; diff --git a/lib/core/endpoints/signal.js b/lib/core/endpoints/signal.js index e72ff68e8..ff3dafde0 100644 --- a/lib/core/endpoints/signal.js +++ b/lib/core/endpoints/signal.js @@ -1,53 +1,107 @@ "use strict"; -/* */ +/** + * Signal REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; +exports.SignalRequest = void 0; +var PubNubError_1 = require("../../models/PubNubError"); +var request_1 = require("../components/request"); var operations_1 = __importDefault(require("../constants/operations")); -var utils_1 = __importDefault(require("../utils")); -function prepareMessagePayload(modules, messagePayload) { - var stringifiedPayload = JSON.stringify(messagePayload); - return stringifiedPayload; -} -function getOperation() { - return operations_1.default.PNSignalOperation; -} -exports.getOperation = getOperation; -function validateParams(_a, incomingParams) { - var config = _a.config; - var message = incomingParams.message, channel = incomingParams.channel; - if (!channel) - return 'Missing Channel'; - if (!message) - return 'Missing Message'; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var config = modules.config; - var channel = incomingParams.channel, message = incomingParams.message; - var stringifiedPayload = prepareMessagePayload(modules, message); - return "/signal/".concat(config.publishKey, "/").concat(config.subscribeKey, "/0/").concat(utils_1.default.encodeString(channel), "/0/").concat(utils_1.default.encodeString(stringifiedPayload)); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams() { - var params = {}; - return params; -} -exports.prepareParams = prepareParams; -function handleResponse(modules, serverResponse) { - return { timetoken: serverResponse[2] }; -} -exports.handleResponse = handleResponse; +var utils_1 = require("../utils"); +// endregion +var SignalRequest = /** @class */ (function (_super) { + __extends(SignalRequest, _super); + function SignalRequest(parameters) { + var _this = _super.call(this) || this; + _this.parameters = parameters; + return _this; + } + SignalRequest.prototype.operation = function () { + return operations_1.default.PNSignalOperation; + }; + SignalRequest.prototype.validate = function () { + var _a = this.parameters, message = _a.message, channel = _a.channel, publishKey = _a.keySet.publishKey; + if (!channel) + return "Missing 'channel''"; + if (!message) + return "Missing 'message'"; + if (!publishKey) + return "Missing 'publishKey'"; + }; + SignalRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, { timetoken: serviceResponse[2] }]; + }); + }); + }; + Object.defineProperty(SignalRequest.prototype, "path", { + get: function () { + var _a = this.parameters, _b = _a.keySet, publishKey = _b.publishKey, subscribeKey = _b.subscribeKey, channel = _a.channel, message = _a.message; + var stringifiedPayload = JSON.stringify(message); + return "/signal/".concat(publishKey, "/").concat(subscribeKey, "/0/").concat((0, utils_1.encodeString)(channel), "/0/").concat((0, utils_1.encodeString)(stringifiedPayload)); + }, + enumerable: false, + configurable: true + }); + return SignalRequest; +}(request_1.AbstractRequest)); +exports.SignalRequest = SignalRequest; diff --git a/lib/core/endpoints/subscribe.js b/lib/core/endpoints/subscribe.js index 702295738..5938f7b44 100644 --- a/lib/core/endpoints/subscribe.js +++ b/lib/core/endpoints/subscribe.js @@ -1,88 +1,402 @@ "use strict"; +/** + * Subscription REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +var __read = (this && this.__read) || function (o, n) { + var m = typeof Symbol === "function" && o[Symbol.iterator]; + if (!m) return o; + var i = m.call(o), r, ar = [], e; + try { + while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); + } + catch (error) { e = { error: error }; } + finally { + try { + if (r && !r.done && (m = i["return"])) m.call(i); + } + finally { if (e) throw e.error; } + } + return ar; +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.handleResponse = exports.prepareParams = exports.isAuthSupported = exports.getRequestTimeout = exports.getURL = exports.validateParams = exports.getOperation = void 0; -/* */ +exports.SubscribeRequest = exports.BaseSubscribeRequest = exports.PubNubEventType = void 0; +var PubNubError_1 = require("../../models/PubNubError"); +var request_1 = require("../components/request"); var operations_1 = __importDefault(require("../constants/operations")); -var utils_1 = __importDefault(require("../utils")); -function getOperation() { - return operations_1.default.PNSubscribeOperation; -} -exports.getOperation = getOperation; -function validateParams(modules) { - var config = modules.config; - if (!config.subscribeKey) - return 'Missing Subscribe Key'; -} -exports.validateParams = validateParams; -function getURL(modules, incomingParams) { - var config = modules.config; - var _a = incomingParams.channels, channels = _a === void 0 ? [] : _a; - var stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return "/v2/subscribe/".concat(config.subscribeKey, "/").concat(utils_1.default.encodeString(stringifiedChannels), "/0"); -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getSubscribeTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function isAuthSupported() { - return true; -} -exports.isAuthSupported = isAuthSupported; -function prepareParams(_a, incomingParams) { - var config = _a.config; - var state = incomingParams.state, _b = incomingParams.channelGroups, channelGroups = _b === void 0 ? [] : _b, timetoken = incomingParams.timetoken, filterExpression = incomingParams.filterExpression, region = incomingParams.region; - var params = { - heartbeat: config.getPresenceTimeout(), - }; - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); - } - if (filterExpression && filterExpression.length > 0) { - params['filter-expr'] = filterExpression; +var utils_1 = require("../utils"); +// -------------------------------------------------------- +// ---------------------- Defaults ------------------------ +// -------------------------------------------------------- +// region Defaults +/** + * Whether should subscribe to channels / groups presence announcements or not. + */ +var WITH_PRESENCE = false; +// endregion +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types +/** + * PubNub-defined event types by payload. + */ +var PubNubEventType; +(function (PubNubEventType) { + /** + * Presence change event. + */ + PubNubEventType[PubNubEventType["Presence"] = -2] = "Presence"; + /** + * Regular message event. + * + * **Note:** This is default type assigned for non-presence events if `e` field is missing. + */ + PubNubEventType[PubNubEventType["Message"] = -1] = "Message"; + /** + * Signal data event. + */ + PubNubEventType[PubNubEventType["Signal"] = 1] = "Signal"; + /** + * App Context object event. + */ + PubNubEventType[PubNubEventType["AppContext"] = 2] = "AppContext"; + /** + * Message reaction event. + */ + PubNubEventType[PubNubEventType["MessageAction"] = 3] = "MessageAction"; + /** + * Files event. + */ + PubNubEventType[PubNubEventType["Files"] = 4] = "Files"; +})(PubNubEventType || (exports.PubNubEventType = PubNubEventType = {})); +// endregion +/** + * Base subscription request implementation. + * + * Subscription request used in small variations in two cases: + * - subscription manager + * - event engine + */ +var BaseSubscribeRequest = /** @class */ (function (_super) { + __extends(BaseSubscribeRequest, _super); + function BaseSubscribeRequest(parameters) { + var _a, _b, _c; + var _d, _e, _f; + var _this = _super.call(this, { cancellable: true }) || this; + _this.parameters = parameters; + // Apply default request parameters. + (_a = (_d = _this.parameters).withPresence) !== null && _a !== void 0 ? _a : (_d.withPresence = WITH_PRESENCE); + (_b = (_e = _this.parameters).channelGroups) !== null && _b !== void 0 ? _b : (_e.channelGroups = []); + (_c = (_f = _this.parameters).channels) !== null && _c !== void 0 ? _c : (_f.channels = []); + return _this; } - if (Object.keys(state).length) { - params.state = JSON.stringify(state); - } - if (timetoken) { - params.tt = timetoken; - } - if (region) { - params.tr = region; - } - return params; -} -exports.prepareParams = prepareParams; -function handleResponse(modules, serverResponse) { - var messages = []; - serverResponse.m.forEach(function (rawMessage) { - var publishMetaData = { - publishTimetoken: rawMessage.p.t, - region: rawMessage.p.r, + BaseSubscribeRequest.prototype.operation = function () { + return operations_1.default.PNSubscribeOperation; + }; + BaseSubscribeRequest.prototype.validate = function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channels = _a.channels, channelGroups = _a.channelGroups; + if (!subscribeKey) + return 'Missing Subscribe Key'; + if (!channels && !channelGroups) + return '`channels` and `channelGroups` both should not be empty'; + }; + BaseSubscribeRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse, events; + var _this = this; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + events = serviceResponse.m.map(function (envelope) { + var eventType = envelope.e; + // Resolve missing event type. + eventType !== null && eventType !== void 0 ? eventType : (eventType = envelope.c.endsWith('-pnpres') ? PubNubEventType.Presence : PubNubEventType.Message); + // Check whether payload is string (potentially encrypted data). + if (typeof envelope.d === 'string') { + if (eventType == PubNubEventType.Message) { + return { + type: PubNubEventType.Message, + data: _this.messageFromEnvelope(envelope), + }; + } + return { + type: PubNubEventType.Files, + data: _this.fileFromEnvelope(envelope), + }; + } + else if (eventType === PubNubEventType.Presence) { + return { + type: PubNubEventType.Presence, + data: _this.presenceEventFromEnvelope(envelope), + }; + } + else if (eventType == PubNubEventType.Signal) { + return { + type: PubNubEventType.Signal, + data: _this.signalFromEnvelope(envelope), + }; + } + else if (eventType === PubNubEventType.AppContext) { + return { + type: PubNubEventType.AppContext, + data: _this.appContextFromEnvelope(envelope), + }; + } + else if (eventType === PubNubEventType.MessageAction) { + return { + type: PubNubEventType.MessageAction, + data: _this.messageActionFromEnvelope(envelope), + }; + } + return { + type: PubNubEventType.Files, + data: _this.fileFromEnvelope(envelope), + }; + }); + return [2 /*return*/, { + cursor: { timetoken: serviceResponse.t.t, region: serviceResponse.t.r }, + messages: events, + }]; + }); + }); + }; + // -------------------------------------------------------- + // ------------------ Envelope parsing -------------------- + // -------------------------------------------------------- + // region Envelope parsing + BaseSubscribeRequest.prototype.presenceEventFromEnvelope = function (envelope) { + var payload = envelope.d; + var _a = __read(this.subscriptionChannelFromEnvelope(envelope), 2), channel = _a[0], subscription = _a[1]; + // Clean up channel and subscription name from presence suffix. + channel = channel.replace('-pnpres', ''); + if (subscription) + subscription = subscription.replace('-pnpres', ''); + // Backward compatibility with deprecated properties. + var actualChannel = subscription !== null ? channel : null; + var subscribedChannel = subscription !== null ? subscription : channel; + return __assign({ channel: channel, subscription: subscription, actualChannel: actualChannel, subscribedChannel: subscribedChannel, timetoken: envelope.p.t }, payload); + }; + BaseSubscribeRequest.prototype.messageFromEnvelope = function (envelope) { + var _a = __read(this.subscriptionChannelFromEnvelope(envelope), 2), channel = _a[0], subscription = _a[1]; + var _b = __read(this.decryptedData(envelope.d), 2), message = _b[0], decryptionError = _b[1]; + // Backward compatibility with deprecated properties. + var actualChannel = subscription !== null ? channel : null; + var subscribedChannel = subscription !== null ? subscription : channel; + // Basic message event payload. + var event = { + channel: channel, + subscription: subscription, + actualChannel: actualChannel, + subscribedChannel: subscribedChannel, + timetoken: envelope.p.t, + publisher: envelope.i, + userMetadata: envelope.u, + message: message, + }; + if (decryptionError) + event.error = decryptionError; + return event; + }; + BaseSubscribeRequest.prototype.signalFromEnvelope = function (envelope) { + var _a = __read(this.subscriptionChannelFromEnvelope(envelope), 2), channel = _a[0], subscription = _a[1]; + return { + channel: channel, + subscription: subscription, + timetoken: envelope.p.t, + publisher: envelope.i, + userMetadata: envelope.u, + message: envelope.d, }; - var parsedMessage = { - shard: parseInt(rawMessage.a, 10), - subscriptionMatch: rawMessage.b, - channel: rawMessage.c, - messageType: rawMessage.e, - payload: rawMessage.d, - flags: rawMessage.f, - issuingClientId: rawMessage.i, - subscribeKey: rawMessage.k, - originationTimetoken: rawMessage.o, - userMetadata: rawMessage.u, - publishMetaData: publishMetaData, + }; + BaseSubscribeRequest.prototype.messageActionFromEnvelope = function (envelope) { + var _a = __read(this.subscriptionChannelFromEnvelope(envelope), 2), channel = _a[0], subscription = _a[1]; + var action = envelope.d; + return { + channel: channel, + subscription: subscription, + timetoken: envelope.p.t, + publisher: envelope.i, + event: action.event, + data: __assign(__assign({}, action.data), { uuid: envelope.i }), }; - messages.push(parsedMessage); - }); - var metadata = { - timetoken: serverResponse.t.t, - region: serverResponse.t.r, }; - return { messages: messages, metadata: metadata }; -} -exports.handleResponse = handleResponse; + BaseSubscribeRequest.prototype.appContextFromEnvelope = function (envelope) { + var _a = __read(this.subscriptionChannelFromEnvelope(envelope), 2), channel = _a[0], subscription = _a[1]; + var object = envelope.d; + return { + channel: channel, + subscription: subscription, + timetoken: envelope.p.t, + message: object, + }; + }; + BaseSubscribeRequest.prototype.fileFromEnvelope = function (envelope) { + var _a = __read(this.subscriptionChannelFromEnvelope(envelope), 2), channel = _a[0], subscription = _a[1]; + var _b = __read(this.decryptedData(envelope.d), 2), file = _b[0], decryptionError = _b[1]; + var errorMessage = decryptionError; + // Basic file event payload. + var event = { + channel: channel, + subscription: subscription, + timetoken: envelope.p.t, + publisher: envelope.i, + userMetadata: envelope.u, + }; + if (!file) + errorMessage !== null && errorMessage !== void 0 ? errorMessage : (errorMessage = "File information payload is missing."); + else if (typeof file === 'string') + errorMessage !== null && errorMessage !== void 0 ? errorMessage : (errorMessage = "Unexpected file information payload data type."); + else { + event.message = file.message; + if (file.file) { + event.file = { + id: file.file.id, + name: file.file.name, + url: this.parameters.getFileUrl({ id: file.file.id, name: file.file.name, channel: channel }), + }; + } + } + if (errorMessage) + event.error = errorMessage; + return event; + }; + // endregion + BaseSubscribeRequest.prototype.subscriptionChannelFromEnvelope = function (envelope) { + return [envelope.c, envelope.b === undefined || envelope.b === envelope.c ? null : envelope.b]; + }; + /** + * Decrypt provided `data`. + * + * @param [data] - Message or file information which should be decrypted if possible. + * + * @returns Tuple with decrypted data and decryption error (if any). + */ + BaseSubscribeRequest.prototype.decryptedData = function (data) { + if (!this.parameters.crypto || typeof data !== 'string') + return [data, undefined]; + var payload; + var error; + try { + var decryptedData = this.parameters.crypto.decrypt(data); + payload = + decryptedData instanceof ArrayBuffer + ? JSON.parse(SubscribeRequest.decoder.decode(decryptedData)) + : decryptedData; + } + catch (err) { + payload = null; + error = "Error while decrypting file message content: ".concat(err.message); + } + return [(payload !== null && payload !== void 0 ? payload : data), error]; + }; + return BaseSubscribeRequest; +}(request_1.AbstractRequest)); +exports.BaseSubscribeRequest = BaseSubscribeRequest; +/** + * Subscribe request. + */ +var SubscribeRequest = /** @class */ (function (_super) { + __extends(SubscribeRequest, _super); + function SubscribeRequest() { + return _super !== null && _super.apply(this, arguments) || this; + } + Object.defineProperty(SubscribeRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channels = _a.channels; + return "/v2/subscribe/".concat(subscribeKey, "/").concat((0, utils_1.encodeString)(channels.length > 0 ? channels.join(',') : ','), "/0"); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(SubscribeRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, channelGroups = _a.channelGroups, filterExpression = _a.filterExpression, state = _a.state, timetoken = _a.timetoken, region = _a.region; + var query = {}; + if (channelGroups && channelGroups.length > 0) + query['channel-group'] = channelGroups.join(','); + if (filterExpression && filterExpression.length > 0) + query['filter-expr'] = filterExpression; + if (state && Object.keys(state).length > 0) + query['state'] = JSON.stringify(state); + if (typeof timetoken === 'string') { + if (timetoken && timetoken.length > 0) + query['tt'] = timetoken; + } + else if (timetoken && timetoken > 0) + query['tt'] = timetoken; + if (region) + query['tr'] = region; + return query; + }, + enumerable: false, + configurable: true + }); + return SubscribeRequest; +}(BaseSubscribeRequest)); +exports.SubscribeRequest = SubscribeRequest; diff --git a/lib/core/endpoints/subscriptionUtils/handshake.js b/lib/core/endpoints/subscriptionUtils/handshake.js index c30834e5b..91a174e8d 100644 --- a/lib/core/endpoints/subscriptionUtils/handshake.js +++ b/lib/core/endpoints/subscriptionUtils/handshake.js @@ -1,46 +1,66 @@ "use strict"; +/** + * Handshake subscribe REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); +exports.HandshakeSubscribeRequest = void 0; var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNHandshakeOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channels) && !(params === null || params === void 0 ? void 0 : params.channelGroups)) { - return 'channels and channleGroups both should not be empty'; - } - }, - getURL: function (_a, params) { - var config = _a.config; - var _b = params.channels, channels = _b === void 0 ? [] : _b; - var stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return "/v2/subscribe/".concat(config.subscribeKey, "/").concat(utils_1.default.encodeString(stringifiedChannels), "/0"); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getSubscribeTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_, params) { - var outParams = {}; - if (params.channelGroups && params.channelGroups.length > 0) { - outParams['channel-group'] = params.channelGroups.join(','); - } - outParams.tt = 0; - if (params.state) { - outParams.state = JSON.stringify(params.state); - } - if (params.filterExpression && params.filterExpression.length > 0) { - outParams['filter-expr'] = params.filterExpression; - } - outParams.ee = ''; - return outParams; - }, - handleResponse: function (_, response) { return ({ - region: response.t.r, - timetoken: response.t.t, - }); }, -}; -exports.default = endpoint; +var subscribe_1 = require("../subscribe"); +var utils_1 = require("../../utils"); +/** + * Handshake subscribe request. + * + * Separate subscribe request required by Event Engine. + */ +var HandshakeSubscribeRequest = /** @class */ (function (_super) { + __extends(HandshakeSubscribeRequest, _super); + function HandshakeSubscribeRequest() { + return _super !== null && _super.apply(this, arguments) || this; + } + HandshakeSubscribeRequest.prototype.operation = function () { + return operations_1.default.PNHandshakeOperation; + }; + Object.defineProperty(HandshakeSubscribeRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channels = _a.channels; + return "/v2/subscribe/".concat(subscribeKey, "/").concat((0, utils_1.encodeString)(channels.length > 0 ? channels.join(',') : ','), "/0"); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(HandshakeSubscribeRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, channelGroups = _a.channelGroups, filterExpression = _a.filterExpression, state = _a.state; + var query = { tt: 0, ee: '' }; + if (channelGroups && channelGroups.length > 0) + query['channel-group'] = channelGroups.join(','); + if (filterExpression && filterExpression.length > 0) + query['filter-expr'] = filterExpression; + if (state && Object.keys(state).length > 0) + query['state'] = JSON.stringify(state); + return query; + }, + enumerable: false, + configurable: true + }); + return HandshakeSubscribeRequest; +}(subscribe_1.BaseSubscribeRequest)); +exports.HandshakeSubscribeRequest = HandshakeSubscribeRequest; diff --git a/lib/core/endpoints/subscriptionUtils/receiveMessages.js b/lib/core/endpoints/subscriptionUtils/receiveMessages.js index e9d07554a..c72ede057 100644 --- a/lib/core/endpoints/subscriptionUtils/receiveMessages.js +++ b/lib/core/endpoints/subscriptionUtils/receiveMessages.js @@ -1,75 +1,79 @@ "use strict"; +/** + * Receive messages subscribe REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); +exports.ReceiveMessagesSubscribeRequest = void 0; var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNReceiveMessagesOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.channels) && !(params === null || params === void 0 ? void 0 : params.channelGroups)) { - return 'channels and channleGroups both should not be empty'; - } - if (!(params === null || params === void 0 ? void 0 : params.timetoken)) { +var subscribe_1 = require("../subscribe"); +var utils_1 = require("../../utils"); +/** + * Receive messages subscribe request. + */ +var ReceiveMessagesSubscribeRequest = /** @class */ (function (_super) { + __extends(ReceiveMessagesSubscribeRequest, _super); + function ReceiveMessagesSubscribeRequest() { + return _super !== null && _super.apply(this, arguments) || this; + } + ReceiveMessagesSubscribeRequest.prototype.operation = function () { + return operations_1.default.PNReceiveMessagesOperation; + }; + ReceiveMessagesSubscribeRequest.prototype.validate = function () { + var validationResult = _super.prototype.validate.call(this); + if (validationResult) + return validationResult; + if (!this.parameters.timetoken) return 'timetoken can not be empty'; - } - if (!(params === null || params === void 0 ? void 0 : params.region)) { + if (!this.parameters.region) return 'region can not be empty'; - } - }, - getURL: function (_a, params) { - var config = _a.config; - var _b = params.channels, channels = _b === void 0 ? [] : _b; - var stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return "/v2/subscribe/".concat(config.subscribeKey, "/").concat(utils_1.default.encodeString(stringifiedChannels), "/0"); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getSubscribeTimeout(); - }, - isAuthSupported: function () { return true; }, - getAbortSignal: function (_, params) { return params.abortSignal; }, - prepareParams: function (_, params) { - var outParams = {}; - if (params.channelGroups && params.channelGroups.length > 0) { - outParams['channel-group'] = params.channelGroups.join(','); - } - if (params.filterExpression && params.filterExpression.length > 0) { - outParams['filter-expr'] = params.filterExpression; - } - outParams.tt = params.timetoken; - outParams.tr = params.region; - outParams.ee = ''; - return outParams; - }, - handleResponse: function (_, response) { - var parsedMessages = []; - response.m.forEach(function (envelope) { - var parsedMessage = { - shard: parseInt(envelope.a, 10), - subscriptionMatch: envelope.b, - channel: envelope.c, - messageType: envelope.e, - payload: envelope.d, - flags: envelope.f, - issuingClientId: envelope.i, - subscribeKey: envelope.k, - originationTimetoken: envelope.o, - publishMetaData: { - timetoken: envelope.p.t, - region: envelope.p.r, - }, - }; - parsedMessages.push(parsedMessage); - }); - return { - messages: parsedMessages, - metadata: { - region: response.t.r, - timetoken: response.t.t, - }, - }; - }, -}; -exports.default = endpoint; + }; + Object.defineProperty(ReceiveMessagesSubscribeRequest.prototype, "path", { + get: function () { + var _a = this.parameters, subscribeKey = _a.keySet.subscribeKey, channels = _a.channels; + return "/v2/subscribe/".concat(subscribeKey, "/").concat((0, utils_1.encodeString)(channels.length > 0 ? channels.join(',') : ','), "/0"); + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(ReceiveMessagesSubscribeRequest.prototype, "queryParameters", { + get: function () { + var _a = this.parameters, channelGroups = _a.channelGroups, filterExpression = _a.filterExpression, timetoken = _a.timetoken, region = _a.region; + var query = { ee: '' }; + if (channelGroups && channelGroups.length > 0) + query['channel-group'] = channelGroups.join(','); + if (filterExpression && filterExpression.length > 0) + query['filter-expr'] = filterExpression; + if (typeof timetoken === 'string') { + if (timetoken && timetoken.length > 0) + query['tt'] = timetoken; + } + else if (timetoken && timetoken > 0) + query['tt'] = timetoken; + if (region) + query['tr'] = region; + return query; + }, + enumerable: false, + configurable: true + }); + return ReceiveMessagesSubscribeRequest; +}(subscribe_1.BaseSubscribeRequest)); +exports.ReceiveMessagesSubscribeRequest = ReceiveMessagesSubscribeRequest; diff --git a/lib/core/endpoints/time.js b/lib/core/endpoints/time.js index 8673d0a95..f60e48e7b 100644 --- a/lib/core/endpoints/time.js +++ b/lib/core/endpoints/time.js @@ -1,39 +1,93 @@ "use strict"; +/** + * Time REST API module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.validateParams = exports.handleResponse = exports.isAuthSupported = exports.prepareParams = exports.getRequestTimeout = exports.getURL = exports.getOperation = void 0; -/* */ +exports.TimeRequest = void 0; +var PubNubError_1 = require("../../models/PubNubError"); +var request_1 = require("../components/request"); var operations_1 = __importDefault(require("../constants/operations")); -function getOperation() { - return operations_1.default.PNTimeOperation; -} -exports.getOperation = getOperation; -function getURL() { - return '/time/0'; -} -exports.getURL = getURL; -function getRequestTimeout(_a) { - var config = _a.config; - return config.getTransactionTimeout(); -} -exports.getRequestTimeout = getRequestTimeout; -function prepareParams() { - return {}; -} -exports.prepareParams = prepareParams; -function isAuthSupported() { - return false; -} -exports.isAuthSupported = isAuthSupported; -function handleResponse(modules, serverResponse) { - return { - timetoken: serverResponse[0], +// endregion +var TimeRequest = /** @class */ (function (_super) { + __extends(TimeRequest, _super); + function TimeRequest() { + return _super.call(this) || this; + } + TimeRequest.prototype.operation = function () { + return operations_1.default.PNTimeOperation; + }; + TimeRequest.prototype.parse = function (response) { + return __awaiter(this, void 0, void 0, function () { + var serviceResponse; + return __generator(this, function (_a) { + serviceResponse = this.deserializeResponse(response); + if (!serviceResponse) + throw new PubNubError_1.PubNubError('Service response error, check status for details', (0, PubNubError_1.createValidationError)('Unable to deserialize service response')); + return [2 /*return*/, { timetoken: serviceResponse[0] }]; + }); + }); }; -} -exports.handleResponse = handleResponse; -function validateParams() { - // pass -} -exports.validateParams = validateParams; + Object.defineProperty(TimeRequest.prototype, "path", { + get: function () { + return '/time/0'; + }, + enumerable: false, + configurable: true + }); + return TimeRequest; +}(request_1.AbstractRequest)); +exports.TimeRequest = TimeRequest; diff --git a/lib/core/endpoints/user/create.js b/lib/core/endpoints/user/create.js deleted file mode 100644 index e9526855c..000000000 --- a/lib/core/endpoints/user/create.js +++ /dev/null @@ -1,40 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNCreateUserOperation; }, - validateParams: function (_, params) { - if (!(params === null || params === void 0 ? void 0 : params.data)) { - return 'Data cannot be empty'; - } - }, - usePost: function () { return true; }, - postURL: function (_a, params) { - var _b; - var config = _a.config; - return "/v3/objects/".concat(config.subscribeKey, "/users/").concat(utils_1.default.encodeString((_b = params.userId) !== null && _b !== void 0 ? _b : config.getUserId())); - }, - postPayload: function (_, params) { return params.data; }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_a, params) { - var _b; - var config = _a.config; - var queryParams = { - uuid: (_b = params === null || params === void 0 ? void 0 : params.userId) !== null && _b !== void 0 ? _b : config.getUserId(), - }; - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - }); }, -}; -exports.default = endpoint; diff --git a/lib/core/endpoints/user/fetch.js b/lib/core/endpoints/user/fetch.js deleted file mode 100644 index 473da58c5..000000000 --- a/lib/core/endpoints/user/fetch.js +++ /dev/null @@ -1,34 +0,0 @@ -"use strict"; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -var operations_1 = __importDefault(require("../../constants/operations")); -var utils_1 = __importDefault(require("../../utils")); -var endpoint = { - getOperation: function () { return operations_1.default.PNFetchUserOperation; }, - validateParams: function () { - // No required parameters. - }, - getURL: function (_a, params) { - var _b; - var config = _a.config; - return "/v3/objects/".concat(config.subscribeKey, "/users/").concat(utils_1.default.encodeString((_b = params === null || params === void 0 ? void 0 : params.userId) !== null && _b !== void 0 ? _b : config.getUserId())); - }, - getRequestTimeout: function (_a) { - var config = _a.config; - return config.getTransactionTimeout(); - }, - isAuthSupported: function () { return true; }, - prepareParams: function (_a, params) { - var _b; - var config = _a.config; - var queryParams = { uuid: (_b = params === null || params === void 0 ? void 0 : params.userId) !== null && _b !== void 0 ? _b : config.getUserId() }; - return queryParams; - }, - handleResponse: function (_, response) { return ({ - status: response.status, - data: response.data, - }); }, -}; -exports.default = endpoint; diff --git a/lib/core/interfaces/configuration.js b/lib/core/interfaces/configuration.js new file mode 100644 index 000000000..8593bb901 --- /dev/null +++ b/lib/core/interfaces/configuration.js @@ -0,0 +1,178 @@ +"use strict"; +/** + * {@link PubNub} client configuration module. + */ +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.setDefaults = void 0; +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults +/** + * Whether secured connection should be used by or not. + */ +var USE_SSL = true; +/** + * Whether PubNub client should catch up subscription after network issues. + */ +var RESTORE = false; +/** + * Whether network availability change should be announced with `PNNetworkDownCategory` and + * `PNNetworkUpCategory` state or not. + */ +var AUTO_NETWORK_DETECTION = false; +/** + * Whether messages should be de-duplicated before announcement or not. + */ +var DEDUPE_ON_SUBSCRIBE = false; +/** + * Maximum cache which should be used for message de-duplication functionality. + */ +var DEDUPE_CACHE_SIZE = 100; +/** + * Maximum number of file message publish retries. + */ +var FILE_PUBLISH_RETRY_LIMIT = 5; +/** + * Whether subscription event engine should be used or not. + */ +var ENABLE_EVENT_ENGINE = false; +/** + * Whether configured user presence state should be maintained by the PubNub client or not. + */ +var MAINTAIN_PRESENCE_STATE = true; +/** + * Whether PubNub client should try to utilize existing TCP connection for new requests or not. + */ +var KEEP_ALIVE = false; +/** + * Whether verbose logging should be enabled or not. + */ +var USE_VERBOSE_LOGGING = false; +/** + * Whether leave events should be suppressed or not. + */ +var SUPPRESS_LEAVE_EVENTS = false; +/** + * Whether heartbeat request failure should be announced or not. + */ +var ANNOUNCE_HEARTBEAT_FAILURE = true; +/** + * Whether heartbeat request success should be announced or not. + */ +var ANNOUNCE_HEARTBEAT_SUCCESS = false; +/** + * Whether PubNub client instance id should be added to the requests or not. + */ +var USE_INSTANCE_ID = false; +/** + * Whether unique identifier should be added to the request or not. + */ +var USE_REQUEST_ID = false; +/** + * Transactional requests timeout. + */ +var TRANSACTIONAL_REQUEST_TIMEOUT = 15; +/** + * Subscription request timeout. + */ +var SUBSCRIBE_REQUEST_TIMEOUT = 310; +/** + * Default user presence timeout. + */ +var PRESENCE_TIMEOUT = 300; +/** + * Minimum user presence timeout. + */ +var PRESENCE_TIMEOUT_MINIMUM = 20; +/** + * Apply configuration default values. + * + * @param configuration - User-provided configuration. + */ +var setDefaults = function (configuration) { + var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m; + // Copy configuration. + var configurationCopy = __assign({}, configuration); + (_a = configurationCopy.logVerbosity) !== null && _a !== void 0 ? _a : (configurationCopy.logVerbosity = USE_VERBOSE_LOGGING); + (_b = configurationCopy.ssl) !== null && _b !== void 0 ? _b : (configurationCopy.ssl = USE_SSL); + (_c = configurationCopy.transactionalRequestTimeout) !== null && _c !== void 0 ? _c : (configurationCopy.transactionalRequestTimeout = TRANSACTIONAL_REQUEST_TIMEOUT); + (_d = configurationCopy.subscribeRequestTimeout) !== null && _d !== void 0 ? _d : (configurationCopy.subscribeRequestTimeout = SUBSCRIBE_REQUEST_TIMEOUT); + (_e = configurationCopy.restore) !== null && _e !== void 0 ? _e : (configurationCopy.restore = RESTORE); + (_f = configurationCopy.useInstanceId) !== null && _f !== void 0 ? _f : (configurationCopy.useInstanceId = USE_INSTANCE_ID); + (_g = configurationCopy.suppressLeaveEvents) !== null && _g !== void 0 ? _g : (configurationCopy.suppressLeaveEvents = SUPPRESS_LEAVE_EVENTS); + (_h = configurationCopy.requestMessageCountThreshold) !== null && _h !== void 0 ? _h : (configurationCopy.requestMessageCountThreshold = DEDUPE_CACHE_SIZE); + (_j = configurationCopy.autoNetworkDetection) !== null && _j !== void 0 ? _j : (configurationCopy.autoNetworkDetection = AUTO_NETWORK_DETECTION); + (_k = configurationCopy.enableEventEngine) !== null && _k !== void 0 ? _k : (configurationCopy.enableEventEngine = ENABLE_EVENT_ENGINE); + (_l = configurationCopy.maintainPresenceState) !== null && _l !== void 0 ? _l : (configurationCopy.maintainPresenceState = MAINTAIN_PRESENCE_STATE); + (_m = configurationCopy.keepAlive) !== null && _m !== void 0 ? _m : (configurationCopy.keepAlive = KEEP_ALIVE); + // Generate default origin subdomains. + if (!configurationCopy.origin) + configurationCopy.origin = Array.from({ length: 20 }, function (_, i) { return "ps".concat(i + 1, ".pndsn.com"); }); + var keySet = { + subscribeKey: configurationCopy.subscribeKey, + publishKey: configurationCopy.publishKey, + secretKey: configurationCopy.secretKey, + }; + if (configurationCopy.presenceTimeout && configurationCopy.presenceTimeout < PRESENCE_TIMEOUT_MINIMUM) { + configurationCopy.presenceTimeout = PRESENCE_TIMEOUT_MINIMUM; + // eslint-disable-next-line no-console + console.log('WARNING: Presence timeout is less than the minimum. Using minimum value: ', PRESENCE_TIMEOUT_MINIMUM); + } + if (configurationCopy.presenceTimeout) { + configurationCopy.heartbeatInterval = configurationCopy.presenceTimeout / 2 - 1; + } + else + configurationCopy.presenceTimeout = PRESENCE_TIMEOUT; + // Apply extended configuration defaults. + var announceSuccessfulHeartbeats = ANNOUNCE_HEARTBEAT_SUCCESS; + var announceFailedHeartbeats = ANNOUNCE_HEARTBEAT_FAILURE; + var fileUploadPublishRetryLimit = FILE_PUBLISH_RETRY_LIMIT; + var dedupeOnSubscribe = DEDUPE_ON_SUBSCRIBE; + var maximumCacheSize = DEDUPE_CACHE_SIZE; + var useRequestId = USE_REQUEST_ID; + // @ts-expect-error Not documented legacy configuration options. + if (configurationCopy.dedupeOnSubscribe && typeof configurationCopy.dedupeOnSubscribe === 'boolean') { + // @ts-expect-error Not documented legacy configuration options. + dedupeOnSubscribe = configurationCopy.dedupeOnSubscribe; + } + // @ts-expect-error Not documented legacy configuration options. + if (configurationCopy.useRequestId && typeof configurationCopy.useRequestId === 'boolean') { + // @ts-expect-error Not documented legacy configuration options. + useRequestId = configurationCopy.useRequestId; + } + if ( + // @ts-expect-error Not documented legacy configuration options. + configurationCopy.announceSuccessfulHeartbeats && + // @ts-expect-error Not documented legacy configuration options. + typeof configurationCopy.announceSuccessfulHeartbeats === 'boolean') { + // @ts-expect-error Not documented legacy configuration options. + announceSuccessfulHeartbeats = configurationCopy.announceSuccessfulHeartbeats; + } + // @ts-expect-error Not documented legacy configuration options. + if (configurationCopy.announceFailedHeartbeats && typeof configurationCopy.announceFailedHeartbeats === 'boolean') { + // @ts-expect-error Not documented legacy configuration options. + announceFailedHeartbeats = configurationCopy.announceFailedHeartbeats; + } + if ( + // @ts-expect-error Not documented legacy configuration options. + configurationCopy.fileUploadPublishRetryLimit && + // @ts-expect-error Not documented legacy configuration options. + typeof configurationCopy.fileUploadPublishRetryLimit === 'number') { + // @ts-expect-error Not documented legacy configuration options. + fileUploadPublishRetryLimit = configurationCopy.fileUploadPublishRetryLimit; + } + return __assign(__assign({}, configurationCopy), { keySet: keySet, dedupeOnSubscribe: dedupeOnSubscribe, maximumCacheSize: maximumCacheSize, useRequestId: useRequestId, announceSuccessfulHeartbeats: announceSuccessfulHeartbeats, announceFailedHeartbeats: announceFailedHeartbeats, fileUploadPublishRetryLimit: fileUploadPublishRetryLimit }); +}; +exports.setDefaults = setDefaults; diff --git a/lib/core/interfaces/crypto-module.js b/lib/core/interfaces/crypto-module.js new file mode 100644 index 000000000..e7627af5c --- /dev/null +++ b/lib/core/interfaces/crypto-module.js @@ -0,0 +1,90 @@ +"use strict"; +/** + * Crypto module. + */ +var __read = (this && this.__read) || function (o, n) { + var m = typeof Symbol === "function" && o[Symbol.iterator]; + if (!m) return o; + var i = m.call(o), r, ar = [], e; + try { + while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); + } + catch (error) { e = { error: error }; } + finally { + try { + if (r && !r.done && (m = i["return"])) m.call(i); + } + finally { if (e) throw e.error; } + } + return ar; +}; +var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { + if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { + if (ar || !(i in from)) { + if (!ar) ar = Array.prototype.slice.call(from, 0, i); + ar[i] = from[i]; + } + } + return to.concat(ar || Array.prototype.slice.call(from)); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.AbstractCryptoModule = void 0; +var AbstractCryptoModule = /** @class */ (function () { + // endregion + function AbstractCryptoModule(configuration) { + var _a; + this.defaultCryptor = configuration.default; + this.cryptors = (_a = configuration.cryptors) !== null && _a !== void 0 ? _a : []; + } + // -------------------------------------------------------- + // --------------- Convenience functions ------------------ + // -------------------------------------------------------- + // region Convenience functions + /** + * Construct crypto module with legacy cryptor for encryption and both legacy and AES-CBC + * cryptors for decryption. + * + * @param config Cryptors configuration options. + * + * @returns Crypto module which encrypts data using legacy cryptor. + * + * @throws Error if `config.cipherKey` not set. + */ + AbstractCryptoModule.legacyCryptoModule = function (config) { + throw new Error('Should be implemented by concrete crypto module implementation.'); + }; + /** + * Construct crypto module with AES-CBC cryptor for encryption and both AES-CBC and legacy + * cryptors for decryption. + * + * @param config Cryptors configuration options. + * + * @returns Crypto module which encrypts data using AES-CBC cryptor. + * + * @throws Error if `config.cipherKey` not set. + */ + AbstractCryptoModule.aesCbcCryptoModule = function (config) { + throw new Error('Should be implemented by concrete crypto module implementation.'); + }; + // endregion + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + // region Helpers + /** + * Retrieve list of module's cryptors. + */ + AbstractCryptoModule.prototype.getAllCryptors = function () { + return __spreadArray([this.defaultCryptor], __read(this.cryptors), false); + }; + /** + * `String` to {@link ArrayBuffer} response decoder. + */ + AbstractCryptoModule.encoder = new TextEncoder(); + /** + * {@link ArrayBuffer} to {@link string} decoder. + */ + AbstractCryptoModule.decoder = new TextDecoder(); + return AbstractCryptoModule; +}()); +exports.AbstractCryptoModule = AbstractCryptoModule; diff --git a/lib/core/interfaces/cryptography.js b/lib/core/interfaces/cryptography.js new file mode 100644 index 000000000..23aacc798 --- /dev/null +++ b/lib/core/interfaces/cryptography.js @@ -0,0 +1,5 @@ +"use strict"; +/** + * Legacy Cryptography module interface. + */ +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/lib/core/components/_endpoint.js b/lib/core/interfaces/request.js similarity index 100% rename from lib/core/components/_endpoint.js rename to lib/core/interfaces/request.js diff --git a/lib/entities/common.js b/lib/core/interfaces/transport.js similarity index 100% rename from lib/entities/common.js rename to lib/core/interfaces/transport.js diff --git a/lib/core/pubnub-channel-groups.js b/lib/core/pubnub-channel-groups.js new file mode 100644 index 000000000..3a40a811a --- /dev/null +++ b/lib/core/pubnub-channel-groups.js @@ -0,0 +1,166 @@ +"use strict"; +/** + * PubNub Channel Groups API module. + */ +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var remove_channels_1 = require("./endpoints/channel_groups/remove_channels"); +var add_channels_1 = require("./endpoints/channel_groups/add_channels"); +var list_channels_1 = require("./endpoints/channel_groups/list_channels"); +var delete_group_1 = require("./endpoints/channel_groups/delete_group"); +var list_groups_1 = require("./endpoints/channel_groups/list_groups"); +var PubnubChannelGroups = /** @class */ (function () { + function PubnubChannelGroups(keySet, + /* eslint-disable @typescript-eslint/no-explicit-any */ + sendRequest) { + this.keySet = keySet; + this.sendRequest = sendRequest; + } + /** + * Fetch channel group channels. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get channel group channels response or `void` in case if `callback` + * provided. + */ + PubnubChannelGroups.prototype.listChannels = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new list_channels_1.ListChannelGroupChannels(__assign(__assign({}, parameters), { keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Fetch all channel groups. + * + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get all channel groups response or `void` in case if `callback` provided. + * + * @deprecated + */ + PubnubChannelGroups.prototype.listGroups = function (callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new list_groups_1.ListChannelGroupsRequest({ keySet: this.keySet }); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Add channels to the channel group. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous add channels to the channel group response or `void` in case if + * `callback` provided. + */ + PubnubChannelGroups.prototype.addChannels = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new add_channels_1.AddChannelGroupChannelsRequest(__assign(__assign({}, parameters), { keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Remove channels from the channel group. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous remove channels from the channel group response or `void` in + * case if `callback` provided. + */ + PubnubChannelGroups.prototype.removeChannels = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new remove_channels_1.RemoveChannelGroupChannelsRequest(__assign(__assign({}, parameters), { keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Remove channel group. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous remove channel group response or `void` in case if `callback` provided. + */ + PubnubChannelGroups.prototype.deleteGroup = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new delete_group_1.DeleteChannelGroupRequest(__assign(__assign({}, parameters), { keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + return PubnubChannelGroups; +}()); +exports.default = PubnubChannelGroups; diff --git a/lib/core/pubnub-common.js b/lib/core/pubnub-common.js index 9a145cdc7..a8e1e9353 100644 --- a/lib/core/pubnub-common.js +++ b/lib/core/pubnub-common.js @@ -33,16 +33,41 @@ var __importStar = (this && this.__importStar) || function (mod) { __setModuleDefault(result, mod); return result; }; -var __values = (this && this.__values) || function(o) { - var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; - if (m) return m.call(o); - if (o && typeof o.length === "number") return { - next: function () { - if (o && i >= o.length) o = void 0; - return { value: o && o[i++], done: !o }; - } - }; - throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } }; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; @@ -60,614 +85,1828 @@ var __read = (this && this.__read) || function (o, n) { } return ar; }; -var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { - if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { - if (ar || !(i in from)) { - if (!ar) ar = Array.prototype.slice.call(from, 0, i); - ar[i] = from[i]; - } - } - return to.concat(ar || Array.prototype.slice.call(from)); -}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -var config_1 = __importDefault(require("./components/config")); -var index_1 = __importDefault(require("./components/cryptography/index")); -var base64_codec_1 = require("./components/base64_codec"); -var subscription_manager_1 = __importDefault(require("./components/subscription_manager")); -var telemetry_manager_1 = __importDefault(require("./components/telemetry_manager")); +exports.PubNubCore = void 0; +// region Imports +// region Components +var listener_manager_1 = require("./components/listener_manager"); +var subscription_manager_1 = require("./components/subscription-manager"); var push_payload_1 = __importDefault(require("./components/push_payload")); -var listener_manager_1 = __importDefault(require("./components/listener_manager")); -var token_manager_1 = __importDefault(require("./components/token_manager")); -var endpoint_1 = __importDefault(require("./components/endpoint")); -var addChannelsChannelGroupConfig = __importStar(require("./endpoints/channel_groups/add_channels")); -var removeChannelsChannelGroupConfig = __importStar(require("./endpoints/channel_groups/remove_channels")); -var deleteChannelGroupConfig = __importStar(require("./endpoints/channel_groups/delete_group")); -var listChannelGroupsConfig = __importStar(require("./endpoints/channel_groups/list_groups")); -var listChannelsInChannelGroupConfig = __importStar(require("./endpoints/channel_groups/list_channels")); -var addPushChannelsConfig = __importStar(require("./endpoints/push/add_push_channels")); -var removePushChannelsConfig = __importStar(require("./endpoints/push/remove_push_channels")); -var listPushChannelsConfig = __importStar(require("./endpoints/push/list_push_channels")); -var removeDevicePushConfig = __importStar(require("./endpoints/push/remove_device")); -var presenceLeaveEndpointConfig = __importStar(require("./endpoints/presence/leave")); -var presenceWhereNowEndpointConfig = __importStar(require("./endpoints/presence/where_now")); -var presenceHeartbeatEndpointConfig = __importStar(require("./endpoints/presence/heartbeat")); -var presenceGetStateConfig = __importStar(require("./endpoints/presence/get_state")); -var presenceSetStateConfig = __importStar(require("./endpoints/presence/set_state")); -var presenceHereNowConfig = __importStar(require("./endpoints/presence/here_now")); -// Actions API -var addMessageActionEndpointConfig = __importStar(require("./endpoints/actions/add_message_action")); -var removeMessageActionEndpointConfig = __importStar(require("./endpoints/actions/remove_message_action")); -var getMessageActionEndpointConfig = __importStar(require("./endpoints/actions/get_message_actions")); -// File Upload API v1 -var list_files_1 = __importDefault(require("./endpoints/file_upload/list_files")); -var generate_upload_url_1 = __importDefault(require("./endpoints/file_upload/generate_upload_url")); -var publish_file_1 = __importDefault(require("./endpoints/file_upload/publish_file")); -var send_file_1 = __importDefault(require("./endpoints/file_upload/send_file")); -var get_file_url_1 = __importDefault(require("./endpoints/file_upload/get_file_url")); -var download_file_1 = __importDefault(require("./endpoints/file_upload/download_file")); -var delete_file_1 = __importDefault(require("./endpoints/file_upload/delete_file")); -// Object API v2 -var get_all_1 = __importDefault(require("./endpoints/objects/uuid/get_all")); -var get_1 = __importDefault(require("./endpoints/objects/uuid/get")); -var set_1 = __importDefault(require("./endpoints/objects/uuid/set")); -var remove_1 = __importDefault(require("./endpoints/objects/uuid/remove")); -var get_all_2 = __importDefault(require("./endpoints/objects/channel/get_all")); -var get_2 = __importDefault(require("./endpoints/objects/channel/get")); -var set_2 = __importDefault(require("./endpoints/objects/channel/set")); -var remove_2 = __importDefault(require("./endpoints/objects/channel/remove")); -var get_3 = __importDefault(require("./endpoints/objects/member/get")); -var set_3 = __importDefault(require("./endpoints/objects/member/set")); -var get_4 = __importDefault(require("./endpoints/objects/membership/get")); -var set_4 = __importDefault(require("./endpoints/objects/membership/set")); -var auditEndpointConfig = __importStar(require("./endpoints/access_manager/audit")); -var grantEndpointConfig = __importStar(require("./endpoints/access_manager/grant")); -var grantTokenEndpointConfig = __importStar(require("./endpoints/access_manager/grant_token")); -var revoke_token_1 = __importDefault(require("./endpoints/access_manager/revoke_token")); -var publishEndpointConfig = __importStar(require("./endpoints/publish")); -var signalEndpointConfig = __importStar(require("./endpoints/signal")); -var historyEndpointConfig = __importStar(require("./endpoints/history/get_history")); -var deleteMessagesEndpointConfig = __importStar(require("./endpoints/history/delete_messages")); -var messageCountsEndpointConfig = __importStar(require("./endpoints/history/message_counts")); -var fetchMessagesEndpointConfig = __importStar(require("./endpoints/fetch_messages")); -var timeEndpointConfig = __importStar(require("./endpoints/time")); -var subscribeEndpointConfig = __importStar(require("./endpoints/subscribe")); -// subscription utilities -var handshake_1 = __importDefault(require("./endpoints/subscriptionUtils/handshake")); -var receiveMessages_1 = __importDefault(require("./endpoints/subscriptionUtils/receiveMessages")); +var eventEmitter_1 = __importDefault(require("./components/eventEmitter")); +var base64_codec_1 = require("./components/base64_codec"); +var uuid_1 = __importDefault(require("./components/uuid")); +// endregion +// region Constants var operations_1 = __importDefault(require("./constants/operations")); var categories_1 = __importDefault(require("./constants/categories")); -var uuid_1 = __importDefault(require("./components/uuid")); -var event_engine_1 = require("../event-engine"); +// endregion +var PubNubError_1 = require("../models/PubNubError"); +// region Event Engine var presence_1 = require("../event-engine/presence/presence"); var retryPolicy_1 = require("../event-engine/core/retryPolicy"); -var eventEmitter_1 = __importDefault(require("./components/eventEmitter")); -var Channel_1 = require("../entities/Channel"); -var ChannelGroup_1 = require("../entities/ChannelGroup"); +var event_engine_1 = require("../event-engine"); +// endregion +// region Publish & Signal +var Publish = __importStar(require("./endpoints/publish")); +var Signal = __importStar(require("./endpoints/signal")); +// endregion +// region Subscription +var subscribe_1 = require("./endpoints/subscribe"); +var receiveMessages_1 = require("./endpoints/subscriptionUtils/receiveMessages"); +var handshake_1 = require("./endpoints/subscriptionUtils/handshake"); +// endregion +// region Presence +var get_state_1 = require("./endpoints/presence/get_state"); +var set_state_1 = require("./endpoints/presence/set_state"); +var heartbeat_1 = require("./endpoints/presence/heartbeat"); +var leave_1 = require("./endpoints/presence/leave"); +var where_now_1 = require("./endpoints/presence/where_now"); +var here_now_1 = require("./endpoints/presence/here_now"); +// endregion +// region Message Storage +var delete_messages_1 = require("./endpoints/history/delete_messages"); +var message_counts_1 = require("./endpoints/history/message_counts"); +var get_history_1 = require("./endpoints/history/get_history"); +var fetch_messages_1 = require("./endpoints/fetch_messages"); +// endregion +// region Message Actions +var get_message_actions_1 = require("./endpoints/actions/get_message_actions"); +var add_message_action_1 = require("./endpoints/actions/add_message_action"); +var remove_message_action_1 = require("./endpoints/actions/remove_message_action"); +// endregion +// region File sharing +var publish_file_1 = require("./endpoints/file_upload/publish_file"); +var get_file_url_1 = require("./endpoints/file_upload/get_file_url"); +var delete_file_1 = require("./endpoints/file_upload/delete_file"); +var list_files_1 = require("./endpoints/file_upload/list_files"); +var send_file_1 = require("./endpoints/file_upload/send_file"); +// endregion +// region PubNub Access Manager +var revoke_token_1 = require("./endpoints/access_manager/revoke_token"); +var grant_token_1 = require("./endpoints/access_manager/grant_token"); +var grant_1 = require("./endpoints/access_manager/grant"); +var audit_1 = require("./endpoints/access_manager/audit"); var ChannelMetadata_1 = require("../entities/ChannelMetadata"); -var UserMetadata_1 = require("../entities/UserMetadata"); var SubscriptionSet_1 = require("../entities/SubscriptionSet"); -var default_1 = /** @class */ (function () { - function default_1(setup) { +var ChannelGroup_1 = require("../entities/ChannelGroup"); +var UserMetadata_1 = require("../entities/UserMetadata"); +var Channel_1 = require("../entities/Channel"); +// endregion +// region Channel Groups +var pubnub_channel_groups_1 = __importDefault(require("./pubnub-channel-groups")); +// endregion +// region Push Notifications +var pubnub_push_1 = __importDefault(require("./pubnub-push")); +var pubnub_objects_1 = __importDefault(require("./pubnub-objects")); +// endregion +// region Time +var Time = __importStar(require("./endpoints/time")); +// endregion +var utils_1 = require("./utils"); +var download_file_1 = require("./endpoints/file_upload/download_file"); +// endregion +/** + * Platform-agnostic PubNub client core. + */ +var PubNubCore = /** @class */ (function () { + // endregion + function PubNubCore(configuration) { var _this = this; - var networking = setup.networking, cbor = setup.cbor; - var config = new config_1.default({ setup: setup }); - this._config = config; - var crypto = new index_1.default({ config: config }); // LEGACY - var cryptography = setup.cryptography; - networking.init(config); - var tokenManager = new token_manager_1.default(config, cbor); - this._tokenManager = tokenManager; - var telemetryManager = new telemetry_manager_1.default({ - maximumSamplesCount: 60000, - }); - this._telemetryManager = telemetryManager; - var cryptoModule = this._config.cryptoModule; - var modules = { - config: config, - networking: networking, - crypto: crypto, - cryptography: cryptography, - tokenManager: tokenManager, - telemetryManager: telemetryManager, - PubNubFile: setup.PubNubFile, - cryptoModule: cryptoModule, - }; - this.File = setup.PubNubFile; - this.encryptFile = function (key, file) { - if (arguments.length == 1 && typeof key != 'string' && modules.cryptoModule) { - file = key; - return modules.cryptoModule.encryptFile(file, this.File); - } - return cryptography.encryptFile(key, file, this.File); - }; - this.decryptFile = function (key, file) { - if (arguments.length == 1 && typeof key != 'string' && modules.cryptoModule) { - file = key; - return modules.cryptoModule.decryptFile(file, this.File); - } - return cryptography.decryptFile(key, file, this.File); - }; - var timeEndpoint = endpoint_1.default.bind(this, modules, timeEndpointConfig); - var leaveEndpoint = endpoint_1.default.bind(this, modules, presenceLeaveEndpointConfig); - var heartbeatEndpoint = endpoint_1.default.bind(this, modules, presenceHeartbeatEndpointConfig); - var setStateEndpoint = endpoint_1.default.bind(this, modules, presenceSetStateConfig); - var subscribeEndpoint = endpoint_1.default.bind(this, modules, subscribeEndpointConfig); - // managers - var listenerManager = new listener_manager_1.default(); - this._listenerManager = listenerManager; - this.iAmHere = endpoint_1.default.bind(this, modules, presenceHeartbeatEndpointConfig); - this.iAmAway = endpoint_1.default.bind(this, modules, presenceLeaveEndpointConfig); - this.setPresenceState = endpoint_1.default.bind(this, modules, presenceSetStateConfig); - this.handshake = endpoint_1.default.bind(this, modules, handshake_1.default); - this.receiveMessages = endpoint_1.default.bind(this, modules, receiveMessages_1.default); - this._eventEmitter = new eventEmitter_1.default({ - modules: modules, - listenerManager: this._listenerManager, - getFileUrl: function (params) { return (0, get_file_url_1.default)(modules, params); }, - }); - if (config.enableEventEngine === true) { - if (config.maintainPresenceState) { - this.presenceState = {}; - this.setState = function (args) { - var _a, _b; - (_a = args.channels) === null || _a === void 0 ? void 0 : _a.forEach(function (channel) { return (_this.presenceState[channel] = args.state); }); - (_b = args.channelGroups) === null || _b === void 0 ? void 0 : _b.forEach(function (group) { return (_this.presenceState[group] = args.state); }); - return _this.setPresenceState({ - channels: args.channels, - channelGroups: args.channelGroups, - state: _this.presenceState, - }); - }; - } - if (config.getHeartbeatInterval()) { - var presenceEventEngine = new presence_1.PresenceEventEngine({ - heartbeat: this.iAmHere, - leave: this.iAmAway, + var _a, _b, _c; + this._configuration = configuration.configuration; + this.cryptography = configuration.cryptography; + this.tokenManager = configuration.tokenManager; + this.transport = configuration.transport; + this.crypto = configuration.crypto; + // API group entry points initialization. + this._objects = new pubnub_objects_1.default(this._configuration, this.sendRequest); + this._channelGroups = new pubnub_channel_groups_1.default(this._configuration.keySet, this.sendRequest); + this._push = new pubnub_push_1.default(this._configuration.keySet, this.sendRequest); + // Prepare for real-time events announcement. + this.listenerManager = new listener_manager_1.ListenerManager(); + this.eventEmitter = new eventEmitter_1.default(this.listenerManager); + if (this._configuration.enableEventEngine) { + var heartbeatInterval_1 = this._configuration.getHeartbeatInterval(); + this.presenceState = {}; + if (heartbeatInterval_1) { + this.presenceEventEngine = new presence_1.PresenceEventEngine({ + heartbeat: this.heartbeat, + leave: this.unsubscribe, heartbeatDelay: function () { - return new Promise(function (resolve) { return setTimeout(resolve, modules.config.getHeartbeatInterval() * 1000); }); + return new Promise(function (resolve, reject) { + heartbeatInterval_1 = _this._configuration.getHeartbeatInterval(); + if (!heartbeatInterval_1) + reject(new PubNubError_1.PubNubError('Heartbeat interval has been reset.')); + else + setTimeout(resolve, heartbeatInterval_1 * 1000); + }); }, retryDelay: function (amount) { return new Promise(function (resolve) { return setTimeout(resolve, amount); }); }, - config: modules.config, + emitStatus: function (status) { return _this.listenerManager.announceStatus(status); }, + config: this._configuration, presenceState: this.presenceState, - emitStatus: function (status) { - listenerManager.announceStatus(status); - }, }); - this.presenceEventEngine = presenceEventEngine; - this.join = this.presenceEventEngine.join.bind(presenceEventEngine); - this.leave = this.presenceEventEngine.leave.bind(presenceEventEngine); - this.leaveAll = this.presenceEventEngine.leaveAll.bind(presenceEventEngine); } - var eventEngine = new event_engine_1.EventEngine({ - handshake: this.handshake, - receiveMessages: this.receiveMessages, + this.eventEngine = new event_engine_1.EventEngine({ + handshake: this.subscribeHandshake, + receiveMessages: this.subscribeReceiveMessages, delay: function (amount) { return new Promise(function (resolve) { return setTimeout(resolve, amount); }); }, - join: this.join, - leave: this.leave, - leaveAll: this.leaveAll, + join: (_a = this.presenceEventEngine) === null || _a === void 0 ? void 0 : _a.join, + leave: (_b = this.presenceEventEngine) === null || _b === void 0 ? void 0 : _b.leave, + leaveAll: (_c = this.presenceEventEngine) === null || _c === void 0 ? void 0 : _c.leaveAll, presenceState: this.presenceState, - config: modules.config, - emitMessages: function (events) { - var e_1, _a; - try { - for (var events_1 = __values(events), events_1_1 = events_1.next(); !events_1_1.done; events_1_1 = events_1.next()) { - var event_1 = events_1_1.value; - _this._eventEmitter.emitEvent(event_1); - } - } - catch (e_1_1) { e_1 = { error: e_1_1 }; } - finally { - try { - if (events_1_1 && !events_1_1.done && (_a = events_1.return)) _a.call(events_1); - } - finally { if (e_1) throw e_1.error; } - } - }, - emitStatus: function (status) { - listenerManager.announceStatus(status); - }, - }); - this.subscribe = eventEngine.subscribe.bind(eventEngine); - this.unsubscribe = eventEngine.unsubscribe.bind(eventEngine); - this.unsubscribeAll = eventEngine.unsubscribeAll.bind(eventEngine); - this.reconnect = eventEngine.reconnect.bind(eventEngine); - this.disconnect = eventEngine.disconnect.bind(eventEngine); - this.destroy = eventEngine.dispose.bind(eventEngine); - this.getSubscribedChannels = eventEngine.getSubscribedChannels.bind(eventEngine); - this.getSubscribedChannelGroups = eventEngine.getSubscribedChannelGroups.bind(eventEngine); - this.eventEngine = eventEngine; + config: this._configuration, + emitMessages: function (events) { return events.forEach(function (event) { return _this.eventEmitter.emitEvent(event); }); }, + emitStatus: function (status) { return _this.listenerManager.announceStatus(status); }, + }); } else { - var subscriptionManager_1 = new subscription_manager_1.default({ - timeEndpoint: timeEndpoint, - leaveEndpoint: leaveEndpoint, - heartbeatEndpoint: heartbeatEndpoint, - setStateEndpoint: setStateEndpoint, - subscribeEndpoint: subscribeEndpoint, - crypto: modules.crypto, - config: modules.config, - listenerManager: listenerManager, - getFileUrl: function (params) { return (0, get_file_url_1.default)(modules, params); }, - cryptoModule: modules.cryptoModule, - eventEmitter: this._eventEmitter, - }); - this.subscribe = subscriptionManager_1.adaptSubscribeChange.bind(subscriptionManager_1); - this.unsubscribe = subscriptionManager_1.adaptUnsubscribeChange.bind(subscriptionManager_1); - this.disconnect = subscriptionManager_1.disconnect.bind(subscriptionManager_1); - this.reconnect = subscriptionManager_1.reconnect.bind(subscriptionManager_1); - this.unsubscribeAll = subscriptionManager_1.unsubscribeAll.bind(subscriptionManager_1); - this.getSubscribedChannels = subscriptionManager_1.getSubscribedChannels.bind(subscriptionManager_1); - this.getSubscribedChannelGroups = subscriptionManager_1.getSubscribedChannelGroups.bind(subscriptionManager_1); - this.setState = subscriptionManager_1.adaptStateChange.bind(subscriptionManager_1); - this.presence = subscriptionManager_1.adaptPresenceChange.bind(subscriptionManager_1); - this.destroy = function (isOffline) { - subscriptionManager_1.unsubscribeAll(isOffline); - subscriptionManager_1.disconnect(); - }; + this.subscriptionManager = new subscription_manager_1.SubscriptionManager(this._configuration, this.listenerManager, this.eventEmitter, this.makeSubscribe, this.heartbeat, this.makeUnsubscribe, this.time); } - this.addListener = this._eventEmitter.addListener.bind(this._eventEmitter); - this.removeListener = this._eventEmitter.removeListener.bind(this._eventEmitter); - this.removeAllListeners = this._eventEmitter.removeAllListeners.bind(this._eventEmitter); - this.parseToken = tokenManager.parseToken.bind(tokenManager); - this.setToken = tokenManager.setToken.bind(tokenManager); - this.getToken = tokenManager.getToken.bind(tokenManager); - /* channel groups */ - this.channelGroups = { - listGroups: endpoint_1.default.bind(this, modules, listChannelGroupsConfig), - listChannels: endpoint_1.default.bind(this, modules, listChannelsInChannelGroupConfig), - addChannels: endpoint_1.default.bind(this, modules, addChannelsChannelGroupConfig), - removeChannels: endpoint_1.default.bind(this, modules, removeChannelsChannelGroupConfig), - deleteGroup: endpoint_1.default.bind(this, modules, deleteChannelGroupConfig), - }; - /* push */ - this.push = { - addChannels: endpoint_1.default.bind(this, modules, addPushChannelsConfig), - removeChannels: endpoint_1.default.bind(this, modules, removePushChannelsConfig), - deleteDevice: endpoint_1.default.bind(this, modules, removeDevicePushConfig), - listChannels: endpoint_1.default.bind(this, modules, listPushChannelsConfig), - }; - /* presence */ - this.hereNow = endpoint_1.default.bind(this, modules, presenceHereNowConfig); - this.whereNow = endpoint_1.default.bind(this, modules, presenceWhereNowEndpointConfig); - this.getState = endpoint_1.default.bind(this, modules, presenceGetStateConfig); - /* PAM */ - this.grant = endpoint_1.default.bind(this, modules, grantEndpointConfig); - this.grantToken = endpoint_1.default.bind(this, modules, grantTokenEndpointConfig); - this.audit = endpoint_1.default.bind(this, modules, auditEndpointConfig); - this.revokeToken = endpoint_1.default.bind(this, modules, revoke_token_1.default); - this.publish = endpoint_1.default.bind(this, modules, publishEndpointConfig); - this.fire = function (args, callback) { - args.replicate = false; - args.storeInHistory = false; - return _this.publish(args, callback); - }; - this.signal = endpoint_1.default.bind(this, modules, signalEndpointConfig); - this.history = endpoint_1.default.bind(this, modules, historyEndpointConfig); - this.deleteMessages = endpoint_1.default.bind(this, modules, deleteMessagesEndpointConfig); - this.messageCounts = endpoint_1.default.bind(this, modules, messageCountsEndpointConfig); - this.fetchMessages = endpoint_1.default.bind(this, modules, fetchMessagesEndpointConfig); - // Actions API - this.addMessageAction = endpoint_1.default.bind(this, modules, addMessageActionEndpointConfig); - this.removeMessageAction = endpoint_1.default.bind(this, modules, removeMessageActionEndpointConfig); - this.getMessageActions = endpoint_1.default.bind(this, modules, getMessageActionEndpointConfig); - // File Upload API v1 - this.listFiles = endpoint_1.default.bind(this, modules, list_files_1.default); - var generateUploadUrl = endpoint_1.default.bind(this, modules, generate_upload_url_1.default); - this.publishFile = endpoint_1.default.bind(this, modules, publish_file_1.default); - this.sendFile = (0, send_file_1.default)({ - generateUploadUrl: generateUploadUrl, - publishFile: this.publishFile, - modules: modules, - }); - this.getFileUrl = function (params) { return (0, get_file_url_1.default)(modules, params); }; - this.downloadFile = endpoint_1.default.bind(this, modules, download_file_1.default); - this.deleteFile = endpoint_1.default.bind(this, modules, delete_file_1.default); - // entities - this.channel = function (name) { return new Channel_1.Channel(name, _this._eventEmitter, _this); }; - this.channelGroup = function (name) { return new ChannelGroup_1.ChannelGroup(name, _this._eventEmitter, _this); }; - this.channelMetadata = function (id) { return new ChannelMetadata_1.ChannelMetadata(id, _this._eventEmitter, _this); }; - this.userMetadata = function (id) { return new UserMetadata_1.UserMetadata(id, _this._eventEmitter, _this); }; - this.subscriptionSet = function (args) { - return new SubscriptionSet_1.SubscriptionSet({ - channels: args.channels, - channelGroups: args.channelGroups, - subscriptionOptions: args.subscriptionOptions, - eventEmitter: _this._eventEmitter, - pubnub: _this, - }); - }; - // Objects API v2 - this.objects = { - getAllUUIDMetadata: endpoint_1.default.bind(this, modules, get_all_1.default), - getUUIDMetadata: endpoint_1.default.bind(this, modules, get_1.default), - setUUIDMetadata: endpoint_1.default.bind(this, modules, set_1.default), - removeUUIDMetadata: endpoint_1.default.bind(this, modules, remove_1.default), - getAllChannelMetadata: endpoint_1.default.bind(this, modules, get_all_2.default), - getChannelMetadata: endpoint_1.default.bind(this, modules, get_2.default), - setChannelMetadata: endpoint_1.default.bind(this, modules, set_2.default), - removeChannelMetadata: endpoint_1.default.bind(this, modules, remove_2.default), - getChannelMembers: endpoint_1.default.bind(this, modules, get_3.default), - setChannelMembers: function (parameters) { - var rest = []; - for (var _i = 1; _i < arguments.length; _i++) { - rest[_i - 1] = arguments[_i]; - } - return endpoint_1.default.call.apply(endpoint_1.default, __spreadArray([_this, - modules, - set_3.default, __assign({ type: 'set' }, parameters)], __read(rest), false)); - }, - removeChannelMembers: function (parameters) { - var rest = []; - for (var _i = 1; _i < arguments.length; _i++) { - rest[_i - 1] = arguments[_i]; + } + /** + * Construct notification payload which will trigger push notification. + * + * @param title - Title which will be shown on notification. + * @param body - Payload which will be sent as part of notification. + * + * @returns Pre-formatted message payload which will trigger push notification. + */ + PubNubCore.notificationPayload = function (title, body) { + return new push_payload_1.default(title, body); + }; + /** + * Generate unique identifier. + * + * @returns Unique identifier. + */ + PubNubCore.generateUUID = function () { + return uuid_1.default.createUUID(); + }; + Object.defineProperty(PubNubCore.prototype, "configuration", { + // -------------------------------------------------------- + // -------------------- Configuration ---------------------- + // -------------------------------------------------------- + // region Configuration + /** + * PubNub client configuration. + * + * @returns Currently user PubNub client configuration. + */ + get: function () { + return this._configuration; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(PubNubCore.prototype, "_config", { + /** + * Current PubNub client configuration. + * + * @returns Currently user PubNub client configuration. + * + * @deprecated Use {@link configuration} getter instead. + */ + get: function () { + return this.configuration; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(PubNubCore.prototype, "authKey", { + /** + * REST API endpoint access authorization key. + * + * It is required to have `authorization key` with required permissions to access REST API + * endpoints when `PAM` enabled for user key set. + */ + get: function () { + var _a; + return (_a = this._configuration.authKey) !== null && _a !== void 0 ? _a : undefined; + }, + enumerable: false, + configurable: true + }); + /** + * REST API endpoint access authorization key. + * + * It is required to have `authorization key` with required permissions to access REST API + * endpoints when `PAM` enabled for user key set. + */ + PubNubCore.prototype.getAuthKey = function () { + return this.authKey; + }; + /** + * Change REST API endpoint access authorization key. + * + * @param authKey - New authorization key which should be used with new requests. + */ + PubNubCore.prototype.setAuthKey = function (authKey) { + this._configuration.setAuthKey(authKey); + }; + Object.defineProperty(PubNubCore.prototype, "userId", { + /** + * Get a PubNub client user identifier. + * + * @returns Current PubNub client user identifier. + */ + get: function () { + return this._configuration.userId; + }, + /** + * Change the current PubNub client user identifier. + * + * **Important:** Change won't affect ongoing REST API calls. + * + * @param value - New PubNub client user identifier. + * + * @throws Error empty user identifier has been provided. + */ + set: function (value) { + this._configuration.userId = value; + }, + enumerable: false, + configurable: true + }); + /** + * Get a PubNub client user identifier. + * + * @returns Current PubNub client user identifier. + */ + PubNubCore.prototype.getUserId = function () { + return this._configuration.userId; + }; + /** + * Change the current PubNub client user identifier. + * + * **Important:** Change won't affect ongoing REST API calls. + * + * @param value - New PubNub client user identifier. + * + * @throws Error empty user identifier has been provided. + */ + PubNubCore.prototype.setUserId = function (value) { + this._configuration.userId = value; + }; + Object.defineProperty(PubNubCore.prototype, "filterExpression", { + /** + * Real-time updates filtering expression. + * + * @returns Filtering expression. + */ + get: function () { + var _a; + return (_a = this._configuration.getFilterExpression()) !== null && _a !== void 0 ? _a : undefined; + }, + /** + * Update real-time updates filtering expression. + * + * @param expression - New expression which should be used or `undefined` to disable filtering. + */ + set: function (expression) { + this._configuration.setFilterExpression(expression); + }, + enumerable: false, + configurable: true + }); + /** + * Real-time updates filtering expression. + * + * @returns Filtering expression. + */ + PubNubCore.prototype.getFilterExpression = function () { + return this.filterExpression; + }; + /** + * Update real-time updates filtering expression. + * + * @param expression - New expression which should be used or `undefined` to disable filtering. + */ + PubNubCore.prototype.setFilterExpression = function (expression) { + this.filterExpression = expression; + }; + Object.defineProperty(PubNubCore.prototype, "cipherKey", { + /** + * Dta encryption / decryption key. + * + * @returns Currently used key for data encryption / decryption. + */ + get: function () { + return this._configuration.cipherKey; + }, + /** + * Change data encryption / decryption key. + * + * @param key - New key which should be used for data encryption / decryption. + */ + set: function (key) { + this._configuration.setCipherKey(key); + }, + enumerable: false, + configurable: true + }); + /** + * Change data encryption / decryption key. + * + * @param key - New key which should be used for data encryption / decryption. + */ + PubNubCore.prototype.setCipherKey = function (key) { + this.cipherKey = key; + }; + Object.defineProperty(PubNubCore.prototype, "heartbeatInterval", { + /** + * Change heartbeat requests interval. + * + * @param interval - New presence request heartbeat intervals. + */ + set: function (interval) { + this._configuration.setHeartbeatInterval(interval); + }, + enumerable: false, + configurable: true + }); + /** + * Change heartbeat requests interval. + * + * @param interval - New presence request heartbeat intervals. + */ + PubNubCore.prototype.setHeartbeatInterval = function (interval) { + this.heartbeatInterval = interval; + }; + /** + * Get PubNub SDK version. + * + * @returns Current SDK version. + */ + PubNubCore.prototype.getVersion = function () { + return this._configuration.version; + }; + /** + * Add framework's prefix. + * + * @param name - Name of the framework which would want to add own data into `pnsdk` suffix. + * @param suffix - Suffix with information about framework. + */ + PubNubCore.prototype._addPnsdkSuffix = function (name, suffix) { + this._configuration._addPnsdkSuffix(name, suffix); + }; + // -------------------------------------------------------- + // ---------------------- Deprecated ---------------------- + // -------------------------------------------------------- + // region Deprecated + /** + * Get a PubNub client user identifier. + * + * @returns Current PubNub client user identifier. + * + * @deprecated Use the {@link getUserId} or {@link userId} getter instead. + */ + PubNubCore.prototype.getUUID = function () { + return this.userId; + }; + /** + * Change the current PubNub client user identifier. + * + * **Important:** Change won't affect ongoing REST API calls. + * + * @param value - New PubNub client user identifier. + * + * @throws Error empty user identifier has been provided. + * + * @deprecated Use the {@link PubNubCore#setUserId} or {@link PubNubCore#userId} setter instead. + */ + PubNubCore.prototype.setUUID = function (value) { + this.userId = value; + }; + Object.defineProperty(PubNubCore.prototype, "customEncrypt", { + /** + * Custom data encryption method. + * + * @deprecated Instead use {@link cryptoModule} for data encryption. + */ + get: function () { + return this._configuration.customEncrypt; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(PubNubCore.prototype, "customDecrypt", { + /** + * Custom data decryption method. + * + * @deprecated Instead use {@link cryptoModule} for data decryption. + */ + get: function () { + return this._configuration.customDecrypt; + }, + enumerable: false, + configurable: true + }); + // endregion + // endregion + // -------------------------------------------------------- + // ---------------------- Entities ------------------------ + // -------------------------------------------------------- + // region Entities + /** + * Create a `Channel` entity. + * + * Entity can be used for the interaction with the following API: + * - `subscribe` + * + * @param name - Unique channel name. + * @returns `Channel` entity. + */ + PubNubCore.prototype.channel = function (name) { + return new Channel_1.Channel(name, this.eventEmitter, this); + }; + /** + * Create a `ChannelGroup` entity. + * + * Entity can be used for the interaction with the following API: + * - `subscribe` + * + * @param name - Unique channel group name. + * @returns `ChannelGroup` entity. + */ + PubNubCore.prototype.channelGroup = function (name) { + return new ChannelGroup_1.ChannelGroup(name, this.eventEmitter, this); + }; + /** + * Create a `ChannelMetadata` entity. + * + * Entity can be used for the interaction with the following API: + * - `subscribe` + * + * @param id - Unique channel metadata object identifier. + * @returns `ChannelMetadata` entity. + */ + PubNubCore.prototype.channelMetadata = function (id) { + return new ChannelMetadata_1.ChannelMetadata(id, this.eventEmitter, this); + }; + /** + * Create a `UserMetadata` entity. + * + * Entity can be used for the interaction with the following API: + * - `subscribe` + * + * @param id - Unique user metadata object identifier. + * @returns `UserMetadata` entity. + */ + PubNubCore.prototype.userMetadata = function (id) { + return new UserMetadata_1.UserMetadata(id, this.eventEmitter, this); + }; + /** + * Create subscriptions set object. + * + * @param parameters - Subscriptions set configuration parameters. + */ + PubNubCore.prototype.subscriptionSet = function (parameters) { + return new SubscriptionSet_1.SubscriptionSet(__assign(__assign({}, parameters), { eventEmitter: this.eventEmitter, pubnub: this })); + }; + /** + * Schedule request execution. + * + * @param request - REST API request. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous request execution and response parsing result or `void` in case if + * `callback` provided. + * + * @throws PubNubError in case of request processing error. + */ + PubNubCore.prototype.sendRequest = function (request, callback) { + return __awaiter(this, void 0, void 0, function () { + var validationResult, transportRequest, status, _a, sendableRequest, cancellationController; + return __generator(this, function (_b) { + validationResult = request.validate(); + if (validationResult) { + if (callback) + return [2 /*return*/, callback((0, PubNubError_1.createValidationError)(validationResult), null)]; + throw new PubNubError_1.PubNubError('Validation failed, check status for details', (0, PubNubError_1.createValidationError)(validationResult)); } - return endpoint_1.default.call.apply(endpoint_1.default, __spreadArray([_this, - modules, - set_3.default, __assign({ type: 'delete' }, parameters)], __read(rest), false)); - }, - getMemberships: endpoint_1.default.bind(this, modules, get_4.default), - setMemberships: function (parameters) { - var rest = []; - for (var _i = 1; _i < arguments.length; _i++) { - rest[_i - 1] = arguments[_i]; + transportRequest = request.request(); + if (transportRequest.body && + typeof transportRequest.body === 'object' && + 'toArrayBuffer' in transportRequest.body) { + // Set 300 seconds file upload request delay. + transportRequest.timeout = 300; } - return endpoint_1.default.call.apply(endpoint_1.default, __spreadArray([_this, - modules, - set_4.default, __assign({ type: 'set' }, parameters)], __read(rest), false)); - }, - removeMemberships: function (parameters) { - var rest = []; - for (var _i = 1; _i < arguments.length; _i++) { - rest[_i - 1] = arguments[_i]; + else { + if (request.operation() === operations_1.default.PNSubscribeOperation) + transportRequest.timeout = this._configuration.getSubscribeTimeout(); + else + transportRequest.timeout = this._configuration.getTransactionTimeout(); } - return endpoint_1.default.call.apply(endpoint_1.default, __spreadArray([_this, - modules, - set_4.default, __assign({ type: 'delete' }, parameters)], __read(rest), false)); - }, - }; - // User Apis - this.createUser = function (args) { - return _this.objects.setUUIDMetadata({ - uuid: args.userId, - data: args.data, - include: args.include, - }); - }; - this.updateUser = this.createUser; - this.removeUser = function (args) { - return _this.objects.removeUUIDMetadata({ - uuid: args === null || args === void 0 ? void 0 : args.userId, - }); - }; - this.fetchUser = function (args) { - return _this.objects.getUUIDMetadata({ - uuid: args === null || args === void 0 ? void 0 : args.userId, - include: args === null || args === void 0 ? void 0 : args.include, - }); - }; - this.fetchUsers = this.objects.getAllUUIDMetadata; - // Space apis - this.createSpace = function (args) { - return _this.objects.setChannelMetadata({ - channel: args.spaceId, - data: args.data, - include: args.include, - }); - }; - this.updateSpace = this.createSpace; - this.removeSpace = function (args) { - return _this.objects.removeChannelMetadata({ - channel: args.spaceId, - }); - }; - this.fetchSpace = function (args) { - return _this.objects.getChannelMetadata({ - channel: args.spaceId, - include: args.include, - }); - }; - this.fetchSpaces = this.objects.getAllChannelMetadata; - // Membership apis - this.addMemberships = function (parameters) { - var _a, _b; - if (typeof parameters.spaceId === 'string') { - return _this.objects.setChannelMembers({ - channel: parameters.spaceId, - uuids: (_a = parameters.users) === null || _a === void 0 ? void 0 : _a.map(function (user) { - if (typeof user === 'string') { - return user; - } - return { - id: user.userId, - custom: user.custom, - status: user.status, - }; - }), - limit: 0, - }); - } - else { - return _this.objects.setMemberships({ - uuid: parameters.userId, - channels: (_b = parameters.spaces) === null || _b === void 0 ? void 0 : _b.map(function (space) { - if (typeof space === 'string') { - return space; - } - return { - id: space.spaceId, - custom: space.custom, - status: space.status, - }; - }), - limit: 0, - }); - } - }; - this.updateMemberships = this.addMemberships; - this.removeMemberships = function (parameters) { - if (typeof parameters.spaceId === 'string') { - return _this.objects.removeChannelMembers({ - channel: parameters.spaceId, - uuids: parameters.userIds, - limit: 0, + status = { + error: false, + operation: request.operation(), + statusCode: 0, + }; + _a = __read(this.transport.makeSendable(transportRequest), 2), sendableRequest = _a[0], cancellationController = _a[1]; + /** + * **Important:** Because of multiple environments where JS SDK can be used control over + * cancellation had to be inverted to let transport provider solve request cancellation task + * more efficiently. As result, cancellation controller can be retrieved and used only after + * request will be scheduled by transport provider. + */ + request.cancellationController = cancellationController ? cancellationController : null; + return [2 /*return*/, sendableRequest + .then(function (response) { + status.statusCode = response.status; + return request.parse(response); + }) + .then(function (parsed) { + // Notify callback (if possible). + if (callback) + return callback(status, parsed); + return parsed; + }) + .catch(function (error) { + var errorStatus = error.toStatus(request.operation()); + // Notify callback (if possible). + if (callback) + callback(errorStatus, null); + throw new PubNubError_1.PubNubError('REST API request processing error, check status for details', errorStatus); + })]; + }); + }); + }; + /** + * Unsubscribe from all channels and groups. + * + * @param isOffline - Whether `offline` presence should be notified or not. + */ + PubNubCore.prototype.destroy = function (isOffline) { + if (this.subscriptionManager) { + this.subscriptionManager.unsubscribeAll(isOffline); + this.subscriptionManager.disconnect(); + } + else if (this.eventEngine) + this.eventEngine.dispose(); + }; + // endregion + // -------------------------------------------------------- + // ----------------------- Listener ----------------------- + // -------------------------------------------------------- + // region Listener + /** + * Register real-time events listener. + * + * @param listener - Listener with event callbacks to handle different types of events. + */ + PubNubCore.prototype.addListener = function (listener) { + this.listenerManager.addListener(listener); + }; + /** + * Remove real-time event listener. + * + * @param listener - Event listeners which should be removed. + */ + PubNubCore.prototype.removeListener = function (listener) { + this.listenerManager.removeListener(listener); + }; + /** + * Clear all real-time event listeners. + */ + PubNubCore.prototype.removeAllListeners = function () { + this.listenerManager.removeAllListeners(); + }; + /** + * Publish data to a specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous publish data response or `void` in case if `callback` provided. + */ + PubNubCore.prototype.publish = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new Publish.PublishRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet, crypto: this._configuration.cryptoModule })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Signal data to a specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous signal data response or `void` in case if `callback` provided. + */ + PubNubCore.prototype.signal = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new Signal.SignalRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * `Fire` a data to a specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous signal data response or `void` in case if `callback` provided. + * + * @deprecated Use {@link publish} method instead. + */ + PubNubCore.prototype.fire = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + callback !== null && callback !== void 0 ? callback : (callback = function () { }); + return [2 /*return*/, this.publish(__assign(__assign({}, parameters), { replicate: false, storeInHistory: false }), callback)]; + }); + }); + }; + // endregion + // -------------------------------------------------------- + // -------------------- Subscribe API --------------------- + // -------------------------------------------------------- + // region Subscribe API + /** + * Get list of channels on which PubNub client currently subscribed. + * + * @returns List of active channels. + */ + PubNubCore.prototype.getSubscribedChannels = function () { + if (this.subscriptionManager) + return this.subscriptionManager.subscribedChannels; + else if (this.eventEngine) + return this.eventEngine.getSubscribedChannels(); + return []; + }; + /** + * Get list of channel groups on which PubNub client currently subscribed. + * + * @returns List of active channel groups. + */ + PubNubCore.prototype.getSubscribedChannelGroups = function () { + if (this.subscriptionManager) + return this.subscriptionManager.subscribedChannelGroups; + else if (this.eventEngine) + return this.eventEngine.getSubscribedChannelGroups(); + return []; + }; + /** + * Subscribe to specified channels and groups real-time events. + * + * @param parameters - Request configuration parameters. + */ + PubNubCore.prototype.subscribe = function (parameters) { + if (this.subscriptionManager) + this.subscriptionManager.subscribe(parameters); + else if (this.eventEngine) + this.eventEngine.subscribe(parameters); + }; + /** + * Perform subscribe request. + * + * **Note:** Method passed into managers to let them use it when required. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + PubNubCore.prototype.makeSubscribe = function (parameters, callback) { + var _this = this; + var request = new subscribe_1.SubscribeRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet, getFileUrl: this.getFileUrl })); + this.sendRequest(request, function (status, result) { + if (_this.subscriptionManager && _this.subscriptionManager.abort === request.abort) + _this.subscriptionManager.abort = null; + callback(status, result); + }); + /** + * Allow subscription cancellation. + * + * **Note:** Had to be done after scheduling because transport provider return cancellation + * controller only when schedule new request. + */ + if (this.subscriptionManager) + this.subscriptionManager.abort = request.abort; + }; + /** + * Unsubscribe from specified channels and groups real-time events. + * + * @param parameters - Request configuration parameters. + */ + PubNubCore.prototype.unsubscribe = function (parameters) { + if (this.subscriptionManager) + this.subscriptionManager.unsubscribe(parameters); + else if (this.eventEngine) + this.eventEngine.unsubscribe(parameters); + }; + /** + * Perform unsubscribe request. + * + * **Note:** Method passed into managers to let them use it when required. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + PubNubCore.prototype.makeUnsubscribe = function (parameters, callback) { + this.sendRequest(new leave_1.PresenceLeaveRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet })), callback); + }; + /** + * Unsubscribe from all channels and groups. + */ + PubNubCore.prototype.unsubscribeAll = function () { + if (this.subscriptionManager) + this.subscriptionManager.unsubscribeAll(); + else if (this.eventEngine) + this.eventEngine.unsubscribeAll(); + }; + /** + * Temporarily disconnect from real-time events stream. + */ + PubNubCore.prototype.disconnect = function () { + if (this.subscriptionManager) + this.subscriptionManager.disconnect(); + else if (this.eventEngine) + this.eventEngine.disconnect(); + }; + /** + * Restore connection to the real-time events stream. + * + * @param parameters - Reconnection catch up configuration. **Note:** available only with + * enabled event engine. + */ + PubNubCore.prototype.reconnect = function (parameters) { + if (this.subscriptionManager) + this.subscriptionManager.reconnect(); + else if (this.eventEngine) + this.eventEngine.reconnect(parameters !== null && parameters !== void 0 ? parameters : {}); + }; + /** + * Event engine handshake subscribe. + * + * @param parameters - Request configuration parameters. + */ + PubNubCore.prototype.subscribeHandshake = function (parameters) { + return __awaiter(this, void 0, void 0, function () { + var request, abortUnsubscribe, handshakeResponse; + return __generator(this, function (_a) { + request = new handshake_1.HandshakeSubscribeRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet, crypto: this._configuration.cryptoModule, getFileUrl: this.getFileUrl })); + abortUnsubscribe = parameters.abortSignal.subscribe(request.abort); + handshakeResponse = this.sendRequest(request); + return [2 /*return*/, handshakeResponse.then(function (response) { + abortUnsubscribe(); + return response.cursor; + })]; + }); + }); + }; + /** + * Event engine receive messages subscribe. + * + * @param parameters - Request configuration parameters. + */ + PubNubCore.prototype.subscribeReceiveMessages = function (parameters) { + return __awaiter(this, void 0, void 0, function () { + var request, abortUnsubscribe, handshakeResponse; + return __generator(this, function (_a) { + request = new receiveMessages_1.ReceiveMessagesSubscribeRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet, crypto: this._configuration.cryptoModule, getFileUrl: this.getFileUrl })); + abortUnsubscribe = parameters.abortSignal.subscribe(request.abort); + handshakeResponse = this.sendRequest(request); + return [2 /*return*/, handshakeResponse.then(function (response) { + abortUnsubscribe(); + return response; + })]; + }); + }); + }; + /** + * Get reactions to a specific message. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get reactions response or `void` in case if `callback` provided. + */ + PubNubCore.prototype.getMessageActions = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new get_message_actions_1.GetMessageActionsRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Add a reaction to a specific message. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous add a reaction response or `void` in case if `callback` provided. + */ + PubNubCore.prototype.addMessageAction = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new add_message_action_1.AddMessageActionRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Remove a reaction from a specific message. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous remove a reaction response or `void` in case if `callback` provided. + */ + PubNubCore.prototype.removeMessageAction = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new remove_message_action_1.RemoveMessageAction(__assign(__assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Fetch messages history for channels. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous fetch messages response or `void` in case if `callback` provided. + * + * @deprecated + */ + PubNubCore.prototype.fetchMessages = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new fetch_messages_1.FetchMessagesRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet, crypto: this._configuration.cryptoModule, getFileUrl: this.getFileUrl })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Delete messages from the channel history. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous delete messages response or `void` in case if `callback` provided. + * + * @deprecated + */ + PubNubCore.prototype.deleteMessages = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new delete_messages_1.DeleteMessageRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Count messages from the channels' history. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous count messages response or `void` in case if `callback` provided. + * + * @deprecated + */ + PubNubCore.prototype.messageCounts = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new message_counts_1.MessageCountRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Fetch single channel history. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous fetch channel history response or `void` in case if `callback` provided. + * + * @deprecated + */ + PubNubCore.prototype.history = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new get_history_1.GetHistoryRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet, crypto: this._configuration.cryptoModule })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Get channel's presence information. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get channel's presence response or `void` in case if `callback` provided. + */ + PubNubCore.prototype.hereNow = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new here_now_1.HereNowRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Get user's presence information. + * + * Get list of channels to which `uuid` currently subscribed. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get user's presence response or `void` in case if `callback` provided. + */ + PubNubCore.prototype.whereNow = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + var _a; + return __generator(this, function (_b) { + request = new where_now_1.WhereNowRequest({ + uuid: (_a = parameters.uuid) !== null && _a !== void 0 ? _a : this._configuration.userId, + keySet: this._configuration.keySet, }); - } - else { - return _this.objects.removeMemberships({ - uuid: parameters.userId, - channels: parameters.spaceIds, + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Get associated user's data for channels and groups. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get user's data response or `void` in case if `callback` provided. + */ + PubNubCore.prototype.getState = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + var _a; + return __generator(this, function (_b) { + request = new get_state_1.GetPresenceStateRequest(__assign(__assign({}, parameters), { uuid: (_a = parameters.uuid) !== null && _a !== void 0 ? _a : this._configuration.userId, keySet: this._configuration.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Set associated user's data for channels and groups. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous set user's data response or `void` in case if `callback` provided. + */ + PubNubCore.prototype.setState = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var _a, keySet, uuid, heartbeat, request, presenceState_1; + var _b, _c; + return __generator(this, function (_d) { + _a = this._configuration, keySet = _a.keySet, uuid = _a.userId; + heartbeat = this._configuration.getPresenceTimeout(); + // Maintain presence information (if required). + if (this._configuration.enableEventEngine && this.presenceState) { + presenceState_1 = this.presenceState; + (_b = parameters.channels) === null || _b === void 0 ? void 0 : _b.forEach(function (channel) { return (presenceState_1[channel] = parameters.state); }); + if ('channelGroups' in parameters) { + (_c = parameters.channelGroups) === null || _c === void 0 ? void 0 : _c.forEach(function (group) { return (presenceState_1[group] = parameters.state); }); + } + } + // Check whether state should be set with heartbeat or not. + if ('withHeartbeat' in parameters) { + request = new heartbeat_1.HeartbeatRequest(__assign(__assign({}, parameters), { keySet: keySet, heartbeat: heartbeat })); + } + else { + request = new set_state_1.SetPresenceStateRequest(__assign(__assign({}, parameters), { keySet: keySet, uuid: uuid })); + } + // Update state used by subscription manager. + if (this.subscriptionManager) + this.subscriptionManager.setState(parameters); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + // endregion + // region Change presence state + /** + * Manual presence management. + * + * @param parameters - Desired presence state for provided list of channels and groups. + */ + PubNubCore.prototype.presence = function (parameters) { + var _a; + (_a = this.subscriptionManager) === null || _a === void 0 ? void 0 : _a.changePresence(parameters); + }; + // endregion + // region Heartbeat + /** + * Announce user presence + * + * @param parameters - Desired presence state for provided list of channels and groups. + */ + PubNubCore.prototype.heartbeat = function (parameters) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + // Manual presence management possible only with subscription manager. + if (!this.subscriptionManager) + return [2 /*return*/]; + request = new heartbeat_1.HeartbeatRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet })); + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Grant token permission. + * + * Generate access token with requested permissions. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous grant token response or `void` in case if `callback` provided. + */ + PubNubCore.prototype.grantToken = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new grant_token_1.GrantTokenRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Revoke token permission. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous revoke token response or `void` in case if `callback` provided. + */ + PubNubCore.prototype.revokeToken = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new revoke_token_1.RevokeTokenRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + Object.defineProperty(PubNubCore.prototype, "token", { + // endregion + // region Token Manipulation + /** + * Get current access token. + * + * @returns Previously configured access token using {@link setToken} method. + */ + get: function () { + return this.tokenManager.getToken(); + }, + /** + * Set current access token. + * + * @param token - New access token which should be used with next REST API endpoint calls. + */ + set: function (token) { + this.tokenManager.setToken(token); + }, + enumerable: false, + configurable: true + }); + /** + * Get current access token. + * + * @returns Previously configured access token using {@link setToken} method. + */ + PubNubCore.prototype.getToken = function () { + return this.token; + }; + /** + * Set current access token. + * + * @param token - New access token which should be used with next REST API endpoint calls. + */ + PubNubCore.prototype.setToken = function (token) { + this.token = token; + }; + /** + * Parse access token. + * + * Parse token to see what permissions token owner has. + * + * @param token - Token which should be parsed. + * + * @returns Token's permissions information for the resources. + */ + PubNubCore.prototype.parseToken = function (token) { + return this.tokenManager.parseToken(token); + }; + /** + * Grant auth key(s) permission. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous grant auth key(s) permissions or `void` in case if `callback` provided. + * + * @deprecated Use {@link grantToken} and {@link setToken} methods instead. + */ + PubNubCore.prototype.grant = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new grant_1.GrantRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Audit auth key(s) permission. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @deprecated + * + * @deprecated Use {@link grantToken} and {@link setToken} methods instead. + */ + PubNubCore.prototype.audit = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new audit_1.AuditRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + Object.defineProperty(PubNubCore.prototype, "objects", { + // endregion + // endregion + // endregion + // -------------------------------------------------------- + // ------------------- App Context API -------------------- + // -------------------------------------------------------- + // region App Context API + /** + * PubNub App Context API group. + */ + get: function () { + return this._objects; + }, + enumerable: false, + configurable: true + }); + /** + Fetch a paginated list of User objects. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get all User objects response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.getAllUUIDMetadata} method instead. + */ + PubNubCore.prototype.fetchUsers = function (parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this.objects._getAllUUIDMetadata(parametersOrCallback, callback)]; + }); + }); + }; + /** + * Fetch User object for currently configured PubNub client `uuid`. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get User object response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.getUUIDMetadata} method instead. + */ + PubNubCore.prototype.fetchUser = function (parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this.objects._getUUIDMetadata(parametersOrCallback, callback)]; + }); + }); + }; + /** + * Create User object. + * + * @param parameters - Request configuration parameters. Will create User object for currently + * configured PubNub client `uuid` if not set. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous create User object response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.setUUIDMetadata} method instead. + */ + PubNubCore.prototype.createUser = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this.objects._setUUIDMetadata(parameters, callback)]; + }); + }); + }; + /** + * Update User object. + * + * @param parameters - Request configuration parameters. Will update User object for currently + * configured PubNub client `uuid` if not set. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous update User object response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.setUUIDMetadata} method instead. + */ + PubNubCore.prototype.updateUser = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this.objects._setUUIDMetadata(parameters, callback)]; + }); + }); + }; + /** + * Remove a specific User object. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous User object remove response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.removeUUIDMetadata} method instead. + */ + PubNubCore.prototype.removeUser = function (parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this.objects._removeUUIDMetadata(parametersOrCallback, callback)]; + }); + }); + }; + /** + * Fetch a paginated list of Space objects. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get all Space objects response or `void` in case if `callback` + * provided. + * + * @deprecated Use {@link PubNubCore#objects.getAllChannelMetadata} method instead. + */ + PubNubCore.prototype.fetchSpaces = function (parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this.objects._getAllChannelMetadata(parametersOrCallback, callback)]; + }); + }); + }; + /** + * Fetch a specific Space object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get Space object response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.getChannelMetadata} method instead. + */ + PubNubCore.prototype.fetchSpace = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this.objects._getChannelMetadata(parameters, callback)]; + }); + }); + }; + /** + * Create specific Space object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous create Space object response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.setChannelMetadata} method instead. + */ + PubNubCore.prototype.createSpace = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this.objects._setChannelMetadata(parameters, callback)]; + }); + }); + }; + /** + * Update specific Space object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous update Space object response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.setChannelMetadata} method instead. + */ + PubNubCore.prototype.updateSpace = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this.objects._setChannelMetadata(parameters, callback)]; + }); + }); + }; + /** + * Remove a specific Space object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous Space object remove response or `void` in case if `callback` + * provided. + * + * @deprecated Use {@link PubNubCore#objects.removeChannelMetadata} method instead. + */ + PubNubCore.prototype.removeSpace = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this.objects._removeChannelMetadata(parameters, callback)]; + }); + }); + }; + /** + * Fetch paginated list of specific Space members or specific User memberships. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get specific Space members or specific User memberships response or + * `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.getChannelMembers} or {@link PubNubCore#objects.getMemberships} + * methods instead. + */ + PubNubCore.prototype.fetchMemberships = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this.objects.fetchMemberships(parameters, callback)]; + }); + }); + }; + /** + * Add members to specific Space or memberships specific User. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous add members to specific Space or memberships specific User response or + * `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.setChannelMembers} or {@link PubNubCore#objects.setMemberships} + * methods instead. + */ + PubNubCore.prototype.addMemberships = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this.objects.addMemberships(parameters, callback)]; + }); + }); + }; + /** + * Update specific Space members or User memberships. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous update Space members or User memberships response or `void` in case + * if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.setChannelMembers} or {@link PubNubCore#objects.setMemberships} + * methods instead. + */ + PubNubCore.prototype.updateMemberships = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this.objects.addMemberships(parameters, callback)]; + }); + }); + }; + /** + * Remove User membership. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous memberships modification response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.removeMemberships} or {@link PubNubCore#objects.removeChannelMembers} + * methods instead + * from `objects` API group.. + */ + PubNubCore.prototype.removeMemberships = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var spaceParameters, requestParameters_1, userParameters, requestParameters; + var _a, _b, _c; + return __generator(this, function (_d) { + if ('spaceId' in parameters) { + spaceParameters = parameters; + requestParameters_1 = { + channel: (_a = spaceParameters.spaceId) !== null && _a !== void 0 ? _a : spaceParameters.channel, + uuids: (_b = spaceParameters.userIds) !== null && _b !== void 0 ? _b : spaceParameters.uuids, + limit: 0, + }; + if (callback) + return [2 /*return*/, this.objects.removeChannelMembers(requestParameters_1, callback)]; + return [2 /*return*/, this.objects.removeChannelMembers(requestParameters_1)]; + } + userParameters = parameters; + requestParameters = { + uuid: userParameters.userId, + channels: (_c = userParameters.spaceIds) !== null && _c !== void 0 ? _c : userParameters.channels, limit: 0, - }); - } - }; - this.fetchMemberships = function (params) { - if (typeof params.spaceId === 'string') { - return _this.objects - .getChannelMembers({ - channel: params.spaceId, - filter: params.filter, - limit: params.limit, - page: params.page, - include: { - customFields: params.include.customFields, - UUIDFields: params.include.userFields, - customUUIDFields: params.include.customUserFields, - statusField: params.include.statusField, - UUIDStatusField: params.include.userStatusField, - UUIDTypeField: params.include.userTypeField, - totalCount: params.include.totalCount, - }, - sort: params.sort != null - ? Object.fromEntries(Object.entries(params.sort).map(function (_a) { - var _b = __read(_a, 2), k = _b[0], v = _b[1]; - return [k.replace('user', 'uuid'), v]; - })) - : null, - }) - .then(function (res) { - var _a; - res.data = (_a = res.data) === null || _a === void 0 ? void 0 : _a.map(function (m) { - return { - user: m.uuid, - custom: m.custom, - updated: m.updated, - eTag: m.eTag, - }; - }); - return res; - }); - } - else { - return _this.objects - .getMemberships({ - uuid: params.userId, - filter: params.filter, - limit: params.limit, - page: params.page, - include: { - customFields: params.include.customFields, - channelFields: params.include.spaceFields, - customChannelFields: params.include.customSpaceFields, - statusField: params.include.statusField, - channelStatusField: params.include.spaceStatusField, - channelTypeField: params.include.spaceTypeField, - totalCount: params.include.totalCount, - }, - sort: params.sort != null - ? Object.fromEntries(Object.entries(params.sort).map(function (_a) { - var _b = __read(_a, 2), k = _b[0], v = _b[1]; - return [k.replace('space', 'channel'), v]; - })) - : null, - }) - .then(function (res) { - var _a; - res.data = (_a = res.data) === null || _a === void 0 ? void 0 : _a.map(function (m) { - return { - space: m.channel, - custom: m.custom, - updated: m.updated, - eTag: m.eTag, - }; - }); - return res; - }); - } - }; - this.time = timeEndpoint; - // --- deprecated ------------------ - this.stop = this.destroy; // -------- - // --- deprecated ------------------ - // mount crypto - this.encrypt = function (data, key) { - if (typeof key === 'undefined' && modules.cryptoModule) { - var encrypted = modules.cryptoModule.encrypt(data); - return typeof encrypted === 'string' ? encrypted : (0, base64_codec_1.encode)(encrypted); - } - else { - return crypto.encrypt(data, key); - } - }; - this.decrypt = function (data, key) { - if (typeof key === 'undefined' && cryptoModule) { - var decrypted = modules.cryptoModule.decrypt(data); - return decrypted instanceof ArrayBuffer ? JSON.parse(new TextDecoder().decode(decrypted)) : decrypted; - } - else { - return crypto.decrypt(data, key); - } - }; - /* config */ - this.getAuthKey = modules.config.getAuthKey.bind(modules.config); - this.setAuthKey = modules.config.setAuthKey.bind(modules.config); - this.getUUID = modules.config.getUUID.bind(modules.config); - this.setUUID = modules.config.setUUID.bind(modules.config); - this.getUserId = modules.config.getUserId.bind(modules.config); - this.setUserId = modules.config.setUserId.bind(modules.config); - this.getFilterExpression = modules.config.getFilterExpression.bind(modules.config); - this.setFilterExpression = modules.config.setFilterExpression.bind(modules.config); - this.setCipherKey = function (key) { return modules.config.setCipherKey(key, setup, modules); }; - this.setHeartbeatInterval = modules.config.setHeartbeatInterval.bind(modules.config); - if (networking.hasModule('proxy')) { - this.setProxy = function (proxy) { - modules.config.setProxy(proxy); - _this.reconnect(); - }; - } - } - default_1.prototype.getVersion = function () { - return this._config.getVersion(); + }; + if (callback) + return [2 /*return*/, this.objects.removeMemberships(requestParameters, callback)]; + return [2 /*return*/, this.objects.removeMemberships(requestParameters)]; + }); + }); + }; + Object.defineProperty(PubNubCore.prototype, "channelGroups", { + // endregion + // endregion + // -------------------------------------------------------- + // ----------------- Channel Groups API ------------------- + // -------------------------------------------------------- + // region Channel Groups API + /** + * PubNub Channel Groups API group. + */ + get: function () { + return this._channelGroups; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(PubNubCore.prototype, "push", { + // endregion + // -------------------------------------------------------- + // ---------------- Push Notifications API ----------------- + // -------------------------------------------------------- + // region Push Notifications API + /** + * PubNub Push Notifications API group. + */ + get: function () { + return this._push; + }, + enumerable: false, + configurable: true + }); + /** + * Share file to a specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous file sharing response or `void` in case if `callback` provided. + */ + PubNubCore.prototype.sendFile = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var sendFileRequest, status; + var _a; + return __generator(this, function (_b) { + if (!this._configuration.PubNubFile) + throw new Error("Validation failed: 'PubNubFile' not configured or file upload not supported by the platform."); + sendFileRequest = new send_file_1.SendFileRequest(__assign(__assign({}, parameters), { cipherKey: (_a = parameters.cipherKey) !== null && _a !== void 0 ? _a : this._configuration.cipherKey, keySet: this._configuration.keySet, PubNubFile: this._configuration.PubNubFile, fileUploadPublishRetryLimit: this._configuration.fileUploadPublishRetryLimit, file: parameters.file, sendRequest: this.sendRequest, publishFile: this.publishFile, crypto: this._configuration.cryptoModule, cryptography: this.cryptography ? this.cryptography : undefined })); + status = { + error: false, + operation: operations_1.default.PNPublishFileOperation, + statusCode: 0, + }; + return [2 /*return*/, sendFileRequest + .process() + .then(function (response) { + status.statusCode = response.status; + if (callback) + return callback(status, response); + return response; + }) + .catch(function (error) { + var errorStatus = error.toStatus(status.operation); + // Notify callback (if possible). + if (callback) + callback(errorStatus, null); + throw new PubNubError_1.PubNubError('REST API request processing error, check status for details', errorStatus); + })]; + }); + }); }; - default_1.prototype._addPnsdkSuffix = function (name, suffix) { - this._config._addPnsdkSuffix(name, suffix); + /** + * Publish file message to a specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous publish file message response or `void` in case if `callback` provided. + */ + PubNubCore.prototype.publishFile = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + if (!this._configuration.PubNubFile) + throw new Error("Validation failed: 'PubNubFile' not configured or file upload not supported by the platform."); + request = new publish_file_1.PublishFileMessageRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet, crypto: this._configuration.cryptoModule })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); }; - // network hooks to indicate network changes - default_1.prototype.networkDownDetected = function () { - this._listenerManager.announceNetworkDown(); - if (this._config.restore) { - this.disconnect(); - } - else { - this.destroy(true); + /** + * Retrieve list of shared files in specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous shared files list response or `void` in case if `callback` provided. + */ + PubNubCore.prototype.listFiles = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new list_files_1.FilesListRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + // endregion + // region Get Download Url + /** + * Get file download Url. + * + * @param parameters - Request configuration parameters. + * + * @returns File download Url. + */ + PubNubCore.prototype.getFileUrl = function (parameters) { + var _a; + var request = this.transport.request(new get_file_url_1.GetFileDownloadUrlRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet })).request()); + var query = (_a = request.queryParameters) !== null && _a !== void 0 ? _a : {}; + var queryString = Object.keys(query) + .map(function (key) { + var queryValue = query[key]; + if (!Array.isArray(queryValue)) + return "".concat(key, "=").concat((0, utils_1.encodeString)(queryValue)); + return queryValue.map(function (value) { return "".concat(key, "=").concat((0, utils_1.encodeString)(value)); }).join('&'); + }) + .join('&'); + return "".concat(request.origin).concat(request.path, "?").concat(queryString); + }; + /** + * Download shared file from specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous download shared file response or `void` in case if `callback` provided. + */ + PubNubCore.prototype.downloadFile = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + var _a; + return __generator(this, function (_b) { + switch (_b.label) { + case 0: + if (!this._configuration.PubNubFile) + throw new Error("Validation failed: 'PubNubFile' not configured or file upload not supported by the platform."); + request = new download_file_1.DownloadFileRequest(__assign(__assign({}, parameters), { cipherKey: (_a = parameters.cipherKey) !== null && _a !== void 0 ? _a : this._configuration.cipherKey, keySet: this._configuration.keySet, PubNubFile: this._configuration.PubNubFile, cryptography: this.cryptography ? this.cryptography : undefined, crypto: this._configuration.cryptoModule })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [4 /*yield*/, this.sendRequest(request)]; + case 1: return [2 /*return*/, (_b.sent())]; + } + }); + }); + }; + /** + * Delete shared file from specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous delete shared file response or `void` in case if `callback` provided. + */ + PubNubCore.prototype.deleteFile = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new delete_file_1.DeleteFileRequest(__assign(__assign({}, parameters), { keySet: this._configuration.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + Get current high-precision timetoken. + * + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get current timetoken response or `void` in case if `callback` provided. + */ + PubNubCore.prototype.time = function (callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new Time.TimeRequest(); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + // endregion + // -------------------------------------------------------- + // ------------------ Cryptography API -------------------- + // -------------------------------------------------------- + // region Cryptography + // region Common + /** + * Encrypt data. + * + * @param data - Stringified data which should be encrypted using `CryptoModule`. + * @deprecated + * @param [customCipherKey] - Cipher key which should be used to encrypt data. **Deprecated:** + * use {@link Configuration#cryptoModule|cryptoModule} instead. + * + * @returns Data encryption result as a string. + */ + PubNubCore.prototype.encrypt = function (data, customCipherKey) { + if (typeof customCipherKey === 'undefined' && this._configuration.cryptoModule) { + var encrypted = this._configuration.cryptoModule.encrypt(data); + return typeof encrypted === 'string' ? encrypted : (0, base64_codec_1.encode)(encrypted); } + if (!this.crypto) + throw new Error('Encryption error: cypher key not set'); + return this.crypto.encrypt(data, customCipherKey); }; - default_1.prototype.networkUpDetected = function () { - this._listenerManager.announceNetworkUp(); - this.reconnect(); + /** + * Decrypt data. + * + * @param data - Stringified data which should be encrypted using `CryptoModule`. + * @param [customCipherKey] - Cipher key which should be used to decrypt data. **Deprecated:** + * use {@link Configuration#cryptoModule|cryptoModule} instead. + * + * @returns Data decryption result as an object. + */ + PubNubCore.prototype.decrypt = function (data, customCipherKey) { + if (typeof customCipherKey === 'undefined' && this._configuration.cryptoModule) { + var decrypted = this._configuration.cryptoModule.decrypt(data); + return decrypted instanceof ArrayBuffer ? JSON.parse(new TextDecoder().decode(decrypted)) : decrypted; + } + if (!this.crypto) + throw new Error('Decryption error: cypher key not set'); + return this.crypto.decrypt(data, customCipherKey); }; - default_1.notificationPayload = function (title, body) { - return new push_payload_1.default(title, body); + /** + * Encrypt file content. + * + * @param keyOrFile - Cipher key which should be used to encrypt data or file which should be + * encrypted using `CryptoModule`. + * @param [file] - File which should be encrypted using legacy cryptography. + * + * @returns Asynchronous file encryption result. + * + * @throws Error if source file not provided. + * @throws File constructor not provided. + * @throws Crypto module is missing (if non-legacy flow used). + */ + PubNubCore.prototype.encryptFile = function (keyOrFile, file) { + return __awaiter(this, void 0, void 0, function () { + var _a; + return __generator(this, function (_b) { + if (typeof keyOrFile !== 'string') + file = keyOrFile; + if (!file) + throw new Error('File encryption error. Source file is missing.'); + if (!this._configuration.PubNubFile) + throw new Error('File encryption error. File constructor not configured.'); + if (typeof keyOrFile !== 'string' && !this._configuration.cryptoModule) + throw new Error('File encryption error. Crypto module not configured.'); + if (typeof keyOrFile === 'string') { + if (!this.cryptography) + throw new Error('File encryption error. File encryption not available'); + return [2 /*return*/, this.cryptography.encryptFile(keyOrFile, file, this._configuration.PubNubFile)]; + } + return [2 /*return*/, (_a = this._configuration.cryptoModule) === null || _a === void 0 ? void 0 : _a.encryptFile(file, this._configuration.PubNubFile)]; + }); + }); }; - default_1.generateUUID = function () { - return uuid_1.default.createUUID(); + /** + * Decrypt file content. + * + * @param keyOrFile - Cipher key which should be used to decrypt data or file which should be + * decrypted using `CryptoModule`. + * @param [file] - File which should be decrypted using legacy cryptography. + * + * @returns Asynchronous file decryption result. + * + * @throws Error if source file not provided. + * @throws File constructor not provided. + * @throws Crypto module is missing (if non-legacy flow used). + */ + PubNubCore.prototype.decryptFile = function (keyOrFile, file) { + return __awaiter(this, void 0, void 0, function () { + var _a; + return __generator(this, function (_b) { + if (typeof keyOrFile !== 'string') + file = keyOrFile; + if (!file) + throw new Error('File encryption error. Source file is missing.'); + if (!this._configuration.PubNubFile) + throw new Error('File decryption error. File constructor' + ' not configured.'); + if (typeof keyOrFile === 'string' && !this._configuration.cryptoModule) + throw new Error('File decryption error. Crypto module not configured.'); + if (typeof keyOrFile === 'string') { + if (!this.cryptography) + throw new Error('File decryption error. File decryption not available'); + return [2 /*return*/, this.cryptography.decryptFile(keyOrFile, file, this._configuration.PubNubFile)]; + } + return [2 /*return*/, (_a = this._configuration.cryptoModule) === null || _a === void 0 ? void 0 : _a.decryptFile(file, this._configuration.PubNubFile)]; + }); + }); }; - default_1.OPERATIONS = operations_1.default; - default_1.CATEGORIES = categories_1.default; - default_1.LinearRetryPolicy = retryPolicy_1.RetryPolicy.LinearRetryPolicy; - default_1.ExponentialRetryPolicy = retryPolicy_1.RetryPolicy.ExponentialRetryPolicy; - return default_1; + // -------------------------------------------------------- + // ----------------------- Static ------------------------- + // -------------------------------------------------------- + // region Static + /** + * Type of REST API endpoint which reported status. + */ + PubNubCore.OPERATIONS = operations_1.default; + /** + * API call status category. + */ + PubNubCore.CATEGORIES = categories_1.default; + /** + * Exponential retry policy constructor. + */ + PubNubCore.ExponentialRetryPolicy = retryPolicy_1.RetryPolicy.ExponentialRetryPolicy; + /** + * Linear retry policy constructor. + */ + PubNubCore.LinearRetryPolicy = retryPolicy_1.RetryPolicy.LinearRetryPolicy; + return PubNubCore; }()); -exports.default = default_1; +exports.PubNubCore = PubNubCore; diff --git a/lib/core/pubnub-objects.js b/lib/core/pubnub-objects.js new file mode 100644 index 000000000..ffd339cd9 --- /dev/null +++ b/lib/core/pubnub-objects.js @@ -0,0 +1,663 @@ +"use strict"; +/** + * PubNub Objects API module. + */ +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +var __read = (this && this.__read) || function (o, n) { + var m = typeof Symbol === "function" && o[Symbol.iterator]; + if (!m) return o; + var i = m.call(o), r, ar = [], e; + try { + while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); + } + catch (error) { e = { error: error }; } + finally { + try { + if (r && !r.done && (m = i["return"])) m.call(i); + } + finally { if (e) throw e.error; } + } + return ar; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var get_all_1 = require("./endpoints/objects/channel/get_all"); +var remove_1 = require("./endpoints/objects/channel/remove"); +var get_1 = require("./endpoints/objects/membership/get"); +var set_1 = require("./endpoints/objects/membership/set"); +var get_all_2 = require("./endpoints/objects/uuid/get_all"); +var get_2 = require("./endpoints/objects/channel/get"); +var set_2 = require("./endpoints/objects/channel/set"); +var remove_2 = require("./endpoints/objects/uuid/remove"); +var get_3 = require("./endpoints/objects/member/get"); +var set_3 = require("./endpoints/objects/member/set"); +var get_4 = require("./endpoints/objects/uuid/get"); +var PubNubObjects = /** @class */ (function () { + function PubNubObjects(configuration, + /* eslint-disable @typescript-eslint/no-explicit-any */ + sendRequest) { + this.configuration = configuration; + this.sendRequest = sendRequest; + this.keySet = configuration.keySet; + } + /** + * Fetch a paginated list of UUID Metadata objects. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get all UUID metadata response or `void` in case if `callback` provided. + */ + PubNubObjects.prototype.getAllUUIDMetadata = function (parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this._getAllUUIDMetadata(parametersOrCallback, callback)]; + }); + }); + }; + /** + * Fetch a paginated list of UUID Metadata objects. + * + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get all UUID metadata response or `void` in case if `callback` provided. + */ + PubNubObjects.prototype._getAllUUIDMetadata = function (parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function () { + var parameters, request; + return __generator(this, function (_a) { + parameters = parametersOrCallback && typeof parametersOrCallback !== 'function' ? parametersOrCallback : {}; + callback !== null && callback !== void 0 ? callback : (callback = typeof parametersOrCallback === 'function' ? parametersOrCallback : undefined); + request = new get_all_2.GetAllUUIDMetadataRequest(__assign(__assign({}, parameters), { keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Fetch a specific UUID Metadata object. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get UUID metadata response or `void` in case if `callback` provided. + */ + PubNubObjects.prototype.getUUIDMetadata = function (parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this._getUUIDMetadata(parametersOrCallback, callback)]; + }); + }); + }; + /** + * Fetch a specific UUID Metadata object. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get UUID metadata response or `void` in case if `callback` provided. + */ + PubNubObjects.prototype._getUUIDMetadata = function (parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function () { + var parameters, request; + var _a; + return __generator(this, function (_b) { + parameters = parametersOrCallback && typeof parametersOrCallback !== 'function' ? parametersOrCallback : {}; + callback !== null && callback !== void 0 ? callback : (callback = typeof parametersOrCallback === 'function' ? parametersOrCallback : undefined); + if (parameters.userId) + parameters.uuid = parameters.userId; + (_a = parameters.uuid) !== null && _a !== void 0 ? _a : (parameters.uuid = this.configuration.userId); + request = new get_4.GetUUIDMetadataRequest(__assign(__assign({}, parameters), { keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Update specific UUID Metadata object. + * + * @param parameters - Request configuration parameters. Will set UUID metadata for currently + * configured PubNub client `uuid` if not set. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous set UUID metadata response or `void` in case if `callback` provided. + */ + PubNubObjects.prototype.setUUIDMetadata = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this._setUUIDMetadata(parameters, callback)]; + }); + }); + }; + /** + * Update specific UUID Metadata object. + * + * @param parameters - Request configuration parameters. Will set UUID metadata for currently + * configured PubNub client `uuid` if not set. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous set UUID metadata response or `void` in case if `callback` provided. + */ + PubNubObjects.prototype._setUUIDMetadata = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + var _a; + return __generator(this, function (_b) { + if (parameters.userId) + parameters.uuid = parameters.userId; + (_a = parameters.uuid) !== null && _a !== void 0 ? _a : (parameters.uuid = this.configuration.userId); + request = new get_4.GetUUIDMetadataRequest(__assign(__assign({}, parameters), { keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Remove a specific UUID Metadata object. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous UUID metadata remove response or `void` in case if `callback` provided. + */ + PubNubObjects.prototype.removeUUIDMetadata = function (parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this._removeUUIDMetadata(parametersOrCallback, callback)]; + }); + }); + }; + /** + * Remove a specific UUID Metadata object. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous UUID metadata remove response or `void` in case if `callback` provided. + */ + PubNubObjects.prototype._removeUUIDMetadata = function (parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function () { + var parameters, request; + var _a; + return __generator(this, function (_b) { + parameters = parametersOrCallback && typeof parametersOrCallback !== 'function' ? parametersOrCallback : {}; + callback !== null && callback !== void 0 ? callback : (callback = typeof parametersOrCallback === 'function' ? parametersOrCallback : undefined); + if (parameters.userId) + parameters.uuid = parameters.userId; + (_a = parameters.uuid) !== null && _a !== void 0 ? _a : (parameters.uuid = this.configuration.userId); + request = new remove_2.RemoveUUIDMetadataRequest(__assign(__assign({}, parameters), { keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Fetch a paginated list of Channel Metadata objects. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get all Channel metadata response or `void` in case if `callback` + * provided. + */ + PubNubObjects.prototype.getAllChannelMetadata = function (parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this._getAllChannelMetadata(parametersOrCallback, callback)]; + }); + }); + }; + /** + * Fetch a paginated list of Channel Metadata objects. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get all Channel metadata response or `void` in case if `callback` + * provided. + */ + PubNubObjects.prototype._getAllChannelMetadata = function (parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function () { + var parameters, request; + return __generator(this, function (_a) { + parameters = parametersOrCallback && typeof parametersOrCallback !== 'function' ? parametersOrCallback : {}; + callback !== null && callback !== void 0 ? callback : (callback = typeof parametersOrCallback === 'function' ? parametersOrCallback : undefined); + request = new get_all_1.GetAllChannelsMetadataRequest(__assign(__assign({}, parameters), { keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Fetch Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get Channel metadata response or `void` in case if `callback` provided. + */ + PubNubObjects.prototype.getChannelMetadata = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this._getChannelMetadata(parameters, callback)]; + }); + }); + }; + /** + * Fetch Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get Channel metadata response or `void` in case if `callback` provided. + */ + PubNubObjects.prototype._getChannelMetadata = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new get_2.GetChannelMetadataRequest(__assign(__assign({}, parameters), { keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Update specific Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous set Channel metadata response or `void` in case if `callback` provided. + */ + PubNubObjects.prototype.setChannelMetadata = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this._setChannelMetadata(parameters, callback)]; + }); + }); + }; + /** + * Update specific Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous set Channel metadata response or `void` in case if `callback` provided. + */ + PubNubObjects.prototype._setChannelMetadata = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new set_2.SetChannelMetadataRequest(__assign(__assign({}, parameters), { keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Remove a specific Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous Channel metadata remove response or `void` in case if `callback` + * provided. + */ + PubNubObjects.prototype.removeChannelMetadata = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this._removeChannelMetadata(parameters, callback)]; + }); + }); + }; + /** + * Remove a specific Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous Channel metadata remove response or `void` in case if `callback` + * provided. + */ + PubNubObjects.prototype._removeChannelMetadata = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new remove_1.RemoveChannelMetadataRequest(__assign(__assign({}, parameters), { keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Fetch a paginated list of Channel Member objects. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get Channel Members response or `void` in case if `callback` provided. + */ + PubNubObjects.prototype.getChannelMembers = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new get_3.GetChannelMembersRequest(__assign(__assign({}, parameters), { keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Update specific Channel Members list. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous update Channel members list response or `void` in case if `callback` + * provided. + */ + PubNubObjects.prototype.setChannelMembers = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new set_3.SetChannelMembersRequest(__assign(__assign({}, parameters), { type: 'set', keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Remove Members from the Channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous Channel Members remove response or `void` in case if `callback` provided. + */ + PubNubObjects.prototype.removeChannelMembers = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new set_3.SetChannelMembersRequest(__assign(__assign({}, parameters), { type: 'delete', keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Fetch a specific UUID Memberships list. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get UUID Memberships response or `void` in case if `callback` provided. + */ + PubNubObjects.prototype.getMemberships = function (parametersOrCallback, callback) { + return __awaiter(this, void 0, void 0, function () { + var parameters, request; + var _a; + return __generator(this, function (_b) { + parameters = parametersOrCallback && typeof parametersOrCallback !== 'function' ? parametersOrCallback : {}; + callback !== null && callback !== void 0 ? callback : (callback = typeof parametersOrCallback === 'function' ? parametersOrCallback : undefined); + if (parameters.userId) + parameters.uuid = parameters.userId; + (_a = parameters.uuid) !== null && _a !== void 0 ? _a : (parameters.uuid = this.configuration.userId); + request = new get_1.GetUUIDMembershipsRequest(__assign(__assign({}, parameters), { keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Update specific UUID Memberships list. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous update UUID Memberships list response or `void` in case if `callback` + * provided. + */ + PubNubObjects.prototype.setMemberships = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + var _a; + return __generator(this, function (_b) { + if (parameters.userId) + parameters.uuid = parameters.userId; + (_a = parameters.uuid) !== null && _a !== void 0 ? _a : (parameters.uuid = this.configuration.userId); + request = new set_1.SetUUIDMembershipsRequest(__assign(__assign({}, parameters), { type: 'set', keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Remove a specific UUID Memberships. + * + * @param parameters - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous UUID Memberships remove response or `void` in case if `callback` + * provided. + */ + PubNubObjects.prototype.removeMemberships = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + var _a; + return __generator(this, function (_b) { + if (parameters.userId) + parameters.uuid = parameters.userId; + (_a = parameters.uuid) !== null && _a !== void 0 ? _a : (parameters.uuid = this.configuration.userId); + request = new set_1.SetUUIDMembershipsRequest(__assign(__assign({}, parameters), { type: 'delete', keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + // endregion + // endregion + // -------------------------------------------------------- + // --------------------- Deprecated API ------------------- + // -------------------------------------------------------- + // region Deprecated + /** + * Fetch paginated list of specific Space members or specific User memberships. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get specific Space members or specific User memberships response. + * + * @deprecated Use {@link PubNubObjects#getChannelMembers} or {@link PubNubObjects#getMemberships} methods instead. + */ + PubNubObjects.prototype.fetchMemberships = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var spaceParameters, mappedParameters_1, mapMembers_1, userParameters, mappedParameters, mapMemberships; + var _a, _b; + return __generator(this, function (_c) { + if ('spaceId' in parameters) { + spaceParameters = parameters; + mappedParameters_1 = { + channel: (_a = spaceParameters.spaceId) !== null && _a !== void 0 ? _a : spaceParameters.channel, + filter: spaceParameters.filter, + limit: spaceParameters.limit, + page: spaceParameters.page, + include: __assign({}, spaceParameters.include), + sort: spaceParameters.sort + ? Object.fromEntries(Object.entries(spaceParameters.sort).map(function (_a) { + var _b = __read(_a, 2), key = _b[0], value = _b[1]; + return [key.replace('user', 'uuid'), value]; + })) + : undefined, + }; + mapMembers_1 = function (response) { + return ({ + status: response.status, + data: response.data.map(function (members) { return ({ + user: members.uuid, + custom: members.custom, + updated: members.updated, + eTag: members.eTag, + }); }), + totalCount: response.totalCount, + next: response.next, + prev: response.prev, + }); + }; + if (callback) + return [2 /*return*/, this.getChannelMembers(mappedParameters_1, function (status, result) { + callback(status, result ? mapMembers_1(result) : result); + })]; + return [2 /*return*/, this.getChannelMembers(mappedParameters_1).then(mapMembers_1)]; + } + userParameters = parameters; + mappedParameters = { + uuid: (_b = userParameters.userId) !== null && _b !== void 0 ? _b : userParameters.uuid, + filter: userParameters.filter, + limit: userParameters.limit, + page: userParameters.page, + include: __assign({}, userParameters.include), + sort: userParameters.sort + ? Object.fromEntries(Object.entries(userParameters.sort).map(function (_a) { + var _b = __read(_a, 2), key = _b[0], value = _b[1]; + return [key.replace('space', 'channel'), value]; + })) + : undefined, + }; + mapMemberships = function (response) { + return ({ + status: response.status, + data: response.data.map(function (membership) { return ({ + space: membership.channel, + custom: membership.custom, + updated: membership.updated, + eTag: membership.eTag, + }); }), + totalCount: response.totalCount, + next: response.next, + prev: response.prev, + }); + }; + if (callback) + return [2 /*return*/, this.getMemberships(mappedParameters, function (status, result) { + callback(status, result ? mapMemberships(result) : result); + })]; + return [2 /*return*/, this.getMemberships(mappedParameters).then(mapMemberships)]; + }); + }); + }; + /** + * Add members to specific Space or memberships specific User. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous add members to specific Space or memberships specific User response or + * `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubObjects#setChannelMembers} or {@link PubNubObjects#setMemberships} methods instead. + */ + PubNubObjects.prototype.addMemberships = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var spaceParameters, mappedParameters_2, userParameters, mappedParameters; + var _a, _b, _c, _d, _e, _f; + return __generator(this, function (_g) { + if ('spaceId' in parameters) { + spaceParameters = parameters; + mappedParameters_2 = { + channel: (_a = spaceParameters.spaceId) !== null && _a !== void 0 ? _a : spaceParameters.channel, + uuids: (_c = (_b = spaceParameters.users) === null || _b === void 0 ? void 0 : _b.map(function (user) { + if (typeof user === 'string') + return user; + user.userId; + return { id: user.userId, custom: user.custom }; + })) !== null && _c !== void 0 ? _c : spaceParameters.uuids, + limit: 0, + }; + if (callback) + return [2 /*return*/, this.setChannelMembers(mappedParameters_2, callback)]; + return [2 /*return*/, this.setChannelMembers(mappedParameters_2)]; + } + userParameters = parameters; + mappedParameters = { + uuid: (_d = userParameters.userId) !== null && _d !== void 0 ? _d : userParameters.uuid, + channels: (_f = (_e = userParameters.spaces) === null || _e === void 0 ? void 0 : _e.map(function (space) { + if (typeof space === 'string') + return space; + return { + id: space.spaceId, + custom: space.custom, + }; + })) !== null && _f !== void 0 ? _f : userParameters.channels, + limit: 0, + }; + if (callback) + return [2 /*return*/, this.setMemberships(mappedParameters, callback)]; + return [2 /*return*/, this.setMemberships(mappedParameters)]; + }); + }); + }; + return PubNubObjects; +}()); +exports.default = PubNubObjects; diff --git a/lib/core/pubnub-push.js b/lib/core/pubnub-push.js new file mode 100644 index 000000000..db5378079 --- /dev/null +++ b/lib/core/pubnub-push.js @@ -0,0 +1,136 @@ +"use strict"; +/** + * PubNub Push Notifications API module. + */ +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var remove_push_channels_1 = require("./endpoints/push/remove_push_channels"); +var list_push_channels_1 = require("./endpoints/push/list_push_channels"); +var add_push_channels_1 = require("./endpoints/push/add_push_channels"); +var remove_device_1 = require("./endpoints/push/remove_device"); +var PubNubPushNotifications = /** @class */ (function () { + function PubNubPushNotifications(keySet, + /* eslint-disable @typescript-eslint/no-explicit-any */ + sendRequest) { + this.keySet = keySet; + this.sendRequest = sendRequest; + } + /** + * Fetch device's push notification enabled channels. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get device channels response or `void` in case if `callback` provided. + */ + PubNubPushNotifications.prototype.listChannels = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new list_push_channels_1.ListDevicePushNotificationChannelsRequest(__assign(__assign({}, parameters), { keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Enable push notifications on channels for device. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + */ + PubNubPushNotifications.prototype.addChannels = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new add_push_channels_1.AddDevicePushNotificationChannelsRequest(__assign(__assign({}, parameters), { keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Disable push notifications on channels for device. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + */ + PubNubPushNotifications.prototype.removeChannels = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new remove_push_channels_1.RemoveDevicePushNotificationChannelsRequest(__assign(__assign({}, parameters), { keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + /** + * Disable push notifications for device. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + */ + PubNubPushNotifications.prototype.deleteDevice = function (parameters, callback) { + return __awaiter(this, void 0, void 0, function () { + var request; + return __generator(this, function (_a) { + request = new remove_device_1.RemoveDevicePushNotificationRequest(__assign(__assign({}, parameters), { keySet: this.keySet })); + if (callback) + return [2 /*return*/, this.sendRequest(request, callback)]; + return [2 /*return*/, this.sendRequest(request)]; + }); + }); + }; + return PubNubPushNotifications; +}()); +exports.default = PubNubPushNotifications; diff --git a/lib/core/types/api/access-panager.js b/lib/core/types/api/access-panager.js new file mode 100644 index 000000000..5bff3536a --- /dev/null +++ b/lib/core/types/api/access-panager.js @@ -0,0 +1,4 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +// endregion +// endregion diff --git a/lib/core/types/api/app-context.js b/lib/core/types/api/app-context.js new file mode 100644 index 000000000..6c5bae6f7 --- /dev/null +++ b/lib/core/types/api/app-context.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +// endregion diff --git a/lib/core/types/api/channel-groups.js b/lib/core/types/api/channel-groups.js new file mode 100644 index 000000000..c8ad2e549 --- /dev/null +++ b/lib/core/types/api/channel-groups.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/lib/core/types/api/file-sharing.js b/lib/core/types/api/file-sharing.js new file mode 100644 index 000000000..35c8b7c01 --- /dev/null +++ b/lib/core/types/api/file-sharing.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * File Sharing REST API module. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +// endregion diff --git a/lib/core/types/api/history.js b/lib/core/types/api/history.js new file mode 100644 index 000000000..1653ae13f --- /dev/null +++ b/lib/core/types/api/history.js @@ -0,0 +1,25 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.PubNubMessageType = void 0; +// endregion +// -------------------------------------------------------- +// -------------------- Fetch Messages -------------------- +// -------------------------------------------------------- +// region Fetch Messages +/** + * PubNub-defined message type. + * + * Types of messages which can be retrieved with fetch messages REST API. + */ +var PubNubMessageType; +(function (PubNubMessageType) { + /** + * Regular message. + */ + PubNubMessageType[PubNubMessageType["Message"] = -1] = "Message"; + /** + * File message. + */ + PubNubMessageType[PubNubMessageType["Files"] = 4] = "Files"; +})(PubNubMessageType || (exports.PubNubMessageType = PubNubMessageType = {})); +// endregion diff --git a/lib/core/types/api/index.js b/lib/core/types/api/index.js new file mode 100644 index 000000000..1d4e9196f --- /dev/null +++ b/lib/core/types/api/index.js @@ -0,0 +1,182 @@ +"use strict"; +// PubNub client API common types. +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.PubNubAPIError = void 0; +var categories_1 = __importDefault(require("../../constants/categories")); +/** + * PubNub REST API call error. + */ +var PubNubAPIError = /** @class */ (function (_super) { + __extends(PubNubAPIError, _super); + /** + * Construct PubNub endpoint error. + * + * @param message - Short API call error description. + * @param category - Error category. + * @param statusCode - Response HTTP status code. + * @param errorData - Error information. + */ + function PubNubAPIError(message, category, statusCode, errorData) { + var _this = _super.call(this, message) || this; + _this.category = category; + _this.statusCode = statusCode; + _this.errorData = errorData; + _this.name = _this.constructor.name; + return _this; + } + /** + * Construct API from known error object or {@link PubNub} service error response. + * + * @param errorOrResponse - `Error` or service error response object from which error information + * should be extracted. + * @param data - Preprocessed service error response. + * + * @returns `PubNubAPIError` object with known error category and additional information (if + * available). + */ + PubNubAPIError.create = function (errorOrResponse, data) { + if (errorOrResponse instanceof Error) + return PubNubAPIError.createFromError(errorOrResponse); + else + return PubNubAPIError.createFromServiceResponse(errorOrResponse, data); + }; + /** + * Create API error instance from other error object. + * + * @param error - `Error` object provided by network provider (mostly) or other {@link PubNub} client components. + * + * @returns `PubNubAPIError` object with known error category and additional information (if + * available). + */ + PubNubAPIError.createFromError = function (error) { + var category = categories_1.default.PNUnknownCategory; + var message = 'Unknown error'; + var errorName = 'Error'; + if (!error) + return new PubNubAPIError(message, category, 0); + if (error instanceof Error) { + message = error.message; + errorName = error.name; + } + if (errorName === 'AbortError') { + category = categories_1.default.PNCancelledCategory; + message = 'Request cancelled'; + } + else if (errorName === 'FetchError') { + var errorCode = error.code; + if (errorCode in ['ECONNREFUSED', 'ENOTFOUND', 'ECONNRESET', 'EAI_AGAIN']) + category = categories_1.default.PNNetworkIssuesCategory; + if (errorCode === 'ECONNREFUSED') + message = 'Connection refused'; + else if (errorCode === 'ENOTFOUND') + message = 'Server not found'; + else if (errorCode === 'ECONNRESET') + message = 'Connection reset by peer'; + else if (errorCode === 'EAI_AGAIN') + message = 'Name resolution error'; + else if (errorCode === 'ETIMEDOUT') { + category = categories_1.default.PNTimeoutCategory; + message = 'Request timeout'; + } + else + message = "Unknown system error: ".concat(error); + } + else if (message === 'Request timeout') + category = categories_1.default.PNTimeoutCategory; + return new PubNubAPIError(message, category, 0, error); + }; + /** + * Construct API from known {@link PubNub} service error response. + * + * @param response - Service error response object from which error information should be + * extracted. + * @param data - Preprocessed service error response. + * + * @returns `PubNubAPIError` object with known error category and additional information (if + * available). + */ + PubNubAPIError.createFromServiceResponse = function (response, data) { + var category = categories_1.default.PNUnknownCategory; + var errorData; + var message = 'Unknown error'; + var status = response.status; + if (status === 402) + message = 'Not available for used key set. Contact support@pubnub.com'; + else if (status === 400) { + category = categories_1.default.PNBadRequestCategory; + message = 'Bad request'; + } + else if (status === 403) { + category = categories_1.default.PNAccessDeniedCategory; + message = 'Access denied'; + } + // Try get more information about error from service response. + if (data && data.byteLength > 0) { + var decoded = new TextDecoder().decode(data); + if (response.headers['content-type'].includes('application/json')) { + try { + var errorResponse = JSON.parse(decoded); + if (typeof errorResponse === 'object' && !Array.isArray(errorResponse)) { + if ('error' in errorResponse && + errorResponse.error === 1 && + 'status' in errorResponse && + typeof errorResponse.status === 'number' && + 'message' in errorResponse && + 'service' in errorResponse) { + errorData = errorResponse; + status = errorResponse.status; + } + if ('error' in errorResponse && + typeof errorResponse.error === 'object' && + !Array.isArray(errorResponse.error) && + 'message' in errorResponse.error) { + errorData = errorResponse.error; + } + } + } + catch (_) { + errorData = decoded; + } + } + else + errorData = decoded; + } + return new PubNubAPIError(message, category, status, errorData); + }; + /** + * Convert API error object to API callback status object. + * + * @param operation - Request operation during which error happened. + * + * @returns Pre-formatted API callback status object. + */ + PubNubAPIError.prototype.toStatus = function (operation) { + return { + error: true, + category: this.category, + operation: operation, + statusCode: this.statusCode, + errorData: this.errorData, + }; + }; + return PubNubAPIError; +}(Error)); +exports.PubNubAPIError = PubNubAPIError; diff --git a/lib/core/types/api/message-action.js b/lib/core/types/api/message-action.js new file mode 100644 index 000000000..c8ad2e549 --- /dev/null +++ b/lib/core/types/api/message-action.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/lib/core/types/api/presence.js b/lib/core/types/api/presence.js new file mode 100644 index 000000000..6c5bae6f7 --- /dev/null +++ b/lib/core/types/api/presence.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +// endregion diff --git a/lib/core/types/api/push-notifications.js b/lib/core/types/api/push-notifications.js new file mode 100644 index 000000000..c8ad2e549 --- /dev/null +++ b/lib/core/types/api/push-notifications.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/lib/core/types/api/push.js b/lib/core/types/api/push.js new file mode 100644 index 000000000..6c5bae6f7 --- /dev/null +++ b/lib/core/types/api/push.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +// endregion diff --git a/lib/core/types/api/subscription.js b/lib/core/types/api/subscription.js new file mode 100644 index 000000000..c8ad2e549 --- /dev/null +++ b/lib/core/types/api/subscription.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/lib/core/types/file.js b/lib/core/types/file.js new file mode 100644 index 000000000..6e7b7d2bf --- /dev/null +++ b/lib/core/types/file.js @@ -0,0 +1,5 @@ +"use strict"; +/** + * {@link PubNub} File object interface module. + */ +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/lib/core/types/transport-request.js b/lib/core/types/transport-request.js new file mode 100644 index 000000000..f72b28210 --- /dev/null +++ b/lib/core/types/transport-request.js @@ -0,0 +1,33 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.TransportMethod = void 0; +/** + * Enum representing possible transport methods for HTTP requests. + * + * @enum {number} + */ +var TransportMethod; +(function (TransportMethod) { + /** + * Request will be sent using `GET` method. + */ + TransportMethod["GET"] = "GET"; + /** + * Request will be sent using `POST` method. + */ + TransportMethod["POST"] = "POST"; + /** + * Request will be sent using `PATCH` method. + */ + TransportMethod["PATCH"] = "PATCH"; + /** + * Request will be sent using `DELETE` method. + */ + TransportMethod["DELETE"] = "DELETE"; + /** + * Local request. + * + * Request won't be sent to the service and probably used to compute URL. + */ + TransportMethod["LOCAL"] = "LOCAL"; +})(TransportMethod || (exports.TransportMethod = TransportMethod = {})); diff --git a/lib/core/types/transport-response.js b/lib/core/types/transport-response.js new file mode 100644 index 000000000..c8ad2e549 --- /dev/null +++ b/lib/core/types/transport-response.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/lib/core/utils.js b/lib/core/utils.js index 51f97541f..d493f38ee 100644 --- a/lib/core/utils.js +++ b/lib/core/utils.js @@ -24,42 +24,22 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { } return to.concat(ar || Array.prototype.slice.call(from)); }; -function objectToList(o) { - var l = []; - Object.keys(o).forEach(function (key) { return l.push(key); }); - return l; -} -function encodeString(input) { +Object.defineProperty(exports, "__esModule", { value: true }); +exports.queryStringFromObject = exports.findUniqueCommonElements = exports.removeSingleOccurance = exports.encodeString = void 0; +/** + * Percent-encode input string. + * + * **Note:** Encode content in accordance of the `PubNub` service requirements. + * + * @param input - Source string or number for encoding. + * + * @returns Percent-encoded string. + */ +var encodeString = function (input) { return encodeURIComponent(input).replace(/[!~*'()]/g, function (x) { return "%".concat(x.charCodeAt(0).toString(16).toUpperCase()); }); -} -function objectToListSorted(o) { - return objectToList(o).sort(); -} -function signPamFromParams(params) { - var l = objectToListSorted(params); - return l.map(function (paramKey) { return "".concat(paramKey, "=").concat(encodeString(params[paramKey])); }).join('&'); -} -function endsWith(searchString, suffix) { - return searchString.indexOf(suffix, this.length - suffix.length) !== -1; -} -function createPromise() { - var successResolve; - var failureResolve; - var promise = new Promise(function (fulfill, reject) { - successResolve = fulfill; - failureResolve = reject; - }); - return { promise: promise, reject: failureResolve, fulfill: successResolve }; -} -function stringToArrayBuffer(str) { - var buf = new ArrayBuffer(str.length * 2); - var bufView = new Uint16Array(buf); - for (var i = 0, strLen = str.length; i < strLen; i++) { - bufView[i] = str.charCodeAt(i); - } - return buf; -} -function removeSingleOccurance(source, elementsToRemove) { +}; +exports.encodeString = encodeString; +var removeSingleOccurance = function (source, elementsToRemove) { var removed = Object.fromEntries(elementsToRemove.map(function (prop) { return [prop, false]; })); return source.filter(function (e) { if (elementsToRemove.includes(e) && !removed[e]) { @@ -68,18 +48,29 @@ function removeSingleOccurance(source, elementsToRemove) { } return true; }); -} -function findUniqueCommonElements(a, b) { +}; +exports.removeSingleOccurance = removeSingleOccurance; +var findUniqueCommonElements = function (a, b) { return __spreadArray([], __read(a), false).filter(function (value) { return b.includes(value) && a.indexOf(value) === a.lastIndexOf(value) && b.indexOf(value) === b.lastIndexOf(value); }); -} -module.exports = { - signPamFromParams: signPamFromParams, - endsWith: endsWith, - createPromise: createPromise, - encodeString: encodeString, - stringToArrayBuffer: stringToArrayBuffer, - removeSingleOccurance: removeSingleOccurance, - findUniqueCommonElements: findUniqueCommonElements, }; +exports.findUniqueCommonElements = findUniqueCommonElements; +/** + * Transform query key / value pairs to the string. + * + * @param query - Key / value pairs of the request query parameters. + * + * @returns Stringified query key / value pairs. + */ +var queryStringFromObject = function (query) { + return Object.keys(query) + .map(function (key) { + var queryValue = query[key]; + if (!Array.isArray(queryValue)) + return "".concat(key, "=").concat((0, exports.encodeString)(queryValue)); + return queryValue.map(function (value) { return "".concat(key, "=").concat((0, exports.encodeString)(value)); }).join('&'); + }) + .join('&'); +}; +exports.queryStringFromObject = queryStringFromObject; diff --git a/lib/crypto/modules/NodeCryptoModule/ICryptor.js b/lib/crypto/modules/NodeCryptoModule/ICryptor.js index c8ad2e549..e932a515b 100644 --- a/lib/crypto/modules/NodeCryptoModule/ICryptor.js +++ b/lib/crypto/modules/NodeCryptoModule/ICryptor.js @@ -1,2 +1,5 @@ "use strict"; +/** + * Cryptor module. + */ Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/lib/crypto/modules/NodeCryptoModule/ILegacyCryptor.js b/lib/crypto/modules/NodeCryptoModule/ILegacyCryptor.js index c8ad2e549..afefd5492 100644 --- a/lib/crypto/modules/NodeCryptoModule/ILegacyCryptor.js +++ b/lib/crypto/modules/NodeCryptoModule/ILegacyCryptor.js @@ -1,2 +1,5 @@ "use strict"; +/** + * Legacy cryptor module. + */ Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/lib/crypto/modules/NodeCryptoModule/aesCbcCryptor.js b/lib/crypto/modules/NodeCryptoModule/aesCbcCryptor.js index 613e8cfec..7822b35cd 100644 --- a/lib/crypto/modules/NodeCryptoModule/aesCbcCryptor.js +++ b/lib/crypto/modules/NodeCryptoModule/aesCbcCryptor.js @@ -1,4 +1,7 @@ "use strict"; +/** + * AES-CBC cryptor module. + */ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { @@ -14,7 +17,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) { function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); - while (_) try { + while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { @@ -36,62 +39,43 @@ var __generator = (this && this.__generator) || function (thisArg, body) { } }; Object.defineProperty(exports, "__esModule", { value: true }); -var stream_1 = require("stream"); var crypto_1 = require("crypto"); +var stream_1 = require("stream"); +/** + * AES-CBC cryptor. + * + * AES-CBC cryptor with enhanced cipher strength. + */ var AesCbcCryptor = /** @class */ (function () { - function AesCbcCryptor(configuration) { - this.cipherKey = configuration.cipherKey; + function AesCbcCryptor(_a) { + var cipherKey = _a.cipherKey; + this.cipherKey = cipherKey; } - Object.defineProperty(AesCbcCryptor.prototype, "algo", { - get: function () { - return 'aes-256-cbc'; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(AesCbcCryptor.prototype, "identifier", { - get: function () { - return 'ACRH'; - }, - enumerable: false, - configurable: true - }); - AesCbcCryptor.prototype.getIv = function () { - return (0, crypto_1.randomBytes)(AesCbcCryptor.BLOCK_SIZE); - }; - AesCbcCryptor.prototype.getKey = function () { - var sha = (0, crypto_1.createHash)('sha256'); - sha.update(Buffer.from(this.cipherKey, 'utf8')); - return Buffer.from(sha.digest()); - }; + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + // region Encryption AesCbcCryptor.prototype.encrypt = function (data) { var iv = this.getIv(); var key = this.getKey(); - var plainData = typeof data === 'string' ? new TextEncoder().encode(data) : data; + var plainData = typeof data === 'string' ? AesCbcCryptor.encoder.encode(data) : data; var bPlain = Buffer.from(plainData); if (bPlain.byteLength === 0) - throw new Error('encryption error. empty content'); + throw new Error('Encryption error: empty content'); var aes = (0, crypto_1.createCipheriv)(this.algo, key, iv); return { metadata: iv, data: Buffer.concat([aes.update(bPlain), aes.final()]), }; }; - AesCbcCryptor.prototype.decrypt = function (encryptedData) { - var data = typeof encryptedData.data === 'string' ? new TextEncoder().encode(encryptedData.data) : encryptedData.data; - if (data.byteLength <= 0) - throw new Error('decryption error: empty content'); - var aes = (0, crypto_1.createDecipheriv)(this.algo, this.getKey(), encryptedData.metadata); - return Uint8Array.from(Buffer.concat([aes.update(data), aes.final()])).buffer; - }; AesCbcCryptor.prototype.encryptStream = function (stream) { return __awaiter(this, void 0, void 0, function () { var output, bIv, aes; return __generator(this, function (_a) { + if (!stream.readable) + throw new Error('Encryption error: empty stream'); output = new stream_1.PassThrough(); bIv = this.getIv(); - if (stream.readable === false) - throw new Error('encryption error. empty stream'); aes = (0, crypto_1.createCipheriv)(this.algo, this.getKey(), bIv); stream.pipe(aes).pipe(output); return [2 /*return*/, { @@ -102,7 +86,19 @@ var AesCbcCryptor = /** @class */ (function () { }); }); }; - AesCbcCryptor.prototype.decryptStream = function (encryptedStream) { + // endregion + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + // region Decryption + AesCbcCryptor.prototype.decrypt = function (input) { + var data = typeof input.data === 'string' ? new TextEncoder().encode(input.data) : input.data; + if (data.byteLength <= 0) + throw new Error('Decryption error: empty content'); + var aes = (0, crypto_1.createDecipheriv)(this.algo, this.getKey(), input.metadata); + return Uint8Array.from(Buffer.concat([aes.update(data), aes.final()])).buffer; + }; + AesCbcCryptor.prototype.decryptStream = function (stream) { return __awaiter(this, void 0, void 0, function () { var decryptedStream, bIv, aes, onReadable; var _this = this; @@ -111,11 +107,11 @@ var AesCbcCryptor = /** @class */ (function () { bIv = Buffer.alloc(0); aes = null; onReadable = function () { - var data = encryptedStream.stream.read(); + var data = stream.stream.read(); while (data !== null) { if (data) { var bChunk = Buffer.from(data); - var sliceLen = encryptedStream.metadataLength - bIv.byteLength; + var sliceLen = stream.metadataLength - bIv.byteLength; if (bChunk.byteLength < sliceLen) { bIv = Buffer.concat([bIv, bChunk]); } @@ -126,21 +122,69 @@ var AesCbcCryptor = /** @class */ (function () { aes.write(bChunk.slice(sliceLen)); } } - data = encryptedStream.stream.read(); + data = stream.stream.read(); } }; - encryptedStream.stream.on('readable', onReadable); - encryptedStream.stream.on('end', function () { - if (aes) { + stream.stream.on('readable', onReadable); + stream.stream.on('end', function () { + if (aes) aes.end(); - } decryptedStream.end(); }); return [2 /*return*/, decryptedStream]; }); }); }; + Object.defineProperty(AesCbcCryptor.prototype, "identifier", { + // endregion + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + // region Helpers + get: function () { + return 'ACRH'; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(AesCbcCryptor.prototype, "algo", { + /** + * Cryptor algorithm. + * + * @returns Cryptor module algorithm. + */ + get: function () { + return 'aes-256-cbc'; + }, + enumerable: false, + configurable: true + }); + /** + * Generate random initialization vector. + * + * @returns Random initialization vector. + */ + AesCbcCryptor.prototype.getIv = function () { + return (0, crypto_1.randomBytes)(AesCbcCryptor.BLOCK_SIZE); + }; + /** + * Convert cipher key to the {@link Buffer}. + * + * @returns SHA256 encoded cipher key {@link Buffer}. + */ + AesCbcCryptor.prototype.getKey = function () { + var sha = (0, crypto_1.createHash)('sha256'); + sha.update(Buffer.from(this.cipherKey, 'utf8')); + return Buffer.from(sha.digest()); + }; + /** + * Cryptor block size. + */ AesCbcCryptor.BLOCK_SIZE = 16; + /** + * {@link string|String} to {@link ArrayBuffer} response decoder. + */ + AesCbcCryptor.encoder = new TextEncoder(); return AesCbcCryptor; }()); exports.default = AesCbcCryptor; diff --git a/lib/crypto/modules/NodeCryptoModule/legacyCryptor.js b/lib/crypto/modules/NodeCryptoModule/legacyCryptor.js index 21273869f..6653944f8 100644 --- a/lib/crypto/modules/NodeCryptoModule/legacyCryptor.js +++ b/lib/crypto/modules/NodeCryptoModule/legacyCryptor.js @@ -1,4 +1,18 @@ "use strict"; +/** + * Legacy cryptor module. + */ +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { @@ -14,7 +28,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) { function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); - while (_) try { + while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { @@ -41,46 +55,68 @@ var __importDefault = (this && this.__importDefault) || function (mod) { Object.defineProperty(exports, "__esModule", { value: true }); var index_1 = __importDefault(require("../../../core/components/cryptography/index")); var base64_codec_1 = require("../../../core/components/base64_codec"); +var PubNubError_1 = require("../../../models/PubNubError"); var node_1 = __importDefault(require("../node")); +/** + * Legacy cryptor. + */ var LegacyCryptor = /** @class */ (function () { function LegacyCryptor(config) { this.config = config; - this.cryptor = new index_1.default({ config: config }); + this.cryptor = new index_1.default(__assign({}, config)); this.fileCryptor = new node_1.default(); } - Object.defineProperty(LegacyCryptor.prototype, "identifier", { - get: function () { - return ''; - }, - enumerable: false, - configurable: true - }); + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + // region Encryption LegacyCryptor.prototype.encrypt = function (data) { if (data.length === 0) - throw new Error('encryption error. empty content'); + throw new Error('Encryption error: empty content'); return { data: this.cryptor.encrypt(data), metadata: null, }; }; - LegacyCryptor.prototype.decrypt = function (encryptedData) { - var data = typeof encryptedData.data === 'string' ? encryptedData.data : (0, base64_codec_1.encode)(encryptedData.data); - return this.cryptor.decrypt(data); - }; LegacyCryptor.prototype.encryptFile = function (file, File) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { + if (!this.config.cipherKey) + throw new PubNubError_1.PubNubError('File encryption error: cipher key not set.'); return [2 /*return*/, this.fileCryptor.encryptFile(this.config.cipherKey, file, File)]; }); }); }; + // endregion + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + // region Decryption + LegacyCryptor.prototype.decrypt = function (encryptedData) { + var data = typeof encryptedData.data === 'string' ? encryptedData.data : (0, base64_codec_1.encode)(encryptedData.data); + return this.cryptor.decrypt(data); + }; LegacyCryptor.prototype.decryptFile = function (file, File) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { + if (!this.config.cipherKey) + throw new PubNubError_1.PubNubError('File decryption error: cipher key not set.'); return [2 /*return*/, this.fileCryptor.decryptFile(this.config.cipherKey, file, File)]; }); }); }; + Object.defineProperty(LegacyCryptor.prototype, "identifier", { + // endregion + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + // region Helpers + get: function () { + return ''; + }, + enumerable: false, + configurable: true + }); return LegacyCryptor; }()); exports.default = LegacyCryptor; diff --git a/lib/crypto/modules/NodeCryptoModule/nodeCryptoModule.js b/lib/crypto/modules/NodeCryptoModule/nodeCryptoModule.js index fdaef2d94..0031e5b0d 100644 --- a/lib/crypto/modules/NodeCryptoModule/nodeCryptoModule.js +++ b/lib/crypto/modules/NodeCryptoModule/nodeCryptoModule.js @@ -1,4 +1,33 @@ "use strict"; +/** + * Node.js crypto module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { @@ -14,7 +43,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) { function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); - while (_) try { + while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { @@ -35,129 +64,102 @@ var __generator = (this && this.__generator) || function (thisArg, body) { if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; -var __read = (this && this.__read) || function (o, n) { - var m = typeof Symbol === "function" && o[Symbol.iterator]; - if (!m) return o; - var i = m.call(o), r, ar = [], e; - try { - while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); - } - catch (error) { e = { error: error }; } - finally { - try { - if (r && !r.done && (m = i["return"])) m.call(i); - } - finally { if (e) throw e.error; } - } - return ar; -}; -var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { - if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { - if (ar || !(i in from)) { - if (!ar) ar = Array.prototype.slice.call(from, 0, i); - ar[i] = from[i]; - } - } - return to.concat(ar || Array.prototype.slice.call(from)); -}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.CryptoModule = exports.AesCbcCryptor = exports.LegacyCryptor = void 0; var stream_1 = require("stream"); +var buffer_1 = require("buffer"); +var crypto_module_1 = require("../../../core/interfaces/crypto-module"); var base64_codec_1 = require("../../../core/components/base64_codec"); -var legacyCryptor_1 = __importDefault(require("./legacyCryptor")); -exports.LegacyCryptor = legacyCryptor_1.default; +var PubNubError_1 = require("../../../models/PubNubError"); var aesCbcCryptor_1 = __importDefault(require("./aesCbcCryptor")); exports.AesCbcCryptor = aesCbcCryptor_1.default; -var CryptoModule = /** @class */ (function () { - function CryptoModule(cryptoModuleConfiguration) { - var _a; - this.defaultCryptor = cryptoModuleConfiguration.default; - this.cryptors = (_a = cryptoModuleConfiguration.cryptors) !== null && _a !== void 0 ? _a : []; +var legacyCryptor_1 = __importDefault(require("./legacyCryptor")); +exports.LegacyCryptor = legacyCryptor_1.default; +/** + * CryptoModule for Node.js platform. + */ +var CryptoModule = /** @class */ (function (_super) { + __extends(CryptoModule, _super); + function CryptoModule() { + return _super !== null && _super.apply(this, arguments) || this; } - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore: type detection issue with old Config type assignment + // -------------------------------------------------------- + // --------------- Convenience functions ------------------ + // ------------------------------------------------------- + // region Convenience functions CryptoModule.legacyCryptoModule = function (config) { var _a; + if (!config.cipherKey) + throw new PubNubError_1.PubNubError('Crypto module error: cipher key not set.'); return new this({ - default: new legacyCryptor_1.default({ - cipherKey: config.cipherKey, - useRandomIVs: (_a = config.useRandomIVs) !== null && _a !== void 0 ? _a : true, - }), + default: new legacyCryptor_1.default(__assign(__assign({}, config), { useRandomIVs: (_a = config.useRandomIVs) !== null && _a !== void 0 ? _a : true })), cryptors: [new aesCbcCryptor_1.default({ cipherKey: config.cipherKey })], }); }; CryptoModule.aesCbcCryptoModule = function (config) { var _a; + if (!config.cipherKey) + throw new PubNubError_1.PubNubError('Crypto module error: cipher key not set.'); return new this({ default: new aesCbcCryptor_1.default({ cipherKey: config.cipherKey }), cryptors: [ - new legacyCryptor_1.default({ - cipherKey: config.cipherKey, - useRandomIVs: (_a = config.useRandomIVs) !== null && _a !== void 0 ? _a : true, - }), + new legacyCryptor_1.default(__assign(__assign({}, config), { useRandomIVs: (_a = config.useRandomIVs) !== null && _a !== void 0 ? _a : true })), ], }); }; + /** + * Construct crypto module with `cryptor` as default for data encryption and decryption. + * + * @param defaultCryptor - Default cryptor for data encryption and decryption. + * + * @returns Crypto module with pre-configured default cryptor. + */ CryptoModule.withDefaultCryptor = function (defaultCryptor) { return new this({ default: defaultCryptor }); }; - CryptoModule.prototype.getAllCryptors = function () { - return __spreadArray([this.defaultCryptor], __read(this.cryptors), false); - }; - CryptoModule.prototype.getLegacyCryptor = function () { - return this.getAllCryptors().find(function (c) { return c.identifier === ''; }); - }; + // endregion + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + // region Encryption CryptoModule.prototype.encrypt = function (data) { - var encrypted = this.defaultCryptor.encrypt(data); + // Encrypt data. + var encrypted = data instanceof ArrayBuffer && this.defaultCryptor.identifier === CryptoModule.LEGACY_IDENTIFIER + ? this.defaultCryptor.encrypt(CryptoModule.decoder.decode(data)) + : this.defaultCryptor.encrypt(data); if (!encrypted.metadata) return encrypted.data; - var header = CryptorHeader.from(this.defaultCryptor.identifier, encrypted.metadata); - var headerData = new Uint8Array(header.length); - var pos = 0; - headerData.set(header.data, pos); - pos = header.length - encrypted.metadata.length; - headerData.set(encrypted.metadata, pos); - return Buffer.concat([headerData, Buffer.from(encrypted.data)]); - }; - CryptoModule.prototype.decrypt = function (data) { - var encryptedData = Buffer.from(typeof data === 'string' ? (0, base64_codec_1.decode)(data) : data); - var header = CryptorHeader.tryParse(encryptedData); - var cryptor = this.getCryptor(header); - var metadata = header.length > 0 - ? encryptedData.slice(header.length - header.metadataLength, header.length) - : null; - if (encryptedData.slice(header.length).byteLength <= 0) - throw new Error('decryption error. empty content'); - return cryptor.decrypt({ - data: encryptedData.slice(header.length), - metadata: metadata, - }); + var headerData = this.getHeaderData(encrypted); + // Write encrypted data payload content. + var encryptedData = typeof encrypted.data === 'string' ? CryptoModule.encoder.encode(encrypted.data) : encrypted.data.buffer; + return this.concatArrayBuffer(headerData, encryptedData); }; CryptoModule.prototype.encryptFile = function (file, File) { return __awaiter(this, void 0, void 0, function () { - var encryptedStream, header, payload, pos, output; + var encryptedData, encryptedStream, header, payload, pos, metadata, output; return __generator(this, function (_a) { switch (_a.label) { case 0: /** * Files handled differently in case of Legacy cryptor. - * (as long as we support legacy need to check on intsance type) + * (as long as we support legacy need to check on instance type) */ if (this.defaultCryptor.identifier === CryptorHeader.LEGACY_IDENTIFIER) return [2 /*return*/, this.defaultCryptor.encryptFile(file, File)]; - if (file.data instanceof Buffer) { + if (file.data instanceof buffer_1.Buffer) { + encryptedData = this.encrypt(file.data); return [2 /*return*/, File.create({ name: file.name, mimeType: 'application/octet-stream', - data: Buffer.from(this.encrypt(file.data)), + data: buffer_1.Buffer.from(typeof encryptedData === 'string' ? CryptoModule.encoder.encode(encryptedData) : encryptedData), })]; } if (!(file.data instanceof stream_1.Readable)) return [3 /*break*/, 2]; if (file.contentLength === 0) - throw new Error('encryption error. empty content'); + throw new Error('Encryption error: empty content'); return [4 /*yield*/, this.defaultCryptor.encryptStream(file.data)]; case 1: encryptedStream = _a.sent(); @@ -167,8 +169,9 @@ var CryptoModule = /** @class */ (function () { payload.set(header.data, pos); pos += header.length; if (encryptedStream.metadata) { - pos -= encryptedStream.metadata.length; - payload.set(encryptedStream.metadata, pos); + metadata = new Uint8Array(encryptedStream.metadata); + pos -= encryptedStream.metadata.byteLength; + payload.set(metadata, pos); } output = new stream_1.PassThrough(); output.write(payload); @@ -183,26 +186,45 @@ var CryptoModule = /** @class */ (function () { }); }); }; + // endregion + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + // region Decryption + CryptoModule.prototype.decrypt = function (data) { + var encryptedData = buffer_1.Buffer.from(typeof data === 'string' ? (0, base64_codec_1.decode)(data) : data); + var header = CryptorHeader.tryParse(encryptedData); + var cryptor = this.getCryptor(header); + var metadata = header.length > 0 + ? encryptedData.slice(header.length - header.metadataLength, header.length) + : null; + if (encryptedData.slice(header.length).byteLength <= 0) + throw new Error('Decryption error: empty content'); + return cryptor.decrypt({ + data: encryptedData.slice(header.length), + metadata: metadata, + }); + }; CryptoModule.prototype.decryptFile = function (file, File) { return __awaiter(this, void 0, void 0, function () { var header, cryptor, stream_2; var _this = this; return __generator(this, function (_a) { - if ((file === null || file === void 0 ? void 0 : file.data) instanceof Buffer) { + if (file.data && file.data instanceof buffer_1.Buffer) { header = CryptorHeader.tryParse(file.data); cryptor = this.getCryptor(header); /** - * If It's legacyone then redirect it. + * If It's legacy one then redirect it. * (as long as we support legacy need to check on instance type) */ if ((cryptor === null || cryptor === void 0 ? void 0 : cryptor.identifier) === CryptoModule.LEGACY_IDENTIFIER) return [2 /*return*/, cryptor.decryptFile(file, File)]; return [2 /*return*/, File.create({ name: file.name, - data: Buffer.from(this.decrypt(file === null || file === void 0 ? void 0 : file.data)), + data: buffer_1.Buffer.from(this.decrypt(file.data)), })]; } - if (file.data instanceof stream_1.Readable) { + if (file.data && file.data instanceof stream_1.Readable) { stream_2 = file.data; return [2 /*return*/, new Promise(function (resolve) { stream_2.on('readable', function () { return resolve(_this.onStreamReadable(stream_2, file, File)); }); @@ -212,6 +234,97 @@ var CryptoModule = /** @class */ (function () { }); }); }; + // endregion + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + // region Helpers + /** + * Retrieve registered legacy cryptor. + * + * @returns Previously registered {@link ILegacyCryptor|legacy} cryptor. + * + * @throws Error if legacy cryptor not registered. + */ + CryptoModule.prototype.getLegacyCryptor = function () { + return this.getCryptorFromId(CryptoModule.LEGACY_IDENTIFIER); + }; + /** + * Retrieve registered cryptor by its identifier. + * + * @param id - Unique cryptor identifier. + * + * @returns Registered cryptor with specified identifier. + * + * @throws Error if cryptor with specified {@link id} can't be found. + */ + CryptoModule.prototype.getCryptorFromId = function (id) { + var cryptor = this.getAllCryptors().find(function (cryptor) { return id === cryptor.identifier; }); + if (cryptor) + return cryptor; + throw new Error('Unknown cryptor error'); + }; + /** + * Retrieve cryptor by its identifier. + * + * @param header - Header with cryptor-defined data or raw cryptor identifier. + * + * @returns Cryptor which correspond to provided {@link header}. + */ + CryptoModule.prototype.getCryptor = function (header) { + if (typeof header === 'string') { + var cryptor = this.getAllCryptors().find(function (c) { return c.identifier === header; }); + if (cryptor) + return cryptor; + throw new Error('Unknown cryptor error'); + } + else if (header instanceof CryptorHeaderV1) { + return this.getCryptorFromId(header.identifier); + } + }; + /** + * Create cryptor header data. + * + * @param encrypted - Encryption data object as source for header data. + * + * @returns Binary representation of the cryptor header data. + */ + CryptoModule.prototype.getHeaderData = function (encrypted) { + if (!encrypted.metadata) + return; + var header = CryptorHeader.from(this.defaultCryptor.identifier, encrypted.metadata); + var headerData = new Uint8Array(header.length); + var pos = 0; + headerData.set(header.data, pos); + pos += header.length - encrypted.metadata.byteLength; + headerData.set(new Uint8Array(encrypted.metadata), pos); + return headerData.buffer; + }; + /** + * Merge two {@link ArrayBuffer} instances. + * + * @param ab1 - First {@link ArrayBuffer}. + * @param ab2 - Second {@link ArrayBuffer}. + * + * @returns Merged data as {@link ArrayBuffer}. + */ + CryptoModule.prototype.concatArrayBuffer = function (ab1, ab2) { + var tmp = new Uint8Array(ab1.byteLength + ab2.byteLength); + tmp.set(new Uint8Array(ab1), 0); + tmp.set(new Uint8Array(ab2), ab1.byteLength); + return tmp.buffer; + }; + /** + * {@link Readable} stream event handler. + * + * @param stream - Stream which can be used to read data for decryption. + * @param file - File object which has been created with {@link stream}. + * @param File - Class constructor for {@link PubNub} File object. + * + * @returns Decrypted data as {@link PubNub} File object. + * + * @throws Error if file is empty or contains unsupported data type. + */ CryptoModule.prototype.onStreamReadable = function (stream, file, File) { return __awaiter(this, void 0, void 0, function () { var magicBytes, versionByte, identifier, cryptor, headerSize, _a, _b; @@ -223,7 +336,7 @@ var CryptoModule = /** @class */ (function () { magicBytes = stream.read(4); if (!CryptorHeader.isSentinel(magicBytes)) { if (magicBytes === null) - throw new Error('decryption error. empty content'); + throw new Error('Decryption error: empty content'); stream.unshift(magicBytes); return [2 /*return*/, this.decryptLegacyFileStream(stream, file, File)]; } @@ -232,26 +345,40 @@ var CryptoModule = /** @class */ (function () { identifier = stream.read(4); cryptor = this.getCryptorFromId(CryptorHeader.tryGetIdentifier(identifier)); headerSize = CryptorHeader.tryGetMetadataSizeFromStream(stream); - if (file.contentLength <= CryptorHeader.MIN_HEADER_LEGTH + headerSize) - throw new Error('decryption error. empty content'); + if (!file.contentLength || file.contentLength <= CryptorHeader.MIN_HEADER_LENGTH + headerSize) + throw new Error('Decryption error: empty content'); _b = (_a = File).create; _c = { name: file.name, mimeType: 'application/octet-stream' }; - return [4 /*yield*/, cryptor.decryptStream({ stream: stream, metadataLength: headerSize })]; - case 1: return [2 /*return*/, _b.apply(_a, [(_c.stream = _d.sent(), + return [4 /*yield*/, cryptor.decryptStream({ + stream: stream, + metadataLength: headerSize, + })]; + case 1: return [2 /*return*/, _b.apply(_a, [(_c.stream = (_d.sent()), _c)])]; } }); }); }; + /** + * Decrypt {@link Readable} stream using legacy cryptor. + * + * @param stream - Stream which can be used to read data for decryption. + * @param file - File object which has been created with {@link stream}. + * @param File - Class constructor for {@link PubNub} File object. + * + * @returns Decrypted data as {@link PubNub} File object. + * + * @throws Error if file is empty or contains unsupported data type. + */ CryptoModule.prototype.decryptLegacyFileStream = function (stream, file, File) { return __awaiter(this, void 0, void 0, function () { var cryptor; return __generator(this, function (_a) { - if (file.contentLength <= 16) - throw new Error('decryption error: empty content'); + if (!file.contentLength || file.contentLength <= 16) + throw new Error('Decryption error: empty content'); cryptor = this.getLegacyCryptor(); if (cryptor) { return [2 /*return*/, cryptor.decryptFile(File.create({ @@ -259,123 +386,100 @@ var CryptoModule = /** @class */ (function () { stream: stream, }), File)]; } - else { + else throw new Error('unknown cryptor error'); - } return [2 /*return*/]; }); }); }; - CryptoModule.prototype.getCryptor = function (header) { - if (header === '') { - var cryptor = this.getAllCryptors().find(function (c) { return c.identifier === ''; }); - if (cryptor) - return cryptor; - throw new Error('unknown cryptor error'); - } - else if (header instanceof CryptorHeaderV1) { - return this.getCryptorFromId(header.identifier); - } - }; - CryptoModule.prototype.getCryptorFromId = function (id) { - var cryptor = this.getAllCryptors().find(function (c) { return id === c.identifier; }); - if (cryptor) { - return cryptor; - } - throw new Error('unknown cryptor error'); - }; + /** + * {@link LegacyCryptor|Legacy} cryptor identifier. + */ CryptoModule.LEGACY_IDENTIFIER = ''; return CryptoModule; -}()); +}(crypto_module_1.AbstractCryptoModule)); exports.CryptoModule = CryptoModule; -// CryptorHeader Utility +/** + * CryptorHeader Utility + */ var CryptorHeader = /** @class */ (function () { function CryptorHeader() { } CryptorHeader.from = function (id, metadata) { if (id === CryptorHeader.LEGACY_IDENTIFIER) return; - return new CryptorHeaderV1(id, metadata.length); + return new CryptorHeaderV1(id, metadata.byteLength); }; CryptorHeader.isSentinel = function (bytes) { - if (bytes && bytes.byteLength >= 4) { - if (bytes.toString('utf8') == CryptorHeader.SENTINEL) - return true; - } + return bytes && bytes.byteLength >= 4 && CryptorHeader.decoder.decode(bytes) == CryptorHeader.SENTINEL; }; CryptorHeader.validateVersion = function (data) { if (data && data > CryptorHeader.MAX_VERSION) - throw new Error('decryption error. invalid header version'); + throw new Error('Decryption error: invalid header version'); return data; }; CryptorHeader.tryGetIdentifier = function (data) { - if (data.byteLength < 4) { - throw new Error('unknown cryptor error. decryption failed'); - } - else { - return data.toString('utf8'); - } + if (data.byteLength < 4) + throw new Error('Decryption error: unknown cryptor error'); + else + return CryptorHeader.decoder.decode(data); }; CryptorHeader.tryGetMetadataSizeFromStream = function (stream) { var sizeBuf = stream.read(1); - if (sizeBuf && sizeBuf[0] < 255) { + if (sizeBuf && sizeBuf[0] < 255) return sizeBuf[0]; - } if (sizeBuf[0] === 255) { var nextBuf = stream.read(2); if (nextBuf.length >= 2) { return new Uint16Array([nextBuf[0], nextBuf[1]]).reduce(function (acc, val) { return (acc << 8) + val; }, 0); } } - throw new Error('decryption error. Invalid metadata size'); + throw new Error('Decryption error: invalid metadata size'); }; CryptorHeader.tryParse = function (encryptedData) { - var sentinel = ''; + var encryptedDataView = new DataView(encryptedData); + var sentinel; var version = null; - if (encryptedData.length >= 4) { + if (encryptedData.byteLength >= 4) { sentinel = encryptedData.slice(0, 4); - if (sentinel.toString('utf8') !== CryptorHeader.SENTINEL) - return ''; - } - if (encryptedData.length >= 5) { - version = encryptedData[4]; - } - else { - throw new Error('decryption error. invalid header version'); + if (!this.isSentinel(sentinel)) + return CryptoModule.LEGACY_IDENTIFIER; } + if (encryptedData.byteLength >= 5) + version = encryptedDataView.getInt8(4); + else + throw new Error('Decryption error: invalid header version'); if (version > CryptorHeader.MAX_VERSION) throw new Error('unknown cryptor error'); var identifier; var pos = 5 + CryptorHeader.IDENTIFIER_LENGTH; - if (encryptedData.length >= pos) { + if (encryptedData.byteLength >= pos) identifier = encryptedData.slice(5, pos); - } - else { - throw new Error('decryption error. invalid crypto identifier'); - } + else + throw new Error('Decryption error: invalid crypto identifier'); var metadataLength = null; - if (encryptedData.length >= pos + 1) { - metadataLength = encryptedData[pos]; - } - else { - throw new Error('decryption error. invalid metadata length'); - } + if (encryptedData.byteLength >= pos + 1) + metadataLength = encryptedDataView.getInt8(pos); + else + throw new Error('Decryption error: invalid metadata length'); pos += 1; - if (metadataLength === 255 && encryptedData.length >= pos + 2) { + if (metadataLength === 255 && encryptedData.byteLength >= pos + 2) { metadataLength = new Uint16Array(encryptedData.slice(pos, pos + 2)).reduce(function (acc, val) { return (acc << 8) + val; }, 0); - pos += 2; } - return new CryptorHeaderV1(identifier.toString('utf8'), metadataLength); + return new CryptorHeaderV1(CryptorHeader.decoder.decode(identifier), metadataLength); }; + CryptorHeader.decoder = new TextDecoder(); CryptorHeader.SENTINEL = 'PNED'; CryptorHeader.LEGACY_IDENTIFIER = ''; CryptorHeader.IDENTIFIER_LENGTH = 4; CryptorHeader.VERSION = 1; CryptorHeader.MAX_VERSION = 1; - CryptorHeader.MIN_HEADER_LEGTH = 10; + CryptorHeader.MIN_HEADER_LENGTH = 10; return CryptorHeader; }()); -// v1 CryptorHeader +/** + * Cryptor header (v1). + */ var CryptorHeaderV1 = /** @class */ (function () { function CryptorHeaderV1(id, metadataLength) { this._identifier = id; @@ -423,20 +527,18 @@ var CryptorHeaderV1 = /** @class */ (function () { get: function () { var pos = 0; var header = new Uint8Array(this.length); - header.set(Buffer.from(CryptorHeader.SENTINEL)); + header.set(buffer_1.Buffer.from(CryptorHeader.SENTINEL)); pos += CryptorHeader.SENTINEL.length; header[pos] = this.version; pos++; if (this.identifier) - header.set(Buffer.from(this.identifier), pos); - pos += CryptorHeader.IDENTIFIER_LENGTH; + header.set(buffer_1.Buffer.from(this.identifier), pos); var metadataLength = this.metadataLength; - if (metadataLength < 255) { + pos += CryptorHeader.IDENTIFIER_LENGTH; + if (metadataLength < 255) header[pos] = metadataLength; - } - else { + else header.set([255, metadataLength >> 8, metadataLength & 0xff], pos); - } return header; }, enumerable: false, diff --git a/lib/crypto/modules/WebCryptoModule/ICryptor.js b/lib/crypto/modules/WebCryptoModule/ICryptor.js index c8ad2e549..e932a515b 100644 --- a/lib/crypto/modules/WebCryptoModule/ICryptor.js +++ b/lib/crypto/modules/WebCryptoModule/ICryptor.js @@ -1,2 +1,5 @@ "use strict"; +/** + * Cryptor module. + */ Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/lib/crypto/modules/WebCryptoModule/ILegacyCryptor.js b/lib/crypto/modules/WebCryptoModule/ILegacyCryptor.js index c8ad2e549..afefd5492 100644 --- a/lib/crypto/modules/WebCryptoModule/ILegacyCryptor.js +++ b/lib/crypto/modules/WebCryptoModule/ILegacyCryptor.js @@ -1,2 +1,5 @@ "use strict"; +/** + * Legacy cryptor module. + */ Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/lib/crypto/modules/WebCryptoModule/aesCbcCryptor.js b/lib/crypto/modules/WebCryptoModule/aesCbcCryptor.js index d80cbbb15..054a70297 100644 --- a/lib/crypto/modules/WebCryptoModule/aesCbcCryptor.js +++ b/lib/crypto/modules/WebCryptoModule/aesCbcCryptor.js @@ -1,4 +1,7 @@ "use strict"; +/** + * AES-CBC cryptor module. + */ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { @@ -14,7 +17,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) { function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); - while (_) try { + while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { @@ -41,44 +44,22 @@ var __importDefault = (this && this.__importDefault) || function (mod) { Object.defineProperty(exports, "__esModule", { value: true }); var hmac_sha256_1 = __importDefault(require("../../../core/components/cryptography/hmac-sha256")); var base64_codec_1 = require("../../../core/components/base64_codec"); +/** + * AES-CBC cryptor. + * + * AES-CBC cryptor with enhanced cipher strength. + */ var AesCbcCryptor = /** @class */ (function () { - function AesCbcCryptor(configuration) { - this.cipherKey = configuration.cipherKey; + function AesCbcCryptor(_a) { + var cipherKey = _a.cipherKey; + this.cipherKey = cipherKey; this.CryptoJS = hmac_sha256_1.default; - this.encryptedKey = this.CryptoJS.SHA256(this.cipherKey); + this.encryptedKey = this.CryptoJS.SHA256(cipherKey); } - Object.defineProperty(AesCbcCryptor.prototype, "algo", { - get: function () { - return 'AES-CBC'; - }, - enumerable: false, - configurable: true - }); - Object.defineProperty(AesCbcCryptor.prototype, "identifier", { - get: function () { - return 'ACRH'; - }, - enumerable: false, - configurable: true - }); - AesCbcCryptor.prototype.getIv = function () { - return crypto.getRandomValues(new Uint8Array(AesCbcCryptor.BLOCK_SIZE)); - }; - AesCbcCryptor.prototype.getKey = function () { - return __awaiter(this, void 0, void 0, function () { - var bKey, abHash; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - bKey = AesCbcCryptor.encoder.encode(this.cipherKey); - return [4 /*yield*/, crypto.subtle.digest('SHA-256', bKey.buffer)]; - case 1: - abHash = _a.sent(); - return [2 /*return*/, crypto.subtle.importKey('raw', abHash, this.algo, true, ['encrypt', 'decrypt'])]; - } - }); - }); - }; + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + // region Encryption AesCbcCryptor.prototype.encrypt = function (data) { var stringData = typeof data === 'string' ? data : AesCbcCryptor.decoder.decode(data); if (stringData.length === 0) @@ -92,14 +73,6 @@ var AesCbcCryptor = /** @class */ (function () { }).ciphertext.toString(this.CryptoJS.enc.Base64)), }; }; - AesCbcCryptor.prototype.decrypt = function (encryptedData) { - var iv = this.bufferToWordArray(new Uint8ClampedArray(encryptedData.metadata)); - var data = this.bufferToWordArray(new Uint8ClampedArray(encryptedData.data)); - return AesCbcCryptor.encoder.encode(this.CryptoJS.AES.decrypt({ ciphertext: data }, this.encryptedKey, { - iv: iv, - mode: this.CryptoJS.mode.CBC, - }).toString(this.CryptoJS.enc.Utf8)).buffer; - }; AesCbcCryptor.prototype.encryptFileData = function (data) { return __awaiter(this, void 0, void 0, function () { var key, iv; @@ -119,6 +92,19 @@ var AesCbcCryptor = /** @class */ (function () { }); }); }; + // endregion + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + // region Decryption + AesCbcCryptor.prototype.decrypt = function (encryptedData) { + var iv = this.bufferToWordArray(new Uint8ClampedArray(encryptedData.metadata)); + var data = this.bufferToWordArray(new Uint8ClampedArray(encryptedData.data)); + return AesCbcCryptor.encoder.encode(this.CryptoJS.AES.decrypt({ ciphertext: data }, this.encryptedKey, { + iv: iv, + mode: this.CryptoJS.mode.CBC, + }).toString(this.CryptoJS.enc.Utf8)).buffer; + }; AesCbcCryptor.prototype.decryptFileData = function (encryptedData) { return __awaiter(this, void 0, void 0, function () { var key; @@ -132,6 +118,65 @@ var AesCbcCryptor = /** @class */ (function () { }); }); }; + Object.defineProperty(AesCbcCryptor.prototype, "identifier", { + // endregion + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + // region Helpers + get: function () { + return 'ACRH'; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(AesCbcCryptor.prototype, "algo", { + /** + * Cryptor algorithm. + * + * @returns Cryptor module algorithm. + */ + get: function () { + return 'AES-CBC'; + }, + enumerable: false, + configurable: true + }); + /** + * Generate random initialization vector. + * + * @returns Random initialization vector. + */ + AesCbcCryptor.prototype.getIv = function () { + return crypto.getRandomValues(new Uint8Array(AesCbcCryptor.BLOCK_SIZE)); + }; + /** + * Convert cipher key to the {@link Buffer}. + * + * @returns SHA256 encoded cipher key {@link Buffer}. + */ + AesCbcCryptor.prototype.getKey = function () { + return __awaiter(this, void 0, void 0, function () { + var bKey, abHash; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + bKey = AesCbcCryptor.encoder.encode(this.cipherKey); + return [4 /*yield*/, crypto.subtle.digest('SHA-256', bKey.buffer)]; + case 1: + abHash = _a.sent(); + return [2 /*return*/, crypto.subtle.importKey('raw', abHash, this.algo, true, ['encrypt', 'decrypt'])]; + } + }); + }); + }; + /** + * Convert bytes array to words array. + * + * @param b - Bytes array (buffer) which should be converted. + * + * @returns Word sized array. + */ AesCbcCryptor.prototype.bufferToWordArray = function (b) { var wa = []; var i; @@ -140,8 +185,17 @@ var AesCbcCryptor = /** @class */ (function () { } return this.CryptoJS.lib.WordArray.create(wa, b.length); }; + /** + * Cryptor block size. + */ AesCbcCryptor.BLOCK_SIZE = 16; + /** + * {@link string|String} to {@link ArrayBuffer} response decoder. + */ AesCbcCryptor.encoder = new TextEncoder(); + /** + * {@link ArrayBuffer} to {@link string} decoder. + */ AesCbcCryptor.decoder = new TextDecoder(); return AesCbcCryptor; }()); diff --git a/lib/crypto/modules/WebCryptoModule/legacyCryptor.js b/lib/crypto/modules/WebCryptoModule/legacyCryptor.js index 9b318e359..67c119700 100644 --- a/lib/crypto/modules/WebCryptoModule/legacyCryptor.js +++ b/lib/crypto/modules/WebCryptoModule/legacyCryptor.js @@ -1,4 +1,18 @@ "use strict"; +/** + * Legacy cryptor module. + */ +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { @@ -14,7 +28,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) { function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); - while (_) try { + while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { @@ -40,51 +54,77 @@ var __importDefault = (this && this.__importDefault) || function (mod) { }; Object.defineProperty(exports, "__esModule", { value: true }); var index_1 = __importDefault(require("../../../core/components/cryptography/index")); -var web_1 = __importDefault(require("../web")); var base64_codec_1 = require("../../../core/components/base64_codec"); +var PubNubError_1 = require("../../../models/PubNubError"); +var web_1 = __importDefault(require("../web")); +/** + * Legacy cryptor. + */ var LegacyCryptor = /** @class */ (function () { function LegacyCryptor(config) { this.config = config; - this.cryptor = new index_1.default({ config: config }); + this.cryptor = new index_1.default(__assign({}, config)); this.fileCryptor = new web_1.default(); } - Object.defineProperty(LegacyCryptor.prototype, "identifier", { - get: function () { - return ''; - }, - enumerable: false, - configurable: true - }); + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + // region Encryption LegacyCryptor.prototype.encrypt = function (data) { - var stringData = typeof data === 'string' ? data : new TextDecoder().decode(data); + var stringData = typeof data === 'string' ? data : LegacyCryptor.decoder.decode(data); return { - data: this.cryptor.encrypt(stringData), + data: LegacyCryptor.encoder.encode(this.cryptor.encrypt(stringData)), metadata: null, }; }; - LegacyCryptor.prototype.decrypt = function (encryptedData) { - var data = typeof encryptedData.data === 'string' ? encryptedData.data : (0, base64_codec_1.encode)(encryptedData.data); - return this.cryptor.decrypt(data); - }; LegacyCryptor.prototype.encryptFile = function (file, File) { - var _a; return __awaiter(this, void 0, void 0, function () { + var _a; return __generator(this, function (_b) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - //@ts-ignore: can not detect cipherKey from old Config + if (!this.config.cipherKey) + throw new PubNubError_1.PubNubError('File encryption error: cipher key not set.'); return [2 /*return*/, this.fileCryptor.encryptFile((_a = this.config) === null || _a === void 0 ? void 0 : _a.cipherKey, file, File)]; }); }); }; + // endregion + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + // region Decryption + LegacyCryptor.prototype.decrypt = function (encryptedData) { + var data = typeof encryptedData.data === 'string' ? encryptedData.data : (0, base64_codec_1.encode)(encryptedData.data); + return this.cryptor.decrypt(data); + }; LegacyCryptor.prototype.decryptFile = function (file, File) { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - //@ts-ignore: can not detect cipherKey from old Config + if (!this.config.cipherKey) + throw new PubNubError_1.PubNubError('File encryption error: cipher key not set.'); return [2 /*return*/, this.fileCryptor.decryptFile(this.config.cipherKey, file, File)]; }); }); }; + Object.defineProperty(LegacyCryptor.prototype, "identifier", { + // endregion + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + // region Helpers + get: function () { + return ''; + }, + enumerable: false, + configurable: true + }); + /** + * `string` to {@link ArrayBuffer} response decoder. + */ + LegacyCryptor.encoder = new TextEncoder(); + /** + * {@link ArrayBuffer} to {@link string} decoder. + */ + LegacyCryptor.decoder = new TextDecoder(); return LegacyCryptor; }()); exports.default = LegacyCryptor; diff --git a/lib/crypto/modules/WebCryptoModule/webCryptoModule.js b/lib/crypto/modules/WebCryptoModule/webCryptoModule.js index f4c7ccabf..4df8115c3 100644 --- a/lib/crypto/modules/WebCryptoModule/webCryptoModule.js +++ b/lib/crypto/modules/WebCryptoModule/webCryptoModule.js @@ -1,4 +1,33 @@ "use strict"; +/** + * Browser crypto module. + */ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { @@ -14,7 +43,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) { function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); - while (_) try { + while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { @@ -35,107 +64,89 @@ var __generator = (this && this.__generator) || function (thisArg, body) { if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; -var __read = (this && this.__read) || function (o, n) { - var m = typeof Symbol === "function" && o[Symbol.iterator]; - if (!m) return o; - var i = m.call(o), r, ar = [], e; - try { - while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); - } - catch (error) { e = { error: error }; } - finally { - try { - if (r && !r.done && (m = i["return"])) m.call(i); - } - finally { if (e) throw e.error; } - } - return ar; -}; -var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { - if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { - if (ar || !(i in from)) { - if (!ar) ar = Array.prototype.slice.call(from, 0, i); - ar[i] = from[i]; - } - } - return to.concat(ar || Array.prototype.slice.call(from)); -}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.CryptoModule = exports.AesCbcCryptor = exports.LegacyCryptor = void 0; -var legacyCryptor_1 = __importDefault(require("./legacyCryptor")); -exports.LegacyCryptor = legacyCryptor_1.default; +exports.WebCryptoModule = exports.AesCbcCryptor = exports.LegacyCryptor = void 0; +var crypto_module_1 = require("../../../core/interfaces/crypto-module"); +var web_1 = require("../../../file/modules/web"); +var base64_codec_1 = require("../../../core/components/base64_codec"); +var PubNubError_1 = require("../../../models/PubNubError"); var aesCbcCryptor_1 = __importDefault(require("./aesCbcCryptor")); exports.AesCbcCryptor = aesCbcCryptor_1.default; -var base64_codec_1 = require("../../../core/components/base64_codec"); -var CryptoModule = /** @class */ (function () { - function CryptoModule(cryptoModuleConfiguration) { - var _a; - this.defaultCryptor = cryptoModuleConfiguration.default; - this.cryptors = (_a = cryptoModuleConfiguration.cryptors) !== null && _a !== void 0 ? _a : []; +var legacyCryptor_1 = __importDefault(require("./legacyCryptor")); +exports.LegacyCryptor = legacyCryptor_1.default; +/** + * CryptoModule for browser platform. + */ +var WebCryptoModule = /** @class */ (function (_super) { + __extends(WebCryptoModule, _super); + function WebCryptoModule() { + return _super !== null && _super.apply(this, arguments) || this; } - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - //@ts-ignore: type detection issue with old Config type assignment - CryptoModule.legacyCryptoModule = function (config) { + // -------------------------------------------------------- + // --------------- Convenience functions ------------------ + // ------------------------------------------------------- + // region Convenience functions + WebCryptoModule.legacyCryptoModule = function (config) { var _a; - return new this({ - default: new legacyCryptor_1.default({ - cipherKey: config.cipherKey, - useRandomIVs: (_a = config.useRandomIVs) !== null && _a !== void 0 ? _a : true, - }), + if (!config.cipherKey) + throw new PubNubError_1.PubNubError('Crypto module error: cipher key not set.'); + return new WebCryptoModule({ + default: new legacyCryptor_1.default(__assign(__assign({}, config), { useRandomIVs: (_a = config.useRandomIVs) !== null && _a !== void 0 ? _a : true })), cryptors: [new aesCbcCryptor_1.default({ cipherKey: config.cipherKey })], }); }; - CryptoModule.aesCbcCryptoModule = function (config) { + WebCryptoModule.aesCbcCryptoModule = function (config) { var _a; - return new this({ + if (!config.cipherKey) + throw new PubNubError_1.PubNubError('Crypto module error: cipher key not set.'); + return new WebCryptoModule({ default: new aesCbcCryptor_1.default({ cipherKey: config.cipherKey }), cryptors: [ - new legacyCryptor_1.default({ - cipherKey: config.cipherKey, - useRandomIVs: (_a = config.useRandomIVs) !== null && _a !== void 0 ? _a : true, - }), + new legacyCryptor_1.default(__assign(__assign({}, config), { useRandomIVs: (_a = config.useRandomIVs) !== null && _a !== void 0 ? _a : true })), ], }); }; - CryptoModule.withDefaultCryptor = function (defaultCryptor) { + /** + * Construct crypto module with `cryptor` as default for data encryption and decryption. + * + * @param defaultCryptor - Default cryptor for data encryption and decryption. + * + * @returns Crypto module with pre-configured default cryptor. + */ + WebCryptoModule.withDefaultCryptor = function (defaultCryptor) { return new this({ default: defaultCryptor }); }; - CryptoModule.prototype.getAllCryptors = function () { - return __spreadArray([this.defaultCryptor], __read(this.cryptors), false); - }; - CryptoModule.prototype.encrypt = function (data) { - var encrypted = this.defaultCryptor.encrypt(data); + // endregion + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + // region Encryption + WebCryptoModule.prototype.encrypt = function (data) { + // Encrypt data. + var encrypted = data instanceof ArrayBuffer && this.defaultCryptor.identifier === WebCryptoModule.LEGACY_IDENTIFIER + ? this.defaultCryptor.encrypt(WebCryptoModule.decoder.decode(data)) + : this.defaultCryptor.encrypt(data); if (!encrypted.metadata) return encrypted.data; var headerData = this.getHeaderData(encrypted); return this.concatArrayBuffer(headerData, encrypted.data); }; - CryptoModule.prototype.decrypt = function (data) { - var encryptedData = typeof data === 'string' ? (0, base64_codec_1.decode)(data) : data; - var header = CryptorHeader.tryParse(encryptedData); - var cryptor = this.getCryptor(header); - var metadata = header.length > 0 - ? encryptedData.slice(header.length - header.metadataLength, header.length) - : null; - if (encryptedData.slice(header.length).byteLength <= 0) - throw new Error('decryption error. empty content'); - return cryptor.decrypt({ - data: encryptedData.slice(header.length), - metadata: metadata, - }); - }; - CryptoModule.prototype.encryptFile = function (file, File) { + WebCryptoModule.prototype.encryptFile = function (file, File) { return __awaiter(this, void 0, void 0, function () { var fileData, encrypted; return __generator(this, function (_a) { switch (_a.label) { case 0: + /** + * Files handled differently in case of Legacy cryptor. + * (as long as we support legacy need to check on instance type) + */ if (this.defaultCryptor.identifier === CryptorHeader.LEGACY_IDENTIFIER) return [2 /*return*/, this.defaultCryptor.encryptFile(file, File)]; - return [4 /*yield*/, this.getFileData(file.data)]; + return [4 /*yield*/, this.getFileData(file)]; case 1: fileData = _a.sent(); return [4 /*yield*/, this.defaultCryptor.encryptFileData(fileData)]; @@ -150,7 +161,26 @@ var CryptoModule = /** @class */ (function () { }); }); }; - CryptoModule.prototype.decryptFile = function (file, File) { + // endregion + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + // region Decryption + WebCryptoModule.prototype.decrypt = function (data) { + var encryptedData = typeof data === 'string' ? (0, base64_codec_1.decode)(data) : data; + var header = CryptorHeader.tryParse(encryptedData); + var cryptor = this.getCryptor(header); + var metadata = header.length > 0 + ? encryptedData.slice(header.length - header.metadataLength, header.length) + : null; + if (encryptedData.slice(header.length).byteLength <= 0) + throw new Error('Decryption error: empty content'); + return cryptor.decrypt({ + data: encryptedData.slice(header.length), + metadata: metadata, + }); + }; + WebCryptoModule.prototype.decryptFile = function (file, File) { return __awaiter(this, void 0, void 0, function () { var data, header, cryptor, fileData, metadata, _a, _b; var _c; @@ -161,9 +191,12 @@ var CryptoModule = /** @class */ (function () { data = _d.sent(); header = CryptorHeader.tryParse(data); cryptor = this.getCryptor(header); - if ((cryptor === null || cryptor === void 0 ? void 0 : cryptor.identifier) === CryptoModule.LEGACY_IDENTIFIER) { + /** + * Files handled differently in case of Legacy cryptor. + * (as long as we support legacy need to check on instance type) + */ + if ((cryptor === null || cryptor === void 0 ? void 0 : cryptor.identifier) === CryptorHeader.LEGACY_IDENTIFIER) return [2 /*return*/, cryptor.decryptFile(file, File)]; - } return [4 /*yield*/, this.getFileData(data)]; case 2: fileData = _d.sent(); @@ -182,31 +215,52 @@ var CryptoModule = /** @class */ (function () { }); }); }; - CryptoModule.prototype.getCryptor = function (header) { - if (header === '') { - var cryptor = this.getAllCryptors().find(function (c) { return c.identifier === ''; }); + // endregion + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + // region Helpers + /** + * Retrieve registered cryptor by its identifier. + * + * @param id - Unique cryptor identifier. + * + * @returns Registered cryptor with specified identifier. + * + * @throws Error if cryptor with specified {@link id} can't be found. + */ + WebCryptoModule.prototype.getCryptorFromId = function (id) { + var cryptor = this.getAllCryptors().find(function (cryptor) { return id === cryptor.identifier; }); + if (cryptor) + return cryptor; + throw Error('Unknown cryptor error'); + }; + /** + * Retrieve cryptor by its identifier. + * + * @param header - Header with cryptor-defined data or raw cryptor identifier. + * + * @returns Cryptor which correspond to provided {@link header}. + */ + WebCryptoModule.prototype.getCryptor = function (header) { + if (typeof header === 'string') { + var cryptor = this.getAllCryptors().find(function (cryptor) { return cryptor.identifier === header; }); if (cryptor) return cryptor; - throw new Error('unknown cryptor error'); + throw new Error('Unknown cryptor error'); } else if (header instanceof CryptorHeaderV1) { return this.getCryptorFromId(header.identifier); } }; - CryptoModule.prototype.getCryptorFromId = function (id) { - var cryptor = this.getAllCryptors().find(function (c) { return id === c.identifier; }); - if (cryptor) { - return cryptor; - } - throw Error('unknown cryptor error'); - }; - CryptoModule.prototype.concatArrayBuffer = function (ab1, ab2) { - var tmp = new Uint8Array(ab1.byteLength + ab2.byteLength); - tmp.set(new Uint8Array(ab1), 0); - tmp.set(new Uint8Array(ab2), ab1.byteLength); - return tmp.buffer; - }; - CryptoModule.prototype.getHeaderData = function (encrypted) { + /** + * Create cryptor header data. + * + * @param encrypted - Encryption data object as source for header data. + * + * @returns Binary representation of the cryptor header data. + */ + WebCryptoModule.prototype.getHeaderData = function (encrypted) { if (!encrypted.metadata) return; var header = CryptorHeader.from(this.defaultCryptor.identifier, encrypted.metadata); @@ -217,36 +271,48 @@ var CryptoModule = /** @class */ (function () { headerData.set(new Uint8Array(encrypted.metadata), pos); return headerData.buffer; }; - CryptoModule.prototype.getFileData = function (input) { + /** + * Merge two {@link ArrayBuffer} instances. + * + * @param ab1 - First {@link ArrayBuffer}. + * @param ab2 - Second {@link ArrayBuffer}. + * + * @returns Merged data as {@link ArrayBuffer}. + */ + WebCryptoModule.prototype.concatArrayBuffer = function (ab1, ab2) { + var tmp = new Uint8Array(ab1.byteLength + ab2.byteLength); + tmp.set(new Uint8Array(ab1), 0); + tmp.set(new Uint8Array(ab2), ab1.byteLength); + return tmp.buffer; + }; + /** + * Retrieve file content. + * + * @param file - Content of the {@link PubNub} File object. + * + * @returns Normalized file {@link data} as {@link ArrayBuffer}; + */ + WebCryptoModule.prototype.getFileData = function (file) { return __awaiter(this, void 0, void 0, function () { - var fileData; return __generator(this, function (_a) { - switch (_a.label) { - case 0: - if (!(input instanceof Blob)) return [3 /*break*/, 2]; - return [4 /*yield*/, input.arrayBuffer()]; - case 1: - fileData = _a.sent(); - return [2 /*return*/, fileData]; - case 2: - if (input instanceof ArrayBuffer) { - return [2 /*return*/, input]; - } - if (typeof input === 'string') { - return [2 /*return*/, CryptoModule.encoder.encode(input)]; - } - throw new Error('Cannot decrypt/encrypt file. In browsers file encrypt/decrypt supported for string, ArrayBuffer or Blob'); - } + if (file instanceof ArrayBuffer) + return [2 /*return*/, file]; + else if (file instanceof web_1.PubNubFile) + return [2 /*return*/, file.toArrayBuffer()]; + throw new Error('Cannot decrypt/encrypt file. In browsers file encrypt/decrypt supported for string, ArrayBuffer or Blob'); }); }); }; - CryptoModule.LEGACY_IDENTIFIER = ''; - CryptoModule.encoder = new TextEncoder(); - CryptoModule.decoder = new TextDecoder(); - return CryptoModule; -}()); -exports.CryptoModule = CryptoModule; -// CryptorHeader Utility + /** + * {@link LegacyCryptor|Legacy} cryptor identifier. + */ + WebCryptoModule.LEGACY_IDENTIFIER = ''; + return WebCryptoModule; +}(crypto_module_1.AbstractCryptoModule)); +exports.WebCryptoModule = WebCryptoModule; +/** + * CryptorHeader Utility + */ var CryptorHeader = /** @class */ (function () { function CryptorHeader() { } @@ -257,40 +323,33 @@ var CryptorHeader = /** @class */ (function () { }; CryptorHeader.tryParse = function (data) { var encryptedData = new Uint8Array(data); - var sentinel = ''; + var sentinel; var version = null; if (encryptedData.byteLength >= 4) { sentinel = encryptedData.slice(0, 4); if (this.decoder.decode(sentinel) !== CryptorHeader.SENTINEL) - return ''; + return WebCryptoModule.LEGACY_IDENTIFIER; } - if (encryptedData.byteLength >= 5) { + if (encryptedData.byteLength >= 5) version = encryptedData[4]; - } - else { - throw new Error('decryption error. invalid header version'); - } + else + throw new Error('Decryption error: invalid header version'); if (version > CryptorHeader.MAX_VERSION) - throw new Error('unknown cryptor error'); - var identifier = ''; + throw new Error('Decryption error: Unknown cryptor error'); + var identifier; var pos = 5 + CryptorHeader.IDENTIFIER_LENGTH; - if (encryptedData.byteLength >= pos) { + if (encryptedData.byteLength >= pos) identifier = encryptedData.slice(5, pos); - } - else { - throw new Error('decryption error. invalid crypto identifier'); - } + else + throw new Error('Decryption error: invalid crypto identifier'); var metadataLength = null; - if (encryptedData.byteLength >= pos + 1) { + if (encryptedData.byteLength >= pos + 1) metadataLength = encryptedData[pos]; - } - else { - throw new Error('decryption error. invalid metadata length'); - } + else + throw new Error('Decryption error: invalid metadata length'); pos += 1; if (metadataLength === 255 && encryptedData.byteLength >= pos + 2) { metadataLength = new Uint16Array(encryptedData.slice(pos, pos + 2)).reduce(function (acc, val) { return (acc << 8) + val; }, 0); - pos += 2; } return new CryptorHeaderV1(this.decoder.decode(identifier), metadataLength); }; @@ -357,14 +416,12 @@ var CryptorHeaderV1 = /** @class */ (function () { pos++; if (this.identifier) header.set(encoder.encode(this.identifier), pos); - pos += CryptorHeader.IDENTIFIER_LENGTH; var metadataLength = this.metadataLength; - if (metadataLength < 255) { + pos += CryptorHeader.IDENTIFIER_LENGTH; + if (metadataLength < 255) header[pos] = metadataLength; - } - else { + else header.set([255, metadataLength >> 8, metadataLength & 0xff], pos); - } return header; }, enumerable: false, diff --git a/lib/crypto/modules/node.js b/lib/crypto/modules/node.js index cb3968452..28cecf07c 100644 --- a/lib/crypto/modules/node.js +++ b/lib/crypto/modules/node.js @@ -1,4 +1,7 @@ "use strict"; +/** + * Legacy Node.js cryptography module. + */ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { @@ -14,7 +17,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) { function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); - while (_) try { + while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { @@ -36,193 +39,185 @@ var __generator = (this && this.__generator) || function (thisArg, body) { } }; Object.defineProperty(exports, "__esModule", { value: true }); -/** */ -var stream_1 = require("stream"); var crypto_1 = require("crypto"); +var stream_1 = require("stream"); +var buffer_1 = require("buffer"); +/** + * Legacy cryptography implementation for Node.js-based {@link PubNub} client. + */ var NodeCryptography = /** @class */ (function () { function NodeCryptography() { } - Object.defineProperty(NodeCryptography.prototype, "algo", { - get: function () { - return 'aes-256-cbc'; - }, - enumerable: false, - configurable: true - }); + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + // region Encryption NodeCryptography.prototype.encrypt = function (key, input) { return __awaiter(this, void 0, void 0, function () { var bKey; return __generator(this, function (_a) { bKey = this.getKey(key); - if (input instanceof Buffer) { + if (input instanceof buffer_1.Buffer) return [2 /*return*/, this.encryptBuffer(bKey, input)]; - } - if (input instanceof stream_1.Readable) { + if (input instanceof stream_1.Readable) return [2 /*return*/, this.encryptStream(bKey, input)]; - } - if (typeof input === 'string') { + if (typeof input === 'string') return [2 /*return*/, this.encryptString(bKey, input)]; - } - throw new Error('Unsupported input format'); + throw new Error('Encryption error: unsupported input format'); }); }); }; - NodeCryptography.prototype.decrypt = function (key, input) { + /** + * Encrypt provided source {@link Buffer} using specific encryption {@link key}. + * + * @param key - Data encryption key.
**Note:** Same key should be used to `decrypt` {@link Buffer}. + * @param buffer - Source {@link Buffer} for encryption. + * + * @returns Encrypted data as {@link Buffer} object. + */ + NodeCryptography.prototype.encryptBuffer = function (key, buffer) { + var bIv = this.getIv(); + var aes = (0, crypto_1.createCipheriv)(this.algo, key, bIv); + return buffer_1.Buffer.concat([bIv, aes.update(buffer), aes.final()]); + }; + /** + * Encrypt provided source {@link Readable} stream using specific encryption {@link key}. + * + * @param key - Data encryption key.
**Note:** Same key should be used to `decrypt` {@link Readable} stream. + * @param stream - Source {@link Readable} stream for encryption. + * + * @returns Encrypted data as {@link Transform} object. + */ + NodeCryptography.prototype.encryptStream = function (key, stream) { return __awaiter(this, void 0, void 0, function () { - var bKey; + var bIv, aes, initiated; return __generator(this, function (_a) { - bKey = this.getKey(key); - if (input instanceof Buffer) { - return [2 /*return*/, this.decryptBuffer(bKey, input)]; - } - if (input instanceof stream_1.Readable) { - return [2 /*return*/, this.decryptStream(bKey, input)]; - } - if (typeof input === 'string') { - return [2 /*return*/, this.decryptString(bKey, input)]; - } - throw new Error('Unsupported input format'); + bIv = this.getIv(); + aes = (0, crypto_1.createCipheriv)(this.algo, key, bIv).setAutoPadding(true); + initiated = false; + return [2 /*return*/, stream.pipe(aes).pipe(new stream_1.Transform({ + transform: function (chunk, _, cb) { + if (!initiated) { + initiated = true; + this.push(buffer_1.Buffer.concat([bIv, chunk])); + } + else + this.push(chunk); + cb(); + }, + }))]; }); }); }; + /** + * Encrypt provided source {@link string} using specific encryption {@link key}. + * + * @param key - Data encryption key.
**Note:** Same key should be used to `decrypt` {@link string}. + * @param text - Source {@link string} for encryption. + * + * @returns Encrypted data as byte {@link string}. + */ + NodeCryptography.prototype.encryptString = function (key, text) { + var bIv = this.getIv(); + var bPlaintext = buffer_1.Buffer.from(text); + var aes = (0, crypto_1.createCipheriv)(this.algo, key, bIv); + return buffer_1.Buffer.concat([bIv, aes.update(bPlaintext), aes.final()]).toString('utf8'); + }; NodeCryptography.prototype.encryptFile = function (key, file, File) { return __awaiter(this, void 0, void 0, function () { - var bKey, _a, _b, _c, _d; - var _e, _f; - return __generator(this, function (_g) { - switch (_g.label) { + var bKey, _a, _b; + var _c; + return __generator(this, function (_d) { + switch (_d.label) { case 0: bKey = this.getKey(key); - if (!(file.data instanceof Buffer)) return [3 /*break*/, 2]; - if (file.data.byteLength <= 0) - throw new Error('encryption error. empty content'); - _b = (_a = File).create; - _e = { - name: file.name, - mimeType: 'application/octet-stream' - }; - return [4 /*yield*/, this.encryptBuffer(bKey, file.data)]; - case 1: return [2 /*return*/, _b.apply(_a, [(_e.data = _g.sent(), - _e)])]; - case 2: - if (!(file.data instanceof stream_1.Readable)) return [3 /*break*/, 4]; + /** + * Buffer type check also covers `string` which converted to the `Buffer` during file object creation. + */ + if (file.data instanceof buffer_1.Buffer) { + if (file.data.byteLength <= 0) + throw new Error('Encryption error: empty content.'); + return [2 /*return*/, File.create({ + name: file.name, + mimeType: file.mimeType, + data: this.encryptBuffer(bKey, file.data), + })]; + } + if (!(file.data instanceof stream_1.Readable)) return [3 /*break*/, 2]; if (file.contentLength === 0) - throw new Error('encryption error. empty content'); - _d = (_c = File).create; - _f = { + throw new Error('Encryption error: empty content.'); + _b = (_a = File).create; + _c = { name: file.name, - mimeType: 'application/octet-stream' + mimeType: file.mimeType }; return [4 /*yield*/, this.encryptStream(bKey, file.data)]; - case 3: return [2 /*return*/, _d.apply(_c, [(_f.stream = _g.sent(), - _f)])]; - case 4: throw new Error('Cannot encrypt this file. In Node.js file encryption supports only string, Buffer or Stream.'); + case 1: return [2 /*return*/, _b.apply(_a, [(_c.stream = _d.sent(), + _c)])]; + case 2: throw new Error('Cannot encrypt this file. In Node.js file encryption supports only string, Buffer or Stream.'); } }); }); }; - NodeCryptography.prototype.decryptFile = function (key, file, File) { + // endregion + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + // region Decryption + NodeCryptography.prototype.decrypt = function (key, input) { return __awaiter(this, void 0, void 0, function () { - var bKey, _a, _b, _c, _d; - var _e, _f; - return __generator(this, function (_g) { - switch (_g.label) { - case 0: - bKey = this.getKey(key); - if (!(file.data instanceof Buffer)) return [3 /*break*/, 2]; - _b = (_a = File).create; - _e = { - name: file.name - }; - return [4 /*yield*/, this.decryptBuffer(bKey, file.data)]; - case 1: return [2 /*return*/, _b.apply(_a, [(_e.data = _g.sent(), - _e)])]; - case 2: - if (!(file.data instanceof stream_1.Readable)) return [3 /*break*/, 4]; - _d = (_c = File).create; - _f = { - name: file.name - }; - return [4 /*yield*/, this.decryptStream(bKey, file.data)]; - case 3: return [2 /*return*/, _d.apply(_c, [(_f.stream = _g.sent(), - _f)])]; - case 4: throw new Error('Cannot decrypt this file. In Node.js file decryption supports only string, Buffer or Stream.'); - } + var bKey; + return __generator(this, function (_a) { + bKey = this.getKey(key); + if (input instanceof buffer_1.Buffer) + return [2 /*return*/, this.decryptBuffer(bKey, input)]; + if (input instanceof stream_1.Readable) + return [2 /*return*/, this.decryptStream(bKey, input)]; + if (typeof input === 'string') + return [2 /*return*/, this.decryptString(bKey, input)]; + throw new Error('Decryption error: unsupported input format'); }); }); }; - NodeCryptography.prototype.getKey = function (key) { - var sha = (0, crypto_1.createHash)('sha256'); - sha.update(Buffer.from(key, 'utf8')); - return Buffer.from(sha.digest('hex').slice(0, 32), 'utf8'); - }; - NodeCryptography.prototype.getIv = function () { - return (0, crypto_1.randomBytes)(NodeCryptography.IV_LENGTH); - }; - NodeCryptography.prototype.encryptString = function (key, plaintext) { - var bIv = this.getIv(); - var bPlaintext = Buffer.from(plaintext); - var aes = (0, crypto_1.createCipheriv)(this.algo, key, bIv); - return Buffer.concat([bIv, aes.update(bPlaintext), aes.final()]).toString('utf8'); - }; - NodeCryptography.prototype.decryptString = function (key, sCiphertext) { - var ciphertext = Buffer.from(sCiphertext); - var bIv = ciphertext.slice(0, NodeCryptography.IV_LENGTH); - var bCiphertext = ciphertext.slice(NodeCryptography.IV_LENGTH); - var aes = (0, crypto_1.createDecipheriv)(this.algo, key, bIv); - return Buffer.concat([aes.update(bCiphertext), aes.final()]).toString('utf8'); - }; - NodeCryptography.prototype.encryptBuffer = function (key, plaintext) { - var bIv = this.getIv(); - var aes = (0, crypto_1.createCipheriv)(this.algo, key, bIv); - return Buffer.concat([bIv, aes.update(plaintext), aes.final()]); - }; - NodeCryptography.prototype.decryptBuffer = function (key, ciphertext) { - var bIv = ciphertext.slice(0, NodeCryptography.IV_LENGTH); - var bCiphertext = ciphertext.slice(NodeCryptography.IV_LENGTH); + /** + * Decrypt provided encrypted {@link Buffer} using specific decryption {@link key}. + * + * @param key - Data decryption key.
**Note:** Should be the same as used to `encrypt` {@link Buffer}. + * @param buffer - Encrypted {@link Buffer} for decryption. + * + * @returns Decrypted data as {@link Buffer} object. + */ + NodeCryptography.prototype.decryptBuffer = function (key, buffer) { + var bIv = buffer.slice(0, NodeCryptography.IV_LENGTH); + var bCiphertext = buffer.slice(NodeCryptography.IV_LENGTH); if (bCiphertext.byteLength <= 0) - throw new Error('decryption error: empty content'); + throw new Error('Decryption error: empty content'); var aes = (0, crypto_1.createDecipheriv)(this.algo, key, bIv); - return Buffer.concat([aes.update(bCiphertext), aes.final()]); - }; - NodeCryptography.prototype.encryptStream = function (key, stream) { - return __awaiter(this, void 0, void 0, function () { - var bIv, aes, inited; - return __generator(this, function (_a) { - bIv = this.getIv(); - aes = (0, crypto_1.createCipheriv)('aes-256-cbc', key, bIv).setAutoPadding(true); - inited = false; - return [2 /*return*/, stream.pipe(aes).pipe(new stream_1.Transform({ - transform: function (chunk, _, cb) { - if (!inited) { - inited = true; - this.push(Buffer.concat([bIv, chunk])); - } - else { - this.push(chunk); - } - cb(); - }, - }))]; - }); - }); + return buffer_1.Buffer.concat([aes.update(bCiphertext), aes.final()]); }; + /** + * Decrypt provided encrypted {@link Readable} stream using specific decryption {@link key}. + * + * @param key - Data decryption key.
**Note:** Should be the same as used to `encrypt` {@link Readable} stream. + * @param stream - Encrypted {@link Readable} stream for decryption. + * + * @returns Decrypted data as {@link Readable} object. + */ NodeCryptography.prototype.decryptStream = function (key, stream) { var _this = this; - var output = new stream_1.PassThrough(); - var bIv = Buffer.alloc(0); var aes = null; + var output = new stream_1.PassThrough(); + var bIv = buffer_1.Buffer.alloc(0); var getIv = function () { var data = stream.read(); while (data !== null) { if (data) { - var bChunk = Buffer.from(data); + var bChunk = buffer_1.Buffer.from(data); var sliceLen = NodeCryptography.IV_LENGTH - bIv.byteLength; - if (bChunk.byteLength < sliceLen) { - bIv = Buffer.concat([bIv, bChunk]); - } + if (bChunk.byteLength < sliceLen) + bIv = buffer_1.Buffer.concat([bIv, bChunk]); else { - bIv = Buffer.concat([bIv, bChunk.slice(0, sliceLen)]); + bIv = buffer_1.Buffer.concat([bIv, bChunk.slice(0, sliceLen)]); aes = (0, crypto_1.createDecipheriv)(_this.algo, key, bIv); aes.pipe(output); aes.write(bChunk.slice(sliceLen)); @@ -233,13 +228,93 @@ var NodeCryptography = /** @class */ (function () { }; stream.on('readable', getIv); stream.on('end', function () { - if (aes) { + if (aes) aes.end(); - } output.end(); }); return output; }; + /** + * Decrypt provided encrypted {@link string} using specific decryption {@link key}. + * + * @param key - Data decryption key.
**Note:** Should be the same as used to `encrypt` {@link string}. + * @param text - Encrypted {@link string} for decryption. + * + * @returns Decrypted data as byte {@link string}. + */ + NodeCryptography.prototype.decryptString = function (key, text) { + var ciphertext = buffer_1.Buffer.from(text); + var bIv = ciphertext.slice(0, NodeCryptography.IV_LENGTH); + var bCiphertext = ciphertext.slice(NodeCryptography.IV_LENGTH); + var aes = (0, crypto_1.createDecipheriv)(this.algo, key, bIv); + return buffer_1.Buffer.concat([aes.update(bCiphertext), aes.final()]).toString('utf8'); + }; + NodeCryptography.prototype.decryptFile = function (key, file, File) { + return __awaiter(this, void 0, void 0, function () { + var bKey; + return __generator(this, function (_a) { + bKey = this.getKey(key); + /** + * Buffer type check also covers `string` which converted to the `Buffer` during file object creation. + */ + if (file.data instanceof buffer_1.Buffer) { + return [2 /*return*/, File.create({ + name: file.name, + mimeType: file.mimeType, + data: this.decryptBuffer(bKey, file.data), + })]; + } + if (file.data instanceof stream_1.Readable) { + return [2 /*return*/, File.create({ + name: file.name, + mimeType: file.mimeType, + stream: this.decryptStream(bKey, file.data), + })]; + } + throw new Error('Cannot decrypt this file. In Node.js file decryption supports only string, Buffer or Stream.'); + }); + }); + }; + Object.defineProperty(NodeCryptography.prototype, "algo", { + // endregion + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + // region Helpers + /** + * Cryptography algorithm. + * + * @returns Cryptography module algorithm. + */ + get: function () { + return 'aes-256-cbc'; + }, + enumerable: false, + configurable: true + }); + /** + * Convert cipher key to the {@link Buffer}. + * + * @param key - String cipher key. + * + * @returns SHA256 HEX encoded cipher key {@link Buffer}. + */ + NodeCryptography.prototype.getKey = function (key) { + var sha = (0, crypto_1.createHash)('sha256'); + sha.update(buffer_1.Buffer.from(key, 'utf8')); + return buffer_1.Buffer.from(sha.digest('hex').slice(0, 32), 'utf8'); + }; + /** + * Generate random initialization vector. + * + * @returns Random initialization vector. + */ + NodeCryptography.prototype.getIv = function () { + return (0, crypto_1.randomBytes)(NodeCryptography.IV_LENGTH); + }; + /** + * Random initialization vector size. + */ NodeCryptography.IV_LENGTH = 16; return NodeCryptography; }()); diff --git a/lib/crypto/modules/web.js b/lib/crypto/modules/web.js index b7bb887ea..34ff4acb2 100644 --- a/lib/crypto/modules/web.js +++ b/lib/crypto/modules/web.js @@ -1,5 +1,8 @@ "use strict"; /* global crypto */ +/** + * Legacy browser cryptography module. + */ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { @@ -15,7 +18,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) { function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); - while (_) try { + while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { @@ -43,187 +46,283 @@ function concatArrayBuffer(ab1, ab2) { tmp.set(new Uint8Array(ab2), ab1.byteLength); return tmp.buffer; } +/** + * Legacy cryptography implementation for browser-based {@link PubNub} client. + */ var WebCryptography = /** @class */ (function () { function WebCryptography() { } - Object.defineProperty(WebCryptography.prototype, "algo", { - get: function () { - return 'aes-256-cbc'; - }, - enumerable: false, - configurable: true - }); + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + // region Encryption + /** + * Encrypt provided source data using specific encryption {@link key}. + * + * @param key - Data encryption key.
**Note:** Same key should be used to `decrypt` data. + * @param input - Source data for encryption. + * + * @returns Encrypted data as object or stream (depending on from source data type). + * + * @throws Error if unknown data type has been passed. + */ WebCryptography.prototype.encrypt = function (key, input) { return __awaiter(this, void 0, void 0, function () { var cKey; return __generator(this, function (_a) { switch (_a.label) { - case 0: return [4 /*yield*/, this.getKey(key)]; + case 0: + if (!(input instanceof ArrayBuffer) && typeof input !== 'string') + throw new Error('Cannot encrypt this file. In browsers file encryption supports only string or ArrayBuffer'); + return [4 /*yield*/, this.getKey(key)]; case 1: cKey = _a.sent(); - if (input instanceof ArrayBuffer) { - return [2 /*return*/, this.encryptArrayBuffer(cKey, input)]; - } - if (typeof input === 'string') { - return [2 /*return*/, this.encryptString(cKey, input)]; - } - throw new Error('Cannot encrypt this file. In browsers file encryption supports only string or ArrayBuffer'); + return [2 /*return*/, input instanceof ArrayBuffer ? this.encryptArrayBuffer(cKey, input) : this.encryptString(cKey, input)]; } }); }); }; - WebCryptography.prototype.decrypt = function (key, input) { + /** + * Encrypt provided source {@link Buffer} using specific encryption {@link ArrayBuffer}. + * + * @param key - Data encryption key.
**Note:** Same key should be used to `decrypt` {@link ArrayBuffer}. + * @param buffer - Source {@link ArrayBuffer} for encryption. + * + * @returns Encrypted data as {@link ArrayBuffer} object. + */ + WebCryptography.prototype.encryptArrayBuffer = function (key, buffer) { return __awaiter(this, void 0, void 0, function () { - var cKey; + var abIv, _a, _b; + return __generator(this, function (_c) { + switch (_c.label) { + case 0: + abIv = crypto.getRandomValues(new Uint8Array(16)); + _a = concatArrayBuffer; + _b = [abIv.buffer]; + return [4 /*yield*/, crypto.subtle.encrypt({ name: 'AES-CBC', iv: abIv }, key, buffer)]; + case 1: return [2 /*return*/, _a.apply(void 0, _b.concat([_c.sent()]))]; + } + }); + }); + }; + /** + * Encrypt provided source {@link string} using specific encryption {@link key}. + * + * @param key - Data encryption key.
**Note:** Same key should be used to `decrypt` {@link string}. + * @param text - Source {@link string} for encryption. + * + * @returns Encrypted data as byte {@link string}. + */ + WebCryptography.prototype.encryptString = function (key, text) { + return __awaiter(this, void 0, void 0, function () { + var abIv, abPlaintext, abPayload, ciphertext; return __generator(this, function (_a) { switch (_a.label) { - case 0: return [4 /*yield*/, this.getKey(key)]; + case 0: + abIv = crypto.getRandomValues(new Uint8Array(16)); + abPlaintext = WebCryptography.encoder.encode(text).buffer; + return [4 /*yield*/, crypto.subtle.encrypt({ name: 'AES-CBC', iv: abIv }, key, abPlaintext)]; case 1: - cKey = _a.sent(); - if (input instanceof ArrayBuffer) { - return [2 /*return*/, this.decryptArrayBuffer(cKey, input)]; - } - if (typeof input === 'string') { - return [2 /*return*/, this.decryptString(cKey, input)]; - } - throw new Error('Cannot decrypt this file. In browsers file decryption supports only string or ArrayBuffer'); + abPayload = _a.sent(); + ciphertext = concatArrayBuffer(abIv.buffer, abPayload); + return [2 /*return*/, WebCryptography.decoder.decode(ciphertext)]; } }); }); }; + /** + * Encrypt provided {@link PubNub} File object using specific encryption {@link key}. + * + * @param key - Key for {@link PubNub} File object encryption.
**Note:** Same key should be + * used to `decrypt` data. + * @param file - Source {@link PubNub} File object for encryption. + * @param File - Class constructor for {@link PubNub} File object. + * + * @returns Encrypted data as {@link PubNub} File object. + * + * @throws Error if file is empty or contains unsupported data type. + */ WebCryptography.prototype.encryptFile = function (key, file, File) { return __awaiter(this, void 0, void 0, function () { var bKey, abPlaindata, abCipherdata; - return __generator(this, function (_a) { - switch (_a.label) { + var _a, _b; + return __generator(this, function (_c) { + switch (_c.label) { case 0: - if (file.data.byteLength <= 0) + if ((_a = file.contentLength) !== null && _a !== void 0 ? _a : 0 <= 0) throw new Error('encryption error. empty content'); return [4 /*yield*/, this.getKey(key)]; case 1: - bKey = _a.sent(); - return [4 /*yield*/, file.data.arrayBuffer()]; + bKey = _c.sent(); + return [4 /*yield*/, file.toArrayBuffer()]; case 2: - abPlaindata = _a.sent(); + abPlaindata = _c.sent(); return [4 /*yield*/, this.encryptArrayBuffer(bKey, abPlaindata)]; case 3: - abCipherdata = _a.sent(); + abCipherdata = _c.sent(); return [2 /*return*/, File.create({ name: file.name, - mimeType: 'application/octet-stream', + mimeType: (_b = file.mimeType) !== null && _b !== void 0 ? _b : 'application/octet-stream', data: abCipherdata, })]; } }); }); }; - WebCryptography.prototype.decryptFile = function (key, file, File) { + // endregion + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + // region Decryption + /** + * Decrypt provided encrypted data using specific decryption {@link key}. + * + * @param key - Data decryption key.
**Note:** Should be the same as used to `encrypt` data. + * @param input - Encrypted data for decryption. + * + * @returns Decrypted data as object or stream (depending on from encrypted data type). + * + * @throws Error if unknown data type has been passed. + */ + WebCryptography.prototype.decrypt = function (key, input) { return __awaiter(this, void 0, void 0, function () { - var bKey, abCipherdata, abPlaindata; + var cKey; return __generator(this, function (_a) { switch (_a.label) { - case 0: return [4 /*yield*/, this.getKey(key)]; + case 0: + if (!(input instanceof ArrayBuffer) && typeof input !== 'string') + throw new Error('Cannot decrypt this file. In browsers file decryption supports only string or ArrayBuffer'); + return [4 /*yield*/, this.getKey(key)]; case 1: - bKey = _a.sent(); - return [4 /*yield*/, file.data.arrayBuffer()]; - case 2: - abCipherdata = _a.sent(); - return [4 /*yield*/, this.decryptArrayBuffer(bKey, abCipherdata)]; - case 3: - abPlaindata = _a.sent(); - return [2 /*return*/, File.create({ - name: file.name, - data: abPlaindata, - })]; + cKey = _a.sent(); + return [2 /*return*/, input instanceof ArrayBuffer ? this.decryptArrayBuffer(cKey, input) : this.decryptString(cKey, input)]; } }); }); }; - WebCryptography.prototype.getKey = function (key) { + /** + * Decrypt provided encrypted {@link ArrayBuffer} using specific decryption {@link key}. + * + * @param key - Data decryption key.
**Note:** Should be the same as used to `encrypt` {@link ArrayBuffer}. + * @param buffer - Encrypted {@link ArrayBuffer} for decryption. + * + * @returns Decrypted data as {@link ArrayBuffer} object. + */ + WebCryptography.prototype.decryptArrayBuffer = function (key, buffer) { return __awaiter(this, void 0, void 0, function () { - var digest, hashHex, abKey; + var abIv; return __generator(this, function (_a) { switch (_a.label) { - case 0: return [4 /*yield*/, crypto.subtle.digest('SHA-256', WebCryptography.encoder.encode(key))]; - case 1: - digest = _a.sent(); - hashHex = Array.from(new Uint8Array(digest)) - .map(function (b) { return b.toString(16).padStart(2, '0'); }) - .join(''); - abKey = WebCryptography.encoder.encode(hashHex.slice(0, 32)).buffer; - return [2 /*return*/, crypto.subtle.importKey('raw', abKey, 'AES-CBC', true, ['encrypt', 'decrypt'])]; - } - }); - }); - }; - WebCryptography.prototype.encryptArrayBuffer = function (key, plaintext) { - return __awaiter(this, void 0, void 0, function () { - var abIv, _a, _b; - return __generator(this, function (_c) { - switch (_c.label) { case 0: - abIv = crypto.getRandomValues(new Uint8Array(16)); - _a = concatArrayBuffer; - _b = [abIv.buffer]; - return [4 /*yield*/, crypto.subtle.encrypt({ name: 'AES-CBC', iv: abIv }, key, plaintext)]; - case 1: return [2 /*return*/, _a.apply(void 0, _b.concat([_c.sent()]))]; + abIv = buffer.slice(0, 16); + if (buffer.slice(WebCryptography.IV_LENGTH).byteLength <= 0) + throw new Error('decryption error: empty content'); + return [4 /*yield*/, crypto.subtle.decrypt({ name: 'AES-CBC', iv: abIv }, key, buffer.slice(WebCryptography.IV_LENGTH))]; + case 1: return [2 /*return*/, _a.sent()]; } }); }); }; - WebCryptography.prototype.decryptArrayBuffer = function (key, ciphertext) { + /** + * Decrypt provided encrypted {@link string} using specific decryption {@link key}. + * + * @param key - Data decryption key.
**Note:** Should be the same as used to `encrypt` {@link string}. + * @param text - Encrypted {@link string} for decryption. + * + * @returns Decrypted data as byte {@link string}. + */ + WebCryptography.prototype.decryptString = function (key, text) { return __awaiter(this, void 0, void 0, function () { - var abIv, data; + var abCiphertext, abIv, abPayload, abPlaintext; return __generator(this, function (_a) { switch (_a.label) { case 0: - abIv = ciphertext.slice(0, 16); - if (ciphertext.slice(WebCryptography.IV_LENGTH).byteLength <= 0) - throw new Error('decryption error: empty content'); - return [4 /*yield*/, crypto.subtle.decrypt({ name: 'AES-CBC', iv: abIv }, key, ciphertext.slice(WebCryptography.IV_LENGTH))]; + abCiphertext = WebCryptography.encoder.encode(text).buffer; + abIv = abCiphertext.slice(0, 16); + abPayload = abCiphertext.slice(16); + return [4 /*yield*/, crypto.subtle.decrypt({ name: 'AES-CBC', iv: abIv }, key, abPayload)]; case 1: - data = _a.sent(); - return [2 /*return*/, data]; + abPlaintext = _a.sent(); + return [2 /*return*/, WebCryptography.decoder.decode(abPlaintext)]; } }); }); }; - WebCryptography.prototype.encryptString = function (key, plaintext) { + /** + * Decrypt provided {@link PubNub} File object using specific decryption {@link key}. + * + * @param key - Key for {@link PubNub} File object decryption.
**Note:** Should be the same + * as used to `encrypt` data. + * @param file - Encrypted {@link PubNub} File object for decryption. + * @param File - Class constructor for {@link PubNub} File object. + * + * @returns Decrypted data as {@link PubNub} File object. + * + * @throws Error if file is empty or contains unsupported data type. + */ + WebCryptography.prototype.decryptFile = function (key, file, File) { return __awaiter(this, void 0, void 0, function () { - var abIv, abPlaintext, abPayload, ciphertext; + var bKey, abCipherdata, abPlaindata; return __generator(this, function (_a) { switch (_a.label) { - case 0: - abIv = crypto.getRandomValues(new Uint8Array(16)); - abPlaintext = WebCryptography.encoder.encode(plaintext).buffer; - return [4 /*yield*/, crypto.subtle.encrypt({ name: 'AES-CBC', iv: abIv }, key, abPlaintext)]; + case 0: return [4 /*yield*/, this.getKey(key)]; case 1: - abPayload = _a.sent(); - ciphertext = concatArrayBuffer(abIv.buffer, abPayload); - return [2 /*return*/, WebCryptography.decoder.decode(ciphertext)]; + bKey = _a.sent(); + return [4 /*yield*/, file.toArrayBuffer()]; + case 2: + abCipherdata = _a.sent(); + return [4 /*yield*/, this.decryptArrayBuffer(bKey, abCipherdata)]; + case 3: + abPlaindata = _a.sent(); + return [2 /*return*/, File.create({ + name: file.name, + mimeType: file.mimeType, + data: abPlaindata, + })]; } }); }); }; - WebCryptography.prototype.decryptString = function (key, ciphertext) { + // endregion + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + // region Helpers + /** + * Convert cipher key to the {@link Buffer}. + * + * @param key - String cipher key. + * + * @returns SHA256 HEX encoded cipher key {@link CryptoKey}. + */ + WebCryptography.prototype.getKey = function (key) { return __awaiter(this, void 0, void 0, function () { - var abCiphertext, abIv, abPayload, abPlaintext; + var digest, hashHex, abKey; return __generator(this, function (_a) { switch (_a.label) { - case 0: - abCiphertext = WebCryptography.encoder.encode(ciphertext).buffer; - abIv = abCiphertext.slice(0, 16); - abPayload = abCiphertext.slice(16); - return [4 /*yield*/, crypto.subtle.decrypt({ name: 'AES-CBC', iv: abIv }, key, abPayload)]; + case 0: return [4 /*yield*/, crypto.subtle.digest('SHA-256', WebCryptography.encoder.encode(key))]; case 1: - abPlaintext = _a.sent(); - return [2 /*return*/, WebCryptography.decoder.decode(abPlaintext)]; + digest = _a.sent(); + hashHex = Array.from(new Uint8Array(digest)) + .map(function (b) { return b.toString(16).padStart(2, '0'); }) + .join(''); + abKey = WebCryptography.encoder.encode(hashHex.slice(0, 32)).buffer; + return [2 /*return*/, crypto.subtle.importKey('raw', abKey, 'AES-CBC', true, ['encrypt', 'decrypt'])]; } }); }); }; + /** + * Random initialization vector size. + */ WebCryptography.IV_LENGTH = 16; + /** + * {@link string|String} to {@link ArrayBuffer} response decoder. + */ WebCryptography.encoder = new TextEncoder(); + /** + * {@link ArrayBuffer} to {@link string} decoder. + */ WebCryptography.decoder = new TextDecoder(); return WebCryptography; }()); diff --git a/lib/entities/Channel.js b/lib/entities/Channel.js index 0043f20dc..d14114821 100644 --- a/lib/entities/Channel.js +++ b/lib/entities/Channel.js @@ -4,9 +4,9 @@ exports.Channel = void 0; var Subscription_1 = require("./Subscription"); var Channel = /** @class */ (function () { function Channel(channelName, eventEmitter, pubnub) { - this.name = channelName; this.eventEmitter = eventEmitter; this.pubnub = pubnub; + this.name = channelName; } Channel.prototype.subscription = function (subscriptionOptions) { return new Subscription_1.Subscription({ diff --git a/lib/entities/ChannelGroup.js b/lib/entities/ChannelGroup.js index 07a0bea48..8d1a5174b 100644 --- a/lib/entities/ChannelGroup.js +++ b/lib/entities/ChannelGroup.js @@ -4,9 +4,9 @@ exports.ChannelGroup = void 0; var Subscription_1 = require("./Subscription"); var ChannelGroup = /** @class */ (function () { function ChannelGroup(channelGroup, eventEmitter, pubnub) { - this.name = channelGroup; this.eventEmitter = eventEmitter; this.pubnub = pubnub; + this.name = channelGroup; } ChannelGroup.prototype.subscription = function (subscriptionOptions) { return new Subscription_1.Subscription({ diff --git a/lib/entities/SubscribeCapable.js b/lib/entities/SubscribeCapable.js index 554527544..673fa6893 100644 --- a/lib/entities/SubscribeCapable.js +++ b/lib/entities/SubscribeCapable.js @@ -26,15 +26,15 @@ var SubscribeCapable = /** @class */ (function () { }); }; Object.defineProperty(SubscribeCapable.prototype, "onMessage", { - set: function (onMessagelistener) { - this.listener.message = onMessagelistener; + set: function (onMessageListener) { + this.listener.message = onMessageListener; }, enumerable: false, configurable: true }); Object.defineProperty(SubscribeCapable.prototype, "onPresence", { - set: function (onPresencelistener) { - this.listener.presence = onPresencelistener; + set: function (onPresenceListener) { + this.listener.presence = onPresenceListener; }, enumerable: false, configurable: true diff --git a/lib/entities/Subscription.js b/lib/entities/Subscription.js index 586f8d3c3..ef9935116 100644 --- a/lib/entities/Subscription.js +++ b/lib/entities/Subscription.js @@ -52,8 +52,8 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Subscription = void 0; -var SubscriptionSet_1 = require("./SubscriptionSet"); var SubscribeCapable_1 = require("./SubscribeCapable"); +var SubscriptionSet_1 = require("./SubscriptionSet"); var Subscription = /** @class */ (function (_super) { __extends(Subscription, _super); function Subscription(_a) { diff --git a/lib/event-engine/core/reconnectionDelay.js b/lib/event-engine/core/reconnectionDelay.js deleted file mode 100644 index e2078670a..000000000 --- a/lib/event-engine/core/reconnectionDelay.js +++ /dev/null @@ -1,27 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.ReconnectionDelay = void 0; -var ReconnectionDelay = /** @class */ (function () { - function ReconnectionDelay() { - } - ReconnectionDelay.getDelay = function (policy, attempts, backoff) { - var backoffValue = backoff !== null && backoff !== void 0 ? backoff : 5; - switch (policy.toUpperCase()) { - case 'LINEAR': - return attempts * backoffValue + 200; - case 'EXPONENTIAL': - return Math.trunc(Math.pow(2, attempts - 1)) * 1000 + Math.random() * 1000; - default: - throw new Error('invalid policy'); - } - }; - ReconnectionDelay.shouldRetry = function (maxRetries, attempts, policy) { - // maxRetries > attempts && policy && policy != 'None'; - if (policy && policy !== 'None') { - return maxRetries > attempts; - } - return false; - }; - return ReconnectionDelay; -}()); -exports.ReconnectionDelay = ReconnectionDelay; diff --git a/lib/event-engine/core/retryPolicy.js b/lib/event-engine/core/retryPolicy.js index dde639271..a51059978 100644 --- a/lib/event-engine/core/retryPolicy.js +++ b/lib/event-engine/core/retryPolicy.js @@ -8,6 +8,8 @@ var RetryPolicy = /** @class */ (function () { return { delay: configuration.delay, maximumRetry: configuration.maximumRetry, + // TODO: Find out actual `error` type. + /* eslint-disable @typescript-eslint/no-explicit-any */ shouldRetry: function (error, attempt) { var _a; if (((_a = error === null || error === void 0 ? void 0 : error.status) === null || _a === void 0 ? void 0 : _a.statusCode) === 403) { @@ -20,6 +22,8 @@ var RetryPolicy = /** @class */ (function () { var delay = (_a = reason.retryAfter) !== null && _a !== void 0 ? _a : this.delay; return (delay + Math.random()) * 1000; }, + // TODO: Find out actual `error` type. + /* eslint-disable @typescript-eslint/no-explicit-any */ getGiveupReason: function (error, attempt) { var _a; if (this.maximumRetry <= attempt) { @@ -30,6 +34,10 @@ var RetryPolicy = /** @class */ (function () { } return 'unknown error'; }, + validate: function () { + if (this.maximumRetry > 10) + throw new Error('Maximum retry for linear retry policy can not be more than 10'); + }, }; }; RetryPolicy.ExponentialRetryPolicy = function (configuration) { @@ -37,9 +45,9 @@ var RetryPolicy = /** @class */ (function () { minimumDelay: configuration.minimumDelay, maximumDelay: configuration.maximumDelay, maximumRetry: configuration.maximumRetry, - shouldRetry: function (error, attempt) { + shouldRetry: function (reason, attempt) { var _a; - if (((_a = error === null || error === void 0 ? void 0 : error.status) === null || _a === void 0 ? void 0 : _a.statusCode) === 403) { + if (((_a = reason === null || reason === void 0 ? void 0 : reason.status) === null || _a === void 0 ? void 0 : _a.statusCode) === 403) { return false; } return this.maximumRetry > attempt; @@ -49,16 +57,24 @@ var RetryPolicy = /** @class */ (function () { var delay = (_a = reason.retryAfter) !== null && _a !== void 0 ? _a : Math.min(Math.pow(2, attempt), this.maximumDelay); return (delay + Math.random()) * 1000; }, - getGiveupReason: function (error, attempt) { + getGiveupReason: function (reason, attempt) { var _a; if (this.maximumRetry <= attempt) { - return 'retry attempts exhaused.'; + return 'retry attempts exhausted.'; } - if (((_a = error === null || error === void 0 ? void 0 : error.status) === null || _a === void 0 ? void 0 : _a.statusCode) === 403) { + if (((_a = reason === null || reason === void 0 ? void 0 : reason.status) === null || _a === void 0 ? void 0 : _a.statusCode) === 403) { return 'forbidden operation.'; } return 'unknown error'; }, + validate: function () { + if (this.minimumDelay < 2) + throw new Error('Minimum delay can not be set less than 2 seconds for retry'); + else if (this.maximumDelay) + throw new Error('Maximum delay can not be set more than 150 seconds for retry'); + else if (this.maximumRetry > 6) + throw new Error('Maximum retry for exponential retry policy can not be more than 6'); + }, }; }; return RetryPolicy; diff --git a/lib/event-engine/dispatcher.js b/lib/event-engine/dispatcher.js index 27e5c02a9..68fab9594 100644 --- a/lib/event-engine/dispatcher.js +++ b/lib/event-engine/dispatcher.js @@ -63,7 +63,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) { function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); - while (_) try { + while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { @@ -86,7 +86,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) { }; Object.defineProperty(exports, "__esModule", { value: true }); exports.EventEngineDispatcher = void 0; -var endpoint_1 = require("../core/components/endpoint"); +var PubNubError_1 = require("../models/PubNubError"); var core_1 = require("./core"); var effects = __importStar(require("./effects")); var events = __importStar(require("./events")); @@ -94,171 +94,163 @@ var EventEngineDispatcher = /** @class */ (function (_super) { __extends(EventEngineDispatcher, _super); function EventEngineDispatcher(engine, dependencies) { var _this = _super.call(this, dependencies) || this; - _this.on(effects.handshake.type, (0, core_1.asyncHandler)(function (payload, abortSignal, _a) { - var handshake = _a.handshake, presenceState = _a.presenceState, config = _a.config; - return __awaiter(_this, void 0, void 0, function () { - var result, e_1; - return __generator(this, function (_b) { - switch (_b.label) { - case 0: - abortSignal.throwIfAborted(); - _b.label = 1; - case 1: - _b.trys.push([1, 3, , 4]); - return [4 /*yield*/, handshake(__assign({ abortSignal: abortSignal, channels: payload.channels, channelGroups: payload.groups, filterExpression: config.filterExpression }, (config.maintainPresenceState && { state: presenceState })))]; - case 2: - result = _b.sent(); - return [2 /*return*/, engine.transition(events.handshakeSuccess(result))]; - case 3: - e_1 = _b.sent(); - if (e_1 instanceof Error && e_1.message === 'Aborted') { - return [2 /*return*/]; - } - if (e_1 instanceof endpoint_1.PubNubError) { - return [2 /*return*/, engine.transition(events.handshakeFailure(e_1))]; - } - return [3 /*break*/, 4]; - case 4: return [2 /*return*/]; - } - }); + _this.on(effects.handshake.type, (0, core_1.asyncHandler)(function (payload_1, abortSignal_1, _a) { return __awaiter(_this, [payload_1, abortSignal_1, _a], void 0, function (payload, abortSignal, _b) { + var result, e_1; + var handshake = _b.handshake, presenceState = _b.presenceState, config = _b.config; + return __generator(this, function (_c) { + switch (_c.label) { + case 0: + abortSignal.throwIfAborted(); + _c.label = 1; + case 1: + _c.trys.push([1, 3, , 4]); + return [4 /*yield*/, handshake(__assign({ abortSignal: abortSignal, channels: payload.channels, channelGroups: payload.groups, filterExpression: config.filterExpression }, (config.maintainPresenceState && { state: presenceState })))]; + case 2: + result = _c.sent(); + return [2 /*return*/, engine.transition(events.handshakeSuccess(result))]; + case 3: + e_1 = _c.sent(); + if (e_1 instanceof Error && e_1.message === 'Aborted') { + return [2 /*return*/]; + } + if (e_1 instanceof PubNubError_1.PubNubError) { + return [2 /*return*/, engine.transition(events.handshakeFailure(e_1))]; + } + return [3 /*break*/, 4]; + case 4: return [2 /*return*/]; + } }); - })); - _this.on(effects.receiveMessages.type, (0, core_1.asyncHandler)(function (payload, abortSignal, _a) { - var receiveMessages = _a.receiveMessages, config = _a.config; - return __awaiter(_this, void 0, void 0, function () { - var result, error_1; - return __generator(this, function (_b) { - switch (_b.label) { - case 0: - abortSignal.throwIfAborted(); - _b.label = 1; - case 1: - _b.trys.push([1, 3, , 4]); - return [4 /*yield*/, receiveMessages({ - abortSignal: abortSignal, - channels: payload.channels, - channelGroups: payload.groups, - timetoken: payload.cursor.timetoken, - region: payload.cursor.region, - filterExpression: config.filterExpression, - })]; - case 2: - result = _b.sent(); - engine.transition(events.receiveSuccess(result.metadata, result.messages)); - return [3 /*break*/, 4]; - case 3: - error_1 = _b.sent(); - if (error_1 instanceof Error && error_1.message === 'Aborted') { - return [2 /*return*/]; - } - if (error_1 instanceof endpoint_1.PubNubError && !abortSignal.aborted) { - return [2 /*return*/, engine.transition(events.receiveFailure(error_1))]; - } - return [3 /*break*/, 4]; - case 4: return [2 /*return*/]; - } - }); + }); })); + _this.on(effects.receiveMessages.type, (0, core_1.asyncHandler)(function (payload_1, abortSignal_1, _a) { return __awaiter(_this, [payload_1, abortSignal_1, _a], void 0, function (payload, abortSignal, _b) { + var result, error_1; + var receiveMessages = _b.receiveMessages, config = _b.config; + return __generator(this, function (_c) { + switch (_c.label) { + case 0: + abortSignal.throwIfAborted(); + _c.label = 1; + case 1: + _c.trys.push([1, 3, , 4]); + return [4 /*yield*/, receiveMessages({ + abortSignal: abortSignal, + channels: payload.channels, + channelGroups: payload.groups, + timetoken: payload.cursor.timetoken, + region: payload.cursor.region, + filterExpression: config.filterExpression, + })]; + case 2: + result = _c.sent(); + engine.transition(events.receiveSuccess(result.cursor, result.messages)); + return [3 /*break*/, 4]; + case 3: + error_1 = _c.sent(); + if (error_1 instanceof Error && error_1.message === 'Aborted') { + return [2 /*return*/]; + } + if (error_1 instanceof PubNubError_1.PubNubError && !abortSignal.aborted) { + return [2 /*return*/, engine.transition(events.receiveFailure(error_1))]; + } + return [3 /*break*/, 4]; + case 4: return [2 /*return*/]; + } }); - })); - _this.on(effects.emitMessages.type, (0, core_1.asyncHandler)(function (payload, _, _a) { - var emitMessages = _a.emitMessages; - return __awaiter(_this, void 0, void 0, function () { - return __generator(this, function (_b) { - if (payload.length > 0) { - emitMessages(payload); - } - return [2 /*return*/]; - }); + }); })); + _this.on(effects.emitMessages.type, (0, core_1.asyncHandler)(function (payload_1, _1, _a) { return __awaiter(_this, [payload_1, _1, _a], void 0, function (payload, _, _b) { + var emitMessages = _b.emitMessages; + return __generator(this, function (_c) { + if (payload.length > 0) { + emitMessages(payload); + } + return [2 /*return*/]; }); - })); - _this.on(effects.emitStatus.type, (0, core_1.asyncHandler)(function (payload, _, _a) { - var emitStatus = _a.emitStatus; - return __awaiter(_this, void 0, void 0, function () { - return __generator(this, function (_b) { - emitStatus(payload); - return [2 /*return*/]; - }); + }); })); + _this.on(effects.emitStatus.type, (0, core_1.asyncHandler)(function (payload_1, _1, _a) { return __awaiter(_this, [payload_1, _1, _a], void 0, function (payload, _, _b) { + var emitStatus = _b.emitStatus; + return __generator(this, function (_c) { + emitStatus(payload); + return [2 /*return*/]; }); - })); - _this.on(effects.receiveReconnect.type, (0, core_1.asyncHandler)(function (payload, abortSignal, _a) { - var receiveMessages = _a.receiveMessages, delay = _a.delay, config = _a.config; - return __awaiter(_this, void 0, void 0, function () { - var result, error_2; - return __generator(this, function (_b) { - switch (_b.label) { - case 0: - if (!(config.retryConfiguration && config.retryConfiguration.shouldRetry(payload.reason, payload.attempts))) return [3 /*break*/, 6]; - abortSignal.throwIfAborted(); - return [4 /*yield*/, delay(config.retryConfiguration.getDelay(payload.attempts, payload.reason))]; - case 1: - _b.sent(); - abortSignal.throwIfAborted(); - _b.label = 2; - case 2: - _b.trys.push([2, 4, , 5]); - return [4 /*yield*/, receiveMessages({ - abortSignal: abortSignal, - channels: payload.channels, - channelGroups: payload.groups, - timetoken: payload.cursor.timetoken, - region: payload.cursor.region, - filterExpression: config.filterExpression, - })]; - case 3: - result = _b.sent(); - return [2 /*return*/, engine.transition(events.receiveReconnectSuccess(result.metadata, result.messages))]; - case 4: - error_2 = _b.sent(); - if (error_2 instanceof Error && error_2.message === 'Aborted') { - return [2 /*return*/]; - } - if (error_2 instanceof endpoint_1.PubNubError) { - return [2 /*return*/, engine.transition(events.receiveReconnectFailure(error_2))]; - } - return [3 /*break*/, 5]; - case 5: return [3 /*break*/, 7]; - case 6: return [2 /*return*/, engine.transition(events.receiveReconnectGiveup(new endpoint_1.PubNubError(config.retryConfiguration.getGiveupReason(payload.reason, payload.attempts))))]; - case 7: return [2 /*return*/]; - } - }); + }); })); + _this.on(effects.receiveReconnect.type, (0, core_1.asyncHandler)(function (payload_1, abortSignal_1, _a) { return __awaiter(_this, [payload_1, abortSignal_1, _a], void 0, function (payload, abortSignal, _b) { + var result, error_2; + var receiveMessages = _b.receiveMessages, delay = _b.delay, config = _b.config; + return __generator(this, function (_c) { + switch (_c.label) { + case 0: + if (!(config.retryConfiguration && config.retryConfiguration.shouldRetry(payload.reason, payload.attempts))) return [3 /*break*/, 6]; + abortSignal.throwIfAborted(); + return [4 /*yield*/, delay(config.retryConfiguration.getDelay(payload.attempts, payload.reason))]; + case 1: + _c.sent(); + abortSignal.throwIfAborted(); + _c.label = 2; + case 2: + _c.trys.push([2, 4, , 5]); + return [4 /*yield*/, receiveMessages({ + abortSignal: abortSignal, + channels: payload.channels, + channelGroups: payload.groups, + timetoken: payload.cursor.timetoken, + region: payload.cursor.region, + filterExpression: config.filterExpression, + })]; + case 3: + result = _c.sent(); + return [2 /*return*/, engine.transition(events.receiveReconnectSuccess(result.cursor, result.messages))]; + case 4: + error_2 = _c.sent(); + if (error_2 instanceof Error && error_2.message === 'Aborted') { + return [2 /*return*/]; + } + if (error_2 instanceof PubNubError_1.PubNubError) { + return [2 /*return*/, engine.transition(events.receiveReconnectFailure(error_2))]; + } + return [3 /*break*/, 5]; + case 5: return [3 /*break*/, 7]; + case 6: return [2 /*return*/, engine.transition(events.receiveReconnectGiveup(new PubNubError_1.PubNubError(config.retryConfiguration + ? config.retryConfiguration.getGiveupReason(payload.reason, payload.attempts) + : 'Unable to complete subscribe messages receive.')))]; + case 7: return [2 /*return*/]; + } }); - })); - _this.on(effects.handshakeReconnect.type, (0, core_1.asyncHandler)(function (payload, abortSignal, _a) { - var handshake = _a.handshake, delay = _a.delay, presenceState = _a.presenceState, config = _a.config; - return __awaiter(_this, void 0, void 0, function () { - var result, error_3; - return __generator(this, function (_b) { - switch (_b.label) { - case 0: - if (!(config.retryConfiguration && config.retryConfiguration.shouldRetry(payload.reason, payload.attempts))) return [3 /*break*/, 6]; - abortSignal.throwIfAborted(); - return [4 /*yield*/, delay(config.retryConfiguration.getDelay(payload.attempts, payload.reason))]; - case 1: - _b.sent(); - abortSignal.throwIfAborted(); - _b.label = 2; - case 2: - _b.trys.push([2, 4, , 5]); - return [4 /*yield*/, handshake(__assign({ abortSignal: abortSignal, channels: payload.channels, channelGroups: payload.groups, filterExpression: config.filterExpression }, (config.maintainPresenceState && { state: presenceState })))]; - case 3: - result = _b.sent(); - return [2 /*return*/, engine.transition(events.handshakeReconnectSuccess(result))]; - case 4: - error_3 = _b.sent(); - if (error_3 instanceof Error && error_3.message === 'Aborted') { - return [2 /*return*/]; - } - if (error_3 instanceof endpoint_1.PubNubError) { - return [2 /*return*/, engine.transition(events.handshakeReconnectFailure(error_3))]; - } - return [3 /*break*/, 5]; - case 5: return [3 /*break*/, 7]; - case 6: return [2 /*return*/, engine.transition(events.handshakeReconnectGiveup(new endpoint_1.PubNubError(config.retryConfiguration.getGiveupReason(payload.reason, payload.attempts))))]; - case 7: return [2 /*return*/]; - } - }); + }); })); + _this.on(effects.handshakeReconnect.type, (0, core_1.asyncHandler)(function (payload_1, abortSignal_1, _a) { return __awaiter(_this, [payload_1, abortSignal_1, _a], void 0, function (payload, abortSignal, _b) { + var result, error_3; + var handshake = _b.handshake, delay = _b.delay, presenceState = _b.presenceState, config = _b.config; + return __generator(this, function (_c) { + switch (_c.label) { + case 0: + if (!(config.retryConfiguration && config.retryConfiguration.shouldRetry(payload.reason, payload.attempts))) return [3 /*break*/, 6]; + abortSignal.throwIfAborted(); + return [4 /*yield*/, delay(config.retryConfiguration.getDelay(payload.attempts, payload.reason))]; + case 1: + _c.sent(); + abortSignal.throwIfAborted(); + _c.label = 2; + case 2: + _c.trys.push([2, 4, , 5]); + return [4 /*yield*/, handshake(__assign({ abortSignal: abortSignal, channels: payload.channels, channelGroups: payload.groups, filterExpression: config.filterExpression }, (config.maintainPresenceState && { state: presenceState })))]; + case 3: + result = _c.sent(); + return [2 /*return*/, engine.transition(events.handshakeReconnectSuccess(result))]; + case 4: + error_3 = _c.sent(); + if (error_3 instanceof Error && error_3.message === 'Aborted') { + return [2 /*return*/]; + } + if (error_3 instanceof PubNubError_1.PubNubError) { + return [2 /*return*/, engine.transition(events.handshakeReconnectFailure(error_3))]; + } + return [3 /*break*/, 5]; + case 5: return [3 /*break*/, 7]; + case 6: return [2 /*return*/, engine.transition(events.handshakeReconnectGiveup(new PubNubError_1.PubNubError(config.retryConfiguration + ? config.retryConfiguration.getGiveupReason(payload.reason, payload.attempts) + : 'Unable to complete subscribe handshake')))]; + case 7: return [2 /*return*/]; + } }); - })); + }); })); return _this; } return EventEngineDispatcher; diff --git a/lib/event-engine/effects.js b/lib/event-engine/effects.js index 2b5ead623..47b7f21b2 100644 --- a/lib/event-engine/effects.js +++ b/lib/event-engine/effects.js @@ -8,6 +8,8 @@ exports.handshake = (0, core_1.createManagedEffect)('HANDSHAKE', function (chann }); }); exports.receiveMessages = (0, core_1.createManagedEffect)('RECEIVE_MESSAGES', function (channels, groups, cursor) { return ({ channels: channels, groups: groups, cursor: cursor }); }); exports.emitMessages = (0, core_1.createEffect)('EMIT_MESSAGES', function (events) { return events; }); +// TODO: Find out actual `status` type. +/* eslint-disable @typescript-eslint/no-explicit-any */ exports.emitStatus = (0, core_1.createEffect)('EMIT_STATUS', function (status) { return status; }); exports.receiveReconnect = (0, core_1.createManagedEffect)('RECEIVE_RECONNECT', function (context) { return context; }); exports.handshakeReconnect = (0, core_1.createManagedEffect)('HANDSHAKE_RECONNECT', function (context) { return context; }); diff --git a/lib/event-engine/index.js b/lib/event-engine/index.js index 7d8811c25..e6de98ae7 100644 --- a/lib/event-engine/index.js +++ b/lib/event-engine/index.js @@ -144,10 +144,10 @@ var EventEngine = /** @class */ (function () { } }; EventEngine.prototype.getSubscribedChannels = function () { - return this.channels.slice(0); + return Array.from(new Set(this.channels.slice(0))); }; EventEngine.prototype.getSubscribedChannelGroups = function () { - return this.groups.slice(0); + return Array.from(new Set(this.groups.slice(0))); }; EventEngine.prototype.dispose = function () { this.disconnect(); diff --git a/lib/event-engine/presence/dispatcher.js b/lib/event-engine/presence/dispatcher.js index 2b79f44eb..57c705794 100644 --- a/lib/event-engine/presence/dispatcher.js +++ b/lib/event-engine/presence/dispatcher.js @@ -63,7 +63,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) { function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); - while (_) try { + while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { @@ -89,132 +89,113 @@ var __importDefault = (this && this.__importDefault) || function (mod) { }; Object.defineProperty(exports, "__esModule", { value: true }); exports.PresenceEventEngineDispatcher = void 0; -var endpoint_1 = require("../../core/components/endpoint"); var core_1 = require("../core"); var operations_1 = __importDefault(require("../../core/constants/operations")); +var PubNubError_1 = require("../../models/PubNubError"); var effects = __importStar(require("./effects")); var events = __importStar(require("./events")); var PresenceEventEngineDispatcher = /** @class */ (function (_super) { __extends(PresenceEventEngineDispatcher, _super); function PresenceEventEngineDispatcher(engine, dependencies) { var _this = _super.call(this, dependencies) || this; - _this.on(effects.heartbeat.type, (0, core_1.asyncHandler)(function (payload, _, _a) { - var heartbeat = _a.heartbeat, presenceState = _a.presenceState, config = _a.config; - return __awaiter(_this, void 0, void 0, function () { - var result, e_1; - return __generator(this, function (_b) { - switch (_b.label) { - case 0: - _b.trys.push([0, 2, , 3]); - return [4 /*yield*/, heartbeat(__assign({ channels: payload.channels, channelGroups: payload.groups }, (config.maintainPresenceState && { state: presenceState })))]; - case 1: - result = _b.sent(); - engine.transition(events.heartbeatSuccess(200)); - return [3 /*break*/, 3]; - case 2: - e_1 = _b.sent(); - if (e_1 instanceof endpoint_1.PubNubError) { - return [2 /*return*/, engine.transition(events.heartbeatFailure(e_1))]; - } - return [3 /*break*/, 3]; - case 3: return [2 /*return*/]; - } - }); + _this.on(effects.heartbeat.type, (0, core_1.asyncHandler)(function (payload_1, _1, _a) { return __awaiter(_this, [payload_1, _1, _a], void 0, function (payload, _, _b) { + var result, e_1; + var heartbeat = _b.heartbeat, presenceState = _b.presenceState, config = _b.config; + return __generator(this, function (_c) { + switch (_c.label) { + case 0: + _c.trys.push([0, 2, , 3]); + return [4 /*yield*/, heartbeat(__assign(__assign({ channels: payload.channels, channelGroups: payload.groups }, (config.maintainPresenceState && { state: presenceState })), { heartbeat: config.presenceTimeout }))]; + case 1: + result = _c.sent(); + engine.transition(events.heartbeatSuccess(200)); + return [3 /*break*/, 3]; + case 2: + e_1 = _c.sent(); + if (e_1 instanceof PubNubError_1.PubNubError) { + return [2 /*return*/, engine.transition(events.heartbeatFailure(e_1))]; + } + return [3 /*break*/, 3]; + case 3: return [2 /*return*/]; + } }); - })); - _this.on(effects.leave.type, (0, core_1.asyncHandler)(function (payload, _, _a) { - var leave = _a.leave, config = _a.config; - return __awaiter(_this, void 0, void 0, function () { - var result, e_2; - return __generator(this, function (_b) { - switch (_b.label) { - case 0: - if (!!config.suppressLeaveEvents) return [3 /*break*/, 4]; - _b.label = 1; - case 1: - _b.trys.push([1, 3, , 4]); - return [4 /*yield*/, leave({ - channels: payload.channels, - channelGroups: payload.groups, - })]; - case 2: - result = _b.sent(); - return [3 /*break*/, 4]; - case 3: - e_2 = _b.sent(); - return [3 /*break*/, 4]; - case 4: return [2 /*return*/]; + }); })); + _this.on(effects.leave.type, (0, core_1.asyncHandler)(function (payload_1, _1, _a) { return __awaiter(_this, [payload_1, _1, _a], void 0, function (payload, _, _b) { + var leave = _b.leave, config = _b.config; + return __generator(this, function (_c) { + if (!config.suppressLeaveEvents) { + try { + leave({ + channels: payload.channels, + channelGroups: payload.groups, + }); } - }); + catch (e) { } + } + return [2 /*return*/]; }); - })); - _this.on(effects.wait.type, (0, core_1.asyncHandler)(function (_, abortSignal, _a) { - var heartbeatDelay = _a.heartbeatDelay; - return __awaiter(_this, void 0, void 0, function () { - return __generator(this, function (_b) { - switch (_b.label) { - case 0: - abortSignal.throwIfAborted(); - return [4 /*yield*/, heartbeatDelay()]; - case 1: - _b.sent(); - abortSignal.throwIfAborted(); - return [2 /*return*/, engine.transition(events.timesUp())]; - } - }); + }); })); + _this.on(effects.wait.type, (0, core_1.asyncHandler)(function (_1, abortSignal_1, _a) { return __awaiter(_this, [_1, abortSignal_1, _a], void 0, function (_, abortSignal, _b) { + var heartbeatDelay = _b.heartbeatDelay; + return __generator(this, function (_c) { + switch (_c.label) { + case 0: + abortSignal.throwIfAborted(); + return [4 /*yield*/, heartbeatDelay()]; + case 1: + _c.sent(); + abortSignal.throwIfAborted(); + return [2 /*return*/, engine.transition(events.timesUp())]; + } }); - })); - _this.on(effects.delayedHeartbeat.type, (0, core_1.asyncHandler)(function (payload, abortSignal, _a) { - var heartbeat = _a.heartbeat, retryDelay = _a.retryDelay, presenceState = _a.presenceState, config = _a.config; - return __awaiter(_this, void 0, void 0, function () { - var result, e_3; - return __generator(this, function (_b) { - switch (_b.label) { - case 0: - if (!(config.retryConfiguration && config.retryConfiguration.shouldRetry(payload.reason, payload.attempts))) return [3 /*break*/, 6]; - abortSignal.throwIfAborted(); - return [4 /*yield*/, retryDelay(config.retryConfiguration.getDelay(payload.attempts, payload.reason))]; - case 1: - _b.sent(); - abortSignal.throwIfAborted(); - _b.label = 2; - case 2: - _b.trys.push([2, 4, , 5]); - return [4 /*yield*/, heartbeat(__assign({ channels: payload.channels, channelGroups: payload.groups }, (config.maintainPresenceState && { state: presenceState })))]; - case 3: - result = _b.sent(); - return [2 /*return*/, engine.transition(events.heartbeatSuccess(200))]; - case 4: - e_3 = _b.sent(); - if (e_3 instanceof Error && e_3.message === 'Aborted') { - return [2 /*return*/]; - } - if (e_3 instanceof endpoint_1.PubNubError) { - return [2 /*return*/, engine.transition(events.heartbeatFailure(e_3))]; - } - return [3 /*break*/, 5]; - case 5: return [3 /*break*/, 7]; - case 6: return [2 /*return*/, engine.transition(events.heartbeatGiveup())]; - case 7: return [2 /*return*/]; - } - }); + }); })); + _this.on(effects.delayedHeartbeat.type, (0, core_1.asyncHandler)(function (payload_1, abortSignal_1, _a) { return __awaiter(_this, [payload_1, abortSignal_1, _a], void 0, function (payload, abortSignal, _b) { + var result, e_2; + var heartbeat = _b.heartbeat, retryDelay = _b.retryDelay, presenceState = _b.presenceState, config = _b.config; + return __generator(this, function (_c) { + switch (_c.label) { + case 0: + if (!(config.retryConfiguration && config.retryConfiguration.shouldRetry(payload.reason, payload.attempts))) return [3 /*break*/, 6]; + abortSignal.throwIfAborted(); + return [4 /*yield*/, retryDelay(config.retryConfiguration.getDelay(payload.attempts, payload.reason))]; + case 1: + _c.sent(); + abortSignal.throwIfAborted(); + _c.label = 2; + case 2: + _c.trys.push([2, 4, , 5]); + return [4 /*yield*/, heartbeat(__assign(__assign({ channels: payload.channels, channelGroups: payload.groups }, (config.maintainPresenceState && { state: presenceState })), { heartbeat: config.presenceTimeout }))]; + case 3: + result = _c.sent(); + return [2 /*return*/, engine.transition(events.heartbeatSuccess(200))]; + case 4: + e_2 = _c.sent(); + if (e_2 instanceof Error && e_2.message === 'Aborted') { + return [2 /*return*/]; + } + if (e_2 instanceof PubNubError_1.PubNubError) { + return [2 /*return*/, engine.transition(events.heartbeatFailure(e_2))]; + } + return [3 /*break*/, 5]; + case 5: return [3 /*break*/, 7]; + case 6: return [2 /*return*/, engine.transition(events.heartbeatGiveup())]; + case 7: return [2 /*return*/]; + } }); - })); - _this.on(effects.emitStatus.type, (0, core_1.asyncHandler)(function (payload, _, _a) { - var emitStatus = _a.emitStatus, config = _a.config; - return __awaiter(_this, void 0, void 0, function () { - var _b; - return __generator(this, function (_c) { - if (config.announceFailedHeartbeats && ((_b = payload === null || payload === void 0 ? void 0 : payload.status) === null || _b === void 0 ? void 0 : _b.error) === true) { - emitStatus(payload.status); - } - else if (config.announceSuccessfulHeartbeats && payload.statusCode === 200) { - emitStatus(__assign(__assign({}, payload), { operation: operations_1.default.PNHeartbeatOperation, error: false })); - } - return [2 /*return*/]; - }); + }); })); + _this.on(effects.emitStatus.type, (0, core_1.asyncHandler)(function (payload_1, _1, _a) { return __awaiter(_this, [payload_1, _1, _a], void 0, function (payload, _, _b) { + var _c; + var emitStatus = _b.emitStatus, config = _b.config; + return __generator(this, function (_d) { + if (config.announceFailedHeartbeats && ((_c = payload === null || payload === void 0 ? void 0 : payload.status) === null || _c === void 0 ? void 0 : _c.error) === true) { + emitStatus(payload.status); + } + else if (config.announceSuccessfulHeartbeats && payload.statusCode === 200) { + emitStatus(__assign(__assign({}, payload), { operation: operations_1.default.PNHeartbeatOperation, error: false })); + } + return [2 /*return*/]; }); - })); + }); })); return _this; } return PresenceEventEngineDispatcher; diff --git a/lib/event-engine/presence/effects.js b/lib/event-engine/presence/effects.js index 3e6dd2887..dd9732060 100644 --- a/lib/event-engine/presence/effects.js +++ b/lib/event-engine/presence/effects.js @@ -10,6 +10,8 @@ exports.leave = (0, core_1.createEffect)('LEAVE', function (channels, groups) { channels: channels, groups: groups, }); }); +// TODO: Find out actual `status` type. +/* eslint-disable @typescript-eslint/no-explicit-any */ exports.emitStatus = (0, core_1.createEffect)('EMIT_STATUS', function (status) { return status; }); exports.wait = (0, core_1.createManagedEffect)('WAIT', function () { return ({}); }); exports.delayedHeartbeat = (0, core_1.createManagedEffect)('DELAYED_HEARTBEAT', function (context) { return context; }); diff --git a/lib/event-engine/presence/presence.js b/lib/event-engine/presence/presence.js index 40c6c11f3..17cdc4eb6 100644 --- a/lib/event-engine/presence/presence.js +++ b/lib/event-engine/presence/presence.js @@ -56,11 +56,11 @@ var heartbeat_inactive_1 = require("./states/heartbeat_inactive"); var PresenceEventEngine = /** @class */ (function () { function PresenceEventEngine(dependencies) { var _this = this; + this.dependencies = dependencies; this.engine = new core_1.Engine(); this.channels = []; this.groups = []; this.dispatcher = new dispatcher_1.PresenceEventEngineDispatcher(this.engine, dependencies); - this.dependencies = dependencies; this._unsubscribeEngine = this.engine.subscribe(function (change) { if (change.type === 'invocationDispatched') { _this.dispatcher.dispatch(change.invocation); diff --git a/lib/event-engine/states/handshake_failure.js b/lib/event-engine/states/handshake_failure.js deleted file mode 100644 index 4f682098a..000000000 --- a/lib/event-engine/states/handshake_failure.js +++ /dev/null @@ -1,26 +0,0 @@ -"use strict"; -var __assign = (this && this.__assign) || function () { - __assign = Object.assign || function(t) { - for (var s, i = 1, n = arguments.length; i < n; i++) { - s = arguments[i]; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) - t[p] = s[p]; - } - return t; - }; - return __assign.apply(this, arguments); -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.HandshakeFailureState = void 0; -var state_1 = require("../core/state"); -var events_1 = require("../events"); -var handshake_stopped_1 = require("./handshake_stopped"); -var handshaking_1 = require("./handshaking"); -exports.HandshakeFailureState = new state_1.State('HANDSHAKE_FAILURE'); -exports.HandshakeFailureState.on(events_1.disconnect.type, function (context) { - return handshake_stopped_1.HandshakeStoppedState.with({ - channels: context.channels, - groups: context.groups, - }); -}); -exports.HandshakeFailureState.on(events_1.reconnect.type, function (context) { return handshaking_1.HandshakingState.with(__assign({}, context)); }); diff --git a/lib/event-engine/states/receive_failure.js b/lib/event-engine/states/receive_failure.js deleted file mode 100644 index 4eb9e2b72..000000000 --- a/lib/event-engine/states/receive_failure.js +++ /dev/null @@ -1,38 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.ReceiveFailureState = void 0; -var state_1 = require("../core/state"); -var events_1 = require("../events"); -var handshaking_1 = require("./handshaking"); -var receive_stopped_1 = require("./receive_stopped"); -var unsubscribed_1 = require("./unsubscribed"); -exports.ReceiveFailureState = new state_1.State('RECEIVE_FAILED'); -exports.ReceiveFailureState.on(events_1.reconnectingRetry.type, function (context) { - return handshaking_1.HandshakingState.with({ - channels: context.channels, - groups: context.groups, - timetoken: context.cursor.timetoken, - }); -}); -exports.ReceiveFailureState.on(events_1.disconnect.type, function (context) { - return receive_stopped_1.ReceiveStoppedState.with({ - channels: context.channels, - groups: context.groups, - cursor: context.cursor, - }); -}); -exports.ReceiveFailureState.on(events_1.subscriptionChange.type, function (_, event) { - return handshaking_1.HandshakingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - timetoken: event.payload.timetoken, - }); -}); -exports.ReceiveFailureState.on(events_1.restore.type, function (_, event) { - return handshaking_1.HandshakingState.with({ - channels: event.payload.channels, - groups: event.payload.groups, - timetoken: event.payload.timetoken, - }); -}); -exports.ReceiveFailureState.on(events_1.unsubscribeAll.type, function (_) { return unsubscribed_1.UnsubscribedState.with(undefined); }); diff --git a/lib/file/index.js b/lib/file/index.js deleted file mode 100644 index 1e44d895d..000000000 --- a/lib/file/index.js +++ /dev/null @@ -1,2 +0,0 @@ -"use strict"; -/** */ diff --git a/lib/file/modules/node.js b/lib/file/modules/node.js index bb0988238..5a0cf7b9c 100644 --- a/lib/file/modules/node.js +++ b/lib/file/modules/node.js @@ -1,4 +1,7 @@ "use strict"; +/** + * Node.js {@link PubNub} File object module. + */ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { @@ -14,7 +17,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) { function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); - while (_) try { + while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { @@ -38,137 +41,211 @@ var __generator = (this && this.__generator) || function (thisArg, body) { var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; -var _a; Object.defineProperty(exports, "__esModule", { value: true }); var stream_1 = require("stream"); -var fs_1 = __importDefault(require("fs")); +var buffer_1 = require("buffer"); var path_1 = require("path"); -var PubNubFile = (_a = /** @class */ (function () { - function PubNubFile(_a) { - var stream = _a.stream, data = _a.data, encoding = _a.encoding, name = _a.name, mimeType = _a.mimeType; - if (stream instanceof stream_1.Readable) { - this.data = stream; - if (stream instanceof fs_1.default.ReadStream) { - // $FlowFixMe: incomplete flow node definitions - this.name = (0, path_1.basename)(stream.path); - this.contentLength = fs_1.default.statSync(stream.path).size; - } - } - else if (data instanceof Buffer) { - this.data = Buffer.from(data); - } - else if (typeof data === 'string') { - // $FlowFixMe: incomplete flow node definitions - this.data = Buffer.from(data, encoding !== null && encoding !== void 0 ? encoding : 'utf8'); - } - if (name) { - this.name = (0, path_1.basename)(name); - } - if (mimeType) { - this.mimeType = mimeType; - } - if (this.data === undefined) { - throw new Error("Couldn't construct a file out of supplied options."); - } - if (this.name === undefined) { - throw new Error("Couldn't guess filename out of the options. Please provide one."); +var fs_1 = __importDefault(require("fs")); +// endregion +/** + * Node.js implementation for {@link PubNub} File object. + * + * **Important:** Class should implement constructor and class fields from {@link PubNubFileConstructor}. + */ +var PubNubFile = /** @class */ (function () { + function PubNubFile(file) { + var stream = file.stream, data = file.data, encoding = file.encoding, name = file.name, mimeType = file.mimeType; + var fileData; + var contentLength; + var fileMimeType; + var fileName; + if (stream && stream instanceof stream_1.Readable) { + fileData = stream; + if (stream instanceof fs_1.default.ReadStream) { + var streamFilePath = stream.path instanceof buffer_1.Buffer ? new TextDecoder().decode(stream.path) : stream.path; + fileName = (0, path_1.basename)(streamFilePath); + contentLength = fs_1.default.statSync(streamFilePath).size; } } - PubNubFile.create = function (config) { - return new this(config); - }; - PubNubFile.prototype.toBuffer = function () { - if (this.data instanceof Buffer) { - return Promise.resolve(Buffer.from(this.data)); - } - if (this.data instanceof stream_1.Readable) { - var stream_2 = this.data; - return new Promise(function (resolve, reject) { - var chunks = []; - stream_2.on('data', function (chunk) { return chunks.push(chunk); }); - stream_2.once('error', reject); - stream_2.once('end', function () { - resolve(Buffer.concat(chunks)); - }); - }); - } - if (typeof this.data === 'string') { - return Promise.resolve(Buffer.from(this.data)); - } - throw new Error("Can't cast to 'buffer'."); - }; - PubNubFile.prototype.toArrayBuffer = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - throw new Error('This feature is only supported in browser environments.'); - }); + else if (data instanceof buffer_1.Buffer) { + contentLength = data.length; + // Copy content of the source Buffer. + fileData = buffer_1.Buffer.alloc(contentLength); + data.copy(fileData); + } + else if (data instanceof ArrayBuffer) { + contentLength = data.byteLength; + fileData = buffer_1.Buffer.from(data); + } + else if (typeof data === 'string') { + fileData = buffer_1.Buffer.from(data, encoding !== null && encoding !== void 0 ? encoding : 'utf8'); + contentLength = fileData.length; + } + if (contentLength) + this.contentLength = contentLength; + if (mimeType) + fileMimeType = mimeType; + else + fileMimeType = 'application/octet-stream'; + if (name) + fileName = (0, path_1.basename)(name); + if (fileData === undefined) + throw new Error("Couldn't construct a file out of supplied options."); + if (fileName === undefined) + throw new Error("Couldn't guess filename out of the options. Please provide one."); + this.mimeType = fileMimeType; + this.data = fileData; + this.name = fileName; + } + // endregion + PubNubFile.create = function (file) { + return new PubNubFile(file); + }; + /** + * Convert {@link PubNub} File object content to {@link Buffer}. + * + * @returns Asynchronous results of conversion to the {@link Buffer}. + */ + PubNubFile.prototype.toBuffer = function () { + return __awaiter(this, void 0, void 0, function () { + var stream; + return __generator(this, function (_a) { + if (this.data instanceof buffer_1.Buffer) + return [2 /*return*/, this.data]; + stream = this.data; + return [2 /*return*/, new Promise(function (resolve, reject) { + var chunks = []; + stream.on('data', function (chunk) { + chunks.push(chunk); + }); + stream.on('end', function () { + resolve(buffer_1.Buffer.concat(chunks)); + }); + // Handle any errors during streaming + stream.on('error', function (error) { return reject(error); }); + })]; }); - }; - PubNubFile.prototype.toString = function (encoding) { + }); + }; + /** + * Convert {@link PubNub} File object content to {@link ArrayBuffer}. + * + * @returns Asynchronous results of conversion to the {@link ArrayBuffer}. + */ + PubNubFile.prototype.toArrayBuffer = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this.toBuffer().then(function (buffer) { return buffer.buffer; })]; + }); + }); + }; + /** + * Convert {@link PubNub} File object content to {@link string}. + * + * @returns Asynchronous results of conversion to the {@link string}. + */ + PubNubFile.prototype.toString = function () { + return __awaiter(this, arguments, void 0, function (encoding) { if (encoding === void 0) { encoding = 'utf8'; } - return __awaiter(this, void 0, void 0, function () { - var buffer; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: return [4 /*yield*/, this.toBuffer()]; - case 1: - buffer = _a.sent(); - return [2 /*return*/, buffer.toString(encoding)]; - } - }); + return __generator(this, function (_a) { + return [2 /*return*/, this.toBuffer().then(function (buffer) { return buffer.toString(encoding); })]; }); - }; - PubNubFile.prototype.toStream = function () { - return __awaiter(this, void 0, void 0, function () { - var input_1, stream; - return __generator(this, function (_a) { - if (!(this.data instanceof stream_1.Readable)) { - input_1 = this.data; - return [2 /*return*/, new stream_1.Readable({ - read: function () { - this.push(Buffer.from(input_1)); - this.push(null); - }, - })]; - } + }); + }; + /** + * Convert {@link PubNub} File object content to {@link Readable} stream. + * + * @returns Asynchronous results of conversion to the {@link Readable} stream. + */ + PubNubFile.prototype.toStream = function () { + return __awaiter(this, void 0, void 0, function () { + var stream; + return __generator(this, function (_a) { + if (this.data instanceof stream_1.Readable) { stream = new stream_1.PassThrough(); - if (this.data instanceof stream_1.Readable) { - this.data.pipe(stream); - } + this.data.pipe(stream); return [2 /*return*/, stream]; - }); + } + return [2 /*return*/, this.toBuffer().then(function (buffer) { + return new stream_1.Readable({ + read: function () { + this.push(buffer); + this.push(null); + }, + }); + })]; }); - }; - PubNubFile.prototype.toFile = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - throw new Error('This feature is only supported in browser environments.'); - }); + }); + }; + /** + * Convert {@link PubNub} File object content to {@link File}. + * + * @throws Error because {@link File} not available in Node.js environment. + */ + PubNubFile.prototype.toFile = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + throw new Error('This feature is only supported in browser environments.'); }); - }; - PubNubFile.prototype.toFileUri = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - throw new Error('This feature is only supported in react native environments.'); - }); + }); + }; + /** + * Convert {@link PubNub} File object content to file `Uri`. + * + * @throws Error because file `Uri` not available in Node.js environment. + */ + PubNubFile.prototype.toFileUri = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + throw new Error('This feature is only supported in React Native environments.'); }); - }; - PubNubFile.prototype.toBlob = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - throw new Error('This feature is only supported in browser environments.'); - }); + }); + }; + /** + * Convert {@link PubNub} File object content to {@link Blob}. + * + * @throws Error because {@link Blob} not available in Node.js environment. + */ + PubNubFile.prototype.toBlob = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + throw new Error('This feature is only supported in browser environments.'); }); - }; - return PubNubFile; - }()), - _a.supportsBlob = false, - _a.supportsFile = false, - _a.supportsBuffer = typeof Buffer !== 'undefined', - _a.supportsStream = true, - _a.supportsString = true, - _a.supportsArrayBuffer = false, - _a.supportsEncryptFile = true, - _a.supportsFileUri = false, - _a); + }); + }; + // region Class properties + /** + * Whether {@link Blob} data supported by platform or not. + */ + PubNubFile.supportsBlob = false; + /** + * Whether {@link File} data supported by platform or not. + */ + PubNubFile.supportsFile = false; + /** + * Whether {@link Buffer} data supported by platform or not. + */ + PubNubFile.supportsBuffer = true; + /** + * Whether {@link Stream} data supported by platform or not. + */ + PubNubFile.supportsStream = true; + /** + * Whether {@link String} data supported by platform or not. + */ + PubNubFile.supportsString = true; + /** + * Whether {@link ArrayBuffer} supported by platform or not. + */ + PubNubFile.supportsArrayBuffer = true; + /** + * Whether {@link PubNub} File object encryption supported or not. + */ + PubNubFile.supportsEncryptFile = true; + /** + * Whether `File Uri` data supported by platform or not. + */ + PubNubFile.supportsFileUri = false; + return PubNubFile; +}()); exports.default = PubNubFile; diff --git a/lib/file/modules/react-native.js b/lib/file/modules/react-native.js index 6a83eca25..b65d77d34 100644 --- a/lib/file/modules/react-native.js +++ b/lib/file/modules/react-native.js @@ -1,5 +1,8 @@ "use strict"; /* global File, FileReader */ +/** + * React Native {@link PubNub} File object module. + */ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { @@ -15,7 +18,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) { function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); - while (_) try { + while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { @@ -36,180 +39,239 @@ var __generator = (this && this.__generator) || function (thisArg, body) { if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; -var _a; Object.defineProperty(exports, "__esModule", { value: true }); -var PubNubFile = (_a = /** @class */ (function () { - function PubNubFile(config) { - if (config instanceof File) { - this.data = config; - this.name = this.data.name; - this.mimeType = this.data.type; - } - else if (config.uri) { - // uri upload for react native - this.data = { - uri: config.uri, - name: config.name, - type: config.mimeType, - }; - this.name = config.name; - if (config.mimeType) { - this.mimeType = config.mimeType; - } - } - else if (config.data) { - this.data = config.data; - this.name = config.name; - if (config.mimeType) { - this.mimeType = config.mimeType; - } - } - else { - throw new Error("Couldn't construct a file out of supplied options. URI or file data required."); - } - if (this.data === undefined) { - throw new Error("Couldn't construct a file out of supplied options."); - } - if (this.name === undefined) { - throw new Error("Couldn't guess filename out of the options. Please provide one."); - } +exports.PubNubFile = void 0; +// endregion +var PubNubFile = /** @class */ (function () { + function PubNubFile(file) { + var fileMimeType; + var fileName; + var fileData; + if (file instanceof File) { + fileData = file; + fileName = file.name; + fileMimeType = file.type; } - PubNubFile.create = function (config) { - return new this(config); - }; - PubNubFile.prototype.toBuffer = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - throw new Error('This feature is only supported in Node.js environments.'); - }); - }); - }; - PubNubFile.prototype.toStream = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - throw new Error('This feature is only supported in Node.js environments.'); - }); - }); - }; - PubNubFile.prototype.toBlob = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - if (this.data && this.data.uri) { - throw new Error('This file contains a file URI and does not contain the file contents.'); - } - else if (this.data instanceof File) { - return [2 /*return*/, this.data]; - } - else { - // data must be a fetch response - return [2 /*return*/, this.data.blob()]; - } - return [2 /*return*/]; - }); - }); - }; - PubNubFile.prototype.toArrayBuffer = function () { - return __awaiter(this, void 0, void 0, function () { - var result, e_1; - var _this = this; - return __generator(this, function (_a) { - switch (_a.label) { - case 0: - if (!(this.data && this.data.uri)) return [3 /*break*/, 1]; - throw new Error('This file contains a file URI and does not contain the file contents.'); - case 1: - if (!(this.data instanceof File)) return [3 /*break*/, 2]; - return [2 /*return*/, new Promise(function (resolve, reject) { - var reader = new FileReader(); - reader.addEventListener('load', function () { - if (reader.result instanceof ArrayBuffer) { - return resolve(reader.result); - } - }); - reader.addEventListener('error', function () { - reject(reader.error); - }); - reader.readAsArrayBuffer(_this.data); - })]; - case 2: - result = void 0; - _a.label = 3; - case 3: - _a.trys.push([3, 5, , 6]); - return [4 /*yield*/, this.data.arrayBuffer()]; - case 4: - result = _a.sent(); - return [3 /*break*/, 6]; - case 5: - e_1 = _a.sent(); - throw new Error("Unable to support toArrayBuffer in ReactNative environment: ".concat(e_1)); - case 6: return [2 /*return*/, result]; - } - }); + else if ('data' in file) { + var contents = file.data; + fileMimeType = file.mimeType; + fileName = file.name; + fileData = new File([contents], fileName, { type: fileMimeType }); + } + else if ('uri' in file) { + fileMimeType = file.mimeType; + fileName = file.name; + fileData = { + uri: file.uri, + name: file.name, + type: file.mimeType, + }; + } + else + throw new Error("Couldn't construct a file out of supplied options. URI or file data required."); + if (fileData === undefined) + throw new Error("Couldn't construct a file out of supplied options."); + if (fileName === undefined) + throw new Error("Couldn't guess filename out of the options. Please provide one."); + this.mimeType = fileMimeType; + this.data = fileData; + this.name = fileName; + } + // endregion + PubNubFile.create = function (file) { + return new PubNubFile(file); + }; + /** + * Convert {@link PubNub} File object content to {@link Buffer}. + * + * @throws Error because {@link Buffer} not available in React Native environment. + */ + PubNubFile.prototype.toBuffer = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + throw new Error('This feature is only supported in Node.js environments.'); }); - }; - PubNubFile.prototype.toString = function () { - return __awaiter(this, void 0, void 0, function () { - var _this = this; - return __generator(this, function (_a) { - if (this.data && this.data.uri) { - return [2 /*return*/, JSON.stringify(this.data)]; - } - if (this.data instanceof File) { + }); + }; + /** + * Convert {@link PubNub} File object content to {@link ArrayBuffer}. + * + * @returns Asynchronous results of conversion to the {@link ArrayBuffer}. + * + * @throws Error if provided {@link PubNub} File object content is not supported for this + * operation. + */ + PubNubFile.prototype.toArrayBuffer = function () { + return __awaiter(this, void 0, void 0, function () { + var data_1, result, error_1; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!(this.data && this.data instanceof File)) return [3 /*break*/, 1]; + data_1 = this.data; return [2 /*return*/, new Promise(function (resolve, reject) { var reader = new FileReader(); reader.addEventListener('load', function () { - if (typeof reader.result === 'string') { + if (reader.result instanceof ArrayBuffer) return resolve(reader.result); - } }); - reader.addEventListener('error', function () { - reject(reader.error); - }); - reader.readAsBinaryString(_this.data); + reader.addEventListener('error', function () { return reject(reader.error); }); + reader.readAsArrayBuffer(data_1); })]; - } - // data must be a fetch response - return [2 /*return*/, this.data.text()]; - }); - }); - }; - PubNubFile.prototype.toFile = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - if (this.data.uri) { + case 1: + if (!(this.data && 'uri' in this.data)) return [3 /*break*/, 2]; throw new Error('This file contains a file URI and does not contain the file contents.'); - } - else if (this.data instanceof File) { - return [2 /*return*/, this.data]; - } - else { - // data must be a fetch response - return [2 /*return*/, this.data.blob()]; - } - return [2 /*return*/]; - }); + case 2: + if (!this.data) return [3 /*break*/, 7]; + result = void 0; + _a.label = 3; + case 3: + _a.trys.push([3, 5, , 6]); + return [4 /*yield*/, this.data.arrayBuffer()]; + case 4: + result = _a.sent(); + return [3 /*break*/, 6]; + case 5: + error_1 = _a.sent(); + throw new Error("Unable to support toArrayBuffer in ReactNative environment: ".concat(error_1)); + case 6: return [2 /*return*/, result]; + case 7: throw new Error('Unable convert provided file content type to ArrayBuffer'); + } + }); + }); + }; + /** + * Convert {@link PubNub} File object content to {@link string}. + * + * @returns Asynchronous results of conversion to the {@link string}. + */ + PubNubFile.prototype.toString = function () { + return __awaiter(this, void 0, void 0, function () { + var data_2; + return __generator(this, function (_a) { + if (this.data && 'uri' in this.data) + return [2 /*return*/, JSON.stringify(this.data)]; + else if (this.data && this.data instanceof File) { + data_2 = this.data; + return [2 /*return*/, new Promise(function (resolve, reject) { + var reader = new FileReader(); + reader.addEventListener('load', function () { + if (typeof reader.result === 'string') + return resolve(reader.result); + }); + reader.addEventListener('error', function () { return reject(reader.error); }); + reader.readAsBinaryString(data_2); + })]; + } + return [2 /*return*/, this.data.text()]; + }); + }); + }; + /** + * Convert {@link PubNub} File object content to {@link Readable} stream. + * + * @throws Error because {@link Readable} stream not available in React Native environment. + */ + PubNubFile.prototype.toStream = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + throw new Error('This feature is only supported in Node.js environments.'); + }); + }); + }; + /** + * Convert {@link PubNub} File object content to {@link File}. + * + * @returns Asynchronous results of conversion to the {@link File}. + * + * @throws Error if provided {@link PubNub} File object content is not supported for this + * operation. + */ + PubNubFile.prototype.toFile = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + if (this.data instanceof File) + return [2 /*return*/, this.data]; + else if ('uri' in this.data) + throw new Error('This file contains a file URI and does not contain the file contents.'); + else + return [2 /*return*/, this.data.blob()]; + return [2 /*return*/]; + }); + }); + }; + /** + * Convert {@link PubNub} File object content to file `Uri`. + * + * @returns Asynchronous results of conversion to file `Uri`. + * + * @throws Error if provided {@link PubNub} File object content is not supported for this + * operation. + */ + PubNubFile.prototype.toFileUri = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + if (this.data && 'uri' in this.data) + return [2 /*return*/, this.data]; + throw new Error('This file does not contain a file URI'); }); - }; - PubNubFile.prototype.toFileUri = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - if (this.data && this.data.uri) { - return [2 /*return*/, this.data]; - } - throw new Error('This file does not contain a file URI'); - }); + }); + }; + /** + * Convert {@link PubNub} File object content to {@link Blob}. + * + * @returns Asynchronous results of conversion to the {@link Blob}. + * + * @throws Error if provided {@link PubNub} File object content is not supported for this + * operation. + */ + PubNubFile.prototype.toBlob = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + if (this.data instanceof File) + return [2 /*return*/, this.data]; + else if (this.data && 'uri' in this.data) + throw new Error('This file contains a file URI and does not contain the file contents.'); + else + return [2 /*return*/, this.data.blob()]; + return [2 /*return*/]; }); - }; - return PubNubFile; - }()), - _a.supportsFile = typeof File !== 'undefined', - _a.supportsBlob = typeof Blob !== 'undefined', - _a.supportsArrayBuffer = typeof ArrayBuffer !== 'undefined', - _a.supportsBuffer = false, - _a.supportsStream = false, - _a.supportsString = true, - _a.supportsEncryptFile = false, - _a.supportsFileUri = true, - _a); + }); + }; + // region Class properties + /** + * Whether {@link Blob} data supported by platform or not. + */ + PubNubFile.supportsBlob = typeof Blob !== 'undefined'; + /** + * Whether {@link File} data supported by platform or not. + */ + PubNubFile.supportsFile = typeof File !== 'undefined'; + /** + * Whether {@link Buffer} data supported by platform or not. + */ + PubNubFile.supportsBuffer = false; + /** + * Whether {@link Stream} data supported by platform or not. + */ + PubNubFile.supportsStream = false; + /** + * Whether {@link String} data supported by platform or not. + */ + PubNubFile.supportsString = true; + /** + * Whether {@link ArrayBuffer} supported by platform or not. + */ + PubNubFile.supportsArrayBuffer = true; + /** + * Whether {@link PubNub} File object encryption supported or not. + */ + PubNubFile.supportsEncryptFile = false; + /** + * Whether `File Uri` data supported by platform or not. + */ + PubNubFile.supportsFileUri = true; + return PubNubFile; +}()); +exports.PubNubFile = PubNubFile; exports.default = PubNubFile; diff --git a/lib/file/modules/web.js b/lib/file/modules/web.js index 36be1d830..7e71d8ccd 100644 --- a/lib/file/modules/web.js +++ b/lib/file/modules/web.js @@ -1,5 +1,8 @@ "use strict"; /* global File, FileReader */ +/** + * Browser {@link PubNub} File object module. + */ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { @@ -15,7 +18,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) { function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); - while (_) try { + while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { @@ -36,115 +39,180 @@ var __generator = (this && this.__generator) || function (thisArg, body) { if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; -var _a; Object.defineProperty(exports, "__esModule", { value: true }); -var PubNubFile = (_a = /** @class */ (function () { - function PubNubFile(config) { - if (config instanceof File) { - this.data = config; - this.name = this.data.name; - this.mimeType = this.data.type; - } - else if (config.data) { - var contents = config.data; - this.data = new File([contents], config.name, { type: config.mimeType }); - this.name = config.name; - if (config.mimeType) { - this.mimeType = config.mimeType; - } - } - if (this.data === undefined) { - throw new Error("Couldn't construct a file out of supplied options."); - } - if (this.name === undefined) { - throw new Error("Couldn't guess filename out of the options. Please provide one."); - } +exports.PubNubFile = void 0; +// endregion +/** + * Web implementation for {@link PubNub} File object. + * + * **Important:** Class should implement constructor and class fields from {@link PubNubFileConstructor}. + */ +var PubNubFile = /** @class */ (function () { + function PubNubFile(file) { + var fileMimeType; + var fileName; + var fileData; + if (file instanceof File) { + fileData = file; + fileName = file.name; + fileMimeType = file.type; + } + else if ('data' in file) { + var contents = file.data; + fileMimeType = file.mimeType; + fileName = file.name; + fileData = new File([contents], fileName, { type: fileMimeType }); } - PubNubFile.create = function (config) { - return new this(config); - }; - PubNubFile.prototype.toBuffer = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - throw new Error('This feature is only supported in Node.js environments.'); - }); + if (fileData === undefined) + throw new Error("Couldn't construct a file out of supplied options."); + if (fileName === undefined) + throw new Error("Couldn't guess filename out of the options. Please provide one."); + this.mimeType = fileMimeType; + this.data = fileData; + this.name = fileName; + } + // endregion + PubNubFile.create = function (file) { + return new PubNubFile(file); + }; + /** + * Convert {@link PubNub} File object content to {@link Buffer}. + * + * @throws Error because {@link Buffer} not available in browser environment. + */ + PubNubFile.prototype.toBuffer = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + throw new Error('This feature is only supported in Node.js environments.'); }); - }; - PubNubFile.prototype.toStream = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - throw new Error('This feature is only supported in Node.js environments.'); - }); + }); + }; + /** + * Convert {@link PubNub} File object content to {@link ArrayBuffer}. + * + * @returns Asynchronous results of conversion to the {@link ArrayBuffer}. + */ + PubNubFile.prototype.toArrayBuffer = function () { + return __awaiter(this, void 0, void 0, function () { + var _this = this; + return __generator(this, function (_a) { + return [2 /*return*/, new Promise(function (resolve, reject) { + var reader = new FileReader(); + reader.addEventListener('load', function () { + if (reader.result instanceof ArrayBuffer) + return resolve(reader.result); + }); + reader.addEventListener('error', function () { return reject(reader.error); }); + reader.readAsArrayBuffer(_this.data); + })]; }); - }; - PubNubFile.prototype.toFileUri = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - throw new Error('This feature is only supported in react native environments.'); - }); + }); + }; + /** + * Convert {@link PubNub} File object content to {@link string}. + * + * @returns Asynchronous results of conversion to the {@link string}. + */ + PubNubFile.prototype.toString = function () { + return __awaiter(this, void 0, void 0, function () { + var _this = this; + return __generator(this, function (_a) { + return [2 /*return*/, new Promise(function (resolve, reject) { + var reader = new FileReader(); + reader.addEventListener('load', function () { + if (typeof reader.result === 'string') { + return resolve(reader.result); + } + }); + reader.addEventListener('error', function () { + reject(reader.error); + }); + reader.readAsBinaryString(_this.data); + })]; }); - }; - PubNubFile.prototype.toBlob = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - return [2 /*return*/, this.data]; - }); + }); + }; + /** + * Convert {@link PubNub} File object content to {@link Readable} stream. + * + * @throws Error because {@link Readable} stream not available in browser environment. + */ + PubNubFile.prototype.toStream = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + throw new Error('This feature is only supported in Node.js environments.'); }); - }; - PubNubFile.prototype.toArrayBuffer = function () { - return __awaiter(this, void 0, void 0, function () { - var _this = this; - return __generator(this, function (_a) { - return [2 /*return*/, new Promise(function (resolve, reject) { - var reader = new FileReader(); - reader.addEventListener('load', function () { - if (reader.result instanceof ArrayBuffer) { - return resolve(reader.result); - } - }); - reader.addEventListener('error', function () { - reject(reader.error); - }); - reader.readAsArrayBuffer(_this.data); - })]; - }); + }); + }; + /** + * Convert {@link PubNub} File object content to {@link File}. + * + * @returns Asynchronous results of conversion to the {@link File}. + */ + PubNubFile.prototype.toFile = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this.data]; }); - }; - PubNubFile.prototype.toString = function () { - return __awaiter(this, void 0, void 0, function () { - var _this = this; - return __generator(this, function (_a) { - return [2 /*return*/, new Promise(function (resolve, reject) { - var reader = new FileReader(); - reader.addEventListener('load', function () { - if (typeof reader.result === 'string') { - return resolve(reader.result); - } - }); - reader.addEventListener('error', function () { - reject(reader.error); - }); - reader.readAsBinaryString(_this.data); - })]; - }); + }); + }; + /** + * Convert {@link PubNub} File object content to file `Uri`. + * + * @throws Error because file `Uri` not available in browser environment. + */ + PubNubFile.prototype.toFileUri = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + throw new Error('This feature is only supported in React Native environments.'); }); - }; - PubNubFile.prototype.toFile = function () { - return __awaiter(this, void 0, void 0, function () { - return __generator(this, function (_a) { - return [2 /*return*/, this.data]; - }); + }); + }; + /** + * Convert {@link PubNub} File object content to {@link Blob}. + * + * @returns Asynchronous results of conversion to the {@link Blob}. + */ + PubNubFile.prototype.toBlob = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2 /*return*/, this.data]; }); - }; - return PubNubFile; - }()), - _a.supportsFile = typeof File !== 'undefined', - _a.supportsBlob = typeof Blob !== 'undefined', - _a.supportsArrayBuffer = typeof ArrayBuffer !== 'undefined', - _a.supportsBuffer = false, - _a.supportsStream = false, - _a.supportsString = true, - _a.supportsEncryptFile = true, - _a.supportsFileUri = false, - _a); -exports.default = PubNubFile; + }); + }; + // region Class properties + /** + * Whether {@link Blob} data supported by platform or not. + */ + PubNubFile.supportsBlob = typeof Blob !== 'undefined'; + /** + * Whether {@link File} data supported by platform or not. + */ + PubNubFile.supportsFile = typeof File !== 'undefined'; + /** + * Whether {@link Buffer} data supported by platform or not. + */ + PubNubFile.supportsBuffer = false; + /** + * Whether {@link Stream} data supported by platform or not. + */ + PubNubFile.supportsStream = false; + /** + * Whether {@link String} data supported by platform or not. + */ + PubNubFile.supportsString = true; + /** + * Whether {@link ArrayBuffer} supported by platform or not. + */ + PubNubFile.supportsArrayBuffer = true; + /** + * Whether {@link PubNub} File object encryption supported or not. + */ + PubNubFile.supportsEncryptFile = true; + /** + * Whether `File Uri` data supported by platform or not. + */ + PubNubFile.supportsFileUri = false; + return PubNubFile; +}()); +exports.PubNubFile = PubNubFile; diff --git a/lib/models/PubNubError.js b/lib/models/PubNubError.js new file mode 100644 index 000000000..fcbd03362 --- /dev/null +++ b/lib/models/PubNubError.js @@ -0,0 +1,52 @@ +"use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.createValidationError = exports.PubNubError = void 0; +var PubNubError = /** @class */ (function (_super) { + __extends(PubNubError, _super); + function PubNubError(message, status) { + var _newTarget = this.constructor; + var _this = _super.call(this, message) || this; + _this.status = status; + _this.name = _this.constructor.name; + _this.message = message; + Object.setPrototypeOf(_this, _newTarget.prototype); + return _this; + } + return PubNubError; +}(Error)); +exports.PubNubError = PubNubError; +function createError(errorPayload, type) { + var _a; + (_a = errorPayload.statusCode) !== null && _a !== void 0 ? _a : (errorPayload.statusCode = 0); + return __assign(__assign({}, errorPayload), { statusCode: errorPayload.statusCode, error: true, type: type }); +} +function createValidationError(message, statusCode) { + return createError(__assign({ message: message }, (statusCode !== undefined ? { statusCode: statusCode } : {})), 'validationError'); +} +exports.createValidationError = createValidationError; diff --git a/lib/networking/index.js b/lib/networking/index.js deleted file mode 100644 index 2b25c9249..000000000 --- a/lib/networking/index.js +++ /dev/null @@ -1,102 +0,0 @@ -"use strict"; -/* */ -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -var categories_1 = __importDefault(require("../core/constants/categories")); -var default_1 = /** @class */ (function () { - function default_1(modules) { - var _this = this; - this._modules = {}; - Object.keys(modules).forEach(function (key) { - _this._modules[key] = modules[key].bind(_this); - }); - } - default_1.prototype.init = function (config) { - this._config = config; - if (Array.isArray(this._config.origin)) { - this._currentSubDomain = Math.floor(Math.random() * this._config.origin.length); - } - else { - this._currentSubDomain = 0; - } - this._coreParams = {}; - // create initial origins - this.shiftStandardOrigin(); - }; - default_1.prototype.nextOrigin = function () { - var protocol = this._config.secure ? 'https://' : 'http://'; - if (typeof this._config.origin === 'string') { - return "".concat(protocol).concat(this._config.origin); - } - this._currentSubDomain += 1; - if (this._currentSubDomain >= this._config.origin.length) { - this._currentSubDomain = 0; - } - var origin = this._config.origin[this._currentSubDomain]; - return "".concat(protocol).concat(origin); - }; - default_1.prototype.hasModule = function (name) { - return name in this._modules; - }; - // origin operations - default_1.prototype.shiftStandardOrigin = function () { - this._standardOrigin = this.nextOrigin(); - return this._standardOrigin; - }; - default_1.prototype.getStandardOrigin = function () { - return this._standardOrigin; - }; - default_1.prototype.POSTFILE = function (url, fields, file) { - return this._modules.postfile(url, fields, file); - }; - default_1.prototype.GETFILE = function (params, endpoint, callback) { - return this._modules.getfile(params, endpoint, callback); - }; - default_1.prototype.POST = function (params, body, endpoint, callback) { - return this._modules.post(params, body, endpoint, callback); - }; - default_1.prototype.PATCH = function (params, body, endpoint, callback) { - return this._modules.patch(params, body, endpoint, callback); - }; - default_1.prototype.GET = function (params, endpoint, callback) { - return this._modules.get(params, endpoint, callback); - }; - default_1.prototype.DELETE = function (params, endpoint, callback) { - return this._modules.del(params, endpoint, callback); - }; - default_1.prototype._detectErrorCategory = function (err) { - if (err.code === 'ENOTFOUND') { - return categories_1.default.PNNetworkIssuesCategory; - } - if (err.code === 'ECONNREFUSED') { - return categories_1.default.PNNetworkIssuesCategory; - } - if (err.code === 'ECONNRESET') { - return categories_1.default.PNNetworkIssuesCategory; - } - if (err.code === 'EAI_AGAIN') { - return categories_1.default.PNNetworkIssuesCategory; - } - if (err.status === 0 || (err.hasOwnProperty('status') && typeof err.status === 'undefined')) { - return categories_1.default.PNNetworkIssuesCategory; - } - if (err.timeout) - return categories_1.default.PNTimeoutCategory; - if (err.code === 'ETIMEDOUT') { - return categories_1.default.PNNetworkIssuesCategory; - } - if (err.response) { - if (err.response.badRequest) { - return categories_1.default.PNBadRequestCategory; - } - if (err.response.forbidden) { - return categories_1.default.PNAccessDeniedCategory; - } - } - return categories_1.default.PNUnknownCategory; - }; - return default_1; -}()); -exports.default = default_1; diff --git a/lib/networking/modules/react_native.js b/lib/networking/modules/react_native.js index 34b26ba0d..85e64a3e0 100644 --- a/lib/networking/modules/react_native.js +++ b/lib/networking/modules/react_native.js @@ -17,7 +17,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) { function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); - while (_) try { + while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { @@ -40,6 +40,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) { }; Object.defineProperty(exports, "__esModule", { value: true }); exports.getfile = exports.postfile = void 0; +var flow_interfaces_1 = require("../../core/flow_interfaces"); var web_node_1 = require("./web-node"); function postfileuri(url, fields, fileInput) { return __awaiter(this, void 0, void 0, function () { diff --git a/lib/networking/modules/web-node.js b/lib/networking/modules/web-node.js index 55b14d860..96a007e57 100644 --- a/lib/networking/modules/web-node.js +++ b/lib/networking/modules/web-node.js @@ -16,7 +16,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) { function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); - while (_) try { + while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { @@ -45,26 +45,18 @@ exports.del = exports.patch = exports.post = exports.get = exports.getfile = exp var superagent_1 = __importDefault(require("superagent")); var categories_1 = __importDefault(require("../../core/constants/categories")); function log(req) { - var _pickLogger = function () { - if (console && console.log) - return console; // eslint-disable-line no-console - if (window && window.console && window.console.log) - return window.console; - return console; - }; var start = new Date().getTime(); var timestamp = new Date().toISOString(); - var logger = _pickLogger(); - logger.log('<<<<<'); - logger.log("[".concat(timestamp, "]"), '\n', req.url, '\n', req.qs); - logger.log('-----'); + console.log('<<<<<'); + console.log("[".concat(timestamp, "]"), '\n', req.url, '\n', req.qs); + console.log('-----'); req.on('response', function (res) { var now = new Date().getTime(); var elapsed = now - start; var timestampDone = new Date().toISOString(); - logger.log('>>>>>>'); - logger.log("[".concat(timestampDone, " / ").concat(elapsed, "]"), '\n', req.url, '\n', req.qs, '\n', res.text); - logger.log('-----'); + console.log('>>>>>>'); + console.log("[".concat(timestampDone, " / ").concat(elapsed, "]"), '\n', req.url, '\n', req.qs, '\n', res.text); + console.log('-----'); }); } function xdr(superagentConstruct, endpoint, callback) { diff --git a/lib/networking/utils.js b/lib/networking/utils.js index a554841c8..6722d3720 100644 --- a/lib/networking/utils.js +++ b/lib/networking/utils.js @@ -2,6 +2,8 @@ /* */ Object.defineProperty(exports, "__esModule", { value: true }); exports.buildUrl = exports.encodedKeyValuePair = void 0; +var api_1 = require("../core/types/api"); +var utils_1 = require("../core/utils"); function encodedKeyValuePair(pairs, key, value) { if (value != null) { if (Array.isArray(value)) { diff --git a/lib/node/configuration.js b/lib/node/configuration.js new file mode 100644 index 000000000..011d23235 --- /dev/null +++ b/lib/node/configuration.js @@ -0,0 +1,40 @@ +"use strict"; +/** + * Node.js specific {@link PubNub} client configuration module. + */ +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.setDefaults = void 0; +var configuration_1 = require("../core/interfaces/configuration"); +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults +/** + * Whether PubNub client should try utilize existing TCP connection for new requests or not. + */ +var KEEP_ALIVE = false; +/** + * Apply configuration default values. + * + * @param configuration - User-provided configuration. + * + * @returns Extended {@link PubNub} client configuration object pre-filled with default values. + */ +var setDefaults = function (configuration) { + var _a; + return __assign(__assign({}, (0, configuration_1.setDefaults)(configuration)), { + // Set platform-specific options. + keepAlive: (_a = configuration.keepAlive) !== null && _a !== void 0 ? _a : KEEP_ALIVE }); +}; +exports.setDefaults = setDefaults; diff --git a/lib/node/index.js b/lib/node/index.js index 7f463e5fa..4a370114d 100644 --- a/lib/node/index.js +++ b/lib/node/index.js @@ -14,52 +14,99 @@ var __extends = (this && this.__extends) || (function () { d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; -var _a; +Object.defineProperty(exports, "__esModule", { value: true }); var cbor_sync_1 = __importDefault(require("cbor-sync")); -var pubnub_common_1 = __importDefault(require("../core/pubnub-common")); -var networking_1 = __importDefault(require("../networking")); -var common_1 = __importDefault(require("../cbor/common")); +var buffer_1 = require("buffer"); +var nodeCryptoModule_1 = require("../crypto/modules/NodeCryptoModule/nodeCryptoModule"); +var node_1 = __importDefault(require("../file/modules/node")); +var configuration_1 = require("../core/components/configuration"); +var configuration_2 = require("./configuration"); +var token_manager_1 = __importDefault(require("../core/components/token_manager")); +var node_transport_1 = require("../transport/node-transport"); +var middleware_1 = require("../transport/middleware"); var base64_codec_1 = require("../core/components/base64_codec"); -var web_node_1 = require("../networking/modules/web-node"); -var node_1 = require("../networking/modules/node"); var node_2 = __importDefault(require("../crypto/modules/node")); -var node_3 = __importDefault(require("../file/modules/node")); -var nodeCryptoModule_1 = require("../crypto/modules/NodeCryptoModule/nodeCryptoModule"); -module.exports = (_a = /** @class */ (function (_super) { - __extends(class_1, _super); - function class_1(setup) { - setup.cbor = new common_1.default(function (buffer) { return cbor_sync_1.default.decode(Buffer.from(buffer)); }, base64_codec_1.decode); - setup.networking = new networking_1.default({ - keepAlive: node_1.keepAlive, - del: web_node_1.del, - get: web_node_1.get, - post: web_node_1.post, - patch: web_node_1.patch, - proxy: node_1.proxy, - getfile: web_node_1.getfile, - postfile: web_node_1.postfile, +var cryptography_1 = __importDefault(require("../core/components/cryptography")); +var PubNubError_1 = require("../models/PubNubError"); +var pubnub_common_1 = require("../core/pubnub-common"); +var common_1 = __importDefault(require("../cbor/common")); +/** + * PubNub client for Node.js platform. + */ +var PubNub = /** @class */ (function (_super) { + __extends(PubNub, _super); + function PubNub(configuration) { + var _this = this; + var configurationCopy = (0, configuration_2.setDefaults)(configuration); + var platformConfiguration = __assign(__assign({}, configurationCopy), { sdkFamily: 'Nodejs', PubNubFile: node_1.default }); + // Prepare full client configuration. + var clientConfiguration = (0, configuration_1.makeConfiguration)(platformConfiguration, function (cryptoConfiguration) { + if (!cryptoConfiguration.cipherKey) + return undefined; + return new nodeCryptoModule_1.CryptoModule({ + default: new nodeCryptoModule_1.LegacyCryptor(__assign({}, cryptoConfiguration)), + cryptors: [new nodeCryptoModule_1.AesCbcCryptor({ cipherKey: cryptoConfiguration.cipherKey })], }); - setup.sdkFamily = 'Nodejs'; - setup.PubNubFile = node_3.default; - setup.cryptography = new node_2.default(); - setup.initCryptoModule = function (cryptoConfiguration) { - return new nodeCryptoModule_1.CryptoModule({ - default: new nodeCryptoModule_1.LegacyCryptor({ - cipherKey: cryptoConfiguration.cipherKey, - useRandomIVs: cryptoConfiguration.useRandomIVs, - }), - cryptors: [new nodeCryptoModule_1.AesCbcCryptor({ cipherKey: cryptoConfiguration.cipherKey })], - }); - }; - if (!('ssl' in setup)) { - setup.ssl = true; - } - return _super.call(this, setup) || this; + }); + // Prepare Token manager. + var tokenManager = new token_manager_1.default(new common_1.default(function (buffer) { return cbor_sync_1.default.decode(buffer_1.Buffer.from(buffer)); }, base64_codec_1.decode)); + // Legacy crypto (legacy data encryption / decryption and request signature support). + var crypto; + if (clientConfiguration.cipherKey || clientConfiguration.secretKey) { + var secretKey = clientConfiguration.secretKey, cipherKey = clientConfiguration.cipherKey, useRandomIVs = clientConfiguration.useRandomIVs, customEncrypt = clientConfiguration.customEncrypt, customDecrypt = clientConfiguration.customDecrypt; + crypto = new cryptography_1.default({ secretKey: secretKey, cipherKey: cipherKey, useRandomIVs: useRandomIVs, customEncrypt: customEncrypt, customDecrypt: customDecrypt }); } - return class_1; - }(pubnub_common_1.default)), - _a.CryptoModule = nodeCryptoModule_1.CryptoModule, - _a); + // Setup transport provider. + var transport = new node_transport_1.NodeTransport(configuration.keepAlive, configuration.keepAliveSettings); + var transportMiddleware = new middleware_1.PubNubMiddleware({ + clientConfiguration: clientConfiguration, + tokenManager: tokenManager, + transport: transport, + shaHMAC: crypto === null || crypto === void 0 ? void 0 : crypto.HMACSHA256, + }); + _this = _super.call(this, { + configuration: clientConfiguration, + transport: transportMiddleware, + cryptography: new node_2.default(), + tokenManager: tokenManager, + crypto: crypto, + }) || this; + _this.nodeTransport = transport; + return _this; + } + /** + * Update request proxy configuration. + * + * @param configuration - Updated request proxy configuration. + * + * @throws An error if {@link PubNub} client already configured to use `keepAlive`. + * `keepAlive` and `proxy` can't be used simultaneously. + */ + PubNub.prototype.setProxy = function (configuration) { + var _a; + if (configuration && ((_a = this._configuration.keepAlive) !== null && _a !== void 0 ? _a : false)) + throw new PubNubError_1.PubNubError("Can't set 'proxy' because already configured for 'keepAlive'"); + this.nodeTransport.setProxy(configuration); + this.reconnect(); + }; + /** + * Data encryption / decryption module constructor. + */ + PubNub.CryptoModule = nodeCryptoModule_1.CryptoModule; + return PubNub; +}(pubnub_common_1.PubNubCore)); +exports.default = PubNub; diff --git a/lib/react_native/configuration.js b/lib/react_native/configuration.js new file mode 100644 index 000000000..6593c1ff7 --- /dev/null +++ b/lib/react_native/configuration.js @@ -0,0 +1,13 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.setDefaults = void 0; +var configuration_1 = require("../core/interfaces/configuration"); +/** + * Apply configuration default values. + * + * @param configuration - User-provided configuration. + */ +var setDefaults = function (configuration) { + return (0, configuration_1.setDefaults)(configuration); +}; +exports.setDefaults = setDefaults; diff --git a/lib/react_native/index.js b/lib/react_native/index.js index 8c1e501cb..1328d393e 100644 --- a/lib/react_native/index.js +++ b/lib/react_native/index.js @@ -14,38 +14,66 @@ var __extends = (this && this.__extends) || (function () { d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); var cbor_js_1 = __importDefault(require("cbor-js")); var buffer_1 = require("buffer"); -var pubnub_common_1 = __importDefault(require("../core/pubnub-common")); -var networking_1 = __importDefault(require("../networking")); -var base64_codec_1 = require("../core/components/base64_codec"); var stringify_buffer_keys_1 = require("../core/components/stringify_buffer_keys"); +var react_native_transport_1 = require("../transport/react-native-transport"); +var configuration_1 = require("../core/components/configuration"); +var token_manager_1 = __importDefault(require("../core/components/token_manager")); +var middleware_1 = require("../transport/middleware"); +var base64_codec_1 = require("../core/components/base64_codec"); +var cryptography_1 = __importDefault(require("../core/components/cryptography")); +var react_native_1 = __importDefault(require("../file/modules/react-native")); +var pubnub_common_1 = require("../core/pubnub-common"); +var configuration_2 = require("../web/configuration"); var common_1 = __importDefault(require("../cbor/common")); -var web_node_1 = require("../networking/modules/web-node"); -var react_native_1 = require("../networking/modules/react_native"); -var react_native_2 = __importDefault(require("../file/modules/react-native")); global.Buffer = global.Buffer || buffer_1.Buffer; -var default_1 = /** @class */ (function (_super) { - __extends(default_1, _super); - function default_1(setup) { - setup.cbor = new common_1.default(function (arrayBuffer) { return (0, stringify_buffer_keys_1.stringifyBufferKeys)(cbor_js_1.default.decode(arrayBuffer)); }, base64_codec_1.decode); - setup.PubNubFile = react_native_2.default; - setup.networking = new networking_1.default({ - del: web_node_1.del, - get: web_node_1.get, - post: web_node_1.post, - patch: web_node_1.patch, - getfile: react_native_1.getfile, - postfile: react_native_1.postfile, +/** + * PubNub client for React Native platform. + */ +var PubNub = /** @class */ (function (_super) { + __extends(PubNub, _super); + function PubNub(configuration) { + var configurationCopy = (0, configuration_2.setDefaults)(configuration); + var platformConfiguration = __assign(__assign({}, configurationCopy), { sdkFamily: 'ReactNative', PubNubFile: react_native_1.default }); + // Prepare full client configuration. + var clientConfiguration = (0, configuration_1.makeConfiguration)(platformConfiguration); + // Prepare Token manager. + var tokenManager = new token_manager_1.default(new common_1.default(function (arrayBuffer) { return (0, stringify_buffer_keys_1.stringifyBufferKeys)(cbor_js_1.default.decode(arrayBuffer)); }, base64_codec_1.decode)); + // Legacy crypto (legacy data encryption / decryption and request signature support). + var crypto; + if (clientConfiguration.cipherKey || clientConfiguration.secretKey) { + var secretKey = clientConfiguration.secretKey, cipherKey = clientConfiguration.cipherKey, useRandomIVs = clientConfiguration.useRandomIVs, customEncrypt = clientConfiguration.customEncrypt, customDecrypt = clientConfiguration.customDecrypt; + crypto = new cryptography_1.default({ secretKey: secretKey, cipherKey: cipherKey, useRandomIVs: useRandomIVs, customEncrypt: customEncrypt, customDecrypt: customDecrypt }); + } + // Setup transport layer. + var transportMiddleware = new middleware_1.PubNubMiddleware({ + clientConfiguration: clientConfiguration, + tokenManager: tokenManager, + transport: new react_native_transport_1.ReactNativeTransport(clientConfiguration.keepAlive, clientConfiguration.logVerbosity), }); - setup.sdkFamily = 'ReactNative'; - setup.ssl = true; - return _super.call(this, setup) || this; + return _super.call(this, { + configuration: clientConfiguration, + transport: transportMiddleware, + tokenManager: tokenManager, + crypto: crypto, + }) || this; } - return default_1; -}(pubnub_common_1.default)); -exports.default = default_1; + return PubNub; +}(pubnub_common_1.PubNubCore)); +exports.default = PubNub; diff --git a/lib/transport/middleware.js b/lib/transport/middleware.js new file mode 100644 index 000000000..db7a2f40f --- /dev/null +++ b/lib/transport/middleware.js @@ -0,0 +1,135 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.PubNubMiddleware = exports.RequestSignature = void 0; +var transport_request_1 = require("../core/types/transport-request"); +var utils_1 = require("../core/utils"); +var RequestSignature = /** @class */ (function () { + function RequestSignature(publishKey, secretKey, hasher) { + this.publishKey = publishKey; + this.secretKey = secretKey; + this.hasher = hasher; + } + /** + * Compute request signature. + * + * @param req - Request which will be used to compute signature. + * @returns {string} `v2` request signature. + */ + RequestSignature.prototype.signature = function (req) { + var method = req.path.startsWith('/publish') ? transport_request_1.TransportMethod.GET : req.method; + var signatureInput = "".concat(method, "\n").concat(this.publishKey, "\n").concat(req.path, "\n").concat(this.queryParameters(req.queryParameters), "\n"); + if (method === transport_request_1.TransportMethod.POST || method === transport_request_1.TransportMethod.PATCH) { + var body = req.body; + var payload = void 0; + if (body && body instanceof ArrayBuffer) { + payload = RequestSignature.textDecoder.decode(body); + } + else if (body && typeof body !== 'object') { + payload = body; + } + if (payload) + signatureInput += payload; + } + return "v2.".concat(this.hasher(signatureInput, this.secretKey)) + .replace(/\+/g, '-') + .replace(/\//g, '_') + .replace(/=+$/, ''); + }; + /** + * Prepare request query parameters for signature. + * + * @param query - Key / value pair of the request query parameters. + * @private + */ + RequestSignature.prototype.queryParameters = function (query) { + return Object.keys(query) + .sort() + .map(function (key) { + var queryValue = query[key]; + if (!Array.isArray(queryValue)) + return "".concat(key, "=").concat((0, utils_1.encodeString)(queryValue)); + return queryValue + .sort() + .map(function (value) { return "".concat(key, "=").concat((0, utils_1.encodeString)(value)); }) + .join('&'); + }) + .join('&'); + }; + RequestSignature.textDecoder = new TextDecoder('utf-8'); + return RequestSignature; +}()); +exports.RequestSignature = RequestSignature; +var PubNubMiddleware = /** @class */ (function () { + function PubNubMiddleware(configuration) { + this.configuration = configuration; + var keySet = configuration.clientConfiguration.keySet, shaHMAC = configuration.shaHMAC; + if (keySet.secretKey && shaHMAC) + this.signatureGenerator = new RequestSignature(keySet.publishKey, keySet.secretKey, shaHMAC); + } + PubNubMiddleware.prototype.makeSendable = function (req) { + return this.configuration.transport.makeSendable(this.request(req)); + }; + PubNubMiddleware.prototype.request = function (req) { + var _a; + var clientConfiguration = this.configuration.clientConfiguration; + if (!req.queryParameters) + req.queryParameters = {}; + // Modify request with required information. + if (clientConfiguration.useInstanceId) + req.queryParameters['instanceid'] = clientConfiguration.instanceId; + if (!req.queryParameters['uuid']) + req.queryParameters['uuid'] = clientConfiguration.userId; + req.queryParameters['requestid'] = req.identifier; + req.queryParameters['pnsdk'] = this.generatePNSDK(); + (_a = req.origin) !== null && _a !== void 0 ? _a : (req.origin = clientConfiguration.origin); + // Authenticate request if required. + this.authenticateRequest(req); + // Sign request if it is required. + this.signRequest(req); + return req; + }; + PubNubMiddleware.prototype.authenticateRequest = function (req) { + var _a; + // Access management endpoints doesn't need authentication (signature required instead). + if (req.path.startsWith('/v2/auth/') || req.path.startsWith('/v3/pam/') || req.path.startsWith('/time')) + return; + var _b = this.configuration, clientConfiguration = _b.clientConfiguration, tokenManager = _b.tokenManager; + var accessKey = (_a = tokenManager.getToken()) !== null && _a !== void 0 ? _a : clientConfiguration.authKey; + if (accessKey) + req.queryParameters['auth'] = accessKey; + }; + /** + * Compute and append request signature. + * + * @param req - Transport request with information which should be used to generate signature. + */ + PubNubMiddleware.prototype.signRequest = function (req) { + if (!this.signatureGenerator || req.path.startsWith('/time')) + return; + req.queryParameters['timestamp'] = String(Math.floor(new Date().getTime() / 1000)); + req.queryParameters['signature'] = this.signatureGenerator.signature(req); + }; + /** + * Compose `pnsdk` query parameter. + * + * SDK provides ability to set custom name or append vendor information to the `pnsdk` query + * parameter. + * + * @returns Finalized `pnsdk` query parameter value. + */ + PubNubMiddleware.prototype.generatePNSDK = function () { + var clientConfiguration = this.configuration.clientConfiguration; + if (clientConfiguration.sdkName) + return clientConfiguration.sdkName; + var base = "PubNub-JS-".concat(clientConfiguration.sdkFamily); + if (clientConfiguration.partnerId) + base += "-".concat(clientConfiguration.partnerId); + base += "/".concat(clientConfiguration.version); + var pnsdkSuffix = clientConfiguration._getPnsdkSuffix(' '); + if (pnsdkSuffix.length > 0) + base += pnsdkSuffix; + return base; + }; + return PubNubMiddleware; +}()); +exports.PubNubMiddleware = PubNubMiddleware; diff --git a/lib/transport/node-transport.js b/lib/transport/node-transport.js new file mode 100644 index 000000000..596ed282d --- /dev/null +++ b/lib/transport/node-transport.js @@ -0,0 +1,324 @@ +"use strict"; +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +var __values = (this && this.__values) || function(o) { + var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; + if (m) return m.call(o); + if (o && typeof o.length === "number") return { + next: function () { + if (o && i >= o.length) o = void 0; + return { value: o && o[i++], done: !o }; + } + }; + throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); +}; +var __read = (this && this.__read) || function (o, n) { + var m = typeof Symbol === "function" && o[Symbol.iterator]; + if (!m) return o; + var i = m.call(o), r, ar = [], e; + try { + while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); + } + catch (error) { e = { error: error }; } + finally { + try { + if (r && !r.done && (m = i["return"])) m.call(i); + } + finally { if (e) throw e.error; } + } + return ar; +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.NodeTransport = void 0; +var node_fetch_1 = __importStar(require("node-fetch")); +var proxy_agent_1 = require("proxy-agent"); +var https_1 = require("https"); +var http_1 = require("http"); +var form_data_1 = __importDefault(require("form-data")); +var buffer_1 = require("buffer"); +var utils_1 = require("../core/utils"); +var api_1 = require("../core/types/api"); +/** + * Class representing a fetch-based Node.js transport provider. + */ +var NodeTransport = /** @class */ (function () { + /** + * Creates a new `fetch`-based transport instance. + * + * @param keepAlive - Indicates whether keep-alive should be enabled. + * @param [keepAliveSettings] - Optional settings for keep-alive. + * @param [logVerbosity] - Whether verbose logging enabled or not. + * + * @returns Transport for performing network requests. + */ + function NodeTransport(keepAlive, keepAliveSettings, logVerbosity) { + if (keepAlive === void 0) { keepAlive = false; } + if (keepAliveSettings === void 0) { keepAliveSettings = { timeout: 30000 }; } + if (logVerbosity === void 0) { logVerbosity = false; } + this.keepAlive = keepAlive; + this.keepAliveSettings = keepAliveSettings; + this.logVerbosity = logVerbosity; + } + /** + * Update request proxy configuration. + * + * @param configuration - New proxy configuration. + */ + NodeTransport.prototype.setProxy = function (configuration) { + this.proxyConfiguration = configuration; + }; + NodeTransport.prototype.makeSendable = function (req) { + var _this = this; + var controller = undefined; + var abortController; + if (req.cancellable) { + abortController = new AbortController(); + controller = { + // Storing controller inside to prolong object lifetime. + abortController: abortController, + abort: function () { return abortController === null || abortController === void 0 ? void 0 : abortController.abort(); }, + }; + } + return [ + this.requestFromTransportRequest(req).then(function (request) { + var start = new Date().getTime(); + _this.logRequestProcessProgress(request); + return (0, node_fetch_1.default)(request, { + signal: abortController === null || abortController === void 0 ? void 0 : abortController.signal, + timeout: req.timeout * 1000, + }) + .then(function (response) { + if (parseInt(response.headers.get('Content-Length'), 10) > 0) { + return response.arrayBuffer().then(function (arrayBuffer) { return [response, arrayBuffer]; }); + } + return [response, undefined]; + }) + .then(function (response) { + var _a = response[0], status = _a.status, requestHeaders = _a.headers; + var headers = {}; + // Copy Headers object content into plain Record. + requestHeaders.forEach(function (value, key) { return (headers[key] = value.toLowerCase()); }); + var transportResponse = { + status: status, + url: request.url, + headers: headers, + body: response[1], + }; + if (status >= 400) + throw api_1.PubNubAPIError.create(transportResponse); + _this.logRequestProcessProgress(request, new Date().getTime() - start, response[1]); + return transportResponse; + }) + .catch(function (error) { + throw api_1.PubNubAPIError.create(error); + }); + }), + controller, + ]; + }; + NodeTransport.prototype.request = function (req) { + return req; + }; + /** + * Creates a Request object from a given {@link TransportRequest} object. + * + * @param req - The {@link TransportRequest} object containing request information. + * + * @returns Request object generated from the {@link TransportRequest} object. + */ + NodeTransport.prototype.requestFromTransportRequest = function (req) { + return __awaiter(this, void 0, void 0, function () { + var headers, body, path, _a, _b, _c, key, value, fileData, formData, _d, _e, _f, key, value; + var e_1, _g, e_2, _h; + var _j; + return __generator(this, function (_k) { + switch (_k.label) { + case 0: + headers = undefined; + path = req.path; + if (req.headers) { + headers = {}; + try { + for (_a = __values(Object.entries(req.headers)), _b = _a.next(); !_b.done; _b = _a.next()) { + _c = __read(_b.value, 2), key = _c[0], value = _c[1]; + headers[key] = value; + } + } + catch (e_1_1) { e_1 = { error: e_1_1 }; } + finally { + try { + if (_b && !_b.done && (_g = _a.return)) _g.call(_a); + } + finally { if (e_1) throw e_1.error; } + } + } + if (req.queryParameters && Object.keys(req.queryParameters).length !== 0) + path = "".concat(path, "?").concat((0, utils_1.queryStringFromObject)(req.queryParameters)); + if (!(req.body && typeof req.body === 'object')) return [3 /*break*/, 4]; + if (!(req.body instanceof ArrayBuffer)) return [3 /*break*/, 1]; + body = req.body; + return [3 /*break*/, 3]; + case 1: return [4 /*yield*/, req.body.toArrayBuffer()]; + case 2: + fileData = _k.sent(); + formData = new form_data_1.default(); + try { + for (_d = __values(Object.entries((_j = req.formData) !== null && _j !== void 0 ? _j : {})), _e = _d.next(); !_e.done; _e = _d.next()) { + _f = __read(_e.value, 2), key = _f[0], value = _f[1]; + formData.append(key, value); + } + } + catch (e_2_1) { e_2 = { error: e_2_1 }; } + finally { + try { + if (_e && !_e.done && (_h = _d.return)) _h.call(_d); + } + finally { if (e_2) throw e_2.error; } + } + formData.append('file', buffer_1.Buffer.from(fileData), { contentType: req.body.mimeType, filename: req.body.name }); + body = formData; + headers = formData.getHeaders(headers); + _k.label = 3; + case 3: return [3 /*break*/, 5]; + case 4: + body = req.body; + _k.label = 5; + case 5: return [2 /*return*/, new node_fetch_1.Request("".concat(req.origin).concat(path), { + agent: this.agentForTransportRequest(req), + method: req.method, + headers: headers, + redirect: 'follow', + body: body, + })]; + } + }); + }); + }; + /** + * Determines and returns the appropriate agent for a given transport request. + * + * If keep alive is not requested, returns undefined. + * + * @param req - The transport request object. + * + * @returns {HttpAgent | HttpsAgent | undefined} - The appropriate agent for the request, or + * undefined if keep alive or proxy not requested. + */ + NodeTransport.prototype.agentForTransportRequest = function (req) { + // Don't configure any agents if keep alive not requested. + if (!this.keepAlive && !this.proxyConfiguration) + return undefined; + // Create proxy agent (if possible). + if (this.proxyConfiguration) + return this.proxyAgent ? this.proxyAgent : (this.proxyAgent = new proxy_agent_1.ProxyAgent(this.proxyConfiguration)); + // Create keep alive agent. + var useSecureAgent = req.origin.startsWith('https:'); + if (useSecureAgent && this.httpsAgent === undefined) + this.httpsAgent = new https_1.Agent(__assign({ keepAlive: true }, this.keepAliveSettings)); + else if (!useSecureAgent && this.httpAgent === undefined) { + this.httpAgent = new http_1.Agent(__assign({ keepAlive: true }, this.keepAliveSettings)); + } + return useSecureAgent ? this.httpsAgent : this.httpAgent; + }; + /** + * Log out request processing progress and result. + * + * @param request - Platform-specific + * @param [elapsed] - How many time passed since request processing started. + * @param [body] - Service response (if available). + */ + NodeTransport.prototype.logRequestProcessProgress = function (request, elapsed, body) { + if (!this.logVerbosity) + return; + var _a = new URL(request.url), protocol = _a.protocol, host = _a.host, pathname = _a.pathname, search = _a.search; + var timestamp = new Date().toISOString(); + if (!elapsed) { + console.log('<<<<<'); + console.log("[".concat(timestamp, "]"), "\n".concat(protocol, "//").concat(host).concat(pathname), "\n".concat(search)); + console.log('-----'); + } + else { + var stringifiedBody = body ? NodeTransport.decoder.decode(body) : undefined; + console.log('>>>>>>'); + console.log("[".concat(timestamp, " / ").concat(elapsed, "]"), "\n".concat(protocol, "//").concat(host).concat(pathname), "\n".concat(search), "\n".concat(stringifiedBody)); + console.log('-----'); + } + }; + /** + * Service {@link ArrayBuffer} response decoder. + */ + NodeTransport.decoder = new TextDecoder(); + return NodeTransport; +}()); +exports.NodeTransport = NodeTransport; diff --git a/lib/transport/react-native-transport.js b/lib/transport/react-native-transport.js new file mode 100644 index 000000000..896852a10 --- /dev/null +++ b/lib/transport/react-native-transport.js @@ -0,0 +1,252 @@ +"use strict"; +/** + * React Native Transport provider module. + */ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +var __values = (this && this.__values) || function(o) { + var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; + if (m) return m.call(o); + if (o && typeof o.length === "number") return { + next: function () { + if (o && i >= o.length) o = void 0; + return { value: o && o[i++], done: !o }; + } + }; + throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); +}; +var __read = (this && this.__read) || function (o, n) { + var m = typeof Symbol === "function" && o[Symbol.iterator]; + if (!m) return o; + var i = m.call(o), r, ar = [], e; + try { + while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); + } + catch (error) { e = { error: error }; } + finally { + try { + if (r && !r.done && (m = i["return"])) m.call(i); + } + finally { if (e) throw e.error; } + } + return ar; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ReactNativeTransport = void 0; +var utils_1 = require("../core/utils"); +var api_1 = require("../core/types/api"); +/** + * Class representing a fetch-based React Native transport provider. + */ +var ReactNativeTransport = /** @class */ (function () { + function ReactNativeTransport(keepAlive, logVerbosity) { + if (keepAlive === void 0) { keepAlive = false; } + this.keepAlive = keepAlive; + this.logVerbosity = logVerbosity; + } + ReactNativeTransport.prototype.makeSendable = function (req) { + var _this = this; + var controller; + var abortController; + if (req.cancellable) { + abortController = new AbortController(); + controller = { + // Storing controller inside to prolong object lifetime. + abortController: abortController, + abort: function () { return abortController === null || abortController === void 0 ? void 0 : abortController.abort(); }, + }; + } + return [ + this.requestFromTransportRequest(req).then(function (request) { + var start = new Date().getTime(); + _this.logRequestProcessProgress(request); + /** + * Setup request timeout promise. + * + * **Note:** Native Fetch API doesn't support `timeout` out-of-box. + */ + var requestTimeout = new Promise(function (_, reject) { + var timeoutId = setTimeout(function () { + // Clean up. + clearTimeout(timeoutId); + reject(new Error('Request timeout')); + }, req.timeout * 1000); + }); + return Promise.race([ + fetch(request, { + signal: abortController === null || abortController === void 0 ? void 0 : abortController.signal, + timeout: req.timeout * 1000, + keepalive: _this.keepAlive, + }), + requestTimeout, + ]) + .then(function (response) { + if (parseInt(response.headers.get('Content-Length'), 10) > 0) { + return response.arrayBuffer().then(function (arrayBuffer) { return [response, arrayBuffer]; }); + } + return [response, undefined]; + }) + .then(function (response) { + var _a = response[0], status = _a.status, requestHeaders = _a.headers; + var headers = {}; + // Copy Headers object content into plain Record. + requestHeaders.forEach(function (value, key) { return (headers[key] = value.toLowerCase()); }); + var transportResponse = { + status: status, + url: request.url, + headers: headers, + body: response[1], + }; + if (status >= 400) + throw api_1.PubNubAPIError.create(transportResponse); + _this.logRequestProcessProgress(request, new Date().getTime() - start, response[1]); + return transportResponse; + }) + .catch(function (error) { + throw api_1.PubNubAPIError.create(error); + }); + }), + controller, + ]; + }; + ReactNativeTransport.prototype.request = function (req) { + return req; + }; + /** + * Creates a Request object from a given {@link TransportRequest} object. + * + * @param req - The {@link TransportRequest} object containing request information. + * + * @returns Request object generated from the {@link TransportRequest} object. + */ + ReactNativeTransport.prototype.requestFromTransportRequest = function (req) { + return __awaiter(this, void 0, void 0, function () { + var headers, body, path, _a, _b, _c, key, value, fileData, formData, _d, _e, _f, key, value; + var e_1, _g, e_2, _h; + var _j; + return __generator(this, function (_k) { + switch (_k.label) { + case 0: + headers = undefined; + path = req.path; + if (req.headers) { + headers = {}; + try { + for (_a = __values(Object.entries(req.headers)), _b = _a.next(); !_b.done; _b = _a.next()) { + _c = __read(_b.value, 2), key = _c[0], value = _c[1]; + headers[key] = value; + } + } + catch (e_1_1) { e_1 = { error: e_1_1 }; } + finally { + try { + if (_b && !_b.done && (_g = _a.return)) _g.call(_a); + } + finally { if (e_1) throw e_1.error; } + } + } + if (req.queryParameters && Object.keys(req.queryParameters).length !== 0) + path = "".concat(path, "?").concat((0, utils_1.queryStringFromObject)(req.queryParameters)); + if (!(req.body && typeof req.body === 'object')) return [3 /*break*/, 4]; + if (!(req.body instanceof ArrayBuffer)) return [3 /*break*/, 1]; + body = req.body; + return [3 /*break*/, 3]; + case 1: return [4 /*yield*/, req.body.toArrayBuffer()]; + case 2: + fileData = _k.sent(); + formData = new FormData(); + try { + for (_d = __values(Object.entries((_j = req.formData) !== null && _j !== void 0 ? _j : {})), _e = _d.next(); !_e.done; _e = _d.next()) { + _f = __read(_e.value, 2), key = _f[0], value = _f[1]; + formData.append(key, value); + } + } + catch (e_2_1) { e_2 = { error: e_2_1 }; } + finally { + try { + if (_e && !_e.done && (_h = _d.return)) _h.call(_d); + } + finally { if (e_2) throw e_2.error; } + } + formData.append('file', new Blob([fileData], { type: req.body.mimeType }), req.body.name); + body = formData; + _k.label = 3; + case 3: return [3 /*break*/, 5]; + case 4: + body = req.body; + _k.label = 5; + case 5: return [2 /*return*/, new Request("".concat(req.origin).concat(path), { + method: req.method, + headers: headers, + redirect: 'follow', + body: body, + })]; + } + }); + }); + }; + /** + * Log out request processing progress and result. + * + * @param request - Platform-specific + * @param [elapsed] - How many time passed since request processing started. + * @param [body] - Service response (if available). + */ + ReactNativeTransport.prototype.logRequestProcessProgress = function (request, elapsed, body) { + if (!this.logVerbosity) + return; + var _a = new URL(request.url), protocol = _a.protocol, host = _a.host, pathname = _a.pathname, search = _a.search; + var timestamp = new Date().toISOString(); + if (!elapsed) { + console.log('<<<<<'); + console.log("[".concat(timestamp, "]"), "\n".concat(protocol, "//").concat(host).concat(pathname), "\n".concat(search)); + console.log('-----'); + } + else { + var stringifiedBody = body ? ReactNativeTransport.decoder.decode(body) : undefined; + console.log('>>>>>>'); + console.log("[".concat(timestamp, " / ").concat(elapsed, "]"), "\n".concat(protocol, "//").concat(host).concat(pathname), "\n".concat(search), "\n".concat(stringifiedBody)); + console.log('-----'); + } + }; + /** + * Service {@link ArrayBuffer} response decoder. + */ + ReactNativeTransport.decoder = new TextDecoder(); + return ReactNativeTransport; +}()); +exports.ReactNativeTransport = ReactNativeTransport; diff --git a/lib/transport/web-transport.js b/lib/transport/web-transport.js new file mode 100644 index 000000000..9baf47c69 --- /dev/null +++ b/lib/transport/web-transport.js @@ -0,0 +1,133 @@ +"use strict"; +/* global window */ +/** + * Web Transport provider module. + */ +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.WebTransport = void 0; +var api_1 = require("../core/types/api"); +var categories_1 = __importDefault(require("../core/constants/categories")); +var worker = require('./web-worker.ts'); +/** + * Class representing a fetch-based Web Worker transport provider. + */ +var WebTransport = /** @class */ (function () { + function WebTransport(keepAlive, logVerbosity) { + if (keepAlive === void 0) { keepAlive = false; } + this.keepAlive = keepAlive; + this.logVerbosity = logVerbosity; + this.setupWorker(); + } + WebTransport.prototype.makeSendable = function (req) { + var _this = this; + var controller; + var sendRequestEvent = { + type: 'send-request', + request: req, + }; + if (req.cancellable) { + controller = { + abort: function () { + var cancelRequest = { + type: 'cancel-request', + identifier: req.identifier, + }; + // Cancel active request with specified identifier. + _this.worker.postMessage(cancelRequest); + }, + }; + } + return [ + new Promise(function (resolve, reject) { + // Associate Promise resolution / reject with request identifier for future usage in + // `onmessage` handler block to return results. + _this.callbacks.set(req.identifier, { resolve: resolve, reject: reject }); + // Trigger request processing by Web Worker. + _this.worker.postMessage(sendRequestEvent); + }), + controller, + ]; + }; + WebTransport.prototype.request = function (req) { + return req; + }; + /** + * Complete PubNub Web Worker setup. + */ + WebTransport.prototype.setupWorker = function () { + var _this = this; + this.worker = new Worker(URL.createObjectURL(new Blob([worker], { type: 'application/javascript' })), { + name: '/pubnub', + }); + this.callbacks = new Map(); + // Complete Web Worker initialization. + var setupEvent = { + type: 'setup', + logVerbosity: this.logVerbosity, + keepAlive: this.keepAlive, + }; + this.worker.postMessage(setupEvent); + this.worker.onmessage = function (event) { + var data = event.data; + if (data.type === 'request-progress-start' || data.type === 'request-progress-end') { + _this.logRequestProgress(data); + } + else if (data.type === 'request-process-success' || data.type === 'request-process-error') { + var _a = _this.callbacks.get(data.identifier), resolve = _a.resolve, reject = _a.reject; + if (data.type === 'request-process-success') { + resolve({ + status: data.response.status, + url: data.url, + headers: data.response.headers, + body: data.response.body, + }); + } + else { + var category = categories_1.default.PNUnknownCategory; + var message = 'Unknown error'; + // Handle client-side issues (if any). + if (data.error) { + if (data.error.type === 'NETWORK_ISSUE') + category = categories_1.default.PNNetworkIssuesCategory; + else if (data.error.type === 'TIMEOUT') + category = categories_1.default.PNTimeoutCategory; + message = data.error.message; + } + // Handle service error response. + else if (data.response) { + return reject(api_1.PubNubAPIError.create({ + url: data.url, + headers: data.response.headers, + body: data.response.body, + status: data.response.status, + })); + } + reject(new api_1.PubNubAPIError(message, category, 0)); + } + } + }; + }; + /** + * Print request progress information. + * + * @param information - Request progress information from Web Worker. + */ + WebTransport.prototype.logRequestProgress = function (information) { + var _a, _b; + if (information.type === 'request-progress-start') { + console.log('<<<<<'); + console.log("[".concat(information.timestamp, "]"), '\n', information.url, '\n', JSON.stringify((_a = information.query) !== null && _a !== void 0 ? _a : {})); + console.log('-----'); + } + else { + console.log('>>>>>>'); + console.log("[".concat(information.timestamp, " / ").concat(information.duration, "]"), '\n', information.url, '\n', JSON.stringify((_b = information.query) !== null && _b !== void 0 ? _b : {}), '\n', information.response); + console.log('-----'); + } + }; + return WebTransport; +}()); +exports.WebTransport = WebTransport; diff --git a/lib/transport/web-worker.js b/lib/transport/web-worker.js new file mode 100644 index 000000000..cbf69dedc --- /dev/null +++ b/lib/transport/web-worker.js @@ -0,0 +1,362 @@ +"use strict"; +/** + * Web Worker module. + */ +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +var __read = (this && this.__read) || function (o, n) { + var m = typeof Symbol === "function" && o[Symbol.iterator]; + if (!m) return o; + var i = m.call(o), r, ar = [], e; + try { + while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); + } + catch (error) { e = { error: error }; } + finally { + try { + if (r && !r.done && (m = i["return"])) m.call(i); + } + finally { if (e) throw e.error; } + } + return ar; +}; +var __values = (this && this.__values) || function(o) { + var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; + if (m) return m.call(o); + if (o && typeof o.length === "number") return { + next: function () { + if (o && i >= o.length) o = void 0; + return { value: o && o[i++], done: !o }; + } + }; + throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var utils_1 = require("../core/utils"); +// endregion +// endregion +/** + * Map of request identifiers to their abort controllers. + * + * **Note:** Because of message-based nature of interaction it will be impossible to pass actual {@link AbortController} + * to the transport provider code. + */ +var abortControllers = new Map(); +/** + * Service `ArrayBuffer` response decoder. + */ +var decoder = new TextDecoder(); +/** + * Whether verbose logging enabled or not. + */ +var logVerbosity = false; +/** + * If set to `true`, SDK will use the same TCP connection for each HTTP request, instead of + * opening a new one for each new request. + * + * @default `true` + */ +var keepAlive = true; +// -------------------------------------------------------- +// ------------------- Event Handlers --------------------- +// -------------------------------------------------------- +// region Event Handlers +/** + * Handle signals from the PubNub core. + * + * @param event - Event object from the PubNub Core with instructions for worker. + */ +self.onmessage = function (event) { + var data = event.data; + if (data.type === 'setup') { + logVerbosity = data.logVerbosity; + keepAlive = data.keepAlive; + } + else if (data.type === 'send-request') { + sendRequestEventHandler(data.request); + } + if (data.type === 'cancel-request') { + var controller = abortControllers.get(data.identifier); + // Abort request if possible. + if (controller) { + abortControllers.delete(data.identifier); + controller.abort(); + } + } + event.data; +}; +/** + * Handle request send event. + * + * @param req - Data for {@link Request} creation and scheduling. + */ +var sendRequestEventHandler = function (req) { + (function () { return __awaiter(void 0, void 0, void 0, function () { + var request, timestamp, start, requestTimeout; + var _a; + return __generator(this, function (_b) { + switch (_b.label) { + case 0: return [4 /*yield*/, requestFromTransportRequest(req)]; + case 1: + request = _b.sent(); + timestamp = new Date().toISOString(); + start = new Date().getTime(); + if (req.cancellable) + abortControllers.set(req.identifier, new AbortController()); + requestTimeout = new Promise(function (_, reject) { + var timeoutId = setTimeout(function () { + // Clean up. + abortControllers.delete(req.identifier); + clearTimeout(timeoutId); + reject(new Error('Request timeout')); + }, req.timeout * 1000); + }); + if (logVerbosity) + notifyRequestProcessing('start', request, timestamp, req.queryParameters); + Promise.race([ + fetch(request, { signal: (_a = abortControllers.get(req.identifier)) === null || _a === void 0 ? void 0 : _a.signal, keepalive: keepAlive }), + requestTimeout, + ]) + .then(function (response) { + if (parseInt(response.headers.get('Content-Length'), 10) > 0) { + return response.arrayBuffer().then(function (buffer) { return [response, buffer]; }); + } + return [response, undefined]; + }) + .then(function (response) { + if (logVerbosity) { + var contentType = response[0].headers.get('Content-Type'); + var timestampDone = new Date().toISOString(); + var now = new Date().getTime(); + var elapsed = now - start; + var body = void 0; + if (contentType && + (contentType.includes('application/json') || + contentType.includes('text/plain') || + contentType.includes('text/html'))) { + body = decoder.decode(response[1]); + } + notifyRequestProcessing('end', request, timestampDone, req.queryParameters, body, elapsed); + } + // Treat 4xx and 5xx status codes as errors. + if (response[0].status >= 400) + postMessage(requestProcessingError(req.identifier, request.url, undefined, response)); + else + postMessage(requestProcessingSuccess(req.identifier, request.url, response)); + }) + .catch(function (error) { return postMessage(requestProcessingError(error, request.url)); }); + return [2 /*return*/]; + } + }); + }); })(); +}; +// endregion +// -------------------------------------------------------- +// ----------------------- Helpers ------------------------ +// -------------------------------------------------------- +// region Helpers +var notifyRequestProcessing = function (type, request, timestamp, query, response, duration) { + var event; + var _a = __read(request.url.split('?'), 1), url = _a[0]; + if (type === 'start') { + event = { + type: 'request-progress-start', + url: url, + query: query, + timestamp: timestamp, + }; + } + else { + event = { + type: 'request-progress-end', + url: url, + query: query, + response: response, + timestamp: timestamp, + duration: duration, + }; + } + postMessage(event); +}; +/** + * Create processing success event from service response. + * + * @param identifier - Identifier of the processed request. + * @param url - Url which has been used to perform request. + * @param res - Service response for used REST API endpoint along with response body. + * + * @returns Request processing success event object. + */ +var requestProcessingSuccess = function (identifier, url, res) { + var _a = __read(res, 2), response = _a[0], body = _a[1]; + var contentLength = parseInt(response.headers.get('Content-Length'), 10); + var contentType = response.headers.get('Content-Type'); + var headers = {}; + // Copy Headers object content into plain Record. + response.headers.forEach(function (value, key) { return (headers[key] = value.toLowerCase()); }); + return { + type: 'request-process-success', + identifier: identifier, + url: url, + response: { + contentLength: contentLength, + contentType: contentType, + headers: headers, + status: response.status, + body: body, + }, + }; +}; +/** + * Create processing error event from service response. + * + * @param identifier - Identifier of the failed request. + * @param url - Url which has been used to perform request. + * @param [error] - Client-side request processing error (for example network issues). + * @param [res] - Service error response (for example permissions error or malformed + * payload) along with service body. + * + * @returns Request processing error event object. + */ +var requestProcessingError = function (identifier, url, error, res) { + // User service response as error information source. + if (res) { + return __assign(__assign({}, requestProcessingSuccess(identifier, url, res)), { type: 'request-process-error' }); + } + var type = 'NETWORK_ISSUE'; + var message = 'Unknown error'; + var name = 'Error'; + if (error && error instanceof Error) { + message = error.message; + name = error.name; + } + if (name === 'AbortError') { + message = 'Request aborted'; + type = 'ABORTED'; + } + else if (message === 'Request timeout') + type = 'TIMEOUT'; + return { + type: 'request-process-error', + identifier: identifier, + url: url, + error: { name: name, type: type, message: message }, + }; +}; +/** + * Creates a Request object from a given {@link TransportRequest} object. + * + * @param req - The {@link TransportRequest} object containing request information. + * + * @returns {@link Request} object generated from the {@link TransportRequest} object. + */ +var requestFromTransportRequest = function (req) { return __awaiter(void 0, void 0, void 0, function () { + var headers, body, path, _a, _b, _c, key, value, fileData, formData, _d, _e, _f, key, value; + var e_1, _g, e_2, _h; + var _j; + return __generator(this, function (_k) { + switch (_k.label) { + case 0: + headers = undefined; + path = req.path; + if (req.headers) { + headers = {}; + try { + for (_a = __values(Object.entries(req.headers)), _b = _a.next(); !_b.done; _b = _a.next()) { + _c = __read(_b.value, 2), key = _c[0], value = _c[1]; + headers[key] = value; + } + } + catch (e_1_1) { e_1 = { error: e_1_1 }; } + finally { + try { + if (_b && !_b.done && (_g = _a.return)) _g.call(_a); + } + finally { if (e_1) throw e_1.error; } + } + } + if (req.queryParameters && Object.keys(req.queryParameters).length !== 0) + path = "".concat(path, "?").concat((0, utils_1.queryStringFromObject)(req.queryParameters)); + if (!(req.body && typeof req.body === 'object')) return [3 /*break*/, 4]; + if (!(req.body instanceof ArrayBuffer)) return [3 /*break*/, 1]; + body = req.body; + return [3 /*break*/, 3]; + case 1: return [4 /*yield*/, req.body.toArrayBuffer()]; + case 2: + fileData = _k.sent(); + formData = new FormData(); + try { + for (_d = __values(Object.entries((_j = req.formData) !== null && _j !== void 0 ? _j : {})), _e = _d.next(); !_e.done; _e = _d.next()) { + _f = __read(_e.value, 2), key = _f[0], value = _f[1]; + formData.append(key, value); + } + } + catch (e_2_1) { e_2 = { error: e_2_1 }; } + finally { + try { + if (_e && !_e.done && (_h = _d.return)) _h.call(_d); + } + finally { if (e_2) throw e_2.error; } + } + formData.append('file', new Blob([fileData], { type: req.body.mimeType }), req.body.name); + body = formData; + _k.label = 3; + case 3: return [3 /*break*/, 5]; + case 4: + body = req.body; + _k.label = 5; + case 5: return [2 /*return*/, new Request("".concat(req.origin).concat(path), { + method: req.method, + headers: headers, + redirect: 'follow', + body: body, + })]; + } + }); +}); }; +// endregion diff --git a/lib/web/configuration.js b/lib/web/configuration.js new file mode 100644 index 000000000..b8a815397 --- /dev/null +++ b/lib/web/configuration.js @@ -0,0 +1,42 @@ +"use strict"; +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.setDefaults = void 0; +var configuration_1 = require("../core/interfaces/configuration"); +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults +/** + * Whether PubNub client should update its state using browser's reachability events or not. + * + * If the browser fails to detect the network changes from Wi-Fi to LAN and vice versa, or you get + * reconnection issues, set the flag to `false`. This allows the SDK reconnection logic to take over. + */ +var LISTEN_TO_BROWSER_NETWORK_EVENTS = true; +/** + * Whether PubNub client should try utilize existing TCP connection for new requests or not. + */ +var KEEP_ALIVE = true; +/** + * Apply configuration default values. + * + * @param configuration - User-provided configuration. + */ +var setDefaults = function (configuration) { + var _a, _b; + return __assign(__assign({}, (0, configuration_1.setDefaults)(configuration)), { + // Set platform-specific options. + listenToBrowserNetworkEvents: (_a = configuration.listenToBrowserNetworkEvents) !== null && _a !== void 0 ? _a : LISTEN_TO_BROWSER_NETWORK_EVENTS, keepAlive: (_b = configuration.keepAlive) !== null && _b !== void 0 ? _b : KEEP_ALIVE }); +}; +exports.setDefaults = setDefaults; diff --git a/lib/web/index.js b/lib/web/index.js index fcda537bb..0857f0ba2 100644 --- a/lib/web/index.js +++ b/lib/web/index.js @@ -16,59 +16,76 @@ var __extends = (this && this.__extends) || (function () { d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); var cbor_js_1 = __importDefault(require("cbor-js")); -var pubnub_common_1 = __importDefault(require("../core/pubnub-common")); -var networking_1 = __importDefault(require("../networking")); -var base64_codec_1 = require("../core/components/base64_codec"); +var webCryptoModule_1 = require("../crypto/modules/WebCryptoModule/webCryptoModule"); var stringify_buffer_keys_1 = require("../core/components/stringify_buffer_keys"); +var web_1 = require("../file/modules/web"); +var configuration_1 = require("../core/components/configuration"); +var configuration_2 = require("./configuration"); +var token_manager_1 = __importDefault(require("../core/components/token_manager")); +var middleware_1 = require("../transport/middleware"); +var web_transport_1 = require("../transport/web-transport"); +var base64_codec_1 = require("../core/components/base64_codec"); +var cryptography_1 = __importDefault(require("../core/components/cryptography")); +var web_2 = __importDefault(require("../crypto/modules/web")); +var pubnub_common_1 = require("../core/pubnub-common"); var common_1 = __importDefault(require("../cbor/common")); -var web_node_1 = require("../networking/modules/web-node"); -var web_1 = __importDefault(require("../crypto/modules/web")); -var web_2 = __importDefault(require("../file/modules/web")); -var webCryptoModule_1 = require("../crypto/modules/WebCryptoModule/webCryptoModule"); -function sendBeacon(url) { - if (navigator && navigator.sendBeacon) { - navigator.sendBeacon(url); - } - else { - return false; - } -} -var default_1 = /** @class */ (function (_super) { - __extends(default_1, _super); - function default_1(setup) { +/** + * PubNub client for browser platform. + */ +var PubNub = /** @class */ (function (_super) { + __extends(PubNub, _super); + function PubNub(configuration) { var _this = this; - // extract config. - var _a = setup.listenToBrowserNetworkEvents, listenToBrowserNetworkEvents = _a === void 0 ? true : _a; - setup.sdkFamily = 'Web'; - setup.networking = new networking_1.default({ - del: web_node_1.del, - get: web_node_1.get, - post: web_node_1.post, - patch: web_node_1.patch, - sendBeacon: sendBeacon, - getfile: web_node_1.getfile, - postfile: web_node_1.postfile, - }); - setup.cbor = new common_1.default(function (arrayBuffer) { return (0, stringify_buffer_keys_1.stringifyBufferKeys)(cbor_js_1.default.decode(arrayBuffer)); }, base64_codec_1.decode); - setup.PubNubFile = web_2.default; - setup.cryptography = new web_1.default(); - setup.initCryptoModule = function (cryptoConfiguration) { - return new webCryptoModule_1.CryptoModule({ - default: new webCryptoModule_1.LegacyCryptor({ - cipherKey: cryptoConfiguration.cipherKey, - useRandomIVs: cryptoConfiguration.useRandomIVs, - }), + var _a; + var configurationCopy = (0, configuration_2.setDefaults)(configuration); + var platformConfiguration = __assign(__assign({}, configurationCopy), { sdkFamily: 'Nodejs', PubNubFile: web_1.PubNubFile }); + // Prepare full client configuration. + var clientConfiguration = (0, configuration_1.makeConfiguration)(platformConfiguration, function (cryptoConfiguration) { + if (!cryptoConfiguration.cipherKey) + return undefined; + return new webCryptoModule_1.WebCryptoModule({ + default: new webCryptoModule_1.LegacyCryptor(__assign({}, cryptoConfiguration)), cryptors: [new webCryptoModule_1.AesCbcCryptor({ cipherKey: cryptoConfiguration.cipherKey })], }); - }; - _this = _super.call(this, setup) || this; - if (listenToBrowserNetworkEvents) { - // mount network events. + }); + // Prepare Token manager. + var tokenManager = new token_manager_1.default(new common_1.default(function (arrayBuffer) { return (0, stringify_buffer_keys_1.stringifyBufferKeys)(cbor_js_1.default.decode(arrayBuffer)); }, base64_codec_1.decode)); + // Legacy crypto (legacy data encryption / decryption and request signature support). + var crypto; + if (clientConfiguration.cipherKey || clientConfiguration.secretKey) { + var secretKey = clientConfiguration.secretKey, cipherKey = clientConfiguration.cipherKey, useRandomIVs = clientConfiguration.useRandomIVs, customEncrypt = clientConfiguration.customEncrypt, customDecrypt = clientConfiguration.customDecrypt; + crypto = new cryptography_1.default({ secretKey: secretKey, cipherKey: cipherKey, useRandomIVs: useRandomIVs, customEncrypt: customEncrypt, customDecrypt: customDecrypt }); + } + // Setup transport provider. + var transportMiddleware = new middleware_1.PubNubMiddleware({ + clientConfiguration: clientConfiguration, + tokenManager: tokenManager, + transport: new web_transport_1.WebTransport(clientConfiguration.keepAlive, clientConfiguration.logVerbosity), + }); + _this = _super.call(this, { + configuration: clientConfiguration, + transport: transportMiddleware, + cryptography: new web_2.default(), + tokenManager: tokenManager, + crypto: crypto, + }) || this; + if ((_a = configuration.listenToBrowserNetworkEvents) !== null && _a !== void 0 ? _a : true) { window.addEventListener('offline', function () { _this.networkDownDetected(); }); @@ -78,7 +95,21 @@ var default_1 = /** @class */ (function (_super) { } return _this; } - default_1.CryptoModule = webCryptoModule_1.CryptoModule; - return default_1; -}(pubnub_common_1.default)); -exports.default = default_1; + PubNub.prototype.networkDownDetected = function () { + this.listenerManager.announceNetworkDown(); + if (this._configuration.restore) + this.disconnect(); + else + this.destroy(true); + }; + PubNub.prototype.networkUpDetected = function () { + this.listenerManager.announceNetworkUp(); + this.reconnect(); + }; + /** + * Data encryption / decryption module constructor. + */ + PubNub.CryptoModule = webCryptoModule_1.WebCryptoModule; + return PubNub; +}(pubnub_common_1.PubNubCore)); +exports.default = PubNub; diff --git a/package-lock.json b/package-lock.json index 732678f58..d617639b8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,47 +1,52 @@ { "name": "pubnub", - "version": "7.5.0", + "version": "7.6.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "pubnub", - "version": "7.5.0", + "version": "7.6.0", "license": "SEE LICENSE IN LICENSE", "dependencies": { "agentkeepalive": "^3.5.2", "buffer": "^6.0.3", "cbor-js": "^0.1.0", "cbor-sync": "^1.0.4", + "form-data": "^4.0.0", "lil-uuid": "^0.1.1", + "node-fetch": "^3.3.2", "proxy-agent": "^6.3.0", "superagent": "^8.1.2" }, "devDependencies": { "@cucumber/cucumber": "^7.3.1", "@cucumber/pretty-formatter": "^1.0.0", - "@rollup/plugin-commonjs": "^21.0.2", - "@rollup/plugin-json": "^4.1.0", - "@rollup/plugin-node-resolve": "^13.1.3", - "@rollup/plugin-typescript": "^8.3.1", - "@types/chai": "^4.3.3", + "@rollup/plugin-commonjs": "^25.0.7", + "@rollup/plugin-json": "^6.1.0", + "@rollup/plugin-node-resolve": "^15.2.3", + "@rollup/plugin-replace": "^5.0.5", + "@rollup/plugin-terser": "^0.4.4", + "@rollup/plugin-typescript": "^11.1.6", + "@types/cbor-js": "^0.1.1", + "@types/chai": "^4.3.14", "@types/cucumber": "^7.0.0", "@types/expect": "^24.3.0", "@types/mocha": "^9.1.0", "@types/nock": "^9.3.1", - "@types/node-fetch": "^2.6.3", + "@types/node-fetch": "^2.6.11", "@types/pubnub": "^7.2.0", - "@typescript-eslint/eslint-plugin": "^5.12.1", - "@typescript-eslint/parser": "^5.12.1", - "chai": "^4.3.4", + "@typescript-eslint/eslint-plugin": "^7.4.0", + "@typescript-eslint/parser": "^7.4.0", + "chai": "^4.4.1", "chai-as-promised": "^7.1.1", "chai-nock": "^1.2.0", "cucumber-pretty": "^6.0.1", "cucumber-tsflow": "^4.0.0-rc.11", - "es6-shim": "^0.35.6", - "eslint": "^8.9.0", - "eslint-plugin-mocha": "^10.0.3", - "eslint-plugin-prettier": "^4.0.0", + "es6-shim": "^0.35.8", + "eslint": "^8.57.0", + "eslint-plugin-mocha": "^10.4.1", + "eslint-plugin-prettier": "^5.1.3", "js-yaml": "^3.13.1", "karma": "^5.0.3", "karma-chai": "^0.1.0", @@ -53,79 +58,135 @@ "karma-spec-reporter": "0.0.32", "mocha": "^9.2.1", "nock": "^9.6.1", - "node-fetch": "^2.7.0", "phantomjs-prebuilt": "^2.1.16", - "prettier": "^2.5.1", + "prettier": "^3.2.5", "rimraf": "^3.0.2", - "rollup": "^2.68.0", - "rollup-plugin-gzip": "^3.0.1", - "rollup-plugin-terser": "^7.0.2", + "rollup": "^4.13.2", + "rollup-plugin-gzip": "^3.1.2", + "rollup-plugin-string": "^3.0.0", "sinon": "^7.5.0", "sinon-chai": "^3.3.0", "source-map-support": "^0.5.21", "ts-mocha": "^9.0.2", - "ts-node": "^10.9.1", - "typescript": "^4.8.4", + "ts-node": "^10.9.2", + "typescript": "^5.4.3", "underscore": "^1.9.2" } }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/@babel/code-frame": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", - "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", "dev": true, "dependencies": { - "@babel/highlight": "^7.16.7" + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.16.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", - "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", + "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/runtime-corejs3": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.20.0.tgz", - "integrity": "sha512-v1JH7PeAAGBEyTQM9TqojVl+b20zXtesFKCJHu50xMxZKD1fX0TKaKHPsZfFkXfs7D1M9M6Eeqg1FkJ3a0x2dA==", + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, - "peer": true, "dependencies": { - "core-js-pure": "^3.25.1", - "regenerator-runtime": "^0.13.10" + "color-convert": "^1.9.0" }, "engines": { - "node": ">=6.9.0" + "node": ">=4" } }, - "node_modules/@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, - "optional": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, "engines": { - "node": ">=0.1.90" + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/runtime-corejs3": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.24.1.tgz", + "integrity": "sha512-T9ko/35G+Bkl+win48GduaPlhSlOjjE5s1TeiEcD+QpxlLQnoEfb/nO/T+TQqkm+ipFwORn+rB8w14iJ/uD0bg==", + "dev": true, + "peer": true, + "dependencies": { + "core-js-pure": "^3.30.2", + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@cspotcode/source-map-support": { @@ -140,6 +201,16 @@ "node": ">=12" } }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@cucumber/create-meta": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/@cucumber/create-meta/-/create-meta-5.0.0.tgz", @@ -173,6 +244,12 @@ "integrity": "sha512-ETWD/H2TbWbKEi7m9N4Km5+cw1hNcqJSxlSYhsLsNjQzWWiZIYA1zafxpK9PwVfaZ6AqR5rrjPVUBGESm5tQUA==", "dev": true }, + "node_modules/@cucumber/create-meta/node_modules/reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", + "dev": true + }, "node_modules/@cucumber/create-meta/node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -262,20 +339,11 @@ "integrity": "sha512-ETWD/H2TbWbKEi7m9N4Km5+cw1hNcqJSxlSYhsLsNjQzWWiZIYA1zafxpK9PwVfaZ6AqR5rrjPVUBGESm5tQUA==", "dev": true }, - "node_modules/@cucumber/cucumber/node_modules/cli-table3": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.1.tgz", - "integrity": "sha512-w0q/enDHhPLq44ovMGdQeeDLvwxwavsJX7oQGYt/LrBlYsyaxyDnp6z3QzFut/6kLLKnlcUVJLrpB7KBfgG/RA==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0" - }, - "engines": { - "node": "10.* || >= 12.*" - }, - "optionalDependencies": { - "colors": "1.4.0" - } + "node_modules/@cucumber/cucumber/node_modules/reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", + "dev": true }, "node_modules/@cucumber/cucumber/node_modules/uuid": { "version": "8.3.2", @@ -336,6 +404,12 @@ "integrity": "sha512-ETWD/H2TbWbKEi7m9N4Km5+cw1hNcqJSxlSYhsLsNjQzWWiZIYA1zafxpK9PwVfaZ6AqR5rrjPVUBGESm5tQUA==", "dev": true }, + "node_modules/@cucumber/gherkin-streams/node_modules/reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", + "dev": true + }, "node_modules/@cucumber/gherkin-streams/node_modules/source-map-support": { "version": "0.5.19", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", @@ -379,6 +453,12 @@ "integrity": "sha512-ETWD/H2TbWbKEi7m9N4Km5+cw1hNcqJSxlSYhsLsNjQzWWiZIYA1zafxpK9PwVfaZ6AqR5rrjPVUBGESm5tQUA==", "dev": true }, + "node_modules/@cucumber/gherkin/node_modules/reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", + "dev": true + }, "node_modules/@cucumber/gherkin/node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -426,6 +506,12 @@ "integrity": "sha512-ETWD/H2TbWbKEi7m9N4Km5+cw1hNcqJSxlSYhsLsNjQzWWiZIYA1zafxpK9PwVfaZ6AqR5rrjPVUBGESm5tQUA==", "dev": true }, + "node_modules/@cucumber/html-formatter/node_modules/reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", + "dev": true + }, "node_modules/@cucumber/html-formatter/node_modules/source-map-support": { "version": "0.5.19", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", @@ -478,6 +564,12 @@ "integrity": "sha512-ETWD/H2TbWbKEi7m9N4Km5+cw1hNcqJSxlSYhsLsNjQzWWiZIYA1zafxpK9PwVfaZ6AqR5rrjPVUBGESm5tQUA==", "dev": true }, + "node_modules/@cucumber/message-streams/node_modules/reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", + "dev": true + }, "node_modules/@cucumber/message-streams/node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -488,22 +580,22 @@ } }, "node_modules/@cucumber/messages": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/@cucumber/messages/-/messages-21.0.1.tgz", - "integrity": "sha512-pGR7iURM4SF9Qp1IIpNiVQ77J9kfxMkPOEbyy+zRmGABnWWCsqMpJdfHeh9Mb3VskemVw85++e15JT0PYdcR3g==", + "version": "24.1.0", + "resolved": "https://registry.npmjs.org/@cucumber/messages/-/messages-24.1.0.tgz", + "integrity": "sha512-hxVHiBurORcobhVk80I9+JkaKaNXkW6YwGOEFIh/2aO+apAN+5XJgUUWjng9NwqaQrW1sCFuawLB1AuzmBaNdQ==", "dev": true, "peer": true, "dependencies": { - "@types/uuid": "8.3.4", + "@types/uuid": "9.0.8", "class-transformer": "0.5.1", - "reflect-metadata": "0.1.13", - "uuid": "9.0.0" + "reflect-metadata": "0.2.1", + "uuid": "9.0.1" } }, "node_modules/@cucumber/pretty-formatter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@cucumber/pretty-formatter/-/pretty-formatter-1.0.0.tgz", - "integrity": "sha512-wcnIMN94HyaHGsfq72dgCvr1d8q6VGH4Y6Gl5weJ2TNZw1qn2UY85Iki4c9VdaLUONYnyYH3+178YB+9RFe/Hw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@cucumber/pretty-formatter/-/pretty-formatter-1.0.1.tgz", + "integrity": "sha512-A1lU4VVP0aUWdOTmpdzvXOyEYuPtBDI0xYwYJnmoMDplzxMdhcHk86lyyvYDoMoPzzq6OkOE3isuosvUU4X7IQ==", "dev": true, "dependencies": { "ansi-styles": "^5.0.0", @@ -516,18 +608,6 @@ "@cucumber/messages": "*" } }, - "node_modules/@cucumber/pretty-formatter/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/@cucumber/tag-expressions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@cucumber/tag-expressions/-/tag-expressions-3.0.1.tgz", @@ -550,23 +630,23 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.0.tgz", - "integrity": "sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==", + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/eslintrc": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", - "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.5.1", + "espree": "^9.6.0", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -587,6 +667,16 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/@eslint/eslintrc/node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -599,29 +689,63 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@eslint/js": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.37.0.tgz", - "integrity": "sha512-x5vzdtOOGgFVDCUs81QRB2+liax8rFg3+7hqM+QhBG0/G3F1ZsoYl97UrqgHgQ9KKT7G6c4V+aTUCgu/n22v1A==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", - "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", "minimatch": "^3.0.5" }, "engines": { "node": ">=10.10.0" } }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -636,120 +760,108 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", + "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", "dev": true }, - "node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", "dev": true, "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" + "jest-get-type": "^29.6.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/types/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "@sinclair/typebox": "^0.27.8" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/types/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/types/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { - "node": ">=7.0.0" + "node": ">=6.0.0" } }, - "node_modules/@jest/types/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@jest/types/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, "engines": { - "node": ">=8" + "node": ">=6.0.0" } }, - "node_modules/@jest/types/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, "engines": { - "node": ">=8" + "node": ">=6.0.0" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", "dev": true, - "engines": { - "node": ">=6.0.0" + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/@nodelib/fs.scandir": { @@ -787,104 +899,415 @@ "node": ">= 8" } }, - "node_modules/@rollup/plugin-commonjs": { - "version": "21.0.2", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-21.0.2.tgz", - "integrity": "sha512-d/OmjaLVO4j/aQX69bwpWPpbvI3TJkQuxoAk7BH8ew1PyoMBLTOuvJTjzG8oEoW7drIIqB0KCJtfFLu/2GClWg==", + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", "dev": true, - "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "commondir": "^1.0.1", - "estree-walker": "^2.0.1", - "glob": "^7.1.6", - "is-reference": "^1.2.1", - "magic-string": "^0.25.7", - "resolve": "^1.17.0" - }, "engines": { - "node": ">= 8.0.0" + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" }, - "peerDependencies": { - "rollup": "^2.38.3" + "funding": { + "url": "https://opencollective.com/unts" } }, - "node_modules/@rollup/plugin-json": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-4.1.0.tgz", - "integrity": "sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==", + "node_modules/@rollup/plugin-commonjs": { + "version": "25.0.7", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.7.tgz", + "integrity": "sha512-nEvcR+LRjEjsaSsc4x3XZfCCvZIaSMenZu/OiwOKGN2UhQpAYI7ru7czFvyWbErlpoGjnSX3D5Ch5FcMA3kRWQ==", "dev": true, "dependencies": { - "@rollup/pluginutils": "^3.0.8" + "@rollup/pluginutils": "^5.0.1", + "commondir": "^1.0.1", + "estree-walker": "^2.0.2", + "glob": "^8.0.3", + "is-reference": "1.2.1", + "magic-string": "^0.30.3" + }, + "engines": { + "node": ">=14.0.0" }, "peerDependencies": { - "rollup": "^1.20.0 || ^2.0.0" + "rollup": "^2.68.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } } }, - "node_modules/@rollup/plugin-node-resolve": { - "version": "13.1.3", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.1.3.tgz", - "integrity": "sha512-BdxNk+LtmElRo5d06MGY4zoepyrXX1tkzX2hrnPEZ53k78GuOMWLqmJDGIIOPwVRIFZrLQOo+Yr6KtCuLIA0AQ==", + "node_modules/@rollup/plugin-commonjs/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", "dev": true, "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "@types/resolve": "1.17.1", - "builtin-modules": "^3.1.0", + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@rollup/plugin-commonjs/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@rollup/plugin-json": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.1.0.tgz", + "integrity": "sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.1.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "15.2.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz", + "integrity": "sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", "deepmerge": "^4.2.2", + "is-builtin-module": "^3.2.1", "is-module": "^1.0.0", - "resolve": "^1.19.0" + "resolve": "^1.22.1" }, "engines": { - "node": ">= 10.0.0" + "node": ">=14.0.0" }, "peerDependencies": { - "rollup": "^2.42.0" + "rollup": "^2.78.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-replace": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.5.tgz", + "integrity": "sha512-rYO4fOi8lMaTg/z5Jb+hKnrHHVn8j2lwkqwyS4kTRhKyWOLf2wST2sWXr4WzWiTcoHTp2sTjqUbqIj2E39slKQ==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "magic-string": "^0.30.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-terser": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", + "integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==", + "dev": true, + "dependencies": { + "serialize-javascript": "^6.0.1", + "smob": "^1.0.0", + "terser": "^5.17.4" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } } }, "node_modules/@rollup/plugin-typescript": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-8.3.1.tgz", - "integrity": "sha512-84rExe3ICUBXzqNX48WZV2Jp3OddjTMX97O2Py6D1KJaGSwWp0mDHXj+bCGNJqWHIEKDIT2U0sDjhP4czKi6cA==", + "version": "11.1.6", + "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-11.1.6.tgz", + "integrity": "sha512-R92yOmIACgYdJ7dJ97p4K69I8gg6IEHt8M7dUBxN3W6nrO8uUxX5ixl0yU/N3aZTi8WhPuICvOHXQvF6FaykAA==", "dev": true, "dependencies": { - "@rollup/pluginutils": "^3.1.0", - "resolve": "^1.17.0" + "@rollup/pluginutils": "^5.1.0", + "resolve": "^1.22.1" }, "engines": { - "node": ">=8.0.0" + "node": ">=14.0.0" }, "peerDependencies": { - "rollup": "^2.14.0", + "rollup": "^2.14.0||^3.0.0||^4.0.0", "tslib": "*", "typescript": ">=3.7.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + }, + "tslib": { + "optional": true + } } }, "node_modules/@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz", + "integrity": "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==", "dev": true, "dependencies": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" }, "engines": { - "node": ">= 8.0.0" + "node": ">=14.0.0" }, "peerDependencies": { - "rollup": "^1.20.0||^2.0.0" + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } } }, - "node_modules/@rollup/pluginutils/node_modules/estree-walker": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.2.tgz", + "integrity": "sha512-3XFIDKWMFZrMnao1mJhnOT1h2g0169Os848NhhmGweEcfJ4rCi+3yMCOLG4zA61rbJdkcrM/DjVZm9Hg5p5w7g==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.13.2.tgz", + "integrity": "sha512-GdxxXbAuM7Y/YQM9/TwwP+L0omeE/lJAR1J+olu36c3LqqZEBdsIWeQ91KBe6nxwOnb06Xh7JS2U5ooWU5/LgQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.2.tgz", + "integrity": "sha512-mCMlpzlBgOTdaFs83I4XRr8wNPveJiJX1RLfv4hggyIVhfB5mJfN4P8Z6yKh+oE4Luz+qq1P3kVdWrCKcMYrrA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.13.2.tgz", + "integrity": "sha512-yUoEvnH0FBef/NbB1u6d3HNGyruAKnN74LrPAfDQL3O32e3k3OSfLrPgSJmgb3PJrBZWfPyt6m4ZhAFa2nZp2A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.13.2.tgz", + "integrity": "sha512-GYbLs5ErswU/Xs7aGXqzc3RrdEjKdmoCrgzhJWyFL0r5fL3qd1NPcDKDowDnmcoSiGJeU68/Vy+OMUluRxPiLQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.2.tgz", + "integrity": "sha512-L1+D8/wqGnKQIlh4Zre9i4R4b4noxzH5DDciyahX4oOz62CphY7WDWqJoQ66zNR4oScLNOqQJfNSIAe/6TPUmQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.13.2.tgz", + "integrity": "sha512-tK5eoKFkXdz6vjfkSTCupUzCo40xueTOiOO6PeEIadlNBkadH1wNOH8ILCPIl8by/Gmb5AGAeQOFeLev7iZDOA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.13.2.tgz", + "integrity": "sha512-zvXvAUGGEYi6tYhcDmb9wlOckVbuD+7z3mzInCSTACJ4DQrdSLPNUeDIcAQW39M3q6PDquqLWu7pnO39uSMRzQ==", + "cpu": [ + "ppc64le" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.13.2.tgz", + "integrity": "sha512-C3GSKvMtdudHCN5HdmAMSRYR2kkhgdOfye4w0xzyii7lebVr4riCgmM6lRiSCnJn2w1Xz7ZZzHKuLrjx5620kw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.13.2.tgz", + "integrity": "sha512-l4U0KDFwzD36j7HdfJ5/TveEQ1fUTjFFQP5qIt9gBqBgu1G8/kCaq5Ok05kd5TG9F8Lltf3MoYsUMw3rNlJ0Yg==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.2.tgz", + "integrity": "sha512-xXMLUAMzrtsvh3cZ448vbXqlUa7ZL8z0MwHp63K2IIID2+DeP5iWIT6g1SN7hg1VxPzqx0xZdiDM9l4n9LRU1A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.13.2.tgz", + "integrity": "sha512-M/JYAWickafUijWPai4ehrjzVPKRCyDb1SLuO+ZyPfoXgeCEAlgPkNXewFZx0zcnoIe3ay4UjXIMdXQXOZXWqA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.13.2.tgz", + "integrity": "sha512-2YWwoVg9KRkIKaXSh0mz3NmfurpmYoBBTAXA9qt7VXk0Xy12PoOP40EFuau+ajgALbbhi4uTj3tSG3tVseCjuA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.13.2.tgz", + "integrity": "sha512-2FSsE9aQ6OWD20E498NYKEQLneShWes0NGMPQwxWOdws35qQXH+FplabOSP5zEe1pVjurSDOGEVCE2agFwSEsw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.2.tgz", + "integrity": "sha512-7h7J2nokcdPePdKykd8wtc8QqqkqxIrUz7MHj6aNr8waBRU//NLDVnNjQnqQO6fqtjrtCdftpbTuOKAyrAQETQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", "dev": true }, "node_modules/@sinonjs/commons": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", - "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", + "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", "dev": true, "dependencies": { "type-detect": "4.0.8" @@ -912,9 +1335,9 @@ } }, "node_modules/@sinonjs/text-encoding": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", - "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", + "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", "dev": true }, "node_modules/@tootallnate/quickjs-emscripten": { @@ -923,33 +1346,39 @@ "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==" }, "node_modules/@tsconfig/node10": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", - "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", "dev": true }, "node_modules/@tsconfig/node12": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", - "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", "dev": true }, "node_modules/@tsconfig/node14": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", - "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", "dev": true }, "node_modules/@tsconfig/node16": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", - "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, + "node_modules/@types/cbor-js": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@types/cbor-js/-/cbor-js-0.1.1.tgz", + "integrity": "sha512-pfCx/EZC7VNBThwAQ0XvGPOXYm8BUk+gSVonaIGcEKBuqGJHTdcwAGW8WZkdRs/u9n9yOt1pBoPTCS1s8ZYpEQ==", "dev": true }, "node_modules/@types/chai": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.3.tgz", - "integrity": "sha512-hC7OMnszpxhZPduX+m+nrx+uFoLkWOMiR4oa/AZF3MuSETYTZmFfJAHqZEM8MVlvfG7BEUcgvtwoCTxBp6hm3g==", + "version": "4.3.14", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.14.tgz", + "integrity": "sha512-Wj71sXE4Q4AkGdG9Tvq1u/fquNz9EdG4LIJMwVVII7ashjD/8cf8fyIfJAjRr6YcsXnSE8cOGQPq1gqeR8z+3w==", "dev": true }, "node_modules/@types/cucumber": { @@ -963,9 +1392,9 @@ } }, "node_modules/@types/estree": { - "version": "0.0.39", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, "node_modules/@types/expect": { @@ -979,46 +1408,46 @@ } }, "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", "dev": true }, "node_modules/@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", "dev": true, "dependencies": { "@types/istanbul-lib-coverage": "*" } }, "node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", "dev": true, "dependencies": { "@types/istanbul-lib-report": "*" } }, "node_modules/@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true, "optional": true }, "node_modules/@types/mocha": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.0.tgz", - "integrity": "sha512-QCWHkbMv4Y5U9oW10Uxbr45qMMSzl4OzijsozynUAgx3kEHUdXB00udx2dWDQ7f2TU2a2uuiFaRZjCe3unPpeg==", + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz", + "integrity": "sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==", "dev": true }, "node_modules/@types/nock": { @@ -1031,104 +1460,98 @@ } }, "node_modules/@types/node": { - "version": "17.0.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz", - "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==", - "dev": true - }, - "node_modules/@types/node-fetch": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.3.tgz", - "integrity": "sha512-ETTL1mOEdq/sxUtgtOhKjyB2Irra4cjxksvcMUR5Zr4n+PxVhsCD9WS46oPbHL3et9Zde7CNRr+WUNlcHvsX+w==", + "version": "20.11.30", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.30.tgz", + "integrity": "sha512-dHM6ZxwlmuZaRmUPfv1p+KrdD1Dci04FbdEm/9wEMouFqxYoFl5aMkt0VMAUtYRQDyYvD41WJLukhq/ha3YuTw==", "dev": true, "dependencies": { - "@types/node": "*", - "form-data": "^3.0.0" + "undici-types": "~5.26.4" } }, - "node_modules/@types/node-fetch/node_modules/form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "node_modules/@types/node-fetch": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==", "dev": true, "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" + "@types/node": "*", + "form-data": "^4.0.0" } }, "node_modules/@types/pubnub": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@types/pubnub/-/pubnub-7.2.0.tgz", - "integrity": "sha512-Ui58Xsn8/4Ty1hFW0t91ED6FKezzipjO+GEJviOdJdqp817+I5/WMfo5zBsDfjbZQWMqcdrktMauKpUqiIF1wA==", + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/@types/pubnub/-/pubnub-7.4.2.tgz", + "integrity": "sha512-Vjkol3ix8IMrFdwtrLP9XkWc93cWDYpfs4tK6pvOUi8/G5+og2NRJ0AcGhMAQ4wuciHxDzJNkpPIGpRAgYAa4A==", "dev": true }, "node_modules/@types/resolve": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", - "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "dev": true }, "node_modules/@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", "dev": true }, "node_modules/@types/uuid": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", - "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", + "version": "9.0.8", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", + "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==", "dev": true, "peer": true }, "node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", "dev": true, "dependencies": { "@types/yargs-parser": "*" } }, "node_modules/@types/yargs-parser": { - "version": "20.2.1", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", - "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.12.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.12.1.tgz", - "integrity": "sha512-M499lqa8rnNK7mUv74lSFFttuUsubIRdAbHcVaP93oFcKkEmHmLqy2n7jM9C8DVmFMYK61ExrZU6dLYhQZmUpw==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.4.0.tgz", + "integrity": "sha512-yHMQ/oFaM7HZdVrVm/M2WHaNPgyuJH4WelkSVEWSSsir34kxW2kDJCxlXRhhGWEsMN0WAW/vLpKfKVcm8k+MPw==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.12.1", - "@typescript-eslint/type-utils": "5.12.1", - "@typescript-eslint/utils": "5.12.1", - "debug": "^4.3.2", - "functional-red-black-tree": "^1.0.1", - "ignore": "^5.1.8", - "regexpp": "^3.2.0", - "semver": "^7.3.5", - "tsutils": "^3.21.0" + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "7.4.0", + "@typescript-eslint/type-utils": "7.4.0", + "@typescript-eslint/utils": "7.4.0", + "@typescript-eslint/visitor-keys": "7.4.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -1137,25 +1560,26 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "5.12.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.12.1.tgz", - "integrity": "sha512-6LuVUbe7oSdHxUWoX/m40Ni8gsZMKCi31rlawBHt7VtW15iHzjbpj2WLiToG2758KjtCCiLRKZqfrOdl3cNKuw==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.4.0.tgz", + "integrity": "sha512-ZvKHxHLusweEUVwrGRXXUVzFgnWhigo4JurEj0dGF1tbcGh6buL+ejDdjxOQxv6ytcY1uhun1p2sm8iWStlgLQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.12.1", - "@typescript-eslint/types": "5.12.1", - "@typescript-eslint/typescript-estree": "5.12.1", - "debug": "^4.3.2" + "@typescript-eslint/scope-manager": "7.4.0", + "@typescript-eslint/types": "7.4.0", + "@typescript-eslint/typescript-estree": "7.4.0", + "@typescript-eslint/visitor-keys": "7.4.0", + "debug": "^4.3.4" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -1164,16 +1588,16 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.12.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.12.1.tgz", - "integrity": "sha512-J0Wrh5xS6XNkd4TkOosxdpObzlYfXjAFIm9QxYLCPOcHVv1FyyFCPom66uIh8uBr0sZCrtS+n19tzufhwab8ZQ==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.4.0.tgz", + "integrity": "sha512-68VqENG5HK27ypafqLVs8qO+RkNc7TezCduYrx8YJpXq2QGZ30vmNZGJJJC48+MVn4G2dCV8m5ZTVnzRexTVtw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.12.1", - "@typescript-eslint/visitor-keys": "5.12.1" + "@typescript-eslint/types": "7.4.0", + "@typescript-eslint/visitor-keys": "7.4.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -1181,24 +1605,25 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.12.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.12.1.tgz", - "integrity": "sha512-Gh8feEhsNLeCz6aYqynh61Vsdy+tiNNkQtc+bN3IvQvRqHkXGUhYkUi+ePKzP0Mb42se7FDb+y2SypTbpbR/Sg==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.4.0.tgz", + "integrity": "sha512-247ETeHgr9WTRMqHbbQdzwzhuyaJ8dPTuyuUEMANqzMRB1rj/9qFIuIXK7l0FX9i9FXbHeBQl/4uz6mYuCE7Aw==", "dev": true, "dependencies": { - "@typescript-eslint/utils": "5.12.1", - "debug": "^4.3.2", - "tsutils": "^3.21.0" + "@typescript-eslint/typescript-estree": "7.4.0", + "@typescript-eslint/utils": "7.4.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "*" + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -1207,12 +1632,12 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.12.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.12.1.tgz", - "integrity": "sha512-hfcbq4qVOHV1YRdhkDldhV9NpmmAu2vp6wuFODL71Y0Ixak+FLeEU4rnPxgmZMnGreGEghlEucs9UZn5KOfHJA==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.4.0.tgz", + "integrity": "sha512-mjQopsbffzJskos5B4HmbsadSJQWaRK0UxqQ7GuNA9Ga4bEKeiO6b2DnB6cM6bpc8lemaPseh0H9B/wyg+J7rw==", "dev": true, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -1220,21 +1645,22 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.12.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.12.1.tgz", - "integrity": "sha512-ahOdkIY9Mgbza7L9sIi205Pe1inCkZWAHE1TV1bpxlU4RZNPtXaDZfiiFWcL9jdxvW1hDYZJXrFm+vlMkXRbBw==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.4.0.tgz", + "integrity": "sha512-A99j5AYoME/UBQ1ucEbbMEmGkN7SE0BvZFreSnTd1luq7yulcHdyGamZKizU7canpGDWGJ+Q6ZA9SyQobipePg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.12.1", - "@typescript-eslint/visitor-keys": "5.12.1", - "debug": "^4.3.2", - "globby": "^11.0.4", + "@typescript-eslint/types": "7.4.0", + "@typescript-eslint/visitor-keys": "7.4.0", + "debug": "^4.3.4", + "globby": "^11.1.0", "is-glob": "^4.0.3", - "semver": "^7.3.5", - "tsutils": "^3.21.0" + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -1247,62 +1673,41 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "5.12.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.12.1.tgz", - "integrity": "sha512-Qq9FIuU0EVEsi8fS6pG+uurbhNTtoYr4fq8tKjBupsK5Bgbk2I32UGm0Sh+WOyjOPgo/5URbxxSNV6HYsxV4MQ==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.4.0.tgz", + "integrity": "sha512-NQt9QLM4Tt8qrlBVY9lkMYzfYtNz8/6qwZg8pI3cMGlPnj6mOpRxxAm7BMJN9K0AiY+1BwJ5lVC650YJqYOuNg==", "dev": true, "dependencies": { - "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.12.1", - "@typescript-eslint/types": "5.12.1", - "@typescript-eslint/typescript-estree": "5.12.1", - "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "7.4.0", + "@typescript-eslint/types": "7.4.0", + "@typescript-eslint/typescript-estree": "7.4.0", + "semver": "^7.5.4" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" + "eslint": "^8.56.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.12.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.12.1.tgz", - "integrity": "sha512-l1KSLfupuwrXx6wc0AuOmC7Ko5g14ZOQ86wJJqRbdLbXLK02pK/DPiDDqCc7BqqiiA04/eAA6ayL0bgOrAkH7A==", + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.4.0.tgz", + "integrity": "sha512-0zkC7YM0iX5Y41homUUeW1CHtZR01K3ybjM1l6QczoMuay0XKtrb93kv95AxUGwdjGr64nNqnOCwmEl616N8CA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.12.1", - "eslint-visitor-keys": "^3.0.0" + "@typescript-eslint/types": "7.4.0", + "eslint-visitor-keys": "^3.4.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -1315,6 +1720,12 @@ "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", "dev": true }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -1329,9 +1740,9 @@ } }, "node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -1350,9 +1761,9 @@ } }, "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", "dev": true, "engines": { "node": ">=0.4.0" @@ -1361,7 +1772,7 @@ "node_modules/after": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", - "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=", + "integrity": "sha512-QbJ0NTQ/I9DI3uSJA4cbexiwQeRAfjPScqIbSjUDd9TOrcg6pTkdgziesOqxBMBzit8vFCTwrP27t13vFOORRA==", "dev": true }, "node_modules/agent-base": { @@ -1375,22 +1786,6 @@ "node": ">= 14" } }, - "node_modules/agent-base/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/agentkeepalive": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.2.tgz", @@ -1437,27 +1832,27 @@ } }, "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/any-promise": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", "dev": true }, "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, "dependencies": { "normalize-path": "^3.0.0", @@ -1485,7 +1880,7 @@ "node_modules/array-from": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", - "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=", + "integrity": "sha512-GQTc6Uupx1FCavi5mPzBvVT7nEOeWMmUA9P95wpfpW1XwMSKs+KaymD5C2Up7KAUKg/mYwbsUYzdZWcoajlNZg==", "dev": true }, "node_modules/array-union": { @@ -1506,7 +1901,7 @@ "node_modules/arrify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -1529,7 +1924,7 @@ "node_modules/assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", "dev": true, "engines": { "node": ">=0.8" @@ -1569,27 +1964,27 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "node_modules/aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", "dev": true, "engines": { "node": "*" } }, "node_modules/aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", + "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", "dev": true }, "node_modules/backo2": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", - "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=", + "integrity": "sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA==", "dev": true }, "node_modules/balanced-match": { @@ -1601,7 +1996,7 @@ "node_modules/base64-arraybuffer": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz", - "integrity": "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI=", + "integrity": "sha512-a1eIFi4R9ySrbiMuyTGx5e92uRH5tQY6kArNcFaKBUleIoLjdjBg7Zxm3Mqm3Kmkf27HLR/1fnxX9q8GQ7Iavg==", "dev": true, "engines": { "node": ">= 0.6.0" @@ -1636,9 +2031,9 @@ } }, "node_modules/basic-ftp": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.4.tgz", - "integrity": "sha512-8PzkB0arJFV4jJWSGOYR+OEic6aeKMu/osRhBULN6RY0ykby6LKhbmuQ5ublvaas5BOwboah5D87nrHyuh8PPA==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", + "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", "engines": { "node": ">=10.0.0" } @@ -1646,7 +2041,7 @@ "node_modules/bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", "dev": true, "dependencies": { "tweetnacl": "^0.14.3" @@ -1660,12 +2055,15 @@ "peer": true }, "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/blob": { @@ -1681,24 +2079,27 @@ "dev": true }, "node_modules/body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "dev": true, "dependencies": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.8.1", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.9.7", - "raw-body": "2.4.3", - "type-is": "~1.6.18" + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" }, "engines": { - "node": ">= 0.8" + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" } }, "node_modules/body-parser/node_modules/debug": { @@ -1713,17 +2114,16 @@ "node_modules/body-parser/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "node_modules/braces": { @@ -1770,7 +2170,7 @@ "node_modules/buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", "dev": true, "engines": { "node": "*" @@ -1783,9 +2183,9 @@ "dev": true }, "node_modules/builtin-modules": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz", - "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", "dev": true, "engines": { "node": ">=6" @@ -1804,12 +2204,18 @@ } }, "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -1825,12 +2231,15 @@ } }, "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, "engines": { - "node": ">=6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/capital-case": { @@ -1847,13 +2256,13 @@ "node_modules/caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", "dev": true }, "node_modules/cbor-js": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/cbor-js/-/cbor-js-0.1.0.tgz", - "integrity": "sha1-yAzmEg84fo+qdDcN/aIdlluPx/k=" + "integrity": "sha512-7sQ/TvDZPl7csT1Sif9G0+MA0I0JOVah8+wWlJVQdVEgIbCzlN/ab3x+uvMNsc34TUvO6osQTAmB2ls80JX6tw==" }, "node_modules/cbor-sync": { "version": "1.0.4", @@ -1861,17 +2270,18 @@ "integrity": "sha512-GWlXN4wiz0vdWWXBU71Dvc1q3aBo0HytqwAZnXF1wOwjqNnDWA1vZ1gDMFLlqohak31VQzmhiYfiCX5QSSfagA==" }, "node_modules/chai": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.4.tgz", - "integrity": "sha512-yS5H68VYOCtN1cjfwumDSuzn/9c+yza4f3reKXlE5rUg7SFcCEy90gJvydNgOYtblyf4Zi6jIWRnXOgErta0KA==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", + "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", "dev": true, "dependencies": { "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^3.0.1", - "get-func-name": "^2.0.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", "pathval": "^1.1.1", - "type-detect": "^4.0.5" + "type-detect": "^4.0.8" }, "engines": { "node": ">=4" @@ -1900,39 +2310,71 @@ } }, "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/chalk/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/chalk/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/chalk/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, "node_modules/check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", "dev": true, + "dependencies": { + "get-func-name": "^2.0.2" + }, "engines": { "node": "*" } }, "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -1945,10 +2387,40 @@ "engines": { "node": ">= 8.10.0" }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, "optionalDependencies": { "fsevents": "~2.3.2" } }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, "node_modules/class-transformer": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", @@ -1957,9 +2429,9 @@ "peer": true }, "node_modules/cli-table3": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", - "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.1.tgz", + "integrity": "sha512-w0q/enDHhPLq44ovMGdQeeDLvwxwavsJX7oQGYt/LrBlYsyaxyDnp6z3QzFut/6kLLKnlcUVJLrpB7KBfgG/RA==", "dev": true, "dependencies": { "string-width": "^4.2.0" @@ -1968,7 +2440,7 @@ "node": "10.* || >= 12.*" }, "optionalDependencies": { - "@colors/colors": "1.5.0" + "colors": "1.4.0" } }, "node_modules/cliui": { @@ -1994,7 +2466,7 @@ "node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, "node_modules/colors": { @@ -2029,30 +2501,33 @@ "node_modules/commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", "dev": true }, "node_modules/component-bind": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", - "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=", + "integrity": "sha512-WZveuKPeKAG9qY+FkYDeADzdHyTYdIboXS59ixDeRJL5ZhxpqUnxSOwop4FQjMsiYm3/Or8cegVbpAHNA7pHxw==", "dev": true }, "node_modules/component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/component-inherit": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", - "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=", + "integrity": "sha512-w+LhYREhatpVqTESyGFg3NlP6Iu0kEKUHETY9GoZP/pQyW4mHFZuFWRUCIqVPZ36ueVLtoOEZaAqbCF2RDndaA==", "dev": true }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, "node_modules/concat-stream": { @@ -2097,13 +2572,13 @@ "node_modules/connect/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, "node_modules/content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "dev": true, "engines": { "node": ">= 0.6" @@ -2124,9 +2599,9 @@ "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==" }, "node_modules/core-js-pure": { - "version": "3.26.0", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.26.0.tgz", - "integrity": "sha512-LiN6fylpVBVwT8twhhluD9TzXmZQQsr2I2eIKtWNbZI1XMfBT7CV18itaN6RA7EtQd/SDdRx/wzvAShX2HvhQA==", + "version": "3.36.1", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.36.1.tgz", + "integrity": "sha512-NXCvHvSVYSrewP0L5OhltzXeWFJLo2AL2TYnj6iLV3Bw8mM62wAQMNgUCRI6EBu6hVVpbCxmOPlxh1Ikw2PfUA==", "dev": true, "hasInstallScript": true, "peer": true, @@ -2148,29 +2623,14 @@ "dev": true }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/cross-spawn/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" }, "engines": { "node": ">= 8" @@ -2231,16 +2691,6 @@ "xregexp": "^4.2.4" } }, - "node_modules/cucumber-expressions/node_modules/xregexp": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.4.1.tgz", - "integrity": "sha512-2u9HwfadaJaY9zHtRRnH6BY6CQVNQKkYm3oLtC9gJXXzfsbACg5X5e4EZZGVAH+YIfa+QA9lsFQTTe3HURF3ag==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/runtime-corejs3": "^7.12.1" - } - }, "node_modules/cucumber-pretty": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/cucumber-pretty/-/cucumber-pretty-6.0.1.tgz", @@ -2263,9 +2713,9 @@ "peer": true }, "node_modules/cucumber-tsflow": { - "version": "4.0.0-rc.11", - "resolved": "https://registry.npmjs.org/cucumber-tsflow/-/cucumber-tsflow-4.0.0-rc.11.tgz", - "integrity": "sha512-VK/RhJOOxS4KAH6UIkfLsDE2+H7OtP/+cwzx139gldqHP08hoYk/fMwOoXlGWXOOX2O3amJ6RTS0YMF2xCA8Bw==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/cucumber-tsflow/-/cucumber-tsflow-4.4.1.tgz", + "integrity": "sha512-Za/eo4SJxziinl5geLdXnHucpU6bbv1e9fYQjV8Rppc0i87jHLvL5rHRU28798Pk1wBiiDWb10nVGghDIcc2HA==", "dev": true, "dependencies": { "callsites": "^3.1.0", @@ -2274,7 +2724,7 @@ "underscore": "^1.8.3" }, "peerDependencies": { - "@cucumber/cucumber": ">7.0.0-rc || >7.0.0" + "@cucumber/cucumber": "^7 || ^8 || ^9 || ^10" } }, "node_modules/cucumber/node_modules/ansi-regex": { @@ -2311,16 +2761,6 @@ "dev": true, "peer": true }, - "node_modules/cucumber/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, "node_modules/cucumber/node_modules/is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", @@ -2361,23 +2801,26 @@ "node_modules/custom-event": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", - "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", + "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==", "dev": true }, "node_modules/d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.2.tgz", + "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", "dev": true, "dependencies": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" + "es5-ext": "^0.10.64", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.12" } }, "node_modules/dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", "dev": true, "dependencies": { "assert-plus": "^1.0.0" @@ -2387,26 +2830,26 @@ } }, "node_modules/data-uri-to-buffer": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.1.tgz", - "integrity": "sha512-MZd3VlchQkp8rdend6vrx7MmVDJzSNTBvghvKjirLkD+WTChA3KUf0jkE68Q4UyctNqI11zZO9/x2Yx+ub5Cvg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", "engines": { - "node": ">= 14" + "node": ">= 12" } }, "node_modules/date-format": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.3.tgz", - "integrity": "sha512-7P3FyqDcfeznLZp2b+OMitV9Sz2lUnsT87WaTat9nVwqsBkTzPG3lPLNwW3en6F4pHUiWzr6vb8CLhjdK9bcxQ==", + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", + "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", "dev": true, "engines": { "node": ">=4.0" } }, "node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dependencies": { "ms": "2.1.2" }, @@ -2422,36 +2865,39 @@ "node_modules/decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", "dev": true, "engines": { "node": ">=0.10.0" } }, "node_modules/deep-eql": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", - "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", "dev": true, "dependencies": { "type-detect": "^4.0.0" }, "engines": { - "node": ">=0.12" + "node": ">=6" } }, "node_modules/deep-equal": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", - "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.2.tgz", + "integrity": "sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==", "dev": true, "dependencies": { - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.1", - "is-regex": "^1.0.4", - "object-is": "^1.0.1", + "is-arguments": "^1.1.1", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "object-is": "^1.1.5", "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.2.0" + "regexp.prototype.flags": "^1.5.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2464,24 +2910,45 @@ "dev": true }, "node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true, "engines": { "node": ">=0.10.0" } }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", "dev": true, "dependencies": { - "object-keys": "^1.0.12" + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/degenerator": { @@ -2500,18 +2967,28 @@ "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "engines": { "node": ">=0.4.0" } }, "node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "dev": true, "engines": { - "node": ">= 0.6" + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" } }, "node_modules/dezalgo": { @@ -2526,7 +3003,7 @@ "node_modules/di": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", - "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", + "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", "dev": true }, "node_modules/diff": { @@ -2539,12 +3016,12 @@ } }, "node_modules/diff-sequences": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", - "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", "dev": true, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/dir-glob": { @@ -2574,7 +3051,7 @@ "node_modules/dom-serialize": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", - "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", + "integrity": "sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==", "dev": true, "dependencies": { "custom-event": "~1.0.0", @@ -2605,32 +3082,44 @@ "node_modules/ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", "dev": true, "dependencies": { "jsbn": "~0.1.0", "safer-buffer": "^2.1.0" } }, + "node_modules/ecc-jsbn/node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "dev": true + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", "dev": true, "engines": { "node": ">= 0.8" } }, "node_modules/engine.io": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.5.0.tgz", - "integrity": "sha512-21HlvPUKaitDGE4GXNtQ7PLP0Sz4aWLddMPw2VTyFz1FVZqu/kZsJUO8WNpKuE/OCL7nkfRaOui2ZCJloGznGA==", + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.6.1.tgz", + "integrity": "sha512-dfs8EVg/i7QjFsXxn7cCRQ+Wai1G1TlEvHhdYEi80fxn5R1vZ2K661O6v/rezj1FP234SZ14r9CmJke99iYDGg==", "dev": true, "dependencies": { "accepts": "~1.3.4", @@ -2645,9 +3134,9 @@ } }, "node_modules/engine.io-client": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.5.2.tgz", - "integrity": "sha512-QEqIp+gJ/kMHeUun7f5Vv3bteRHppHH/FMBQX/esFj/fuYfjyUKWGMo3VCvIP/V8bE9KcjHmRZrhIz2Z9oNsDA==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.5.3.tgz", + "integrity": "sha512-qsgyc/CEhJ6cgMUwxRRtOndGVhIu5hpL5tR4umSpmX/MvkFoIxUTM7oFMDQumHNzlNLwSVy6qhstFPoWTf7dOw==", "dev": true, "dependencies": { "component-emitter": "~1.3.0", @@ -2675,7 +3164,7 @@ "node_modules/engine.io-client/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, "node_modules/engine.io-parser": { @@ -2704,7 +3193,7 @@ "node_modules/ent": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", - "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", + "integrity": "sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==", "dev": true }, "node_modules/error-stack-parser": { @@ -2716,21 +3205,45 @@ "stackframe": "^1.3.4" } }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es5-ext": { - "version": "0.10.53", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", - "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", + "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", "dev": true, + "hasInstallScript": true, "dependencies": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.3", - "next-tick": "~1.0.0" + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" } }, "node_modules/es6-iterator": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", "dev": true, "dependencies": { "d": "1", @@ -2745,25 +3258,28 @@ "dev": true }, "node_modules/es6-shim": { - "version": "0.35.6", - "resolved": "https://registry.npmjs.org/es6-shim/-/es6-shim-0.35.6.tgz", - "integrity": "sha512-EmTr31wppcaIAgblChZiuN/l9Y7DPyw8Xtbg7fIVngn6zMW+IEBJDJngeKC3x6wr0V/vcA2wqeFnaw1bFJbDdA==", + "version": "0.35.8", + "resolved": "https://registry.npmjs.org/es6-shim/-/es6-shim-0.35.8.tgz", + "integrity": "sha512-Twf7I2v4/1tLoIXMT8HlqaBSS5H2wQTs2wx3MNYCI8K1R1/clXyCazrcVCPm/FuO9cyV8+leEaZOWD5C253NDg==", "dev": true }, "node_modules/es6-symbol": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.4.tgz", + "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", "dev": true, "dependencies": { - "d": "^1.0.1", - "ext": "^1.1.2" + "d": "^1.0.2", + "ext": "^1.7.0" + }, + "engines": { + "node": ">=0.12" } }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "dev": true, "engines": { "node": ">=6" @@ -2772,16 +3288,16 @@ "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", "dev": true }, "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "dev": true, "engines": { - "node": ">=0.8.0" + "node": ">=8" } }, "node_modules/escodegen": { @@ -2805,27 +3321,28 @@ } }, "node_modules/eslint": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.37.0.tgz", - "integrity": "sha512-NU3Ps9nI05GUoVMxcZx1J8CNR6xOvUT4jAUMH5+z8lpp3aEdPVCImKw6PWG4PY+Vfkpr+jvMpxs/qoE7wq0sPw==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.2", - "@eslint/js": "8.37.0", - "@humanwhocodes/config-array": "^0.11.8", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-visitor-keys": "^3.4.0", - "espree": "^9.5.1", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -2833,22 +3350,19 @@ "find-up": "^5.0.0", "glob-parent": "^6.0.2", "globals": "^13.19.0", - "grapheme-splitter": "^1.0.4", + "graphemer": "^1.4.0", "ignore": "^5.2.0", - "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", + "optionator": "^0.9.3", "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" }, "bin": { @@ -2862,13 +3376,14 @@ } }, "node_modules/eslint-plugin-mocha": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-10.0.3.tgz", - "integrity": "sha512-9mM7PZGxfejpjey+MrG0Cu3Lc8MyA5E2s7eUCdHXgS4SY/H9zLuwa7wVAjnEaoDjbBilA+0bPEB+iMO7lBUPcg==", + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-10.4.1.tgz", + "integrity": "sha512-G85ALUgKaLzuEuHhoW3HVRgPTmia6njQC3qCG6CEvA8/Ja9PDZnRZOuzekMki+HaViEQXINuYsmhp5WR5/4MfA==", "dev": true, "dependencies": { "eslint-utils": "^3.0.0", - "ramda": "^0.27.1" + "globals": "^13.24.0", + "rambda": "^7.4.0" }, "engines": { "node": ">=14.0.0" @@ -2878,30 +3393,39 @@ } }, "node_modules/eslint-plugin-prettier": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz", - "integrity": "sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", + "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", "dev": true, "dependencies": { - "prettier-linter-helpers": "^1.0.0" + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.6" }, "engines": { - "node": ">=6.0.0" + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" }, "peerDependencies": { - "eslint": ">=7.28.0", - "prettier": ">=2.0.0" + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": "*", + "prettier": ">=3.0.0" }, "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, "eslint-config-prettier": { "optional": true } } }, "node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", @@ -2909,6 +3433,9 @@ }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-utils": { @@ -2939,9 +3466,9 @@ } }, "node_modules/eslint-visitor-keys": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", - "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -2950,61 +3477,22 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/eslint/node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/eslint/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/eslint/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, "node_modules/eslint/node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -3017,27 +3505,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/eslint/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/eslint/node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -3050,78 +3517,42 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/eslint/node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/eslint/node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/eslint/node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/eslint/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=8" + "node": "*" } }, - "node_modules/eslint/node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "node_modules/esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", "dev": true, "dependencies": { - "prelude-ls": "^1.2.1" + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" }, "engines": { - "node": ">= 0.8.0" + "node": ">=0.10" } }, "node_modules/espree": { - "version": "9.5.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", - "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "dependencies": { - "acorn": "^8.8.0", + "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.0" + "eslint-visitor-keys": "^3.4.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -3188,6 +3619,16 @@ "node": ">=0.10.0" } }, + "node_modules/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, "node_modules/eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", @@ -3195,35 +3636,30 @@ "dev": true }, "node_modules/expect": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", - "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", "dev": true, "dependencies": { - "@jest/types": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1" + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/ext": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.6.0.tgz", - "integrity": "sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", "dev": true, "dependencies": { - "type": "^2.5.0" + "type": "^2.7.2" } }, - "node_modules/ext/node_modules/type": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.6.0.tgz", - "integrity": "sha512-eiDBDOmkih5pMbo9OqsqPRGMljLodLcwd5XD5JbtNB0o89xZAwynY9EdCDsJU7LtcVCClu9DvM7/0Ep1hYX3EQ==", - "dev": true - }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -3257,13 +3693,13 @@ "node_modules/extract-zip/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, "node_modules/extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", "dev": true, "engines": [ "node >=0.6.0" @@ -3276,15 +3712,15 @@ "dev": true }, "node_modules/fast-diff": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", - "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", "dev": true }, "node_modules/fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -3297,6 +3733,18 @@ "node": ">=8.6.0" } }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -3306,7 +3754,7 @@ "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, "node_modules/fast-safe-stringify": { @@ -3315,9 +3763,9 @@ "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" }, "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -3326,12 +3774,34 @@ "node_modules/fd-slicer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", "dev": true, "dependencies": { "pend": "~1.2.0" } }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, "node_modules/figures": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", @@ -3347,6 +3817,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -3401,9 +3880,21 @@ "node_modules/finalhandler/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, + "node_modules/finalhandler/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -3430,12 +3921,13 @@ } }, "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, "dependencies": { - "flatted": "^3.1.0", + "flatted": "^3.2.9", + "keyv": "^4.5.3", "rimraf": "^3.0.2" }, "engines": { @@ -3443,15 +3935,15 @@ } }, "node_modules/flatted": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", - "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "dev": true }, "node_modules/follow-redirects": { - "version": "1.15.4", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz", - "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==", + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "dev": true, "funding": [ { @@ -3471,24 +3963,34 @@ "node_modules/forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", "dev": true, "engines": { "node": "*" } }, "node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", "dependencies": { "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", + "combined-stream": "^1.0.8", "mime-types": "^2.1.12" }, "engines": { - "node": ">= 0.12" + "node": ">= 6" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" } }, "node_modules/formidable": { @@ -3505,24 +4007,10 @@ "url": "https://ko-fi.com/tunnckoCore/commissions" } }, - "node_modules/formidable/node_modules/qs": { - "version": "6.11.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", - "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/fs-extra": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", - "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", + "integrity": "sha512-VerQV6vEKuhDWD2HGOybV6v5I73syoc/cXAbKlgTC7M/oFVEtklWlp9QH2Ijw3IaWDOQcMkldSPa7zXy79Z/UQ==", "dev": true, "dependencies": { "graceful-fs": "^4.1.2", @@ -3533,13 +4021,13 @@ "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, "optional": true, @@ -3551,15 +4039,21 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/get-caller-file": { "version": "2.0.5", @@ -3571,74 +4065,74 @@ } }, "node_modules/get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", "dev": true, "engines": { "node": "*" } }, "node_modules/get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/get-uri": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.2.tgz", - "integrity": "sha512-5KLucCJobh8vBY1K07EFV4+cPZH3mrV9YeAruUseCQKHB58SGjjT2l9/eA9LD082IiuMjSlFJEcdJ27TXvbZNw==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.3.tgz", + "integrity": "sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==", "dependencies": { "basic-ftp": "^5.0.2", - "data-uri-to-buffer": "^6.0.0", + "data-uri-to-buffer": "^6.0.2", "debug": "^4.3.4", - "fs-extra": "^8.1.0" + "fs-extra": "^11.2.0" }, "engines": { "node": ">= 14" } }, - "node_modules/get-uri/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, + "node_modules/get-uri/node_modules/data-uri-to-buffer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">= 14" } }, "node_modules/get-uri/node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", "dependencies": { "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { - "node": ">=6 <7 || >=8" + "node": ">=14.14" } }, "node_modules/get-uri/node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dependencies": { + "universalify": "^2.0.0" + }, "optionalDependencies": { "graceful-fs": "^4.1.6" } @@ -3646,7 +4140,7 @@ "node_modules/getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", "dev": true, "dependencies": { "assert-plus": "^1.0.0" @@ -3664,15 +4158,15 @@ } }, "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" }, @@ -3684,21 +4178,43 @@ } }, "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "dependencies": { - "is-glob": "^4.0.1" + "is-glob": "^4.0.3" }, "engines": { - "node": ">= 6" + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" } }, "node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -3730,15 +4246,26 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, "node_modules/growl": { @@ -3753,7 +4280,7 @@ "node_modules/har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", "dev": true, "engines": { "node": ">=4" @@ -3773,17 +4300,6 @@ "node": ">=6" } }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/has-binary2": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", @@ -3796,28 +4312,50 @@ "node_modules/has-binary2/node_modules/isarray": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", - "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "integrity": "sha512-c2cu3UxbI+b6kR3fy0nRnAhodsvR9dx7U5+znCOzdj6IfP3upFURTr0Xl5BlQZNKZjEtxrmVyfSdeE3O57smoQ==", "dev": true }, "node_modules/has-cors": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", - "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=", + "integrity": "sha512-g5VNKdkFuUuVCP9gYfDJHjK2nqdQJ7aDLTnycnc2+RvsOQbuLdF5pm7vuE5J76SEBIQjs4kQY/BWq74JUmjbXA==", "dev": true }, "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/has-symbols": { + "node_modules/has-property-descriptors": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "engines": { "node": ">= 0.4" }, @@ -3826,12 +4364,12 @@ } }, "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, "dependencies": { - "has-symbols": "^1.0.2" + "has-symbols": "^1.0.3" }, "engines": { "node": ">= 0.4" @@ -3843,7 +4381,7 @@ "node_modules/hasha": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/hasha/-/hasha-2.2.0.tgz", - "integrity": "sha1-eNfL/B5tZjA/55g3NlmEUXsvbuE=", + "integrity": "sha512-jZ38TU/EBiGKrmyTNNZgnvCZHNowiRI4+w/I9noMlekHTZH3KyGgvJLmhSgykeAQ9j2SYPDosM0Bg3wHfzibAQ==", "dev": true, "dependencies": { "is-stream": "^1.0.1", @@ -3856,12 +4394,23 @@ "node_modules/hasha/node_modules/is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", "dev": true, "engines": { "node": ">=0.10.0" } }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/he": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", @@ -3880,19 +4429,28 @@ } }, "node_modules/http-errors": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", - "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "dev": true, "dependencies": { - "depd": "~1.1.2", + "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", + "statuses": "2.0.1", "toidentifier": "1.0.1" }, "engines": { - "node": ">= 0.6" + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" } }, "node_modules/http-proxy": { @@ -3910,9 +4468,9 @@ } }, "node_modules/http-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", - "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" @@ -3921,26 +4479,10 @@ "node": ">= 14" } }, - "node_modules/http-proxy-agent/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", "dev": true, "dependencies": { "assert-plus": "^1.0.0", @@ -3953,9 +4495,9 @@ } }, "node_modules/https-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", - "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", "dependencies": { "agent-base": "^7.0.2", "debug": "4" @@ -3967,7 +4509,7 @@ "node_modules/humanize-ms": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", "dependencies": { "ms": "^2.0.0" } @@ -4004,9 +4546,9 @@ ] }, "node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", "dev": true, "engines": { "node": ">= 4" @@ -4031,7 +4573,7 @@ "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, "engines": { "node": ">=0.8.19" @@ -4049,13 +4591,13 @@ "node_modules/indexof": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", - "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", + "integrity": "sha512-i0G7hLJ1z0DE8dsqJa2rycj9dBmNKgXBvotXtZYXakU9oivfB9Uj2ZBC27qqef2U58/ZLwalxa1X/RDCdkHtVg==", "dev": true }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "dev": true, "dependencies": { "once": "^1.3.0", @@ -4068,10 +4610,22 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, - "node_modules/ip": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz", - "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==" + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/ip-address/node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==" }, "node_modules/is-arguments": { "version": "1.1.1", @@ -4095,19 +4649,34 @@ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, "dependencies": { - "binary-extensions": "^2.0.0" + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-builtin-module": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "dev": true, + "dependencies": { + "builtin-modules": "^3.3.0" }, "engines": { - "node": ">=8" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "dev": true, "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4131,7 +4700,7 @@ "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, "engines": { "node": ">=0.10.0" @@ -4149,7 +4718,7 @@ "node_modules/is-generator": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-generator/-/is-generator-1.0.3.tgz", - "integrity": "sha1-wUwhBX7TbjKNuANHlmxpP4hjifM=", + "integrity": "sha512-G56jBpbJeg7ds83HW1LuShNs8J73Fv3CPz/bmROHOHlnKkN8sWb9ujiagjmxxMUywftgq48HlBZELKKqFLk0oA==", "dev": true }, "node_modules/is-glob": { @@ -4167,7 +4736,7 @@ "node_modules/is-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", "dev": true }, "node_modules/is-number": { @@ -4237,7 +4806,7 @@ "node_modules/is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", "dev": true }, "node_modules/is-unicode-supported": { @@ -4255,13 +4824,13 @@ "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true }, "node_modules/isbinaryfile": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.8.tgz", - "integrity": "sha512-53h6XFniq77YdW+spoRrebh0mnmTxRPTlcuIArO57lmMdq4uBKFKaeTjnb92oYWrSn/LVL+LT+Hap2tFQj8V+w==", + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", + "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", "dev": true, "engines": { "node": ">= 8.0.0" @@ -4273,327 +4842,89 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, "node_modules/isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", "dev": true }, "node_modules/jest-diff": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", - "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", "dev": true, "dependencies": { "chalk": "^4.0.0", - "diff-sequences": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-diff/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-diff/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-diff/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-diff/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-diff/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-diff/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-get-type": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", - "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", "dev": true, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-matcher-utils": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", - "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", "dev": true, "dependencies": { "chalk": "^4.0.0", - "jest-diff": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-matcher-utils/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-matcher-utils/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-matcher-utils/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-matcher-utils/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-matcher-utils/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-matcher-utils/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" }, "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", "dev": true, "dependencies": { "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", + "@jest/types": "^29.6.3", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", + "pretty-format": "^29.7.0", "slash": "^3.0.0", "stack-utils": "^2.0.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-message-util/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-message-util/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-message-util/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/jest-message-util/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/jest-message-util/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-message-util/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-worker": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", - "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", "dev": true, "dependencies": { + "@jest/types": "^29.6.3", "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/jest-worker/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" }, "engines": { - "node": ">=8" - } - }, - "node_modules/js-sdsl": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz", - "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/js-tokens": { @@ -4616,9 +4947,14 @@ } }, "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==" + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true }, "node_modules/json-schema": { @@ -4636,19 +4972,32 @@ "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, "node_modules/json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", "dev": true }, + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "optional": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, "node_modules/jsonfile": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "integrity": "sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw==", "dev": true, "optionalDependencies": { "graceful-fs": "^4.1.6" @@ -4672,13 +5021,13 @@ "node_modules/jsprim/node_modules/core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", "dev": true }, "node_modules/jsprim/node_modules/verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", "dev": true, "engines": [ "node >=0.6.0" @@ -4735,7 +5084,7 @@ "node_modules/karma-chai": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/karma-chai/-/karma-chai-0.1.0.tgz", - "integrity": "sha1-vuWtQEAFF4Ea40u5RfdikJEIt5o=", + "integrity": "sha512-mqKCkHwzPMhgTYca10S90aCEX9+HjVjjrBFAsw36Zj7BlQNbokXXCAe6Ji04VUMsxcY5RLP7YphpfO06XOubdg==", "dev": true, "peerDependencies": { "chai": "*", @@ -4743,14 +5092,26 @@ } }, "node_modules/karma-chrome-launcher": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.1.0.tgz", - "integrity": "sha512-3dPs/n7vgz1rxxtynpzZTvb9y/GIaW8xjAwcIGttLbycqoFtI7yo1NGnQi6oFTherRE+GIhCAHZC4vEqWGhNvg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.2.0.tgz", + "integrity": "sha512-rE9RkUPI7I9mAxByQWkGJFXfFD6lE4gC5nPuZdobf/QdTEJI6EU4yIay/cfU/xV4ZxlM5JiTv7zWYgA64NpS5Q==", "dev": true, "dependencies": { "which": "^1.2.1" } }, + "node_modules/karma-chrome-launcher/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, "node_modules/karma-mocha": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/karma-mocha/-/karma-mocha-2.0.1.tgz", @@ -4763,7 +5124,8 @@ "node_modules/karma-phantomjs-launcher": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/karma-phantomjs-launcher/-/karma-phantomjs-launcher-1.0.4.tgz", - "integrity": "sha1-0jyjSAG9qYY60xjju0vUBisTrNI=", + "integrity": "sha512-tf4P3plsE7wb5Pqh8GJ6RnElxfI/UM4MtVnjbSIZFpdFJlKnjRzfIx8MLCcSYJBwZ1+qSKFz4uBe3XNoq2t3KA==", + "deprecated": "PhantomJS development have stopped, use puppeteer or similar", "dev": true, "dependencies": { "lodash": "^4.0.1", @@ -4796,7 +5158,7 @@ "node_modules/karma-spec-reporter": { "version": "0.0.32", "resolved": "https://registry.npmjs.org/karma-spec-reporter/-/karma-spec-reporter-0.0.32.tgz", - "integrity": "sha1-LpxyB+pyZ3EmAln4K+y1QyCeRAo=", + "integrity": "sha512-ZXsYERZJMTNRR2F3QN11OWF5kgnT/K2dzhM+oY3CDyMrDI3TjIWqYGG7c15rR9wjmy9lvdC+CCshqn3YZqnNrA==", "dev": true, "dependencies": { "colors": "^1.1.2" @@ -4805,16 +5167,59 @@ "karma": ">=0.9" } }, + "node_modules/karma/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/karma/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/karma/node_modules/tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dev": true, + "dependencies": { + "rimraf": "^3.0.0" + }, + "engines": { + "node": ">=8.17.0" + } + }, "node_modules/kew": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz", - "integrity": "sha1-edk9LTM2PW/dKXCzNdkUGtWR15s=", + "integrity": "sha512-IG6nm0+QtAMdXt9KvbgbGdvY50RSrw+U4sGZg+KlrSKPJEwVE5JVoI3d7RWfSMdBQneRheeAOj3lIjX5VL/9RQ==", "dev": true }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, "node_modules/klaw": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", - "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", + "integrity": "sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw==", "dev": true, "optionalDependencies": { "graceful-fs": "^4.1.9" @@ -4823,16 +5228,29 @@ "node_modules/knuth-shuffle-seeded": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/knuth-shuffle-seeded/-/knuth-shuffle-seeded-1.0.6.tgz", - "integrity": "sha1-AfG2VzOqdUDuCNiwF0Fk0iCB5OE=", + "integrity": "sha512-9pFH0SplrfyKyojCLxZfMcvkhf5hH0d+UwR9nTVJ/DDQJGuzcXjTwB7TP7sDfehSudlGGaOLblmEWqv04ERVWg==", "dev": true, "dependencies": { "seed-random": "~2.2.0" } }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/lil-uuid": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/lil-uuid/-/lil-uuid-0.1.1.tgz", - "integrity": "sha1-+e3PI/AOQr9D8PhD2Y2LU/M0HxY=" + "integrity": "sha512-GhWI8f61tBlMeqULZ1QWhFiiyFIFdPlg//S8Udq1wjq1FJhpFKTfnbduSxAQjueofeUtpr7UvQ/lIK/sKUF8dg==" }, "node_modules/locate-path": { "version": "6.0.0", @@ -4877,87 +5295,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/log-symbols/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/log-symbols/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/log-symbols/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/log-symbols/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/log-symbols/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/log-symbols/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/log4js": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.4.1.tgz", - "integrity": "sha512-iUiYnXqAmNKiIZ1XSAitQ4TmNs8CdZYTAWINARF3LjnsLN8tY5m0vRwd6uuWj/yNY0YHxeZodnbmxKFUOM2rMg==", + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.9.1.tgz", + "integrity": "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==", "dev": true, "dependencies": { - "date-format": "^4.0.3", - "debug": "^4.3.3", - "flatted": "^3.2.4", + "date-format": "^4.0.14", + "debug": "^4.3.4", + "flatted": "^3.2.7", "rfdc": "^1.3.0", - "streamroller": "^3.0.2" + "streamroller": "^3.1.5" }, "engines": { "node": ">=8.0" @@ -4969,6 +5317,15 @@ "integrity": "sha512-gKO5uExCXvSm6zbF562EvM+rd1kQDnB9AZBbiQVzf1ZmdDpxUSvpnAaVOP83N/31mRK8Ml8/VE8DMvsAZQ+7wg==", "dev": true }, + "node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.1" + } + }, "node_modules/lower-case": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", @@ -4987,12 +5344,15 @@ } }, "node_modules/magic-string": { - "version": "0.25.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", - "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", + "version": "0.30.8", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", + "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==", "dev": true, "dependencies": { - "sourcemap-codec": "^1.4.4" + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" } }, "node_modules/make-error": { @@ -5004,18 +5364,12 @@ "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", "dev": true, "engines": { "node": ">= 0.6" } }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -5028,19 +5382,19 @@ "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", "engines": { "node": ">= 0.6" } }, "node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" + "braces": "^3.0.2", + "picomatch": "^2.3.1" }, "engines": { "node": ">=8.6" @@ -5058,58 +5412,64 @@ } }, "node_modules/mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dependencies": { - "mime-db": "1.51.0" + "mime-db": "1.52.0" }, "engines": { "node": ">= 0.6" } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "dependencies": { - "minimist": "^1.2.5" + "minimist": "^1.2.6" }, "bin": { "mkdirp": "bin/cmd.js" } }, "node_modules/mocha": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.1.tgz", - "integrity": "sha512-T7uscqjJVS46Pq1XDXyo9Uvey9gd3huT/DD9cYBb4K2Xc/vbKRPUWK067bxDQRK0yIz6Jxk73IrnimvASzBNAQ==", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz", + "integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==", "dev": true, "dependencies": { "@ungap/promise-all-settled": "1.1.2", @@ -5125,9 +5485,9 @@ "he": "1.2.0", "js-yaml": "4.1.0", "log-symbols": "4.1.0", - "minimatch": "3.0.4", + "minimatch": "4.2.1", "ms": "2.1.3", - "nanoid": "3.2.0", + "nanoid": "3.3.1", "serialize-javascript": "6.0.0", "strip-json-comments": "3.1.1", "supports-color": "8.1.1", @@ -5170,6 +5530,43 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, + "node_modules/mocha/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/mocha/node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, "node_modules/mocha/node_modules/cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -5199,6 +5596,29 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/mocha/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/mocha/node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, "node_modules/mocha/node_modules/diff": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", @@ -5220,13 +5640,48 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mocha/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/mocha/node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, "engines": { - "node": ">=8" + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/mocha/node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" } }, "node_modules/mocha/node_modules/js-yaml": { @@ -5242,15 +5697,15 @@ } }, "node_modules/mocha/node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", + "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, "engines": { - "node": "*" + "node": ">=10" } }, "node_modules/mocha/node_modules/ms": { @@ -5283,21 +5738,6 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/mocha/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/mocha/node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -5359,9 +5799,9 @@ } }, "node_modules/nanoid": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", - "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", + "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", "dev": true, "bin": { "nanoid": "bin/nanoid.cjs" @@ -5373,7 +5813,7 @@ "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, "node_modules/negotiator": { @@ -5394,9 +5834,9 @@ } }, "node_modules/next-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", "dev": true }, "node_modules/nise": { @@ -5461,32 +5901,47 @@ } }, "node_modules/nock/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, "bin": { "semver": "bin/semver" } }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "engines": { + "node": ">=10.5.0" + } + }, "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dev": true, + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", "dependencies": { - "whatwg-url": "^5.0.0" + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" }, "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" } }, "node_modules/normalize-path": { @@ -5510,7 +5965,7 @@ "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "dev": true, "engines": { "node": ">=0.10.0" @@ -5525,13 +5980,13 @@ } }, "node_modules/object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" }, "engines": { "node": ">= 0.4" @@ -5550,9 +6005,9 @@ } }, "node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dev": true, "dependencies": { "ee-first": "1.1.1" @@ -5564,11 +6019,28 @@ "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dependencies": { "wrappy": "1" } }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -5599,6 +6071,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/pac-proxy-agent": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.1.tgz", @@ -5617,29 +6098,12 @@ "node": ">= 14" } }, - "node_modules/pac-proxy-agent/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/pac-resolver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.0.tgz", - "integrity": "sha512-Fd9lT9vJbHYRACT8OhCbZBbxr6KRSawSovFpy8nDGshaK99S/EBhVIHp9+crhxrsZOuvLpgL1n23iyPg6Rl2hg==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", "dependencies": { "degenerator": "^5.0.0", - "ip": "^1.1.8", "netmask": "^2.0.2" }, "engines": { @@ -5649,7 +6113,7 @@ "node_modules/pad-right": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/pad-right/-/pad-right-0.2.2.tgz", - "integrity": "sha1-b7ySQEXSRPKiokRQMGDTv8YAl3Q=", + "integrity": "sha512-4cy8M95ioIGolCoMmm2cMntGR1lPLEbOMzOKu8bzjuJP6JpzEMQcDHmh7hHLYGgob+nKe1YHFMaG4V59HQa89g==", "dev": true, "dependencies": { "repeat-string": "^1.5.2" @@ -5703,7 +6167,7 @@ "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, "engines": { "node": ">=0.10.0" @@ -5736,7 +6200,7 @@ "node_modules/path-to-regexp/node_modules/isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", "dev": true }, "node_modules/path-type": { @@ -5760,19 +6224,19 @@ "node_modules/pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", "dev": true }, "node_modules/performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", "dev": true }, "node_modules/phantomjs-prebuilt": { "version": "2.1.16", "resolved": "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.16.tgz", - "integrity": "sha1-79ISpKOWbTZHaE6ouniFSb4q7+8=", + "integrity": "sha512-PIiRzBhW85xco2fuj41FmsyuYHKjKuXWmhjy3A/Y+CMpN/63TV+s9uzfVhsUwFe0G77xWtHBG8xmXf5BqEUEuQ==", "deprecated": "this package is now deprecated", "dev": true, "hasInstallScript": true, @@ -5794,12 +6258,30 @@ "node_modules/phantomjs-prebuilt/node_modules/progress": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", - "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", + "integrity": "sha512-UdA8mJ4weIkUBO224tIarHzuHs4HuYiJvsuGT7j/SPQiUJVjYvNDBIPa0hAorduOfjGohB/qHWRa/lrrWX/mXw==", "dev": true, "engines": { "node": ">=0.4.0" } }, + "node_modules/phantomjs-prebuilt/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -5815,7 +6297,7 @@ "node_modules/pinkie": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", "dev": true, "engines": { "node": ">=0.10.0" @@ -5824,7 +6306,7 @@ "node_modules/pinkie-promise": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", "dev": true, "dependencies": { "pinkie": "^2.0.0" @@ -5833,16 +6315,28 @@ "node": ">=0.10.0" } }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/prettier": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", - "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", "dev": true, "bin": { - "prettier": "bin-prettier.js" + "prettier": "bin/prettier.cjs" }, "engines": { - "node": ">=10.13.0" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, "node_modules/prettier-linter-helpers": { @@ -5858,37 +6352,19 @@ } }, "node_modules/pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, "dependencies": { - "ansi-regex": "^5.0.1", + "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" + "react-is": "^18.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/pretty-format/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -5907,21 +6383,21 @@ "node_modules/propagate": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/propagate/-/propagate-1.0.0.tgz", - "integrity": "sha1-AMLa7t2iDofjeCs0Stuhzd1q1wk=", + "integrity": "sha512-T/rqCJJaIPYObiLSmaDsIf4PGA7y+pkgYFHmwoXQyOHiDDSO1YCxcztNiRBmV4EZha4QIbID3vQIHkqKu5k0Xg==", "dev": true, "engines": [ "node >= 0.8.1" ] }, "node_modules/proxy-agent": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.1.tgz", - "integrity": "sha512-Rb5RVBy1iyqOtNl15Cw/llpeLH8bsb37gM1FUfKQ+Wck6xHlbAhWGUFiTRHtkjqGTA5pSHz6+0hrPW/oECihPQ==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.4.0.tgz", + "integrity": "sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==", "dependencies": { "agent-base": "^7.0.2", "debug": "^4.3.4", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.2", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.3", "lru-cache": "^7.14.1", "pac-proxy-agent": "^7.0.1", "proxy-from-env": "^1.1.0", @@ -5931,37 +6407,21 @@ "node": ">= 14" } }, - "node_modules/proxy-agent/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, "node_modules/psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", "dev": true }, "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "engines": { "node": ">=6" @@ -5977,10 +6437,12 @@ } }, "node_modules/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==", - "dev": true, + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, "engines": { "node": ">=0.6" }, @@ -6008,10 +6470,10 @@ } ] }, - "node_modules/ramda": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.2.tgz", - "integrity": "sha512-SbiLPU40JuJniHexQSAgad32hfwd+DRUdwF2PlVuI5RZD0/vahUco7R8vD86J/tcEKKF9vZrUVwgtmGCqlCKyA==", + "node_modules/rambda": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/rambda/-/rambda-7.5.0.tgz", + "integrity": "sha512-y/M9weqWAH4iopRd7EHDEQQvpFPHj1AA3oHozE9tfITHUtTR7Z9PSlIRRG2l1GuW7sefC1cXFfIcF+cgnShdBA==", "dev": true }, "node_modules/randombytes": { @@ -6033,13 +6495,13 @@ } }, "node_modules/raw-body": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz", - "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dev": true, "dependencies": { "bytes": "3.1.2", - "http-errors": "1.8.1", + "http-errors": "2.0.0", "iconv-lite": "0.4.24", "unpipe": "1.0.0" }, @@ -6047,10 +6509,16 @@ "node": ">= 0.8" } }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, "node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, "dependencies": { "core-util-is": "~1.0.0", @@ -6075,15 +6543,16 @@ } }, "node_modules/reflect-metadata": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", - "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", - "dev": true + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.1.tgz", + "integrity": "sha512-i5lLI6iw9AU3Uu4szRNPPEkomnkjRTaVt9hy/bn5g/oSzekBSMeLZblcjP74AW0vBabqERLLIrz+gR8QYR54Tw==", + "dev": true, + "peer": true }, "node_modules/regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", "dev": true, "peer": true }, @@ -6097,22 +6566,24 @@ } }, "node_modules/regexp-tree": { - "version": "0.1.24", - "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.24.tgz", - "integrity": "sha512-s2aEVuLhvnVJW6s/iPgEGK6R+/xngd2jNQ+xy4bXNDKxZKJH6jpPHY6kVeVv1IeLCHgswRj+Kl3ELaDjG6V1iw==", + "version": "0.1.27", + "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz", + "integrity": "sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==", "dev": true, "bin": { "regexp-tree": "bin/regexp-tree" } }, "node_modules/regexp.prototype.flags": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz", - "integrity": "sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" }, "engines": { "node": ">= 0.4" @@ -6121,22 +6592,10 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, "node_modules/repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", "dev": true, "engines": { "node": ">=0.10" @@ -6177,12 +6636,26 @@ "node_modules/request-progress": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-2.0.1.tgz", - "integrity": "sha1-XTa7V5YcZzqlt4jbyBQf3yO0Tgg=", + "integrity": "sha512-dxdraeZVUNEn9AvLrxkgB2k6buTlym71dJk1fk4v8j3Ou3RKNm07BcgbHdj2lLgYGfqX71F+awb1MR+tWPFJzA==", "dev": true, "dependencies": { "throttleit": "^1.0.0" } }, + "node_modules/request/node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, "node_modules/request/node_modules/qs": { "version": "6.5.3", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", @@ -6205,7 +6678,7 @@ "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, "engines": { "node": ">=0.10.0" @@ -6220,16 +6693,16 @@ "node_modules/requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", "dev": true }, "node_modules/resolve": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", - "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, "dependencies": { - "is-core-module": "^2.8.1", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -6281,9 +6754,9 @@ } }, "node_modules/rfdc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", - "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.1.tgz", + "integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==", "dev": true }, "node_modules/rimraf": { @@ -6302,24 +6775,43 @@ } }, "node_modules/rollup": { - "version": "2.68.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.68.0.tgz", - "integrity": "sha512-XrMKOYK7oQcTio4wyTz466mucnd8LzkiZLozZ4Rz0zQD+HeX4nUK4B8GrTX/2EvN2/vBF/i2WnaXboPxo0JylA==", + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.2.tgz", + "integrity": "sha512-MIlLgsdMprDBXC+4hsPgzWUasLO9CE4zOkj/u6j+Z6j5A4zRY+CtiXAdJyPtgCsc42g658Aeh1DlrdVEJhsL2g==", "dev": true, + "dependencies": { + "@types/estree": "1.0.5" + }, "bin": { "rollup": "dist/bin/rollup" }, "engines": { - "node": ">=10.0.0" + "node": ">=18.0.0", + "npm": ">=8.0.0" }, "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.13.2", + "@rollup/rollup-android-arm64": "4.13.2", + "@rollup/rollup-darwin-arm64": "4.13.2", + "@rollup/rollup-darwin-x64": "4.13.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.13.2", + "@rollup/rollup-linux-arm64-gnu": "4.13.2", + "@rollup/rollup-linux-arm64-musl": "4.13.2", + "@rollup/rollup-linux-powerpc64le-gnu": "4.13.2", + "@rollup/rollup-linux-riscv64-gnu": "4.13.2", + "@rollup/rollup-linux-s390x-gnu": "4.13.2", + "@rollup/rollup-linux-x64-gnu": "4.13.2", + "@rollup/rollup-linux-x64-musl": "4.13.2", + "@rollup/rollup-win32-arm64-msvc": "4.13.2", + "@rollup/rollup-win32-ia32-msvc": "4.13.2", + "@rollup/rollup-win32-x64-msvc": "4.13.2", "fsevents": "~2.3.2" } }, "node_modules/rollup-plugin-gzip": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/rollup-plugin-gzip/-/rollup-plugin-gzip-3.0.1.tgz", - "integrity": "sha512-yzyrbe5cn/3yTqtGpVb+0kQXiqKLZpNpRTGpItc11b8c9IhawpjZPPLMkh1Q7gl6UsHIVjcw9LeEdvom9H3klw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-gzip/-/rollup-plugin-gzip-3.1.2.tgz", + "integrity": "sha512-9xemMyvCjkklgNpu6jCYqQAbvCLJzA2nilkiOGzFuXTUX3cXEFMwIhsIBRF7kTKD/SnZ1tNPcxFm4m4zJ3VfNQ==", "dev": true, "engines": { "node": ">=10.0.0" @@ -6328,21 +6820,30 @@ "rollup": ">=2.0.0" } }, - "node_modules/rollup-plugin-terser": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", - "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", + "node_modules/rollup-plugin-string": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-string/-/rollup-plugin-string-3.0.0.tgz", + "integrity": "sha512-vqyzgn9QefAgeKi+Y4A7jETeIAU1zQmS6VotH6bzm/zmUQEnYkpIGRaOBPY41oiWYV4JyBoGAaBjYMYuv+6wVw==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.10.4", - "jest-worker": "^26.2.1", - "serialize-javascript": "^4.0.0", - "terser": "^5.0.0" - }, - "peerDependencies": { - "rollup": "^2.0.0" + "rollup-pluginutils": "^2.4.1" + } + }, + "node_modules/rollup-pluginutils": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", + "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", + "dev": true, + "dependencies": { + "estree-walker": "^0.6.1" } }, + "node_modules/rollup-pluginutils/node_modules/estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "dev": true + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -6381,13 +6882,13 @@ "node_modules/seed-random": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/seed-random/-/seed-random-2.2.0.tgz", - "integrity": "sha1-KpsZ4lCoFwmSMaW5mk2vgLf77VQ=", + "integrity": "sha512-34EQV6AAHQGhoc0tn/96a9Fsi6v2xdqe/dMUwljGRaFOzR3EgRmECvD0O8vi8X+/uQ50LGHfkNu/Eue5TPKZkQ==", "dev": true }, "node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -6409,11 +6910,6 @@ "node": ">=10" } }, - "node_modules/semver/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "node_modules/serialize-error": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-4.1.0.tgz", @@ -6438,9 +6934,9 @@ } }, "node_modules/serialize-javascript": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", - "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, "dependencies": { "randombytes": "^2.1.0" @@ -6449,9 +6945,40 @@ "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", "dev": true }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -6480,13 +7007,17 @@ } }, "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -6496,6 +7027,7 @@ "version": "7.5.0", "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.5.0.tgz", "integrity": "sha512-AoD0oJWerp0/rY9czP/D6hDTTUYGpObhZjMpd7Cl/A6+j0xBE+ayL/ldfggkBXUs0IkvIiM1ljM8+WkOc5k78Q==", + "deprecated": "16.1.1", "dev": true, "dependencies": { "@sinonjs/commons": "^1.4.0", @@ -6526,6 +7058,27 @@ "node": ">=0.3.1" } }, + "node_modules/sinon/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/sinon/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -6544,17 +7097,23 @@ "npm": ">= 3.0.0" } }, + "node_modules/smob": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/smob/-/smob-1.4.1.tgz", + "integrity": "sha512-9LK+E7Hv5R9u4g4C3p+jjLstaLe11MDsL21UpYaCNmapvMkYhqCV4A/f/3gyH8QjMyh6l68q9xC85vihY9ahMQ==", + "dev": true + }, "node_modules/socket.io": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.4.1.tgz", - "integrity": "sha512-Si18v0mMXGAqLqCVpTxBa8MGqriHGQh8ccEOhmsmNS3thNCGBwO8WGrwMibANsWtQQ5NStdZwHqZR3naJVFc3w==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.5.0.tgz", + "integrity": "sha512-gGunfS0od3VpwDBpGwVkzSZx6Aqo9uOcf1afJj2cKnKFAoyl16fvhpsUhmUFd4Ldbvl5JvRQed6eQw6oQp6n8w==", "dev": true, "dependencies": { "debug": "~4.1.0", - "engine.io": "~3.5.0", + "engine.io": "~3.6.0", "has-binary2": "~1.0.2", "socket.io-adapter": "~1.1.0", - "socket.io-client": "2.4.0", + "socket.io-client": "2.5.0", "socket.io-parser": "~3.4.0" } }, @@ -6565,9 +7124,9 @@ "dev": true }, "node_modules/socket.io-client": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.4.0.tgz", - "integrity": "sha512-M6xhnKQHuuZd4Ba9vltCLT9oa+YvTsP8j9NcEiLElfIg8KeYPyhWOes6x4t+LTAC8enQbE/995AdTem2uNyKKQ==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.5.0.tgz", + "integrity": "sha512-lOO9clmdgssDykiOmVQQitwBAF3I6mYcQAo7hQ7AM6Ny5X7fp8hIJ3HcQs3Rjz4SoggoxA1OgrQyY8EgTbcPYw==", "dev": true, "dependencies": { "backo2": "1.0.2", @@ -6595,19 +7154,19 @@ "node_modules/socket.io-client/node_modules/isarray": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", - "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "integrity": "sha512-c2cu3UxbI+b6kR3fy0nRnAhodsvR9dx7U5+znCOzdj6IfP3upFURTr0Xl5BlQZNKZjEtxrmVyfSdeE3O57smoQ==", "dev": true }, "node_modules/socket.io-client/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, "node_modules/socket.io-client/node_modules/socket.io-parser": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.2.tgz", - "integrity": "sha512-FJvDBuOALxdCI9qwRrO/Rfp9yfndRtc1jSgVgV8FDraihmSP/MLGD5PEuJrNfjALvcQ+vMDM/33AWOYP/JSjDg==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.3.tgz", + "integrity": "sha512-qOg87q1PMWWTeO01768Yh9ogn7chB9zkKtQnya41Y355S0UmpXgpcrFwAgjYJxu9BdKug5r5e9YtVSeWhKBUZg==", "dev": true, "dependencies": { "component-emitter": "~1.3.0", @@ -6616,20 +7175,23 @@ } }, "node_modules/socket.io-parser": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.4.1.tgz", - "integrity": "sha512-11hMgzL+WCLWf1uFtHSNvliI++tcRUWdoeYuwIl+Axvwy9z2gQM+7nJyN3STj1tLj5JyIUH8/gpDGxzAlDdi0A==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.4.3.tgz", + "integrity": "sha512-1rE4dZN3kCI/E5wixd393hmbqa78vVpkKmnEJhLeWoS/C5hbFYAbcSfnWoaVH43u9ToUVtzKjguxEZq+1XZfCQ==", "dev": true, "dependencies": { "component-emitter": "1.2.1", "debug": "~4.1.0", "isarray": "2.0.1" + }, + "engines": { + "node": ">=10.0.0" } }, "node_modules/socket.io-parser/node_modules/component-emitter": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "integrity": "sha512-jPatnhd33viNplKjqXKRkGU345p263OIWzDL2wH3LGIGp5Kojo+uXizHmOADRvhGFFTnJqX3jBAKP6vvmSDKcA==", "dev": true }, "node_modules/socket.io-parser/node_modules/debug": { @@ -6645,7 +7207,7 @@ "node_modules/socket.io-parser/node_modules/isarray": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", - "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "integrity": "sha512-c2cu3UxbI+b6kR3fy0nRnAhodsvR9dx7U5+znCOzdj6IfP3upFURTr0Xl5BlQZNKZjEtxrmVyfSdeE3O57smoQ==", "dev": true }, "node_modules/socket.io/node_modules/debug": { @@ -6659,15 +7221,15 @@ } }, "node_modules/socks": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", - "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.1.tgz", + "integrity": "sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ==", "dependencies": { - "ip": "^2.0.0", + "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" }, "engines": { - "node": ">= 10.13.0", + "node": ">= 10.0.0", "npm": ">= 3.0.0" } }, @@ -6679,32 +7241,11 @@ "agent-base": "^7.0.2", "debug": "^4.3.4", "socks": "^2.7.1" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/socks-proxy-agent/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + }, + "engines": { + "node": ">= 14" } }, - "node_modules/socks/node_modules/ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" - }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -6724,22 +7265,16 @@ "source-map": "^0.6.0" } }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "dev": true - }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, "node_modules/sshpk": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", + "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", "dev": true, "dependencies": { "asn1": "~0.2.3", @@ -6761,6 +7296,12 @@ "node": ">=0.10.0" } }, + "node_modules/sshpk/node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "dev": true + }, "node_modules/stack-chain": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/stack-chain/-/stack-chain-2.0.0.tgz", @@ -6768,18 +7309,18 @@ "dev": true }, "node_modules/stack-generator": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/stack-generator/-/stack-generator-2.0.5.tgz", - "integrity": "sha512-/t1ebrbHkrLrDuNMdeAcsvynWgoH/i4o8EGGfX7dEYDoTXOYVAkEpFdtshlvabzc6JlJ8Kf9YdFEoz7JkzGN9Q==", + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/stack-generator/-/stack-generator-2.0.10.tgz", + "integrity": "sha512-mwnua/hkqM6pF4k8SnmZ2zfETsRUpWXREfA/goT8SLCV4iOFa4bzOX2nDipWAZFPTjLvQB82f5yaodMVhK0yJQ==", "dev": true, "dependencies": { - "stackframe": "^1.1.1" + "stackframe": "^1.3.4" } }, "node_modules/stack-utils": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", - "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", "dev": true, "dependencies": { "escape-string-regexp": "^2.0.0" @@ -6788,15 +7329,6 @@ "node": ">=10" } }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/stackframe": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", @@ -6804,19 +7336,19 @@ "dev": true }, "node_modules/stacktrace-gps": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/stacktrace-gps/-/stacktrace-gps-3.0.4.tgz", - "integrity": "sha512-qIr8x41yZVSldqdqe6jciXEaSCKw1U8XTXpjDuy0ki/apyTn/r3w9hDAAQOhZdxvsC93H+WwwEu5cq5VemzYeg==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/stacktrace-gps/-/stacktrace-gps-3.1.2.tgz", + "integrity": "sha512-GcUgbO4Jsqqg6RxfyTHFiPxdPqF+3LFmQhm7MgCuYQOYuWyqxo5pwRPz5d/u6/WYJdEnWfK4r+jGbyD8TSggXQ==", "dev": true, "dependencies": { "source-map": "0.5.6", - "stackframe": "^1.1.1" + "stackframe": "^1.3.4" } }, "node_modules/stacktrace-gps/node_modules/source-map": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", - "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=", + "integrity": "sha512-MjZkVp0NHr5+TPihLcadqnlVoGIoWo4IBHptutGh9wI3ttUYvCG26HkSuDi+K6lsZ25syXJXcctwgyVCt//xqA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -6836,59 +7368,56 @@ "node_modules/statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "dev": true, "engines": { "node": ">= 0.6" } }, "node_modules/streamroller": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.0.2.tgz", - "integrity": "sha512-ur6y5S5dopOaRXBuRIZ1u6GC5bcEXHRZKgfBjfCglMhmIf+roVCECjvkEYzNQOXIN2/JPnkMPW/8B3CZoKaEPA==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz", + "integrity": "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==", "dev": true, "dependencies": { - "date-format": "^4.0.3", - "debug": "^4.1.1", - "fs-extra": "^10.0.0" + "date-format": "^4.0.14", + "debug": "^4.3.4", + "fs-extra": "^8.1.0" }, "engines": { "node": ">=8.0" } }, "node_modules/streamroller/node_modules/fs-extra": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz", - "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", "dev": true, "dependencies": { "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" }, "engines": { - "node": ">=12" + "node": ">=6 <7 || >=8" } }, "node_modules/streamroller/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", "dev": true, - "dependencies": { - "universalify": "^2.0.0" - }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "node_modules/streamroller/node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true, "engines": { - "node": ">= 10.0.0" + "node": ">= 4.0.0" } }, "node_modules/string_decoder": { @@ -6901,9 +7430,9 @@ } }, "node_modules/string-argv": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", - "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==", + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", "dev": true, "engines": { "node": ">=0.6.19" @@ -6923,12 +7452,6 @@ "node": ">=8" } }, - "node_modules/string-width/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -6944,7 +7467,7 @@ "node_modules/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, "optional": true, "engines": { @@ -6983,59 +7506,16 @@ "node": ">=6.4.0 <13 || >=14" } }, - "node_modules/superagent/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/superagent/node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/superagent/node_modules/qs": { - "version": "6.11.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", - "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/supports-preserve-symlinks-flag": { @@ -7050,15 +7530,31 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/synckit": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", + "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", + "dev": true, + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, "node_modules/terser": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.11.0.tgz", - "integrity": "sha512-uCA9DLanzzWSsN1UirKwylhhRz3aKPInlfmpGfw8VN6jHsAtu8HJtIpeeHHK23rxnE/cDc+yvmq5wqkIC6Kn0A==", + "version": "5.30.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.30.0.tgz", + "integrity": "sha512-Y/SblUl5kEyEFzhMAQdsxVHh+utAxd4IuRNJzKywY/4uzSogh3G219jqbDDxYu4MXO9CzY3tSEqmZvW6AoEDJw==", "dev": true, "dependencies": { - "acorn": "^8.5.0", + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", "commander": "^2.20.0", - "source-map": "~0.7.2", "source-map-support": "~0.5.20" }, "bin": { @@ -7074,19 +7570,10 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true }, - "node_modules/terser/node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, "node_modules/thenify": { @@ -7101,7 +7588,7 @@ "node_modules/thenify-all": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", "dev": true, "dependencies": { "thenify": ">= 3.1.0 < 4" @@ -7111,10 +7598,13 @@ } }, "node_modules/throttleit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", - "integrity": "sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=", - "dev": true + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.1.tgz", + "integrity": "sha512-vDZpf9Chs9mAdfY046mcPt8fg5QSZr37hEH4TXYBnDF+izxgrbRGUAAaBvIk/fJm9aOFCGFd1EsNg5AZCbnQCQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/title-case": { "version": "2.1.1", @@ -7145,21 +7635,18 @@ } }, "node_modules/tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", "dev": true, - "dependencies": { - "rimraf": "^3.0.0" - }, "engines": { - "node": ">=8.17.0" + "node": ">=14.14" } }, "node_modules/to-array": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", - "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=", + "integrity": "sha512-LhVdShQD/4Mk4zXNroIQZJC+Ap3zgLcDuwEdcmLv9CCO73NWockQDwyUnW/m8VX/EElfL6FcYx7EeutN4HJA6A==", "dev": true }, "node_modules/to-regex-range": { @@ -7196,11 +7683,17 @@ "node": ">=0.8" } }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", - "dev": true + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } }, "node_modules/ts-dedent": { "version": "2.2.0", @@ -7266,16 +7759,16 @@ "node_modules/ts-mocha/node_modules/yn": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", - "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=", + "integrity": "sha512-uTv8J/wiWTgUTg+9vLTi//leUl5vDQS6uii/emeTb2ssY7vl6QWf2fFbIIGjnhjvbdKlU0ed7QPgY1htTC86jQ==", "dev": true, "engines": { "node": ">=4" } }, "node_modules/ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", @@ -7316,61 +7809,27 @@ } }, "node_modules/tsconfig-paths": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz", - "integrity": "sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg==", + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", "dev": true, "optional": true, "dependencies": { "@types/json5": "^0.0.29", - "json5": "^1.0.1", - "minimist": "^1.2.0", + "json5": "^1.0.2", + "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, - "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "optional": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, "node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, - "node_modules/tsutils/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "dev": true, "dependencies": { "safe-buffer": "^5.0.1" @@ -7382,15 +7841,27 @@ "node_modules/tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", "dev": true }, "node_modules/type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==", "dev": true }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", @@ -7428,20 +7899,20 @@ "node_modules/typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", "dev": true }, "node_modules/typescript": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", - "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.3.tgz", + "integrity": "sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==", "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" } }, "node_modules/ua-parser-js": { @@ -7454,23 +7925,29 @@ } }, "node_modules/underscore": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.2.tgz", - "integrity": "sha512-ekY1NhRzq0B08g4bGuX4wd2jZx5GnKz6mKSqFL4nqBlfyMGiG10gDFhDTMEfYmDL6Jy0FUIZp7wiRB+0BP7J2g==", + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", + "dev": true + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "dev": true }, "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "engines": { - "node": ">= 4.0.0" + "node": ">= 10.0.0" } }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "dev": true, "engines": { "node": ">= 0.8" @@ -7504,29 +7981,33 @@ "node_modules/util-arity": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/util-arity/-/util-arity-1.1.0.tgz", - "integrity": "sha1-WdAa8f2z/t4KxOYysKtfbOl8kzA=", + "integrity": "sha512-kkyIsXKwemfSy8ZEoaIz06ApApnWsk5hQO0vLjZS6UkBiGiW++Jsyb8vSBoc0WKlffGoGs5yYy/j5pp8zckrFA==", "dev": true }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", "dev": true, "engines": { "node": ">= 0.4.0" } }, "node_modules/uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], "peer": true, "bin": { "uuid": "dist/bin/uuid" @@ -7555,61 +8036,47 @@ "node_modules/verror/node_modules/core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", "dev": true }, "node_modules/void-elements": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", - "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", + "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", "dev": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", - "dev": true - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", - "dev": true, - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "engines": { + "node": ">= 8" } }, "node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "dependencies": { "isexe": "^2.0.0" }, "bin": { - "which": "bin/which" + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" } }, "node_modules/which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", "dev": true }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/workerpool": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", @@ -7666,7 +8133,7 @@ "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/ws": { "version": "7.4.6", @@ -7698,12 +8165,27 @@ "node": ">=0.4.0" } }, + "node_modules/xregexp": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.4.1.tgz", + "integrity": "sha512-2u9HwfadaJaY9zHtRRnH6BY6CQVNQKkYm3oLtC9gJXXzfsbACg5X5e4EZZGVAH+YIfa+QA9lsFQTTe3HURF3ag==", + "dev": true, + "peer": true, + "dependencies": { + "@babel/runtime-corejs3": "^7.12.1" + } + }, "node_modules/y18n": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", "dev": true }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "node_modules/yargs": { "version": "15.4.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", @@ -7750,18 +8232,6 @@ "node": ">=10" } }, - "node_modules/yargs-unparser/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/yargs-unparser/node_modules/decamelize": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", @@ -7774,6 +8244,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/yargs/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/yargs/node_modules/find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -7826,15 +8305,6 @@ "node": ">=8" } }, - "node_modules/yargs/node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/yargs/node_modules/yargs-parser": { "version": "18.1.3", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", @@ -7851,7 +8321,7 @@ "node_modules/yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", "dev": true, "dependencies": { "buffer-crc32": "~0.2.3", @@ -7861,7 +8331,7 @@ "node_modules/yeast": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", - "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=", + "integrity": "sha512-8HFIh676uyGYP6wP13R/j6OJ/1HwJ46snpvzE7aHAN3Ryqh2yX6Xox2B4CUmTwwOIzlG3Bs7ocsP5dZH/R1Qbg==", "dev": true }, "node_modules/yn": { diff --git a/package.json b/package.json index 93692af52..7306b8cb9 100644 --- a/package.json +++ b/package.json @@ -5,18 +5,18 @@ "description": "Publish & Subscribe Real-time Messaging with PubNub", "scripts": { "build": "npm run build:node && npm run build:web", - "build:web": "rollup -c rollup.config.js", + "build:web": "rollup -c rollup.config.js --bundleConfigAsCjs", "build:node": "tsc -p tsconfig.json", "test": "npm run test:web && npm run test:node", "test:web": "karma start ./karma/web.config.js", "test:node": "ts-mocha -p tsconfig.mocha.json --config .mocharc.yml", "clean": "rimraf lib dist upload", - "lint": "eslint \"src/**/*\" --config .eslintrc.js", + "lint": "eslint \"src/**/*\" --config .eslintrc.cjs", "ci": "npm run clean && npm run build && npm run lint && npm run test", "ci:web": "npm run clean && npm run build && npm run lint && npm run test:web", "ci:node": "npm run clean && npm run build && npm run lint && npm run test:node", - "test:feature:objectsv2:node": "ts-mocha -p tsconfig.mocha.json --no-config --require test/setup.js --reporter spec test/dist/objectsv2.test.js", - "test:feature:fileupload:node": "ts-mocha -p tsconfig.mocha.json --no-config --require test/setup.js --reporter spec test/feature/file_upload.node.test.js", + "test:feature:objectsv2:node": "ts-mocha -p tsconfig.mocha.json --no-config --require test/setup.cjs --reporter spec test/dist/objectsv2.test.js", + "test:feature:fileupload:node": "ts-mocha -p tsconfig.mocha.json --no-config --require test/setup.cjs --reporter spec test/feature/file_upload.node.test.js", "test:contract": "npm run test:contract:prepare && npm run test:contract:start", "test:contract:prepare": "rimraf test/specs && git clone --branch master --depth 1 git@github.com:pubnub/sdk-specifications.git test/specs", "test:contract:start": "cucumber-js -p default --tags 'not @na=js'", @@ -35,6 +35,7 @@ "metro": "./lib/react_native/index.js", "nativescript": "./lib/nativescript/index.js", "browser": "./dist/web/pubnub.min.js", + "type": "module", "repository": { "type": "git", "url": "git://github.com/pubnub/javascript.git" @@ -55,35 +56,40 @@ "buffer": "^6.0.3", "cbor-js": "^0.1.0", "cbor-sync": "^1.0.4", + "form-data": "^4.0.0", "lil-uuid": "^0.1.1", + "node-fetch": "^3.3.2", "proxy-agent": "^6.3.0", "superagent": "^8.1.2" }, "devDependencies": { "@cucumber/cucumber": "^7.3.1", "@cucumber/pretty-formatter": "^1.0.0", - "@rollup/plugin-commonjs": "^21.0.2", - "@rollup/plugin-json": "^4.1.0", - "@rollup/plugin-node-resolve": "^13.1.3", - "@rollup/plugin-typescript": "^8.3.1", - "@types/chai": "^4.3.3", + "@rollup/plugin-commonjs": "^25.0.7", + "@rollup/plugin-json": "^6.1.0", + "@rollup/plugin-node-resolve": "^15.2.3", + "@rollup/plugin-replace": "^5.0.5", + "@rollup/plugin-terser": "^0.4.4", + "@rollup/plugin-typescript": "^11.1.6", + "@types/cbor-js": "^0.1.1", + "@types/chai": "^4.3.14", "@types/cucumber": "^7.0.0", "@types/expect": "^24.3.0", "@types/mocha": "^9.1.0", "@types/nock": "^9.3.1", - "@types/node-fetch": "^2.6.3", + "@types/node-fetch": "^2.6.11", "@types/pubnub": "^7.2.0", - "@typescript-eslint/eslint-plugin": "^5.12.1", - "@typescript-eslint/parser": "^5.12.1", - "chai": "^4.3.4", + "@typescript-eslint/eslint-plugin": "^7.4.0", + "@typescript-eslint/parser": "^7.4.0", + "chai": "^4.4.1", "chai-as-promised": "^7.1.1", "chai-nock": "^1.2.0", "cucumber-pretty": "^6.0.1", "cucumber-tsflow": "^4.0.0-rc.11", - "es6-shim": "^0.35.6", - "eslint": "^8.9.0", - "eslint-plugin-mocha": "^10.0.3", - "eslint-plugin-prettier": "^4.0.0", + "es6-shim": "^0.35.8", + "eslint": "^8.57.0", + "eslint-plugin-mocha": "^10.4.1", + "eslint-plugin-prettier": "^5.1.3", "js-yaml": "^3.13.1", "karma": "^5.0.3", "karma-chai": "^0.1.0", @@ -95,19 +101,18 @@ "karma-spec-reporter": "0.0.32", "mocha": "^9.2.1", "nock": "^9.6.1", - "node-fetch": "^2.7.0", "phantomjs-prebuilt": "^2.1.16", - "prettier": "^2.5.1", + "prettier": "^3.2.5", "rimraf": "^3.0.2", - "rollup": "^2.68.0", - "rollup-plugin-gzip": "^3.0.1", - "rollup-plugin-terser": "^7.0.2", + "rollup": "^4.13.2", + "rollup-plugin-gzip": "^3.1.2", + "rollup-plugin-string": "^3.0.0", "sinon": "^7.5.0", "sinon-chai": "^3.3.0", "source-map-support": "^0.5.21", "ts-mocha": "^9.0.2", - "ts-node": "^10.9.1", - "typescript": "^4.8.4", + "ts-node": "^10.9.2", + "typescript": "^5.4.3", "underscore": "^1.9.2" }, "license": "SEE LICENSE IN LICENSE", diff --git a/rollup.config.js b/rollup.config.js index 84d51aa69..84ac03ed9 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,16 +1,54 @@ -import { join, basename, dirname } from 'path'; +import { join, basename, dirname, resolve as pathResolve } from 'path'; +import ts from 'typescript'; +import fs from 'fs'; import typescript from '@rollup/plugin-typescript'; import commonjs from '@rollup/plugin-commonjs'; import resolve from '@rollup/plugin-node-resolve'; +import replace from '@rollup/plugin-replace'; import json from '@rollup/plugin-json'; -import { terser } from 'rollup-plugin-terser'; -import gzipPlugin from 'rollup-plugin-gzip'; +import terser from '@rollup/plugin-terser'; +const gzipPlugin = require('rollup-plugin-gzip').default; import { browser, version } from './package.json'; import tsConfig from './tsconfig.rollup.json'; +function injectWebWorker(webWorkerPath) { + let webWorkerCode = ''; + + return { + name: 'inject-web-worker', + buildStart() { + const sourcePath = pathResolve(webWorkerPath); + const workerContent = fs.readFileSync(sourcePath, 'utf8'); + const result = ts.transpileModule(workerContent, { + compilerOptions: { module: ts.ModuleKind.ESNext }, + }); + + webWorkerCode = JSON.stringify(result.outputText); + }, + transform(code, id) { + if (id.endsWith('.ts')) { + return { + code: code.replace('WEB_WORKER_PLACEHOLDER', () => webWorkerCode), + map: null, + }; + } + return null; + }, + }; +} + +const sourcePath = pathResolve('src/transport/web-worker.ts'); +const workerContent = fs.readFileSync(sourcePath, 'utf8'); +// const result = ts.transpileModule(workerContent, { +// compilerOptions: { module: ts.ModuleKind.ESNext }, +// }); +const result = ts.transpileModule(workerContent, tsConfig); + +const webWorkerCode = JSON.stringify(result.outputText); + export default [ { input: 'src/web/index.ts', @@ -28,7 +66,18 @@ export default [ format: 'umd', name: 'PubNub', }, - plugins: [json(), resolve({ browser: true }), commonjs(), typescript(tsConfig)], + plugins: [ + json(), + resolve({ browser: true }), + // Stringify Web Worker to register it from the Blob URL. + replace({ + WEB_WORKER_PLACEHOLDER: webWorkerCode, + preventAssignment: true, + }), + // injectWebWorker('src/transport/web-worker.ts'), + commonjs(), + typescript(tsConfig), + ], }, { input: 'src/web/index.ts', @@ -40,6 +89,12 @@ export default [ plugins: [ json(), resolve({ browser: true }), + // Stringify Web Worker to register it from the Blob URL. + replace({ + WEB_WORKER_PLACEHOLDER: webWorkerCode, + preventAssignment: true, + }), + // injectWebWorker('src/transport/web-worker.ts'), commonjs(), typescript(tsConfig), terser(), @@ -53,7 +108,19 @@ export default [ format: 'umd', name: 'PubNub', }, - plugins: [json(), resolve({ browser: true }), commonjs(), typescript(tsConfig), gzipPlugin({ fileName: '' })], + plugins: [ + json(), + resolve({ browser: true }), + // Stringify Web Worker to register it from the Blob URL. + replace({ + WEB_WORKER_PLACEHOLDER: webWorkerCode, + preventAssignment: true, + }), + // injectWebWorker('src/transport/web-worker.ts'), + commonjs(), + typescript(tsConfig), + gzipPlugin({ fileName: '' }), + ], }, { input: 'src/web/index.ts', @@ -62,7 +129,19 @@ export default [ format: 'umd', name: 'PubNub', }, - plugins: [json(), resolve({ browser: true }), commonjs(), typescript(tsConfig), terser()], + plugins: [ + json(), + resolve({ browser: true }), + // Stringify Web Worker to register it from the Blob URL. + replace({ + WEB_WORKER_PLACEHOLDER: webWorkerCode, + preventAssignment: true, + }), + // injectWebWorker('src/transport/web-worker.ts'), + commonjs(), + typescript(tsConfig), + terser(), + ], }, { input: 'src/web/index.ts', @@ -71,6 +150,17 @@ export default [ format: 'umd', name: 'PubNub', }, - plugins: [json(), resolve({ browser: true }), commonjs(), typescript(tsConfig)], + plugins: [ + json(), + resolve({ browser: true }), + // Stringify Web Worker to register it from the Blob URL. + replace({ + WEB_WORKER_PLACEHOLDER: webWorkerCode, + preventAssignment: true, + }), + // injectWebWorker('src/transport/web-worker.ts'), + commonjs(), + typescript(tsConfig), + ], }, ]; diff --git a/src/core/components/config.js b/src/core/components/config.js deleted file mode 100644 index 69bef414a..000000000 --- a/src/core/components/config.js +++ /dev/null @@ -1,386 +0,0 @@ -/* */ -/* global location */ - -import uuidGenerator from './uuid'; - -const PRESENCE_TIMEOUT_MINIMUM = 20; -const PRESENCE_TIMEOUT_DEFAULT = 300; - -const makeDefaultOrigins = () => Array.from({ length: 20 }, (_, i) => `ps${i + 1}.pndsn.com`); - -export default class { - subscribeKey; - publishKey; - secretKey; - cipherKey; - authKey; - UUID; - proxy; - - /* - if _useInstanceId is true, this instanceId will be added to all requests - */ - instanceId; - - /* - If the SDK is running as part of another SDK built atop of it, allow a custom pnsdk with name and version. - */ - sdkName; - - /* - keep track of the SDK family for identifier generator - */ - sdkFamily; - - /* - If the SDK is operated by a partner, allow a custom pnsdk item for them. - */ - partnerId; - - /* - filter expression to pass along when subscribing. - */ - filterExpression; - - /* - configuration to supress leave events; when a presence leave is performed - this configuration will disallow the leave event from happening - */ - suppressLeaveEvents; - - /* - use SSL for http requests? - */ - secure; - - // Custom optional origin. - origin; - - // log verbosity: true to output lots of info - logVerbosity; - - // if instanceId config is true, the SDK will pass the unique instance identifier to the server as instanceId= - useInstanceId; - - // if requestId config is true, the SDK will pass a unique request identifier with each request as request_id= - useRequestId; - - // use connection keep-alive for http requests - keepAlive; - - keepAliveSettings; - - // if autoNetworkDetection config is true, the SDK will emit NetworkUp and NetworkDown - // when there changes in the networking - autoNetworkDetection; - - // configure retry policy configuration. - retryConfiguration; - - // alert when a heartbeat works out. - announceSuccessfulHeartbeats; - - announceFailedHeartbeats; - - /* - how long the server will wait before declaring that the client is gone. - */ - _presenceTimeout; - - /* - how often (in seconds) the client should announce its presence to server - */ - _heartbeatInterval; - - /* - how long to wait for the server when running the subscribe loop - */ - _subscribeRequestTimeout; - - /* - how long to wait for the server when making transactional requests - */ - _transactionalRequestTimeout; - - /* - use send beacon API when unsubscribing. - https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon - */ - _useSendBeacon; - - /* - allow frameworks to append to the PNSDK parameter - the key should be an identifier for the specific framework to prevent duplicates - */ - _PNSDKSuffix; - - /* - if set, the SDK will alert if more messages arrive in one subscribe than the theshold - */ - requestMessageCountThreshold; - - /* - Restore subscription list on disconnection. - */ - restore; - - /* - support for client deduping - */ - dedupeOnSubscribe; - - maximumCacheSize; - - /* - support custom encryption and decryption functions. - */ - customEncrypt; // function to support custome encryption of messages - - customDecrypt; // function used to decrypt old version messages - - // File Upload - - // How many times the publish-file should be retried before giving up - fileUploadPublishRetryLimit; - useRandomIVs; - enableEventEngine; - maintainPresenceState; - - /* - set cryptoModule to encrypt/decrypt messages and files. - */ - cryptoModule; - - constructor({ setup }) { - this._PNSDKSuffix = {}; - - this.instanceId = `pn-${uuidGenerator.createUUID()}`; - this.secretKey = setup.secretKey || setup.secret_key; - this.subscribeKey = setup.subscribeKey || setup.subscribe_key; - this.publishKey = setup.publishKey || setup.publish_key; - this.sdkName = setup.sdkName; - this.sdkFamily = setup.sdkFamily; - this.partnerId = setup.partnerId; - this.setAuthKey(setup.authKey); - this.cryptoModule = setup.cryptoModule; - - this.setFilterExpression(setup.filterExpression); - - if (typeof setup.origin !== 'string' && !Array.isArray(setup.origin) && setup.origin !== undefined) { - throw new Error('Origin must be either undefined, a string or a list of strings.'); - } - - this.origin = setup.origin || makeDefaultOrigins(); - this.secure = setup.ssl || false; - this.restore = setup.restore || false; - this.proxy = setup.proxy; - this.keepAlive = setup.keepAlive; - this.keepAliveSettings = setup.keepAliveSettings; - this.autoNetworkDetection = setup.autoNetworkDetection || false; - - this.dedupeOnSubscribe = setup.dedupeOnSubscribe || false; - this.maximumCacheSize = setup.maximumCacheSize || 100; - - this.customEncrypt = setup.customEncrypt; - this.customDecrypt = setup.customDecrypt; - - this.fileUploadPublishRetryLimit = setup.fileUploadPublishRetryLimit ?? 5; - this.useRandomIVs = setup.useRandomIVs ?? true; - - this.enableEventEngine = setup.enableEventEngine ?? false; - this.maintainPresenceState = setup.maintainPresenceState ?? true; - - // if location config exist and we are in https, force secure to true. - if (typeof location !== 'undefined' && location.protocol === 'https:') { - this.secure = true; - } - - this.logVerbosity = setup.logVerbosity || false; - this.suppressLeaveEvents = setup.suppressLeaveEvents || false; - - this.announceFailedHeartbeats = setup.announceFailedHeartbeats || true; - this.announceSuccessfulHeartbeats = setup.announceSuccessfulHeartbeats || false; - - this.useInstanceId = setup.useInstanceId || false; - this.useRequestId = setup.useRequestId || false; - - this.requestMessageCountThreshold = setup.requestMessageCountThreshold; - - if (setup.retryConfiguration) { - this._setRetryConfiguration(setup.retryConfiguration); - } - - // set timeout to how long a transaction request will wait for the server (default 15 seconds) - this.setTransactionTimeout(setup.transactionalRequestTimeout || 15 * 1000); - // set timeout to how long a subscribe event loop will run (default 310 seconds) - this.setSubscribeTimeout(setup.subscribeRequestTimeout || 310 * 1000); - // set config on beacon (https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon) usage - this.setSendBeaconConfig(setup.useSendBeacon || true); - // how long the SDK will report the client to be alive before issuing a timeout - if (setup.presenceTimeout) { - this.setPresenceTimeout(setup.presenceTimeout); - } else { - this._presenceTimeout = PRESENCE_TIMEOUT_DEFAULT; - } - - if (setup.heartbeatInterval != null) { - this.setHeartbeatInterval(setup.heartbeatInterval); - } - - if (typeof setup.userId === 'string') { - if (typeof setup.uuid === 'string') { - throw new Error('Only one of the following configuration options has to be provided: `uuid` or `userId`'); - } - - this.setUserId(setup.userId); - } else { - if (typeof setup.uuid !== 'string') { - throw new Error('One of the following configuration options has to be provided: `uuid` or `userId`'); - } - - this.setUUID(setup.uuid); - } - this.setCipherKey(setup.cipherKey, setup); - } - - // exposed setters - getAuthKey() { - return this.authKey; - } - - setAuthKey(val) { - this.authKey = val; - return this; - } - - setCipherKey(val, setup, modules) { - this.cipherKey = val; - if (this.cipherKey) { - this.cryptoModule = - setup.cryptoModule ?? setup.initCryptoModule({ cipherKey: this.cipherKey, useRandomIVs: this.useRandomIVs }); - if (modules) modules.cryptoModule = this.cryptoModule; - } - return this; - } - - getUUID() { - return this.UUID; - } - - setUUID(val) { - if (!val || typeof val !== 'string' || val.trim().length === 0) { - throw new Error('Missing uuid parameter. Provide a valid string uuid'); - } - this.UUID = val; - return this; - } - - getUserId() { - return this.UUID; - } - - setUserId(value) { - if (!value || typeof value !== 'string' || value.trim().length === 0) { - throw new Error('Missing or invalid userId parameter. Provide a valid string userId'); - } - - this.UUID = value; - return this; - } - - getFilterExpression() { - return this.filterExpression; - } - - setFilterExpression(val) { - this.filterExpression = val; - return this; - } - - getPresenceTimeout() { - return this._presenceTimeout; - } - - setPresenceTimeout(val) { - if (val >= PRESENCE_TIMEOUT_MINIMUM) { - this._presenceTimeout = val; - } else { - this._presenceTimeout = PRESENCE_TIMEOUT_MINIMUM; - - // eslint-disable-next-line no-console - console.log('WARNING: Presence timeout is less than the minimum. Using minimum value: ', this._presenceTimeout); - } - - this.setHeartbeatInterval(this._presenceTimeout / 2 - 1); - - return this; - } - - setProxy(proxy) { - this.proxy = proxy; - } - - getHeartbeatInterval() { - return this._heartbeatInterval; - } - - setHeartbeatInterval(val) { - this._heartbeatInterval = val; - return this; - } - - // deprecated setters. - getSubscribeTimeout() { - return this._subscribeRequestTimeout; - } - - setSubscribeTimeout(val) { - this._subscribeRequestTimeout = val; - return this; - } - - getTransactionTimeout() { - return this._transactionalRequestTimeout; - } - - setTransactionTimeout(val) { - this._transactionalRequestTimeout = val; - return this; - } - - isSendBeaconEnabled() { - return this._useSendBeacon; - } - - setSendBeaconConfig(val) { - this._useSendBeacon = val; - return this; - } - - getVersion() { - return '7.6.0'; - } - - _setRetryConfiguration(configuration) { - if (configuration.minimumdelay < 2) { - throw new Error('Minimum delay can not be set less than 2 seconds for retry'); - } - if (configuration.maximumDelay > 150) { - throw new Error('Maximum delay can not be set more than 150 seconds for retry'); - } - if (configuration.maximumDelay && maximumRetry > 6) { - throw new Error('Maximum retry for exponential retry policy can not be more than 6'); - } else if (configuration.maximumRetry > 10) { - throw new Error('Maximum retry for linear retry policy can not be more than 10'); - } - this.retryConfiguration = configuration; - } - - _addPnsdkSuffix(name, suffix) { - this._PNSDKSuffix[name] = suffix; - } - - _getPnsdkSuffix(separator) { - return Object.keys(this._PNSDKSuffix).reduce((result, key) => result + separator + this._PNSDKSuffix[key], ''); - } -} diff --git a/src/core/components/configuration.ts b/src/core/components/configuration.ts new file mode 100644 index 000000000..540913bdf --- /dev/null +++ b/src/core/components/configuration.ts @@ -0,0 +1,210 @@ +/** + * {@link PubNub} client configuration module. + */ + +import { ExtendedConfiguration, PlatformConfiguration, PrivateClientConfiguration } from '../interfaces/configuration'; +import { CryptoModule, CryptorConfiguration } from '../interfaces/crypto-module'; +import { PubNubFileConstructor, PubNubFileInterface } from '../types/file'; +import uuidGenerator from './uuid'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Whether encryption (if set) should use random initialization vector or not. + */ +const USE_RANDOM_INITIALIZATION_VECTOR = true; +// endregion + +/** + * Crypto Module instance configuration function. + * + * Function will be used each time when `cipherKey` will be changed. + */ +type SetupCryptoModule = (configuration: CryptorConfiguration) => CryptoModule | undefined; + +/** + * Internal state of the {@link PrivateClientConfiguration} to store temporarily information. + */ +type PrivateConfigurationFields = { + /** + * Frameworks suffixes. + * + * Frameworks built atop of PubNub SDK can add key/value pairs which will be added to the + * `pnsdk` query parameter. + * @private + */ + _pnsdkSuffix: Record; + + /** + * Unique PubNub client instance identifier. + */ + _instanceId: string; + + /** + * Crypto Module configuration callback. + * + * Callback allow to setup Crypto Module in platform-independent way. + */ + _setupCryptoModule?: SetupCryptoModule; + + /** + * Configured crypto module. + */ + _cryptoModule?: CryptoModule; + + /** + * Currently used data encryption / decryption key. + */ + _cipherKey: string | undefined; +}; + +/** + * Create {@link PubNub} client private configuration object. + * + * @param base - User- and platform-provided configuration. + * @param setupCryptoModule - Platform-provided {@link CryptoModule} configuration block. + * + * @returns `PubNub` client private configuration. + */ +export const makeConfiguration = ( + base: ExtendedConfiguration & PlatformConfiguration, + setupCryptoModule?: SetupCryptoModule, +): PrivateClientConfiguration & PrivateConfigurationFields => { + // Ensure that retry policy has proper configuration (if has been set). + base.retryConfiguration?.validate(); + + base.useRandomIVs ??= USE_RANDOM_INITIALIZATION_VECTOR; + // Override origin value. + base.origin = standardOrigin(base.ssl ?? false, base.origin!); + + const clientConfiguration: PrivateClientConfiguration & PrivateConfigurationFields = { + ...base, + _pnsdkSuffix: {}, + _instanceId: `pn-${uuidGenerator.createUUID()}`, + _cryptoModule: undefined, + _cipherKey: undefined, + _setupCryptoModule: setupCryptoModule, + get instanceId(): string | undefined { + if (this.useInstanceId) return this._instanceId; + return undefined; + }, + getUserId() { + return this.userId; + }, + setUserId(value: string) { + if (!value || typeof value !== 'string' || value.trim().length === 0) + throw new Error('Missing or invalid userId parameter. Provide a valid string userId'); + + this.userId = value; + }, + getAuthKey() { + return this.authKey; + }, + setAuthKey(authKey: string | null) { + this.authKey = authKey; + }, + getFilterExpression() { + return this.filterExpression; + }, + setFilterExpression(expression: string | null | undefined) { + this.filterExpression = expression; + }, + get cipherKey(): string | undefined { + return this._cipherKey; + }, + setCipherKey(key: string) { + this._cipherKey = key; + + if (!key && this._cryptoModule) { + this._cryptoModule = undefined; + return; + } else if (!key || !this._setupCryptoModule) return; + + this._cryptoModule = this._setupCryptoModule({ + cipherKey: key, + useRandomIVs: base.useRandomIVs, + customEncrypt: this.customEncrypt, + customDecrypt: this.customDecrypt, + }); + }, + get cryptoModule(): CryptoModule | undefined { + return this._cryptoModule; + }, + get useRandomIVs(): boolean | undefined { + return base.useRandomIVs; + }, + getPresenceTimeout(): number { + return this.presenceTimeout!; + }, + getHeartbeatInterval(): number | undefined { + return this.heartbeatInterval; + }, + setHeartbeatInterval(interval: number) { + this.heartbeatInterval = interval; + }, + getTransactionTimeout(): number { + return this.transactionalRequestTimeout!; + }, + getSubscribeTimeout(): number { + return this.subscribeRequestTimeout!; + }, + get PubNubFile(): PubNubFileConstructor | undefined { + return base.PubNubFile; + }, + get version(): string { + return '7.6.0'; + }, + getVersion(): string { + return this.version; + }, + _addPnsdkSuffix(name: string, suffix: string | number) { + this._pnsdkSuffix[name] = `${suffix}`; + }, + _getPnsdkSuffix(separator: string): string { + return Object.values(this._pnsdkSuffix).join(separator); + }, + + // -------------------------------------------------------- + // ---------------------- Deprecated ---------------------- + // -------------------------------------------------------- + // region Deprecated + + getUUID(): string { + return this.getUserId(); + }, + setUUID(value: string) { + this.setUserId(value); + }, + get customEncrypt(): ((data: string) => string) | undefined { + return base.customEncrypt; + }, + get customDecrypt(): ((data: string) => string) | undefined { + return base.customDecrypt; + }, + // endregion + }; + + // Setup `CryptoModule` if possible. + if (base.cipherKey) clientConfiguration.setCipherKey(base.cipherKey); + + return clientConfiguration; +}; + +/** + * Decide {@lin PubNub} service REST API origin. + * + * @param secure - Whether preferred to use secured connection or not. + * @param origin - User-provided or default origin. + * + * @returns `PubNub` REST API endpoints origin. + */ +const standardOrigin = (secure: boolean, origin: string | string[]): string => { + const protocol = secure ? 'https://' : 'http://'; + + if (typeof origin === 'string') return `${protocol}${origin}`; + + return `${protocol}${origin[Math.floor(Math.random() * origin.length)]}`; +}; diff --git a/src/core/components/cryptography/index.js b/src/core/components/cryptography/index.js deleted file mode 100644 index 8d6b400e3..000000000 --- a/src/core/components/cryptography/index.js +++ /dev/null @@ -1,173 +0,0 @@ -import { decode } from '../base64_codec'; -import CryptoJS from './hmac-sha256'; - -function bufferToWordArray(b) { - const wa = []; - let i; - for (i = 0; i < b.length; i += 1) { - wa[(i / 4) | 0] |= b[i] << (24 - 8 * i); - } - - return CryptoJS.lib.WordArray.create(wa, b.length); -} - -export default class { - _config; - - _iv; - - _allowedKeyEncodings; - - _allowedKeyLengths; - - _allowedModes; - - _defaultOptions; - - constructor({ config }) { - this._config = config; - this._iv = '0123456789012345'; - - this._allowedKeyEncodings = ['hex', 'utf8', 'base64', 'binary']; - this._allowedKeyLengths = [128, 256]; - this._allowedModes = ['ecb', 'cbc']; - - this._defaultOptions = { - encryptKey: true, - keyEncoding: 'utf8', - keyLength: 256, - mode: 'cbc', - }; - } - - HMACSHA256(data) { - const hash = CryptoJS.HmacSHA256(data, this._config.secretKey); - return hash.toString(CryptoJS.enc.Base64); - } - - SHA256(s) { - return CryptoJS.SHA256(s).toString(CryptoJS.enc.Hex); - } - - _parseOptions(incomingOptions) { - // Defaults - const options = incomingOptions || {}; - if (!options.hasOwnProperty('encryptKey')) options.encryptKey = this._defaultOptions.encryptKey; - if (!options.hasOwnProperty('keyEncoding')) options.keyEncoding = this._defaultOptions.keyEncoding; - if (!options.hasOwnProperty('keyLength')) options.keyLength = this._defaultOptions.keyLength; - if (!options.hasOwnProperty('mode')) options.mode = this._defaultOptions.mode; - - // Validation - if (this._allowedKeyEncodings.indexOf(options.keyEncoding.toLowerCase()) === -1) { - options.keyEncoding = this._defaultOptions.keyEncoding; - } - - if (this._allowedKeyLengths.indexOf(parseInt(options.keyLength, 10)) === -1) { - options.keyLength = this._defaultOptions.keyLength; - } - - if (this._allowedModes.indexOf(options.mode.toLowerCase()) === -1) { - options.mode = this._defaultOptions.mode; - } - - return options; - } - - _decodeKey(key, options) { - if (options.keyEncoding === 'base64') { - return CryptoJS.enc.Base64.parse(key); - } - if (options.keyEncoding === 'hex') { - return CryptoJS.enc.Hex.parse(key); - } - return key; - } - - _getPaddedKey(key, options) { - key = this._decodeKey(key, options); - if (options.encryptKey) { - return CryptoJS.enc.Utf8.parse(this.SHA256(key).slice(0, 32)); - } - return key; - } - - _getMode(options) { - if (options.mode === 'ecb') { - return CryptoJS.mode.ECB; - } - return CryptoJS.mode.CBC; - } - - _getIV(options) { - return options.mode === 'cbc' ? CryptoJS.enc.Utf8.parse(this._iv) : null; - } - - _getRandomIV() { - return CryptoJS.lib.WordArray.random(16); - } - - encrypt(data, customCipherKey, options) { - if (this._config.customEncrypt) { - return this._config.customEncrypt(data); - } - return this.pnEncrypt(data, customCipherKey, options); - } - - decrypt(data, customCipherKey, options) { - if (this._config.customDecrypt) { - return this._config.customDecrypt(data); - } - return this.pnDecrypt(data, customCipherKey, options); - } - - pnEncrypt(data, customCipherKey, options) { - if (!customCipherKey && !this._config.cipherKey) return data; - options = this._parseOptions(options); - const mode = this._getMode(options); - const cipherKey = this._getPaddedKey(customCipherKey || this._config.cipherKey, options); - - if (this._config.useRandomIVs) { - const waIv = this._getRandomIV(); - const waPayload = CryptoJS.AES.encrypt(data, cipherKey, { iv: waIv, mode }).ciphertext; - - return waIv.clone().concat(waPayload.clone()).toString(CryptoJS.enc.Base64); - } - const iv = this._getIV(options); - const encryptedHexArray = CryptoJS.AES.encrypt(data, cipherKey, { iv, mode }).ciphertext; - const base64Encrypted = encryptedHexArray.toString(CryptoJS.enc.Base64); - return base64Encrypted || data; - } - - pnDecrypt(data, customCipherKey, options) { - if (!customCipherKey && !this._config.cipherKey) return data; - options = this._parseOptions(options); - const mode = this._getMode(options); - const cipherKey = this._getPaddedKey(customCipherKey || this._config.cipherKey, options); - if (this._config.useRandomIVs) { - const ciphertext = new Uint8ClampedArray(decode(data)); - - const iv = bufferToWordArray(ciphertext.slice(0, 16)); - const payload = bufferToWordArray(ciphertext.slice(16)); - - try { - const plainJSON = CryptoJS.AES.decrypt({ ciphertext: payload }, cipherKey, { iv, mode }).toString( - CryptoJS.enc.Utf8, - ); - const plaintext = JSON.parse(plainJSON); - return plaintext; - } catch (e) { - return null; - } - } else { - const iv = this._getIV(options); - try { - const ciphertext = CryptoJS.enc.Base64.parse(data); - const plainJSON = CryptoJS.AES.decrypt({ ciphertext }, cipherKey, { iv, mode }).toString(CryptoJS.enc.Utf8); - const plaintext = JSON.parse(plainJSON); - return plaintext; - } catch (e) { - return null; - } - } - } -} diff --git a/src/core/components/cryptography/index.ts b/src/core/components/cryptography/index.ts new file mode 100644 index 000000000..222e50085 --- /dev/null +++ b/src/core/components/cryptography/index.ts @@ -0,0 +1,309 @@ +/** + * Legacy cryptography module. + */ + +import { CryptorConfiguration } from '../../interfaces/crypto-module'; +import { Payload } from '../../types/api'; +import { decode } from '../base64_codec'; +import CryptoJS from './hmac-sha256'; + +/** + * Convert bytes array to words array. + * + * @param b - Bytes array (buffer) which should be converted. + * + * @returns Word sized array. + */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +function bufferToWordArray(b: string | any[] | Uint8ClampedArray) { + const wa: number[] = []; + let i; + for (i = 0; i < b.length; i += 1) { + wa[(i / 4) | 0] |= b[i] << (24 - 8 * i); + } + + // @ts-expect-error Bundled library without types. + return CryptoJS.lib.WordArray.create(wa, b.length); +} + +/** + * Legacy cryptor configuration options. + */ +type CryptoConfiguration = { + encryptKey?: boolean; + keyEncoding?: 'hex' | 'utf8' | 'base64' | 'binary'; + keyLength?: 128 | 256; + mode?: 'ecb' | 'cbc'; +}; + +export default class { + /** + * Crypto initialization vector. + */ + private iv = '0123456789012345'; + + /** + * List os allowed cipher key encodings. + */ + private allowedKeyEncodings = ['hex', 'utf8', 'base64', 'binary']; + + /** + * Allowed cipher key lengths. + */ + private allowedKeyLengths = [128, 256]; + + /** + * Allowed crypto modes. + */ + private allowedModes = ['ecb', 'cbc']; + + /** + * Default cryptor configuration options. + */ + private readonly defaultOptions: Required; + + constructor(private readonly configuration: CryptorConfiguration) { + this.defaultOptions = { + encryptKey: true, + keyEncoding: 'utf8', + keyLength: 256, + mode: 'cbc', + }; + } + + /** + * Generate HMAC-SHA256 hash from input data. + * + * @param data - Data from which hash should be generated. + * + * @returns HMAC-SHA256 hash from provided `data`. + */ + public HMACSHA256(data: string): string { + // @ts-expect-error Bundled library without types. + const hash = CryptoJS.HmacSHA256(data, this.configuration.secretKey); + // @ts-expect-error Bundled library without types. + return hash.toString(CryptoJS.enc.Base64); + } + + /** + * Generate SHA256 hash from input data. + * + * @param data - Data from which hash should be generated. + * + * @returns SHA256 hash from provided `data`. + */ + public SHA256(data: string): string { + // @ts-expect-error Bundled library without types. + return CryptoJS.SHA256(data).toString(CryptoJS.enc.Hex); + } + + /** + * Encrypt provided data. + * + * @param data - Source data which should be encrypted. + * @param [customCipherKey] - Custom cipher key (different from defined on client level). + * @param [options] - Specific crypto configuration options. + * + * @returns Encrypted `data`. + */ + public encrypt(data: string, customCipherKey?: string, options?: CryptoConfiguration) { + if (this.configuration.customEncrypt) return this.configuration.customEncrypt(data); + + return this.pnEncrypt(data, customCipherKey, options); + } + + /** + * Decrypt provided data. + * + * @param data - Encrypted data which should be decrypted. + * @param [customCipherKey] - Custom cipher key (different from defined on client level). + * @param [options] - Specific crypto configuration options. + * + * @returns Decrypted `data`. + */ + public decrypt(data: string, customCipherKey?: string, options?: CryptoConfiguration) { + if (this.configuration.customDecrypt) return this.configuration.customDecrypt(data); + + return this.pnDecrypt(data, customCipherKey, options); + } + + /** + * Encrypt provided data. + * + * @param data - Source data which should be encrypted. + * @param [customCipherKey] - Custom cipher key (different from defined on client level). + * @param [options] - Specific crypto configuration options. + * + * @returns Encrypted `data` as string. + */ + private pnEncrypt(data: string, customCipherKey?: string, options?: CryptoConfiguration): string { + const decidedCipherKey = customCipherKey ?? this.configuration.cipherKey; + if (!decidedCipherKey) return data; + + options = this.parseOptions(options); + const mode = this.getMode(options); + const cipherKey = this.getPaddedKey(decidedCipherKey, options); + + if (this.configuration.useRandomIVs) { + const waIv = this.getRandomIV(); + // @ts-expect-error Bundled library without types. + const waPayload = CryptoJS.AES.encrypt(data, cipherKey, { iv: waIv, mode }).ciphertext; + + // @ts-expect-error Bundled library without types. + return waIv.clone().concat(waPayload.clone()).toString(CryptoJS.enc.Base64); + } + + const iv = this.getIV(options); + // @ts-expect-error Bundled library without types. + const encryptedHexArray = CryptoJS.AES.encrypt(data, cipherKey, { iv, mode }).ciphertext; + // @ts-expect-error Bundled library without types. + const base64Encrypted = encryptedHexArray.toString(CryptoJS.enc.Base64); + + return base64Encrypted || data; + } + + /** + * Decrypt provided data. + * + * @param data - Encrypted data which should be decrypted. + * @param [customCipherKey] - Custom cipher key (different from defined on client level). + * @param [options] - Specific crypto configuration options. + * + * @returns Decrypted `data`. + */ + private pnDecrypt(data: string, customCipherKey?: string, options?: CryptoConfiguration): Payload | null { + const decidedCipherKey = customCipherKey ?? this.configuration.cipherKey; + if (!decidedCipherKey) return data; + + options = this.parseOptions(options); + const mode = this.getMode(options); + const cipherKey = this.getPaddedKey(decidedCipherKey, options); + + if (this.configuration.useRandomIVs) { + const ciphertext = new Uint8ClampedArray(decode(data)); + + const iv = bufferToWordArray(ciphertext.slice(0, 16)); + const payload = bufferToWordArray(ciphertext.slice(16)); + + try { + // @ts-expect-error Bundled library without types. + const plainJSON = CryptoJS.AES.decrypt({ ciphertext: payload }, cipherKey, { iv, mode }).toString( + // @ts-expect-error Bundled library without types. + CryptoJS.enc.Utf8, + ); + return JSON.parse(plainJSON); + } catch (e) { + return null; + } + } else { + const iv = this.getIV(options); + try { + // @ts-expect-error Bundled library without types. + const ciphertext = CryptoJS.enc.Base64.parse(data); + // @ts-expect-error Bundled library without types. + const plainJSON = CryptoJS.AES.decrypt({ ciphertext }, cipherKey, { iv, mode }).toString(CryptoJS.enc.Utf8); + return JSON.parse(plainJSON); + } catch (e) { + return null; + } + } + } + + /** + * Pre-process provided custom crypto configuration. + * + * @param incomingOptions - Configuration which should be pre-processed before use. + * + * @returns Normalized crypto configuration options. + */ + private parseOptions(incomingOptions?: CryptoConfiguration): Required { + if (!incomingOptions) return this.defaultOptions; + + // Defaults + const options = { + encryptKey: incomingOptions.encryptKey ?? this.defaultOptions.encryptKey, + keyEncoding: incomingOptions.keyEncoding ?? this.defaultOptions.keyEncoding, + keyLength: incomingOptions.keyLength ?? this.defaultOptions.keyLength, + mode: incomingOptions.mode ?? this.defaultOptions.mode, + }; + + // Validation + if (this.allowedKeyEncodings.indexOf(options.keyEncoding!.toLowerCase()) === -1) + options.keyEncoding = this.defaultOptions.keyEncoding; + if (this.allowedKeyLengths.indexOf(options.keyLength!) === -1) options.keyLength = this.defaultOptions.keyLength; + if (this.allowedModes.indexOf(options.mode!.toLowerCase()) === -1) options.mode = this.defaultOptions.mode; + + return options; + } + + /** + * Decode provided cipher key. + * + * @param key - Key in `encoding` provided by `options`. + * @param options - Crypto configuration options with cipher key details. + * + * @returns Array buffer with decoded key. + */ + private decodeKey(key: string, options: CryptoConfiguration) { + // @ts-expect-error Bundled library without types. + if (options.keyEncoding === 'base64') return CryptoJS.enc.Base64.parse(key); + // @ts-expect-error Bundled library without types. + if (options.keyEncoding === 'hex') return CryptoJS.enc.Hex.parse(key); + + return key; + } + + /** + * Add padding to the cipher key. + * + * @param key - Key which should be padded. + * @param options - Crypto configuration options with cipher key details. + * + * @returns Properly padded cipher key. + */ + private getPaddedKey(key: string, options: CryptoConfiguration) { + key = this.decodeKey(key, options); + + // @ts-expect-error Bundled library without types. + if (options.encryptKey) return CryptoJS.enc.Utf8.parse(this.SHA256(key).slice(0, 32)); + + return key; + } + + /** + * Cipher mode. + * + * @param options - Crypto configuration with information about cipher mode. + * + * @returns Crypto cipher mode. + */ + private getMode(options: CryptoConfiguration) { + // @ts-expect-error Bundled library without types. + if (options.mode === 'ecb') return CryptoJS.mode.ECB; + + // @ts-expect-error Bundled library without types. + return CryptoJS.mode.CBC; + } + + /** + * Cipher initialization vector. + * + * @param options - Crypto configuration with information about cipher mode. + * + * @returns Initialization vector. + */ + private getIV(options: CryptoConfiguration) { + // @ts-expect-error Bundled library without types. + return options.mode === 'cbc' ? CryptoJS.enc.Utf8.parse(this.iv) : null; + } + + /** + * Random initialization vector. + * + * @returns Generated random initialization vector. + */ + private getRandomIV() { + // @ts-expect-error Bundled library without types. + return CryptoJS.lib.WordArray.random(16); + } +} diff --git a/src/core/components/deduping_manager.js b/src/core/components/deduping_manager.js index 7ac8aa613..5910bf25b 100644 --- a/src/core/components/deduping_manager.js +++ b/src/core/components/deduping_manager.js @@ -1,7 +1,5 @@ /* */ -import Config from './config'; - const hashCode = (payload) => { let hash = 0; if (payload.length === 0) return hash; diff --git a/src/core/components/endpoint.js b/src/core/components/endpoint.js deleted file mode 100644 index 0cce04a57..000000000 --- a/src/core/components/endpoint.js +++ /dev/null @@ -1,280 +0,0 @@ -import uuidGenerator from './uuid'; -import utils from '../utils'; -import operationConstants from '../constants/operations'; -import categoryConstants from '../constants/categories'; - -export class PubNubError extends Error { - constructor(message, status) { - super(message); - this.name = this.constructor.name; - this.status = status; - this.message = message; - - Object.setPrototypeOf(this, new.target.prototype); - } -} - -function createError(errorPayload, type) { - errorPayload.type = type; - errorPayload.error = true; - return errorPayload; -} - -export function createValidationError(message) { - return createError({ message }, 'validationError'); -} - -function decideURL(endpoint, modules, incomingParams) { - if (endpoint.usePost && endpoint.usePost(modules, incomingParams)) { - return endpoint.postURL(modules, incomingParams); - } - if (endpoint.usePatch && endpoint.usePatch(modules, incomingParams)) { - return endpoint.patchURL(modules, incomingParams); - } - if (endpoint.useGetFile && endpoint.useGetFile(modules, incomingParams)) { - return endpoint.getFileURL(modules, incomingParams); - } - return endpoint.getURL(modules, incomingParams); -} - -export function generatePNSDK(config) { - if (config.sdkName) { - return config.sdkName; - } - - let base = `PubNub-JS-${config.sdkFamily}`; - - if (config.partnerId) { - base += `-${config.partnerId}`; - } - - base += `/${config.getVersion()}`; - - const pnsdkSuffix = config._getPnsdkSuffix(' '); - - if (pnsdkSuffix.length > 0) { - base += pnsdkSuffix; - } - - return base; -} - -function getHttpMethod(modules, endpoint, incomingParams) { - if (endpoint.usePost && endpoint.usePost(modules, incomingParams)) { - return 'POST'; - } - if (endpoint.usePatch && endpoint.usePatch(modules, incomingParams)) { - return 'PATCH'; - } - if (endpoint.useDelete && endpoint.useDelete(modules, incomingParams)) { - return 'DELETE'; - } - if (endpoint.useGetFile && endpoint.useGetFile(modules, incomingParams)) { - return 'GETFILE'; - } - return 'GET'; -} - -export function signRequest(modules, url, outgoingParams, incomingParams, endpoint) { - const { config, crypto } = modules; - - let httpMethod = getHttpMethod(modules, endpoint, incomingParams); - - outgoingParams.timestamp = Math.floor(new Date().getTime() / 1000); - - // This is because of a server-side bug, old publish using post should be deprecated - if ( - endpoint.getOperation() === 'PNPublishOperation' && - endpoint.usePost && - endpoint.usePost(modules, incomingParams) - ) { - httpMethod = 'GET'; - } - - if (httpMethod === 'GETFILE') { - httpMethod = 'GET'; - } - - let signInput = `${httpMethod}\n${config.publishKey}\n${url}\n${utils.signPamFromParams(outgoingParams)}\n`; - - if (httpMethod === 'POST') { - const payload = endpoint.postPayload(modules, incomingParams); - if (typeof payload === 'string') { - signInput += payload; - } else { - signInput += JSON.stringify(payload); - } - } else if (httpMethod === 'PATCH') { - const payload = endpoint.patchPayload(modules, incomingParams); - if (typeof payload === 'string') { - signInput += payload; - } else { - signInput += JSON.stringify(payload); - } - } - - let signature = `v2.${crypto.HMACSHA256(signInput)}`; - signature = signature.replace(/\+/g, '-'); - signature = signature.replace(/\//g, '_'); - signature = signature.replace(/=+$/, ''); - - outgoingParams.signature = signature; -} - -export default function (modules, endpoint, ...args) { - const { networking, config, telemetryManager, tokenManager } = modules; - const requestId = uuidGenerator.createUUID(); - let callback = null; - let promiseComponent = null; - let incomingParams = {}; - - if ( - endpoint.getOperation() === operationConstants.PNTimeOperation || - endpoint.getOperation() === operationConstants.PNChannelGroupsOperation - ) { - callback = args[0]; - } else { - incomingParams = args[0]; - callback = args[1]; - } - - // bridge in Promise support. - if (typeof Promise !== 'undefined' && !callback) { - promiseComponent = utils.createPromise(); - } - - const validationResult = endpoint.validateParams(modules, incomingParams); - - if (validationResult) { - if (callback) { - return callback(createValidationError(validationResult)); - } - if (promiseComponent) { - promiseComponent.reject( - new PubNubError('Validation failed, check status for details', createValidationError(validationResult)), - ); - return promiseComponent.promise; - } - return; - } - - let outgoingParams = endpoint.prepareParams(modules, incomingParams); - const url = decideURL(endpoint, modules, incomingParams); - let callInstance; - const networkingParams = { - url, - operation: endpoint.getOperation(), - timeout: endpoint.getRequestTimeout(modules), - headers: endpoint.getRequestHeaders ? endpoint.getRequestHeaders() : {}, - ignoreBody: typeof endpoint.ignoreBody === 'function' ? endpoint.ignoreBody(modules) : false, - forceBuffered: - typeof endpoint.forceBuffered === 'function' ? endpoint.forceBuffered(modules, incomingParams) : null, - abortSignal: - typeof endpoint.getAbortSignal === 'function' ? endpoint.getAbortSignal(modules, incomingParams) : null, - }; - - outgoingParams.uuid = config.UUID; - outgoingParams.pnsdk = generatePNSDK(config); - - // Add telemetry information (if there is any available). - const telemetryLatencies = telemetryManager.operationsLatencyForRequest(); - if (Object.keys(telemetryLatencies).length) { - outgoingParams = { ...outgoingParams, ...telemetryLatencies }; - } - - if (config.useInstanceId) { - outgoingParams.instanceid = config.instanceId; - } - - if (config.useRequestId) { - outgoingParams.requestid = requestId; - } - - if (endpoint.isAuthSupported()) { - const tokenOrKey = tokenManager.getToken() || config.getAuthKey(); - - if (tokenOrKey) { - outgoingParams.auth = tokenOrKey; - } - } - - if (config.secretKey) { - signRequest(modules, url, outgoingParams, incomingParams, endpoint); - } - - const onResponse = (status, payload) => { - if (status.error) { - if (endpoint.handleError) { - endpoint.handleError(modules, incomingParams, status); - } - if (callback) { - callback(status); - } else if (promiseComponent) { - promiseComponent.reject(new PubNubError('PubNub call failed, check status for details', status)); - } - return; - } - - // Stop endpoint latency tracking. - telemetryManager.stopLatencyMeasure(endpoint.getOperation(), requestId); - - let responseP = endpoint.handleResponse(modules, payload, incomingParams); - - if (typeof responseP?.then !== 'function') { - responseP = Promise.resolve(responseP); - } - - responseP - .then((result) => { - if (callback) { - callback(status, result); - } else if (promiseComponent) { - promiseComponent.fulfill(result); - } - }) - .catch((e) => { - if (callback) { - let errorData = e; - - if (endpoint.getOperation() === operationConstants.PNSubscribeOperation) { - errorData = { - statusCode: 400, - error: true, - operation: endpoint.getOperation(), - errorData: e, - category: categoryConstants.PNUnknownCategory, - }; - } - - callback(errorData, null); - } else if (promiseComponent) { - promiseComponent.reject(new PubNubError('PubNub call failed, check status for details', e)); - } - }); - }; - - // Start endpoint latency tracking. - telemetryManager.startLatencyMeasure(endpoint.getOperation(), requestId); - - if (getHttpMethod(modules, endpoint, incomingParams) === 'POST') { - const payload = endpoint.postPayload(modules, incomingParams); - callInstance = networking.POST(outgoingParams, payload, networkingParams, onResponse); - } else if (getHttpMethod(modules, endpoint, incomingParams) === 'PATCH') { - const payload = endpoint.patchPayload(modules, incomingParams); - callInstance = networking.PATCH(outgoingParams, payload, networkingParams, onResponse); - } else if (getHttpMethod(modules, endpoint, incomingParams) === 'DELETE') { - callInstance = networking.DELETE(outgoingParams, networkingParams, onResponse); - } else if (getHttpMethod(modules, endpoint, incomingParams) === 'GETFILE') { - callInstance = networking.GETFILE(outgoingParams, networkingParams, onResponse); - } else { - callInstance = networking.GET(outgoingParams, networkingParams, onResponse); - } - - if (endpoint.getOperation() === operationConstants.PNSubscribeOperation) { - return callInstance; - } - - if (promiseComponent) { - return promiseComponent.promise; - } -} diff --git a/src/core/components/eventEmitter.js b/src/core/components/eventEmitter.js deleted file mode 100644 index 2157569de..000000000 --- a/src/core/components/eventEmitter.js +++ /dev/null @@ -1,289 +0,0 @@ -export default class EventEmitter { - modules; - listenerManager; - getFileUrl; - - _channelListenerMap; - _groupListenerMap; - _decoder; - constructor({ modules, listenerManager, getFileUrl }) { - this.modules = modules; - this.listenerManager = listenerManager; - this.getFileUrl = getFileUrl; - this._channelListenerMap = new Map(); - this._groupListenerMap = new Map(); - if (modules.cryptoModule) this._decoder = new TextDecoder(); - } - emitEvent(e) { - const { channel, publishMetaData } = e; - let { subscriptionMatch } = e; - if (channel === subscriptionMatch) { - subscriptionMatch = null; - } - - if (e.channel.endsWith('-pnpres')) { - const announce = {}; - announce.channel = null; - announce.subscription = null; - - if (channel) { - announce.channel = channel.substring(0, channel.lastIndexOf('-pnpres')); - } - - if (subscriptionMatch) { - announce.subscription = subscriptionMatch.substring(0, subscriptionMatch.lastIndexOf('-pnpres')); - } - - announce.action = e.payload.action; - announce.state = e.payload.data; - announce.timetoken = publishMetaData.publishTimetoken; - announce.occupancy = e.payload.occupancy; - announce.uuid = e.payload.uuid; - announce.timestamp = e.payload.timestamp; - - if (e.payload.join) { - announce.join = e.payload.join; - } - - if (e.payload.leave) { - announce.leave = e.payload.leave; - } - - if (e.payload.timeout) { - announce.timeout = e.payload.timeout; - } - // deprecated --> - announce.actualChannel = subscriptionMatch != null ? channel : null; - announce.subscribedChannel = subscriptionMatch != null ? subscriptionMatch : channel; - // <-- deprecated - - this.listenerManager.announcePresence(announce); - this._announce('presence', announce, announce.channel, announce.subscription); - } else if (e.messageType === 1) { - const announce = {}; - announce.channel = null; - announce.subscription = null; - - announce.channel = channel; - announce.subscription = subscriptionMatch; - announce.timetoken = publishMetaData.publishTimetoken; - announce.publisher = e.issuingClientId; - if (e.userMetadata) { - announce.userMetadata = e.userMetadata; - } - - announce.message = e.payload; - - this.listenerManager.announceSignal(announce); - this._announce('signal', announce, announce.channel, announce.subscription); - } else if (e.messageType === 2) { - const announce = {}; - announce.channel = null; - announce.subscription = null; - announce.channel = channel; - announce.subscription = subscriptionMatch; - announce.timetoken = publishMetaData.publishTimetoken; - announce.publisher = e.issuingClientId; - if (e.userMetadata) { - announce.userMetadata = e.userMetadata; - } - announce.message = { - event: e.payload.event, - type: e.payload.type, - data: e.payload.data, - }; - this.listenerManager.announceObjects(announce); - this._announce('objects', announce, announce.channel, announce.subscription); - if (e.payload.type === 'uuid') { - const eventData = this._renameChannelField(announce); - const userEvent = { - ...eventData, - message: { - ...eventData.message, - event: this._renameEvent(eventData.message.event), - type: 'user', - }, - }; - this.listenerManager.announceUser(userEvent); - this._announce('user', userEvent, announce.channel, announce.subscription); - } else if (message.payload.type === 'channel') { - const eventData = this._renameChannelField(announce); - const spaceEvent = { - ...eventData, - message: { - ...eventData.message, - event: this._renameEvent(eventData.message.event), - type: 'space', - }, - }; - this.listenerManager.announceSpace(spaceEvent); - this._announce('space', spaceEvent, announce.channel, announce.subscription); - } else if (message.payload.type === 'membership') { - const eventData = this._renameChannelField(announce); - const { uuid: user, channel: space, ...membershipData } = eventData.message.data; - membershipData.user = user; - membershipData.space = space; - const membershipEvent = { - ...eventData, - message: { - ...eventData.message, - event: this._renameEvent(eventData.message.event), - data: membershipData, - }, - }; - this.listenerManager.announceMembership(membershipEvent); - this._announce('membership', membershipEvent, announce.channel, announce.subscription); - } - } else if (e.messageType === 3) { - const announce = {}; - announce.channel = channel; - announce.subscription = subscriptionMatch; - announce.timetoken = publishMetaData.publishTimetoken; - announce.publisher = e.issuingClientId; - announce.data = { - messageTimetoken: e.payload.data.messageTimetoken, - actionTimetoken: e.payload.data.actionTimetoken, - type: e.payload.data.type, - uuid: e.issuingClientId, - value: e.payload.data.value, - }; - announce.event = e.payload.event; - this.listenerManager.announceMessageAction(announce); - this._announce('messageAction', announce, announce.channel, announce.subscription); - } else if (e.messageType === 4) { - const announce = {}; - announce.channel = channel; - announce.subscription = subscriptionMatch; - announce.timetoken = publishMetaData.publishTimetoken; - announce.publisher = e.issuingClientId; - - let msgPayload = e.payload; - - if (this.modules.cryptoModule) { - let decryptedPayload; - try { - const decryptedData = this.modules.cryptoModule.decrypt(e.payload); - decryptedPayload = - decryptedData instanceof ArrayBuffer ? JSON.parse(this._decoder.decode(decryptedData)) : decryptedData; - } catch (e) { - decryptedPayload = null; - announce.error = `Error while decrypting message content: ${e.message}`; - } - if (decryptedPayload !== null) { - msgPayload = decryptedPayload; - } - } - - if (e.userMetadata) { - announce.userMetadata = e.userMetadata; - } - - announce.message = msgPayload.message; - - announce.file = { - id: msgPayload.file.id, - name: msgPayload.file.name, - url: this.getFileUrl({ - id: msgPayload.file.id, - name: msgPayload.file.name, - channel, - }), - }; - - this.listenerManager.announceFile(announce); - this._announce('file', announce, announce.channel, announce.subscription); - } else { - const announce = {}; - announce.channel = null; - announce.subscription = null; - - announce.channel = channel; - announce.subscription = subscriptionMatch; - announce.timetoken = publishMetaData.publishTimetoken; - announce.publisher = e.issuingClientId; - - if (e.userMetadata) { - announce.userMetadata = e.userMetadata; - } - - if (this.modules.cryptoModule) { - let decryptedPayload; - try { - const decryptedData = this.modules.cryptoModule.decrypt(e.payload); - decryptedPayload = - decryptedData instanceof ArrayBuffer ? JSON.parse(this._decoder.decode(decryptedData)) : decryptedData; - } catch (e) { - decryptedPayload = null; - announce.error = `Error while decrypting message content: ${e.message}`; - } - if (decryptedPayload != null) { - announce.message = decryptedPayload; - } else { - announce.message = e.payload; - } - } else { - announce.message = e.payload; - } - // deprecated --> - announce.actualChannel = subscriptionMatch != null ? channel : null; - announce.subscribedChannel = subscriptionMatch != null ? subscriptionMatch : channel; - // <-- deprecated - - this.listenerManager.announceMessage(announce); - this._announce('message', announce, announce.channel, announce.subscription); - } - } - - addListener(l, channels, groups) { - if (!(channels && groups)) { - this.listenerManager.addListener(l); - } else { - channels?.forEach((c) => { - if (this._channelListenerMap[c]) { - if (!this._channelListenerMap[c].includes(l)) this._channelListenerMap[c].push(l); - } else { - this._channelListenerMap[c] = [l]; - } - }); - groups?.forEach((g) => { - if (this._groupListenerMap[g]) { - if (!this._groupListenerMap[g].includes(l)) this._groupListenerMap[g].push(l); - } else { - this._groupListenerMap[g] = [l]; - } - }); - } - } - - removeListener(listener, channels, groups) { - if (!(channels && groups)) { - this.listenerManager.removeListener(listener); - } else { - channels?.forEach((c) => { - this._channelListenerMap[c] = this._channelListenerMap[c]?.filter((l) => l !== listener); - }); - groups?.forEach((g) => { - this._groupListenerMap[g] = this._groupListenerMap[g]?.filter((l) => l !== listener); - }); - } - } - - removeAllListeners() { - this.listenerManager.removeAllListeners(); - } - - _renameEvent(e) { - return e === 'set' ? 'updated' : 'removed'; - } - - _renameChannelField(announce) { - const { channel, ...eventData } = announce; - eventData.spaceId = channel; - return eventData; - } - - _announce(type, event, channel, group) { - this._channelListenerMap[channel]?.forEach((l) => l[type] && l[type](event)); - this._groupListenerMap[group]?.forEach((l) => l[type] && l[type](event)); - } -} diff --git a/src/core/components/eventEmitter.ts b/src/core/components/eventEmitter.ts new file mode 100644 index 000000000..7f10d3112 --- /dev/null +++ b/src/core/components/eventEmitter.ts @@ -0,0 +1,197 @@ +import { Listener, ListenerManager } from './listener_manager'; +import * as Subscription from '../types/api/subscription'; +import { PubNubEventType } from '../endpoints/subscribe'; + +export default class EventEmitter { + /** + * Map of channels to listener callbacks for them. + */ + private readonly channelListenerMap: Map = new Map(); + + /** + * Map of channel group names to the listener callbacks for them. + */ + private readonly groupListenerMap: Map = new Map(); + + constructor(private readonly listenerManager: ListenerManager) {} + + /** + * Emit specific real-time event. + * + * Proper listener will be notified basing on event `type`. + * + * @param event - Received real-time event. + */ + emitEvent(event: Subscription.SubscriptionResponse['messages'][number]) { + if (event.type === PubNubEventType.Message) { + this.listenerManager.announceMessage(event.data); + this.announce('message', event.data, event.data.channel, event.data.subscription); + } else if (event.type === PubNubEventType.Signal) { + this.listenerManager.announceSignal(event.data); + this.announce('signal', event.data, event.data.channel, event.data.subscription); + } else if (event.type === PubNubEventType.Presence) { + this.listenerManager.announcePresence(event.data); + this.announce('presence', event.data, event.data.channel, event.data.subscription); + } else if (event.type === PubNubEventType.AppContext) { + const { data: objectEvent } = event; + const { message: object } = objectEvent; + this.listenerManager.announceObjects(objectEvent); + this.announce('objects', objectEvent, objectEvent.channel, objectEvent.subscription); + + if (object.type === 'uuid') { + const { message, channel, ...restEvent } = objectEvent; + const { event, type, ...restObject } = object; + const userEvent: Subscription.UserAppContextObject = { + ...restEvent, + spaceId: channel, + message: { + ...restObject, + event: event === 'set' ? 'updated' : 'removed', + type: 'user', + }, + }; + + this.listenerManager.announceUser(userEvent); + this.announce('user', userEvent, userEvent.spaceId, userEvent.subscription); + } else if (object.type === 'channel') { + const { message, channel, ...restEvent } = objectEvent; + const { event, type, ...restObject } = object; + const spaceEvent: Subscription.SpaceAppContextObject = { + ...restEvent, + spaceId: channel, + message: { + ...restObject, + event: event === 'set' ? 'updated' : 'removed', + type: 'space', + }, + }; + + this.listenerManager.announceSpace(spaceEvent); + this.announce('space', spaceEvent, spaceEvent.spaceId, spaceEvent.subscription); + } else if (object.type === 'membership') { + const { message, channel, ...restEvent } = objectEvent; + const { event, data, ...restObject } = object; + const { uuid, channel: channelMeta, ...restData } = data; + const membershipEvent: Subscription.VSPMembershipAppContextObject = { + ...restEvent, + spaceId: channel, + message: { + ...restObject, + event: event === 'set' ? 'updated' : 'removed', + data: { + ...restData, + user: uuid, + space: channelMeta, + }, + }, + }; + + this.listenerManager.announceMembership(membershipEvent); + this.announce('membership', membershipEvent, membershipEvent.spaceId, membershipEvent.subscription); + } + } else if (event.type === PubNubEventType.MessageAction) { + this.listenerManager.announceMessageAction(event.data); + this.announce('messageAction', event.data, event.data.channel, event.data.subscription); + } else if (event.type === PubNubEventType.Files) { + this.listenerManager.announceFile(event.data); + this.announce('file', event.data, event.data.channel, event.data.subscription); + } + } + + /** + * Register real-time event listener for specific channels and groups. + * + * @param listener - Listener with event callbacks to handle different types of events. + * @param channels - List of channels for which listener should be registered. + * @param groups - List of channel groups for which listener should be registered. + */ + public addListener(listener: Listener, channels?: string[], groups?: string[]) { + // Register event-listener listener globally. + if (!(channels && groups)) { + this.listenerManager.addListener(listener); + } else { + channels?.forEach((channel) => { + if (this.channelListenerMap.has(channel)) { + const channelListeners = this.channelListenerMap.get(channel)!; + if (!channelListeners.includes(listener)) channelListeners.push(listener); + } else this.channelListenerMap.set(channel, [listener]); + }); + + groups?.forEach((group) => { + if (this.groupListenerMap.has(group)) { + const groupListeners = this.groupListenerMap.get(group)!; + if (!groupListeners.includes(listener)) groupListeners.push(listener); + } else this.groupListenerMap.set(group, [listener]); + }); + } + } + + /** + * Remove real-time event listener. + * + * @param listener - Event listeners which should be removed. + * @param channels - List of channels for which listener should be removed. + * @param groups - List of channel groups for which listener should be removed. + */ + public removeListener(listener: Listener, channels?: string[], groups?: string[]) { + if (!(channels && groups)) { + this.listenerManager.removeListener(listener); + } else { + channels?.forEach((channel) => { + if (this.channelListenerMap.has(channel)) { + this.channelListenerMap.set( + channel, + this.channelListenerMap.get(channel)!.filter((channelListener) => channelListener !== listener), + ); + } + }); + + groups?.forEach((group) => { + if (this.groupListenerMap.has(group)) { + this.groupListenerMap.set( + group, + this.groupListenerMap.get(group)!.filter((groupListener) => groupListener !== listener), + ); + } + }); + } + } + + /** + * Clear all real-time event listeners. + */ + public removeAllListeners() { + this.listenerManager.removeAllListeners(); + this.channelListenerMap.clear(); + this.groupListenerMap.clear(); + } + + /** + * Announce real-time event to all listeners. + * + * @param type - Type of event which should be announced. + * @param event - Announced real-time event payload. + * @param channel - Name of the channel for which registered listeners should be notified. + * @param group - Name of the channel group for which registered listeners should be notified. + */ + private announce( + type: T, + event: Listener[T] extends ((arg: infer P) => void) | undefined ? P : never, + channel: string, + group?: string | null, + ) { + if (event && this.channelListenerMap.has(channel)) + this.channelListenerMap.get(channel)!.forEach((listener) => { + const typedListener = listener[type]; + // @ts-expect-error Dynamic events mapping. + if (typedListener) typedListener(event); + }); + + if (group && this.groupListenerMap.has(group)) + this.groupListenerMap.get(group)!.forEach((listener) => { + const typedListener = listener[type]; + // @ts-expect-error Dynamic events mapping. + if (typedListener) typedListener(event); + }); + } +} diff --git a/src/core/components/listener_manager.js b/src/core/components/listener_manager.js deleted file mode 100644 index fb41c1f2d..000000000 --- a/src/core/components/listener_manager.js +++ /dev/null @@ -1,102 +0,0 @@ -import categoryConstants from '../constants/categories'; - -export default class { - _listeners; - - constructor() { - this._listeners = []; - } - - addListener(newListener) { - if (this._listeners.includes(newListener)) { - return; - } - this._listeners.push(newListener); - } - - removeListener(deprecatedListener) { - const newListeners = []; - - this._listeners.forEach((listener) => { - if (listener !== deprecatedListener) newListeners.push(listener); - }); - - this._listeners = newListeners; - } - - removeAllListeners() { - this._listeners = []; - } - - announcePresence(announce) { - this._listeners.forEach((listener) => { - if (listener.presence) listener.presence(announce); - }); - } - - announceStatus(announce) { - this._listeners.forEach((listener) => { - if (listener.status) listener.status(announce); - }); - } - - announceMessage(announce) { - this._listeners.forEach((listener) => { - if (listener.message) listener.message(announce); - }); - } - - announceSignal(announce) { - this._listeners.forEach((listener) => { - if (listener.signal) listener.signal(announce); - }); - } - - announceMessageAction(announce) { - this._listeners.forEach((listener) => { - if (listener.messageAction) listener.messageAction(announce); - }); - } - - announceFile(announce) { - this._listeners.forEach((listener) => { - if (listener.file) listener.file(announce); - }); - } - - announceObjects(announce) { - this._listeners.forEach((listener) => { - if (listener.objects) listener.objects(announce); - }); - } - - announceUser(announce) { - this._listeners.forEach((listener) => { - if (listener.user) listener.user(announce); - }); - } - - announceSpace(announce) { - this._listeners.forEach((listener) => { - if (listener.space) listener.space(announce); - }); - } - - announceMembership(announce) { - this._listeners.forEach((listener) => { - if (listener.membership) listener.membership(announce); - }); - } - - announceNetworkUp() { - const networkStatus = {}; - networkStatus.category = categoryConstants.PNNetworkUpCategory; - this.announceStatus(networkStatus); - } - - announceNetworkDown() { - const networkStatus = {}; - networkStatus.category = categoryConstants.PNNetworkDownCategory; - this.announceStatus(networkStatus); - } -} diff --git a/src/core/components/listener_manager.ts b/src/core/components/listener_manager.ts new file mode 100644 index 000000000..49e4c47d5 --- /dev/null +++ b/src/core/components/listener_manager.ts @@ -0,0 +1,279 @@ +/** + * Events listener manager module. + */ + +import * as Subscription from '../types/api/subscription'; +import StatusCategory from '../constants/categories'; +import { Status, StatusEvent } from '../types/api'; + +/** + * Real-time events listener. + */ +export type Listener = { + /** + * Real-time message events listener. + * + * @param message - Received message. + */ + message?: (message: Subscription.Message) => void; + + /** + * Real-time message signal listener. + * + * @param signal - Received signal. + */ + signal?: (signal: Subscription.Signal) => void; + + /** + * Real-time presence change events listener. + * + * @param presence - Received presence chane information. + */ + presence?: (presence: Subscription.Presence) => void; + + /** + * Real-time App Context Objects change events listener. + * + * @param object - Changed App Context Object information. + */ + objects?: (object: Subscription.AppContextObject) => void; + + /** + * Real-time message actions events listener. + * + * @param action - Message action information. + */ + messageAction?: (action: Subscription.MessageAction) => void; + + /** + * Real-time file share events listener. + * + * @param file - Shared file information. + */ + file?: (file: Subscription.File) => void; + + /** + * Real-time PubNub client status change event. + * + * @param status - PubNub client status information + */ + status?: (status: Status | StatusEvent) => void; + + // -------------------------------------------------------- + // ---------------------- Deprecated ---------------------- + // -------------------------------------------------------- + // region Deprecated + + /** + * Real-time User App Context Objects change events listener. + * + * @param user - User App Context Object information. + * + * @deprecated Use {@link objects} listener callback instead. + */ + user?: (user: Subscription.UserAppContextObject) => void; + + /** + * Real-time Space App Context Objects change events listener. + * + * @param space - Space App Context Object information. + * + * @deprecated Use {@link objects} listener callback instead. + */ + space?: (space: Subscription.SpaceAppContextObject) => void; + + /** + * Real-time VSP Membership App Context Objects change events listener. + * + * @param membership - VSP Membership App Context Object information. + * + * @deprecated Use {@link objects} listener callback instead. + */ + membership?: (membership: Subscription.VSPMembershipAppContextObject) => void; + // endregion +}; + +/** + * Real-time listeners' manager. + */ +export class ListenerManager { + /** + * List of registered event listeners. + */ + private listeners: Listener[] = []; + + /** + * Register new real-time events listener. + * + * @param listener - Listener with event callbacks to handle different types of events. + */ + public addListener(listener: Listener) { + if (this.listeners.includes(listener)) return; + + this.listeners.push(listener); + } + + /** + * Remove real-time event listener. + * + * @param listener - Event listeners which should be removed. + */ + public removeListener(listener: Listener) { + this.listeners = this.listeners.filter((storedListener) => storedListener !== listener); + } + + /** + * Clear all real-time event listeners. + */ + public removeAllListeners() { + this.listeners = []; + } + + /** + * Announce PubNub client status change event. + * + * @param status - PubNub client status. + */ + public announceStatus(status: Status | StatusEvent) { + this.listeners.forEach((listener) => { + if (listener.status) listener.status(status); + }); + } + + /** + * Announce channel presence change event. + * + * @param presence - Channel presence change information. + */ + public announcePresence(presence: Subscription.Presence) { + this.listeners.forEach((listener) => { + if (listener.presence) listener.presence(presence); + }); + } + + /** + * Announce real-time message event. + * + * @param message - Received real-time message. + */ + public announceMessage(message: Subscription.Message) { + this.listeners.forEach((listener) => { + if (listener.message) listener.message(message); + }); + } + + /** + * Announce real-time signal event. + * + * @param signal - Received real-time signal. + */ + public announceSignal(signal: Subscription.Signal) { + this.listeners.forEach((listener) => { + if (listener.signal) listener.signal(signal); + }); + } + + /** + * Announce message actions change event. + * + * @param messageAction - Message action change information. + */ + public announceMessageAction(messageAction: Subscription.MessageAction) { + this.listeners.forEach((listener) => { + if (listener.messageAction) listener.messageAction(messageAction); + }); + } + + /** + * Announce fie share event. + * + * @param file - Shared file information. + */ + public announceFile(file: Subscription.File) { + this.listeners.forEach((listener) => { + if (listener.file) listener.file(file); + }); + } + + /** + * Announce App Context Object change event. + * + * @param object - App Context change information. + */ + public announceObjects(object: Subscription.AppContextObject) { + this.listeners.forEach((listener) => { + if (listener.objects) listener.objects(object); + }); + } + + /** + * Announce network up status. + */ + public announceNetworkUp() { + this.listeners.forEach((listener) => { + if (listener.status) { + listener.status({ + category: StatusCategory.PNNetworkUpCategory, + }); + } + }); + } + + /** + * Announce network down status. + */ + public announceNetworkDown() { + this.listeners.forEach((listener) => { + if (listener.status) { + listener.status({ + category: StatusCategory.PNNetworkDownCategory, + }); + } + }); + } + + // -------------------------------------------------------- + // ---------------------- Deprecated ---------------------- + // -------------------------------------------------------- + // region Deprecated + + /** + * Announce User App Context Object change event. + * + * @param user - User App Context change information. + * + * @deprecated Use {@link announceObjects} method instead. + */ + public announceUser(user: Subscription.UserAppContextObject) { + this.listeners.forEach((listener) => { + if (listener.user) listener.user(user); + }); + } + + /** + * Announce Space App Context Object change event. + * + * @param space - Space App Context change information. + * + * @deprecated Use {@link announceObjects} method instead. + */ + public announceSpace(space: Subscription.SpaceAppContextObject) { + this.listeners.forEach((listener) => { + if (listener.space) listener.space(space); + }); + } + + /** + * Announce VSP Membership App Context Object change event. + * + * @param membership - VSP Membership App Context change information. + * + * @deprecated Use {@link announceObjects} method instead. + */ + public announceMembership(membership: Subscription.VSPMembershipAppContextObject) { + this.listeners.forEach((listener) => { + if (listener.membership) listener.membership(membership); + }); + } + // endregion +} diff --git a/src/core/components/reconnection_manager.js b/src/core/components/reconnection_manager.js deleted file mode 100644 index 6d221bd01..000000000 --- a/src/core/components/reconnection_manager.js +++ /dev/null @@ -1,34 +0,0 @@ -import TimeEndpoint from '../endpoints/time'; - -export default class { - _reconnectionCallback; - - _timeEndpoint; - - _timeTimer; - - constructor({ timeEndpoint }) { - this._timeEndpoint = timeEndpoint; - } - - onReconnection(reconnectionCallback) { - this._reconnectionCallback = reconnectionCallback; - } - - startPolling() { - this._timeTimer = setInterval(this._performTimeLoop.bind(this), 3000); - } - - stopPolling() { - clearInterval(this._timeTimer); - } - - _performTimeLoop() { - this._timeEndpoint((status) => { - if (!status.error) { - clearInterval(this._timeTimer); - this._reconnectionCallback(); - } - }); - } -} diff --git a/src/core/components/reconnection_manager.ts b/src/core/components/reconnection_manager.ts new file mode 100644 index 000000000..eac22539b --- /dev/null +++ b/src/core/components/reconnection_manager.ts @@ -0,0 +1,56 @@ +/** + * Subscription reconnection-manager. + * + * **Note:** Reconnection manger rely on legacy time-based availability check. + */ + +import { PubNubCore } from '../pubnub-common'; + +export class ReconnectionManager { + /** + * Successful availability check callback. + * + * @private + */ + private callback?: () => void; + + /** + * Time REST API call timer. + */ + private timeTimer?: number | null; + + constructor(private readonly time: typeof PubNubCore.prototype.time) {} + + /** + * Configure reconnection handler. + * + * @param callback - Successful availability check notify callback. + */ + public onReconnect(callback: () => void) { + this.callback = callback; + } + + /** + * Start periodic "availability" check. + */ + public startPolling() { + this.timeTimer = setInterval(() => this.callTime(), 3000) as unknown as number; + } + + /** + * Stop periodic "availability" check. + */ + public stopPolling() { + if (this.timeTimer) clearInterval(this.timeTimer); + this.timeTimer = null; + } + + private callTime() { + this.time((status) => { + if (!status.error) { + this.stopPolling(); + if (this.callback) this.callback(); + } + }); + } +} diff --git a/src/core/components/request.ts b/src/core/components/request.ts new file mode 100644 index 000000000..23616b1c3 --- /dev/null +++ b/src/core/components/request.ts @@ -0,0 +1,176 @@ +import { CancellationController, TransportMethod, TransportRequest } from '../types/transport-request'; +import { TransportResponse } from '../types/transport-response'; +import RequestOperation from '../constants/operations'; +import { PubNubFileInterface } from '../types/file'; +import { Request } from '../interfaces/request'; +import { Query } from '../types/api'; +import uuidGenerator from './uuid'; + +/** + * Base REST API request class. + */ +export abstract class AbstractRequest implements Request { + /** + * Service `ArrayBuffer` response decoder. + */ + protected static decoder = new TextDecoder(); + + /** + * Request cancellation controller. + */ + private _cancellationController: CancellationController | null; + + /** + * Construct base request. + * + * Constructed request by default won't be cancellable and performed using `GET` HTTP method. + * + * @param params - Request configuration parameters. + */ + protected constructor(private readonly params?: { method?: TransportMethod; cancellable?: boolean }) { + this._cancellationController = null; + } + + /** + * Retrieve configured cancellation controller. + * + * @returns Cancellation controller. + */ + public get cancellationController(): CancellationController | null { + return this._cancellationController; + } + + /** + * Update request cancellation controller. + * + * Controller itself provided by transport provider implementation and set only when request + * sending has been scheduled. + * + * @param controller - Cancellation controller or `null` to reset it. + */ + public set cancellationController(controller: CancellationController | null) { + this._cancellationController = controller; + } + /** + * Abort request if possible. + */ + abort(): void { + if (this.cancellationController) this.cancellationController.abort(); + } + + /** + * Target REST API endpoint operation type. + */ + operation(): RequestOperation { + throw Error('Should be implemented by subclass.'); + } + + /** + * Validate user-provided data before scheduling request. + * + * @returns Error message if request can't be sent without missing or malformed parameters. + */ + validate(): string | undefined { + return undefined; + } + + /** + * Parse service response. + * + * @param _response - Raw service response which should be parsed. + */ + async parse(_response: TransportResponse): Promise { + throw Error('Should be implemented by subclass.'); + } + + /** + * Create platform-agnostic request object. + * + * @returns Request object which can be processed using platform-specific requirements. + */ + request(): TransportRequest { + const request: TransportRequest = { + method: this.params?.method ?? TransportMethod.GET, + path: this.path, + queryParameters: this.queryParameters, + cancellable: this.params?.cancellable ?? false, + timeout: 10000, + identifier: uuidGenerator.createUUID(), + }; + + // Attach headers (if required). + const headers = this.headers; + if (headers) request.headers = headers; + + // Attach body (if required). + if (request.method === TransportMethod.POST || request.method === TransportMethod.PATCH) { + const [body, formData] = [this.body, this.formData]; + if (formData) request.formData = formData; + if (body) request.body = body; + } + + return request; + } + + /** + * Target REST API endpoint request headers getter. + * + * @returns Key/value headers which should be used with request. + */ + protected get headers(): Record | undefined { + return undefined; + } + + /** + * Target REST API endpoint request path getter. + * + * @returns REST API path. + */ + protected get path(): string { + throw Error('`path` getter should be implemented by subclass.'); + } + + /** + * Target REST API endpoint request query parameters getter. + * + * @returns Key/value pairs which should be appended to the REST API path. + */ + protected get queryParameters(): Query { + return {}; + } + + protected get formData(): Record | undefined { + return undefined; + } + + /** + * Target REST API Request body payload getter. + * + * @returns Buffer of stringified data which should be sent with `POST` or `PATCH` request. + */ + protected get body(): ArrayBuffer | PubNubFileInterface | string | undefined { + return undefined; + } + + /** + * Deserialize service response. + * + * @param response - Transparent response object with headers and body information. + * + * @returns Deserialized data or `undefined` in case of `JSON.parse(..)` error. + */ + protected deserializeResponse(response: TransportResponse): ServiceResponse | undefined { + const contentType = response.headers['content-type']; + if (contentType.indexOf('javascript') === -1 || contentType.indexOf('json') === -1) return undefined; + + const json = AbstractRequest.decoder.decode(response.body); + + try { + const parsedJson = JSON.parse(json); + return parsedJson as ServiceResponse; + } catch (error) { + console.error('Error parsing JSON response:', error); + return undefined; + } + } +} diff --git a/src/core/components/subscription-manager.ts b/src/core/components/subscription-manager.ts new file mode 100644 index 000000000..a5b139fb6 --- /dev/null +++ b/src/core/components/subscription-manager.ts @@ -0,0 +1,521 @@ +/** + * Subscription manager module. + */ + +import { Payload, ResultCallback, Status, StatusCallback, StatusEvent } from '../types/api'; +import { RequestParameters as SubscribeRequestParameters } from '../endpoints/subscribe'; +import { PrivateClientConfiguration } from '../interfaces/configuration'; +import { HeartbeatRequest } from '../endpoints/presence/heartbeat'; +import { ReconnectionManager } from './reconnection_manager'; +import * as Subscription from '../types/api/subscription'; +import { ListenerManager } from './listener_manager'; +import StatusCategory from '../constants/categories'; +import * as Presence from '../types/api/presence'; +import DedupingManager from './deduping_manager'; +import Categories from '../constants/categories'; +import { PubNubCore } from '../pubnub-common'; +import EventEmitter from './eventEmitter'; + +/** + * Subscription loop manager. + */ +export class SubscriptionManager { + /** + * Connection availability check manager. + */ + private readonly reconnectionManager: ReconnectionManager; + + /** + * Real-time events deduplication manager. + */ + private readonly dedupingManager: DedupingManager; + + /** + * Map between channel / group name and `state` associated with `uuid` there. + */ + private readonly presenceState: Record; + + /** + * List of channel groups for which heartbeat calls should be performed. + */ + private readonly heartbeatChannelGroups: Record>; + + /** + * List of channels for which heartbeat calls should be performed. + */ + private readonly heartbeatChannels: Record>; + + /** + * List of channel groups for which real-time presence change events should be observed. + */ + private readonly presenceChannelGroups: Record>; + + /** + * List of channels for which real-time presence change events should be observed. + */ + private readonly presenceChannels: Record>; + + /** + * New list of channel groups to which manager will try to subscribe, + */ + private pendingChannelGroupSubscriptions: string[]; + + /** + * New list of channels to which manager will try to subscribe, + */ + private pendingChannelSubscriptions: string[]; + + /** + * List of channel groups for which real-time events should be observed. + */ + private readonly channelGroups: Record>; + + /** + * List of channels for which real-time events should be observed. + */ + private readonly channels: Record>; + + /** + * Timetoken which is used by the current subscription loop. + */ + private currentTimetoken: string | number; + + /** + * Timetoken which has been used with previous subscription loop. + */ + private lastTimetoken: string | number; + + /** + * User-provided timetoken or timetoken for catch up. + */ + private storedTimetoken: string | number | null; + + /** + * Timetoken's region. + */ + private region?: number | null; + + private heartbeatTimer: number | null; + + /** + * Whether subscription status change has been announced or not. + */ + private subscriptionStatusAnnounced: boolean; + + /** + * Whether PubNub client is online right now. + */ + private isOnline: boolean; + + /** + * Active subscription request abort method. + * + * **Note:** Reference updated with each subscribe call. + */ + private _subscribeAbort?: (() => void) | null; + + constructor( + private readonly configuration: PrivateClientConfiguration, + private readonly listenerManager: ListenerManager, + private readonly eventEmitter: EventEmitter, + private readonly subscribeCall: ( + parameters: Omit, + callback: ResultCallback, + ) => void, + private readonly heartbeatCall: ( + parameters: Presence.PresenceHeartbeatParameters, + callback: StatusCallback, + ) => void, + private readonly leaveCall: (parameters: Presence.PresenceLeaveParameters, callback: StatusCallback) => void, + time: typeof PubNubCore.prototype.time, + ) { + this.reconnectionManager = new ReconnectionManager(time); + this.dedupingManager = new DedupingManager({ config: this.configuration }); + this.heartbeatChannelGroups = {}; + this.heartbeatChannels = {}; + this.presenceChannelGroups = {}; + this.presenceChannels = {}; + this.heartbeatTimer = null; + this.presenceState = {}; + this.pendingChannelGroupSubscriptions = []; + this.pendingChannelSubscriptions = []; + this.channelGroups = {}; + this.channels = {}; + + this.currentTimetoken = '0'; + this.lastTimetoken = '0'; + this.storedTimetoken = null; + + this.subscriptionStatusAnnounced = false; + this.isOnline = true; + } + + // region Information + get subscribedChannels(): string[] { + return Object.keys(this.channels); + } + + get subscribedChannelGroups(): string[] { + return Object.keys(this.channelGroups); + } + + set abort(call: (() => void) | null) { + this._subscribeAbort = call; + } + // endregion + + // region Subscription + + public disconnect() { + this.stopSubscribeLoop(); + this.stopHeartbeatTimer(); + this.reconnectionManager.stopPolling(); + } + + public reconnect() { + this.startSubscribeLoop(); + this.startHeartbeatTimer(); + } + + /** + * Update channels and groups used in subscription loop. + * + * @param parameters - Subscribe configuration parameters. + */ + public subscribe(parameters: Subscription.SubscribeParameters) { + const { channels, channelGroups, timetoken, withPresence = false, withHeartbeats = false } = parameters; + + if (timetoken) { + this.lastTimetoken = this.currentTimetoken; + this.currentTimetoken = timetoken; + } + + if (this.currentTimetoken !== '0' && this.currentTimetoken !== 0) { + this.storedTimetoken = this.currentTimetoken; + this.currentTimetoken = 0; + } + + channels?.forEach((channel) => { + this.pendingChannelSubscriptions.push(channel); + this.channels[channel] = {}; + + if (withPresence) this.presenceChannels[channel] = {}; + if (withHeartbeats || this.configuration.getHeartbeatInterval()) this.heartbeatChannels[channel] = {}; + }); + + channelGroups?.forEach((group) => { + this.pendingChannelGroupSubscriptions.push(group); + this.channelGroups[group] = {}; + + if (withPresence) this.presenceChannelGroups[group] = {}; + if (withHeartbeats || this.configuration.getHeartbeatInterval()) this.heartbeatChannelGroups[group] = {}; + }); + + this.subscriptionStatusAnnounced = false; + this.reconnect(); + } + + public unsubscribe(parameters: Presence.PresenceLeaveParameters, isOffline?: boolean) { + const { channels, channelGroups } = parameters; + + const actualChannelGroups: string[] = []; + const actualChannels: string[] = []; + + channels?.forEach((channel) => { + if (channel in this.channels) { + delete this.channels[channel]; + actualChannels.push(channel); + + if (channel in this.heartbeatChannels) delete this.heartbeatChannels[channel]; + } + + if (channel in this.presenceState) delete this.presenceState[channel]; + if (channel in this.presenceChannels) { + delete this.presenceChannels[channel]; + actualChannels.push(channel); + } + }); + + channelGroups?.forEach((group) => { + if (group in this.channelGroups) { + delete this.channelGroups[group]; + actualChannelGroups.push(group); + + if (group in this.heartbeatChannelGroups) delete this.heartbeatChannelGroups[group]; + } + + if (group in this.presenceState) delete this.presenceState[group]; + if (group in this.presenceChannelGroups) { + delete this.presenceChannelGroups[group]; + actualChannelGroups.push(group); + } + }); + + // There is no need to unsubscribe to empty list of data sources. + if (actualChannels.length === 0 && actualChannelGroups.length === 0) return; + + if (this.configuration.suppressLeaveEvents === false && !isOffline) { + this.leaveCall({ channels: actualChannels, channelGroups: actualChannelGroups }, (status) => { + this.listenerManager.announceStatus({ + ...status, + affectedChannels: actualChannels, + affectedChannelGroups: actualChannelGroups, + currentTimetoken: this.currentTimetoken, + lastTimetoken: this.lastTimetoken, + } as StatusEvent); + }); + } + + if ( + Object.keys(this.channels).length === 0 && + Object.keys(this.presenceChannels).length === 0 && + Object.keys(this.channelGroups).length === 0 && + Object.keys(this.presenceChannelGroups).length === 0 + ) { + this.lastTimetoken = 0; + this.currentTimetoken = 0; + this.storedTimetoken = null; + this.region = null; + this.reconnectionManager.stopPolling(); + } + + this.reconnect(); + } + + public unsubscribeAll(isOffline?: boolean) { + this.unsubscribe( + { + channels: this.subscribedChannels, + channelGroups: this.subscribedChannelGroups, + }, + isOffline, + ); + } + + private startSubscribeLoop() { + this.stopSubscribeLoop(); + const channelGroups = [...Object.keys(this.channelGroups)]; + const channels = [...Object.keys(this.channels)]; + + Object.keys(this.presenceChannelGroups).forEach((group) => channelGroups.push(`${group}-pnpres`)); + Object.keys(this.presenceChannels).forEach((channel) => channels.push(`${channel}-pnpres`)); + + // There is no need to start subscription loop for empty list of data sources. + if (channels.length === 0 && channelGroups.length === 0) return; + + this.subscribeCall( + { + channels, + channelGroups, + state: this.presenceState, + timetoken: this.currentTimetoken, + region: this.region !== null ? this.region : undefined, + filterExpression: this.configuration.filterExpression, + }, + (status, result) => { + this.processSubscribeResponse(status, result); + }, + ); + } + + private stopSubscribeLoop() { + if (this._subscribeAbort) { + this._subscribeAbort(); + this._subscribeAbort = null; + } + } + + /** + * Process subscribe REST API endpoint response. + */ + private processSubscribeResponse(status: Status, result: Subscription.SubscriptionResponse | null) { + if (status.error) { + // Ignore aborted request. + if (typeof status.errorData === 'object' && 'name' in status.errorData && status.errorData.name === 'AbortError') + return; + + if (status.category === Categories.PNTimeoutCategory) { + this.startSubscribeLoop(); + } else if (status.category === Categories.PNNetworkIssuesCategory) { + this.disconnect(); + + if (status.error && this.configuration.autoNetworkDetection && this.isOnline) { + this.isOnline = false; + this.listenerManager.announceNetworkDown(); + } + + this.reconnectionManager.onReconnect(() => { + if (this.configuration.autoNetworkDetection && !this.isOnline) { + this.isOnline = true; + this.listenerManager.announceNetworkUp(); + } + + this.reconnect(); + this.subscriptionStatusAnnounced = true; + + const reconnectedAnnounce = { + category: Categories.PNReconnectedCategory, + operation: status.operation, + lastTimetoken: this.lastTimetoken, + currentTimetoken: this.currentTimetoken, + }; + this.listenerManager.announceStatus(reconnectedAnnounce); + }); + + this.reconnectionManager.startPolling(); + this.listenerManager.announceStatus(status); + } else if (status.category === Categories.PNBadRequestCategory) { + this.stopHeartbeatTimer(); + this.listenerManager.announceStatus(status); + } else { + this.listenerManager.announceStatus(status); + } + + return; + } + + if (this.storedTimetoken) { + this.currentTimetoken = this.storedTimetoken; + this.storedTimetoken = null; + } else { + this.lastTimetoken = this.currentTimetoken; + this.currentTimetoken = result!.cursor.timetoken; + } + + if (!this.subscriptionStatusAnnounced) { + const connected: StatusEvent = { + category: StatusCategory.PNConnectedCategory, + operation: status.operation, + affectedChannels: this.pendingChannelSubscriptions, + subscribedChannels: this.subscribedChannels, + affectedChannelGroups: this.pendingChannelGroupSubscriptions, + lastTimetoken: this.lastTimetoken, + currentTimetoken: this.currentTimetoken, + }; + + this.subscriptionStatusAnnounced = true; + this.listenerManager.announceStatus(connected); + + // Clear pending channels and groups. + this.pendingChannelGroupSubscriptions = []; + this.pendingChannelSubscriptions = []; + } + + const { messages } = result!; + const { requestMessageCountThreshold, dedupeOnSubscribe } = this.configuration; + + if (requestMessageCountThreshold && messages.length >= requestMessageCountThreshold) { + this.listenerManager.announceStatus({ + category: StatusCategory.PNRequestMessageCountExceededCategory, + operation: status.operation, + }); + } + + messages.forEach((message) => { + if (dedupeOnSubscribe) { + if (this.dedupingManager.isDuplicate(message)) return; + this.dedupingManager.addEntry(message); + } + + this.eventEmitter.emitEvent(message); + }); + + this.region = result!.cursor.region; + this.startSubscribeLoop(); + } + // endregion + + // region Presence + /** + * Update `uuid` state which should be sent with subscribe request. + * + * @param parameters - Channels and groups with state which should be associated to `uuid`. + */ + public setState(parameters: { state: Payload; channels?: string[]; channelGroups?: string[] }) { + const { state, channels, channelGroups } = parameters; + channels?.forEach((channel) => channel in this.channels && (this.presenceState[channel] = state)); + channelGroups?.forEach((group) => group in this.channelGroups && (this.presenceState[group] = state)); + } + + /** + * Manual presence management. + * + * @param parameters - Desired presence state for provided list of channels and groups. + */ + public changePresence(parameters: { connected: boolean; channels?: string[]; channelGroups?: string[] }) { + const { connected, channels, channelGroups } = parameters; + + if (connected) { + channels?.forEach((channel) => (this.heartbeatChannels[channel] = {})); + channelGroups?.forEach((group) => (this.heartbeatChannelGroups[group] = {})); + } else { + channels?.forEach((channel) => { + if (channel in this.heartbeatChannels) delete this.heartbeatChannels[channel]; + }); + + channelGroups?.forEach((group) => { + if (group in this.heartbeatChannelGroups) delete this.heartbeatChannelGroups[group]; + }); + + if (this.configuration.suppressLeaveEvents === false) { + this.leaveCall({ channels, channelGroups }, (status) => this.listenerManager.announceStatus(status)); + } + } + + this.reconnect(); + } + + private startHeartbeatTimer() { + this.stopHeartbeatTimer(); + + const heartbeatInterval = this.configuration.getHeartbeatInterval(); + if (!heartbeatInterval || heartbeatInterval === 0) return; + + this.sendHeartbeat(); + this.heartbeatTimer = setInterval(() => this.sendHeartbeat(), heartbeatInterval * 1000) as unknown as number; + } + + /** + * Stop heartbeat. + * + * Stop timer which trigger {@link HeartbeatRequest} sending with configured presence intervals. + */ + private stopHeartbeatTimer() { + if (!this.heartbeatTimer) return; + + clearInterval(this.heartbeatTimer); + this.heartbeatTimer = null; + } + + /** + * Send heartbeat request. + */ + private sendHeartbeat() { + const heartbeatChannelGroups = Object.keys(this.heartbeatChannelGroups); + const heartbeatChannels = Object.keys(this.heartbeatChannels); + + // There is no need to start heartbeat loop if there is no channels and groups to use. + if (heartbeatChannels.length === 0 && heartbeatChannelGroups.length === 0) return; + + this.heartbeatCall( + { + channels: heartbeatChannels, + channelGroups: heartbeatChannelGroups, + heartbeat: this.configuration.getPresenceTimeout(), + state: this.presenceState, + }, + (status) => { + if (status.error && this.configuration.announceFailedHeartbeats) this.listenerManager.announceStatus(status); + if (status.error && this.configuration.autoNetworkDetection && this.isOnline) { + this.isOnline = false; + this.disconnect(); + this.listenerManager.announceNetworkDown(); + this.reconnect(); + } + + if (!status.error && this.configuration.announceSuccessfulHeartbeats) this.listenerManager.announceNetworkUp(); + }, + ); + } + // endregion +} diff --git a/src/core/components/subscription_manager.js b/src/core/components/subscription_manager.js deleted file mode 100644 index 1dd6fbed2..000000000 --- a/src/core/components/subscription_manager.js +++ /dev/null @@ -1,579 +0,0 @@ -import ReconnectionManager from './reconnection_manager'; -import DedupingManager from './deduping_manager'; -import utils from '../utils'; -import categoryConstants from '../constants/categories'; - -export default class { - _crypto; - - _config; - - _listenerManager; - - _reconnectionManager; - - _leaveEndpoint; - - _heartbeatEndpoint; - - _setStateEndpoint; - - _subscribeEndpoint; - - _getFileUrl; - - _channels; - - _presenceChannels; - - _heartbeatChannels; - - _heartbeatChannelGroups; - - _channelGroups; - - _presenceChannelGroups; - - _currentTimetoken; - - _lastTimetoken; - - _storedTimetoken; - - _region; - - _subscribeCall; - - _heartbeatTimer; - - _subscriptionStatusAnnounced; - - _autoNetworkDetection; - - _isOnline; - - // store pending connection elements - _pendingChannelSubscriptions; - - _pendingChannelGroupSubscriptions; - // - - _cryptoModule; - - _decoder; - - _dedupingManager; - - _eventEmitter; - - constructor({ - subscribeEndpoint, - leaveEndpoint, - heartbeatEndpoint, - setStateEndpoint, - timeEndpoint, - getFileUrl, - config, - crypto, - listenerManager, - cryptoModule, - eventEmitter, - }) { - this._listenerManager = listenerManager; - this._config = config; - - this._leaveEndpoint = leaveEndpoint; - this._heartbeatEndpoint = heartbeatEndpoint; - this._setStateEndpoint = setStateEndpoint; - this._subscribeEndpoint = subscribeEndpoint; - this._getFileUrl = getFileUrl; - - this._crypto = crypto; - this._cryptoModule = cryptoModule; - - this._channels = {}; - this._presenceChannels = {}; - - this._heartbeatChannels = {}; - this._heartbeatChannelGroups = {}; - - this._channelGroups = {}; - this._presenceChannelGroups = {}; - - this._pendingChannelSubscriptions = []; - this._pendingChannelGroupSubscriptions = []; - - this._currentTimetoken = 0; - this._lastTimetoken = 0; - this._storedTimetoken = null; - - this._subscriptionStatusAnnounced = false; - - this._isOnline = true; - - this._reconnectionManager = new ReconnectionManager({ timeEndpoint }); - this._dedupingManager = new DedupingManager({ config }); - - if (this._cryptoModule) this._decoder = new TextDecoder(); - - this._eventEmitter = eventEmitter; - } - - adaptStateChange(args, callback) { - const { state, channels = [], channelGroups = [], withHeartbeat = false } = args; - - channels.forEach((channel) => { - if (channel in this._channels) this._channels[channel].state = state; - }); - - channelGroups.forEach((channelGroup) => { - if (channelGroup in this._channelGroups) { - this._channelGroups[channelGroup].state = state; - } - }); - - if (withHeartbeat) { - let presenceState = {}; - channels.forEach((channel) => (presenceState[channel] = state)); - channelGroups.forEach((group) => (presenceState[group] = state)); - return this._heartbeatEndpoint( - { channels: channels, channelGroups: channelGroups, state: presenceState }, - callback, - ); - } - - return this._setStateEndpoint({ state, channels, channelGroups }, callback); - } - - adaptPresenceChange(args) { - const { connected, channels = [], channelGroups = [] } = args; - - if (connected) { - channels.forEach((channel) => { - this._heartbeatChannels[channel] = { state: {} }; - }); - - channelGroups.forEach((channelGroup) => { - this._heartbeatChannelGroups[channelGroup] = { state: {} }; - }); - } else { - channels.forEach((channel) => { - if (channel in this._heartbeatChannels) { - delete this._heartbeatChannels[channel]; - } - }); - - channelGroups.forEach((channelGroup) => { - if (channelGroup in this._heartbeatChannelGroups) { - delete this._heartbeatChannelGroups[channelGroup]; - } - }); - - if (this._config.suppressLeaveEvents === false) { - this._leaveEndpoint({ channels, channelGroups }, (status) => { - this._listenerManager.announceStatus(status); - }); - } - } - - this.reconnect(); - } - - adaptSubscribeChange(args) { - const { timetoken, channels = [], channelGroups = [], withPresence = false, withHeartbeats = false } = args; - - if (!this._config.subscribeKey || this._config.subscribeKey === '') { - // eslint-disable-next-line - if (console && console.log) { - console.log('subscribe key missing; aborting subscribe'); //eslint-disable-line - } - return; - } - - if (timetoken) { - this._lastTimetoken = this._currentTimetoken; - this._currentTimetoken = timetoken; - } - - // reset the current timetoken to get a connect event. - // $FlowFixMe - if (this._currentTimetoken !== '0' && this._currentTimetoken !== 0) { - this._storedTimetoken = this._currentTimetoken; - this._currentTimetoken = 0; - } - - channels.forEach((channel) => { - this._channels[channel] = { state: {} }; - if (withPresence) this._presenceChannels[channel] = {}; - if (withHeartbeats || this._config.getHeartbeatInterval()) this._heartbeatChannels[channel] = {}; - - this._pendingChannelSubscriptions.push(channel); - }); - - channelGroups.forEach((channelGroup) => { - this._channelGroups[channelGroup] = { state: {} }; - if (withPresence) this._presenceChannelGroups[channelGroup] = {}; - if (withHeartbeats || this._config.getHeartbeatInterval()) this._heartbeatChannelGroups[channelGroup] = {}; - - this._pendingChannelGroupSubscriptions.push(channelGroup); - }); - - this._subscriptionStatusAnnounced = false; - this.reconnect(); - } - - adaptUnsubscribeChange(args, isOffline) { - const { channels = [], channelGroups = [] } = args; - - // keep track of which channels and channel groups - // we are going to unsubscribe from. - const actualChannels = []; - const actualChannelGroups = []; - // - - channels.forEach((channel) => { - if (channel in this._channels) { - delete this._channels[channel]; - actualChannels.push(channel); - - if (channel in this._heartbeatChannels) { - delete this._heartbeatChannels[channel]; - } - } - if (channel in this._presenceChannels) { - delete this._presenceChannels[channel]; - actualChannels.push(channel); - } - }); - - channelGroups.forEach((channelGroup) => { - if (channelGroup in this._channelGroups) { - delete this._channelGroups[channelGroup]; - actualChannelGroups.push(channelGroup); - - if (channelGroup in this._heartbeatChannelGroups) { - delete this._heartbeatChannelGroups[channelGroup]; - } - } - if (channelGroup in this._presenceChannelGroups) { - delete this._presenceChannelGroups[channelGroup]; - actualChannelGroups.push(channelGroup); - } - }); - - // no-op if there are no channels and cg's to unsubscribe from. - if (actualChannels.length === 0 && actualChannelGroups.length === 0) { - return; - } - - if (this._config.suppressLeaveEvents === false && !isOffline) { - this._leaveEndpoint({ channels: actualChannels, channelGroups: actualChannelGroups }, (status) => { - status.affectedChannels = actualChannels; - status.affectedChannelGroups = actualChannelGroups; - status.currentTimetoken = this._currentTimetoken; - status.lastTimetoken = this._lastTimetoken; - this._listenerManager.announceStatus(status); - }); - } - - // if we have nothing to subscribe to, reset the timetoken. - if ( - Object.keys(this._channels).length === 0 && - Object.keys(this._presenceChannels).length === 0 && - Object.keys(this._channelGroups).length === 0 && - Object.keys(this._presenceChannelGroups).length === 0 - ) { - this._lastTimetoken = 0; - this._currentTimetoken = 0; - this._storedTimetoken = null; - this._region = null; - this._reconnectionManager.stopPolling(); - } - - this.reconnect(); - } - - unsubscribeAll(isOffline) { - this.adaptUnsubscribeChange( - { - channels: this.getSubscribedChannels(), - channelGroups: this.getSubscribedChannelGroups(), - }, - isOffline, - ); - } - - getHeartbeatChannels() { - return Object.keys(this._heartbeatChannels); - } - - getHeartbeatChannelGroups() { - return Object.keys(this._heartbeatChannelGroups); - } - - getSubscribedChannels() { - return Object.keys(this._channels); - } - - getSubscribedChannelGroups() { - return Object.keys(this._channelGroups); - } - - reconnect() { - this._startSubscribeLoop(); - this._registerHeartbeatTimer(); - } - - disconnect() { - this._stopSubscribeLoop(); - this._stopHeartbeatTimer(); - this._reconnectionManager.stopPolling(); - } - - _registerHeartbeatTimer() { - this._stopHeartbeatTimer(); - - // if the interval is 0 or undefined, do not queue up heartbeating - if (this._config.getHeartbeatInterval() === 0 || this._config.getHeartbeatInterval() === undefined) { - return; - } - - this._performHeartbeatLoop(); - // $FlowFixMe - this._heartbeatTimer = setInterval( - this._performHeartbeatLoop.bind(this), - this._config.getHeartbeatInterval() * 1000, - ); - } - - _stopHeartbeatTimer() { - if (this._heartbeatTimer) { - // $FlowFixMe - clearInterval(this._heartbeatTimer); - this._heartbeatTimer = null; - } - } - - _performHeartbeatLoop() { - const heartbeatChannels = this.getHeartbeatChannels(); - - const heartbeatChannelGroups = this.getHeartbeatChannelGroups(); - - const presenceState = {}; - - if (heartbeatChannels.length === 0 && heartbeatChannelGroups.length === 0) { - return; - } - - this.getSubscribedChannels().forEach((channel) => { - const channelState = this._channels[channel].state; - if (Object.keys(channelState).length) { - presenceState[channel] = channelState; - } - }); - - this.getSubscribedChannelGroups().forEach((channelGroup) => { - const channelGroupState = this._channelGroups[channelGroup].state; - if (Object.keys(channelGroupState).length) { - presenceState[channelGroup] = channelGroupState; - } - }); - - const onHeartbeat = (status) => { - if (status.error && this._config.announceFailedHeartbeats) { - this._listenerManager.announceStatus(status); - } - - if (status.error && this._config.autoNetworkDetection && this._isOnline) { - this._isOnline = false; - this.disconnect(); - this._listenerManager.announceNetworkDown(); - this.reconnect(); - } - - if (!status.error && this._config.announceSuccessfulHeartbeats) { - this._listenerManager.announceStatus(status); - } - }; - - this._heartbeatEndpoint( - { - channels: heartbeatChannels, - channelGroups: heartbeatChannelGroups, - state: presenceState, - }, - onHeartbeat.bind(this), - ); - } - - _startSubscribeLoop() { - this._stopSubscribeLoop(); - const presenceState = {}; - const channels = []; - const channelGroups = []; - - Object.keys(this._channels).forEach((channel) => { - const channelState = this._channels[channel].state; - - if (Object.keys(channelState).length) { - presenceState[channel] = channelState; - } - - channels.push(channel); - }); - Object.keys(this._presenceChannels).forEach((channel) => { - channels.push(`${channel}-pnpres`); - }); - - Object.keys(this._channelGroups).forEach((channelGroup) => { - const channelGroupState = this._channelGroups[channelGroup].state; - - if (Object.keys(channelGroupState).length) { - presenceState[channelGroup] = channelGroupState; - } - - channelGroups.push(channelGroup); - }); - Object.keys(this._presenceChannelGroups).forEach((channelGroup) => { - channelGroups.push(`${channelGroup}-pnpres`); - }); - - if (channels.length === 0 && channelGroups.length === 0) { - return; - } - - const subscribeArgs = { - channels, - channelGroups, - state: presenceState, - timetoken: this._currentTimetoken, - filterExpression: this._config.filterExpression, - region: this._region, - }; - - this._subscribeCall = this._subscribeEndpoint(subscribeArgs, this._processSubscribeResponse.bind(this)); - } - - _processSubscribeResponse(status, payload) { - if (status.error) { - // if error comes from request abort, ignore - if (status.errorData && status.errorData.message === 'Aborted') { - return; - } - - // if we timeout from server, restart the loop. - if (status.category === categoryConstants.PNTimeoutCategory) { - this._startSubscribeLoop(); - } else if (status.category === categoryConstants.PNNetworkIssuesCategory) { - // we lost internet connection, alert the reconnection manager and terminate all loops - this.disconnect(); - - if (status.error && this._config.autoNetworkDetection && this._isOnline) { - this._isOnline = false; - this._listenerManager.announceNetworkDown(); - } - - this._reconnectionManager.onReconnection(() => { - if (this._config.autoNetworkDetection && !this._isOnline) { - this._isOnline = true; - this._listenerManager.announceNetworkUp(); - } - this.reconnect(); - this._subscriptionStatusAnnounced = true; - const reconnectedAnnounce = { - category: categoryConstants.PNReconnectedCategory, - operation: status.operation, - lastTimetoken: this._lastTimetoken, - currentTimetoken: this._currentTimetoken, - }; - this._listenerManager.announceStatus(reconnectedAnnounce); - }); - - this._reconnectionManager.startPolling(); - this._listenerManager.announceStatus(status); - } else if (status.category === categoryConstants.PNBadRequestCategory) { - this._stopHeartbeatTimer(); - this._listenerManager.announceStatus(status); - } else { - this._listenerManager.announceStatus(status); - } - - return; - } - - if (this._storedTimetoken) { - this._currentTimetoken = this._storedTimetoken; - this._storedTimetoken = null; - } else { - this._lastTimetoken = this._currentTimetoken; - this._currentTimetoken = payload.metadata.timetoken; - } - - if (!this._subscriptionStatusAnnounced) { - const connectedAnnounce = {}; - connectedAnnounce.category = categoryConstants.PNConnectedCategory; - connectedAnnounce.operation = status.operation; - connectedAnnounce.affectedChannels = this._pendingChannelSubscriptions; - connectedAnnounce.subscribedChannels = this.getSubscribedChannels(); - connectedAnnounce.affectedChannelGroups = this._pendingChannelGroupSubscriptions; - connectedAnnounce.lastTimetoken = this._lastTimetoken; - connectedAnnounce.currentTimetoken = this._currentTimetoken; - this._subscriptionStatusAnnounced = true; - this._listenerManager.announceStatus(connectedAnnounce); - - // clear the pending connections list - this._pendingChannelSubscriptions = []; - this._pendingChannelGroupSubscriptions = []; - } - - const messages = payload.messages || []; - const { requestMessageCountThreshold, dedupeOnSubscribe } = this._config; - - if (requestMessageCountThreshold && messages.length >= requestMessageCountThreshold) { - const countAnnouncement = {}; - countAnnouncement.category = categoryConstants.PNRequestMessageCountExceededCategory; - countAnnouncement.operation = status.operation; - this._listenerManager.announceStatus(countAnnouncement); - } - - messages.forEach((message) => { - const { channel } = message; - let { subscriptionMatch } = message; - - if (channel === subscriptionMatch) { - subscriptionMatch = null; - } - - if (dedupeOnSubscribe) { - if (this._dedupingManager.isDuplicate(message)) { - return; - } - this._dedupingManager.addEntry(message); - } - - this._eventEmitter.emitEvent(message); - }); - - this._region = payload.metadata.region; - this._startSubscribeLoop(); - } - - _stopSubscribeLoop() { - if (this._subscribeCall) { - if (typeof this._subscribeCall.abort === 'function') { - this._subscribeCall.abort(); - } - this._subscribeCall = null; - } - } - - _renameEvent(e) { - return e === 'set' ? 'updated' : 'removed'; - } - - _renameChannelField(announce) { - const { channel, ...eventData } = announce; - eventData.spaceId = channel; - return eventData; - } -} diff --git a/src/core/components/telemetry_manager.js b/src/core/components/telemetry_manager.js deleted file mode 100644 index fa4392df4..000000000 --- a/src/core/components/telemetry_manager.js +++ /dev/null @@ -1,151 +0,0 @@ -/* */ -import operationConstants from '../constants/operations'; - -export default class { - _maximumSamplesCount = 100; - - _trackedLatencies = {}; - - _latencies = {}; - - _telemetryExcludeOperations = [ - operationConstants.PNSubscribeOperation, - operationConstants.PNReceiveMessagesOperation, - operationConstants.PNHandshakeOperation, - ]; - - constructor(configuration) { - this._maximumSamplesCount = configuration.maximumSamplesCount || this._maximumSamplesCount; - } - - /** - * Compose object with latency information of recently used API endpoints. - * - * @return {Object} Object with request query key/value pairs. - */ - operationsLatencyForRequest() { - const latencies = {}; - - Object.keys(this._latencies).forEach((endpointName) => { - const operationLatencies = this._latencies[endpointName]; - const averageLatency = this._averageLatency(operationLatencies); - - if (averageLatency > 0) { - latencies[`l_${endpointName}`] = averageLatency; - } - }); - - return latencies; - } - - startLatencyMeasure(operationType, identifier) { - if (this._telemetryExcludeOperations.includes(operationType) || !identifier) { - return; - } - - this._trackedLatencies[identifier] = Date.now(); - } - - stopLatencyMeasure(operationType, identifier) { - if (this._telemetryExcludeOperations.includes(operationType) || !identifier) { - return; - } - - const endpointName = this._endpointName(operationType); - /** @type Array */ - let endpointLatencies = this._latencies[endpointName]; - const startDate = this._trackedLatencies[identifier]; - - if (!endpointLatencies) { - this._latencies[endpointName] = []; - endpointLatencies = this._latencies[endpointName]; - } - - endpointLatencies.push(Date.now() - startDate); - - // Truncate samples count if there is more then configured. - if (endpointLatencies.length > this._maximumSamplesCount) { - endpointLatencies.splice(0, endpointLatencies.length - this._maximumSamplesCount); - } - - delete this._trackedLatencies[identifier]; - } - - _averageLatency(latencies) { - const arrayReduce = (accumulatedLatency, latency) => accumulatedLatency + latency; - - return Math.floor(latencies.reduce(arrayReduce, 0) / latencies.length); - } - - _endpointName(operationType) { - let operation = null; - - switch (operationType) { - case operationConstants.PNPublishOperation: - operation = 'pub'; - break; - case operationConstants.PNSignalOperation: - operation = 'sig'; - break; - case operationConstants.PNHistoryOperation: - case operationConstants.PNFetchMessagesOperation: - case operationConstants.PNDeleteMessagesOperation: - case operationConstants.PNMessageCounts: - operation = 'hist'; - break; - case operationConstants.PNUnsubscribeOperation: - case operationConstants.PNWhereNowOperation: - case operationConstants.PNHereNowOperation: - case operationConstants.PNHeartbeatOperation: - case operationConstants.PNSetStateOperation: - case operationConstants.PNGetStateOperation: - operation = 'pres'; - break; - case operationConstants.PNAddChannelsToGroupOperation: - case operationConstants.PNRemoveChannelsFromGroupOperation: - case operationConstants.PNChannelGroupsOperation: - case operationConstants.PNRemoveGroupOperation: - case operationConstants.PNChannelsForGroupOperation: - operation = 'cg'; - break; - case operationConstants.PNPushNotificationEnabledChannelsOperation: - case operationConstants.PNRemoveAllPushNotificationsOperation: - operation = 'push'; - break; - case operationConstants.PNCreateUserOperation: - case operationConstants.PNUpdateUserOperation: - case operationConstants.PNDeleteUserOperation: - case operationConstants.PNGetUserOperation: - case operationConstants.PNGetUsersOperation: - case operationConstants.PNCreateSpaceOperation: - case operationConstants.PNUpdateSpaceOperation: - case operationConstants.PNDeleteSpaceOperation: - case operationConstants.PNGetSpaceOperation: - case operationConstants.PNGetSpacesOperation: - case operationConstants.PNGetMembersOperation: - case operationConstants.PNUpdateMembersOperation: - case operationConstants.PNGetMembershipsOperation: - case operationConstants.PNUpdateMembershipsOperation: - operation = 'obj'; - break; - case operationConstants.PNAddMessageActionOperation: - case operationConstants.PNRemoveMessageActionOperation: - case operationConstants.PNGetMessageActionsOperation: - operation = 'msga'; - break; - case operationConstants.PNAccessManagerGrant: - case operationConstants.PNAccessManagerAudit: - operation = 'pam'; - break; - case operationConstants.PNAccessManagerGrantToken: - case operationConstants.PNAccessManagerRevokeToken: - operation = 'pamv3'; - break; - default: - operation = 'time'; - break; - } - - return operation; - } -} diff --git a/src/core/components/token_manager.js b/src/core/components/token_manager.js index 72dfa8617..895bc29eb 100644 --- a/src/core/components/token_manager.js +++ b/src/core/components/token_manager.js @@ -1,12 +1,9 @@ export default class { - _config; - _cbor; _token; - constructor(config, cbor) { - this._config = config; + constructor(cbor) { this._cbor = cbor; } diff --git a/src/core/constants/categories.js b/src/core/constants/categories.js deleted file mode 100644 index bf48a79d1..000000000 --- a/src/core/constants/categories.js +++ /dev/null @@ -1,36 +0,0 @@ -/* */ -export default { - // SDK will announce when the network appears to be connected again. - PNNetworkUpCategory: 'PNNetworkUpCategory', - - // SDK will announce when the network appears to down. - PNNetworkDownCategory: 'PNNetworkDownCategory', - - // call failed when network was unable to complete the call. - PNNetworkIssuesCategory: 'PNNetworkIssuesCategory', - - // network call timed out - PNTimeoutCategory: 'PNTimeoutCategory', - - // server responded with bad response - PNBadRequestCategory: 'PNBadRequestCategory', - - // server responded with access denied - PNAccessDeniedCategory: 'PNAccessDeniedCategory', - - // something strange happened; please check the logs. - PNUnknownCategory: 'PNUnknownCategory', - - // on reconnection - PNReconnectedCategory: 'PNReconnectedCategory', - - PNConnectedCategory: 'PNConnectedCategory', - - PNRequestMessageCountExceededCategory: 'PNRequestMessageCountExceededCategory', - - PNDisconnectedCategory: 'PNDisconnectedCategory', - - PNConnectionErrorCategory: 'PNConnectionErrorCategory', - - PNDisconnectedUnexpectedlyCategory: 'PNDisconnectedUnexpectedlyCategory', -}; diff --git a/src/core/constants/categories.ts b/src/core/constants/categories.ts new file mode 100644 index 000000000..060c59988 --- /dev/null +++ b/src/core/constants/categories.ts @@ -0,0 +1,87 @@ +/** + * Request processing status categories. + */ +enum StatusCategory { + /** + * Call failed when network was unable to complete the call. + */ + PNNetworkIssuesCategory = 'PNNetworkIssuesCategory', + + /** + * Network call timed out. + */ + PNTimeoutCategory = 'PNTimeoutCategory', + + /** + * Request has been cancelled. + */ + PNCancelledCategory = 'PNCancelledCategory', + + /** + * Server responded with bad response. + */ + PNBadRequestCategory = 'PNBadRequestCategory', + + /** + * Server responded with access denied. + */ + PNAccessDeniedCategory = 'PNAccessDeniedCategory', + + /** + * Something strange happened; please check the logs. + */ + PNUnknownCategory = 'PNUnknownCategory', + + // -------------------------------------------------------- + // --------------------- Network status ------------------- + // -------------------------------------------------------- + + /** + * SDK will announce when the network appears to be connected again. + */ + PNNetworkUpCategory = 'PNNetworkUpCategory', + + /** + * SDK will announce when the network appears to down. + */ + PNNetworkDownCategory = 'PNNetworkDownCategory', + + // -------------------------------------------------------- + // -------------------- Real-time events ------------------ + // -------------------------------------------------------- + + /** + * PubNub client reconnected to the real-time updates stream. + */ + PNReconnectedCategory = 'PNReconnectedCategory', + + /** + * PubNub client connected to the real-time updates stream. + */ + PNConnectedCategory = 'PNConnectedCategory', + + /** + * Received real-time updates exceed specified threshold. + * + * After temporary disconnection and catchup, this category means that potentially some + * real-time updates have been pushed into `storage` and need to be requested separately. + */ + PNRequestMessageCountExceededCategory = 'PNRequestMessageCountExceededCategory', + + /** + * PubNub client disconnected from the real-time updates streams. + */ + PNDisconnectedCategory = 'PNDisconnectedCategory', + + /** + * PubNub client wasn't able to connect to the real-time updates streams. + */ + PNConnectionErrorCategory = 'PNConnectionErrorCategory', + + /** + * PubNub client unexpectedly disconnected from the real-time updates streams. + */ + PNDisconnectedUnexpectedlyCategory = 'PNDisconnectedUnexpectedlyCategory', +} + +export default StatusCategory; diff --git a/src/core/constants/operations.js b/src/core/constants/operations.js deleted file mode 100644 index 7d1ffcaca..000000000 --- a/src/core/constants/operations.js +++ /dev/null @@ -1,92 +0,0 @@ -/* */ -export default { - PNTimeOperation: 'PNTimeOperation', - - PNHistoryOperation: 'PNHistoryOperation', - PNDeleteMessagesOperation: 'PNDeleteMessagesOperation', - PNFetchMessagesOperation: 'PNFetchMessagesOperation', - PNMessageCounts: 'PNMessageCountsOperation', - - // pubsub - PNSubscribeOperation: 'PNSubscribeOperation', - PNUnsubscribeOperation: 'PNUnsubscribeOperation', - PNPublishOperation: 'PNPublishOperation', - PNSignalOperation: 'PNSignalOperation', - - // Actions API - PNAddMessageActionOperation: 'PNAddActionOperation', - PNRemoveMessageActionOperation: 'PNRemoveMessageActionOperation', - PNGetMessageActionsOperation: 'PNGetMessageActionsOperation', - - // Objects API - PNCreateUserOperation: 'PNCreateUserOperation', - PNUpdateUserOperation: 'PNUpdateUserOperation', - PNDeleteUserOperation: 'PNDeleteUserOperation', - PNGetUserOperation: 'PNGetUsersOperation', - PNGetUsersOperation: 'PNGetUsersOperation', - PNCreateSpaceOperation: 'PNCreateSpaceOperation', - PNUpdateSpaceOperation: 'PNUpdateSpaceOperation', - PNDeleteSpaceOperation: 'PNDeleteSpaceOperation', - PNGetSpaceOperation: 'PNGetSpacesOperation', - PNGetSpacesOperation: 'PNGetSpacesOperation', - PNGetMembersOperation: 'PNGetMembersOperation', - PNUpdateMembersOperation: 'PNUpdateMembersOperation', - PNGetMembershipsOperation: 'PNGetMembershipsOperation', - PNUpdateMembershipsOperation: 'PNUpdateMembershipsOperation', - - // File Upload API v1 - PNListFilesOperation: 'PNListFilesOperation', - PNGenerateUploadUrlOperation: 'PNGenerateUploadUrlOperation', - PNPublishFileOperation: 'PNPublishFileOperation', - PNGetFileUrlOperation: 'PNGetFileUrlOperation', - PNDownloadFileOperation: 'PNDownloadFileOperation', - - // Objects API v2 - // UUID - PNGetAllUUIDMetadataOperation: 'PNGetAllUUIDMetadataOperation', - PNGetUUIDMetadataOperation: 'PNGetUUIDMetadataOperation', - PNSetUUIDMetadataOperation: 'PNSetUUIDMetadataOperation', - PNRemoveUUIDMetadataOperation: 'PNRemoveUUIDMetadataOperation', - // channel - PNGetAllChannelMetadataOperation: 'PNGetAllChannelMetadataOperation', - PNGetChannelMetadataOperation: 'PNGetChannelMetadataOperation', - PNSetChannelMetadataOperation: 'PNSetChannelMetadataOperation', - PNRemoveChannelMetadataOperation: 'PNRemoveChannelMetadataOperation', - // member - // PNGetMembersOperation: 'PNGetMembersOperation', - PNSetMembersOperation: 'PNSetMembersOperation', - // PNGetMembershipsOperation: 'PNGetMembersOperation', - PNSetMembershipsOperation: 'PNSetMembershipsOperation', - - // push - PNPushNotificationEnabledChannelsOperation: 'PNPushNotificationEnabledChannelsOperation', - PNRemoveAllPushNotificationsOperation: 'PNRemoveAllPushNotificationsOperation', - // - - // presence - PNWhereNowOperation: 'PNWhereNowOperation', - PNSetStateOperation: 'PNSetStateOperation', - PNHereNowOperation: 'PNHereNowOperation', - PNGetStateOperation: 'PNGetStateOperation', - PNHeartbeatOperation: 'PNHeartbeatOperation', - // - - // channel group - PNChannelGroupsOperation: 'PNChannelGroupsOperation', - PNRemoveGroupOperation: 'PNRemoveGroupOperation', - PNChannelsForGroupOperation: 'PNChannelsForGroupOperation', - PNAddChannelsToGroupOperation: 'PNAddChannelsToGroupOperation', - PNRemoveChannelsFromGroupOperation: 'PNRemoveChannelsFromGroupOperation', - // - - // PAM - PNAccessManagerGrant: 'PNAccessManagerGrant', - PNAccessManagerGrantToken: 'PNAccessManagerGrantToken', - PNAccessManagerAudit: 'PNAccessManagerAudit', - PNAccessManagerRevokeToken: 'PNAccessManagerRevokeToken', - // - - // subscription utilities - PNHandshakeOperation: 'PNHandshakeOperation', - PNReceiveMessagesOperation: 'PNReceiveMessagesOperation', -}; diff --git a/src/core/constants/operations.ts b/src/core/constants/operations.ts new file mode 100644 index 000000000..586b91ab2 --- /dev/null +++ b/src/core/constants/operations.ts @@ -0,0 +1,293 @@ +/* */ +enum RequestOperation { + // -------------------------------------------------------- + // ---------------------- Publish API --------------------- + // -------------------------------------------------------- + /** + * Data publish REST API operation. + */ + PNPublishOperation = 'PNPublishOperation', + + /** + * Signal sending REST API operation. + */ + PNSignalOperation = 'PNSignalOperation', + + // -------------------------------------------------------- + // --------------------- Subscribe API -------------------- + // -------------------------------------------------------- + /** + * Subscribe for real-time updates REST API operation. + * + * User's presence change on specified entities will trigger `join` event. + */ + PNSubscribeOperation = 'PNSubscribeOperation', + + /** + * Unsubscribe from real-time updates REST API operation. + * + * User's presence change on specified entities will trigger `leave` event. + */ + PNUnsubscribeOperation = 'PNUnsubscribeOperation', + + // -------------------------------------------------------- + // --------------------- Presence API --------------------- + // -------------------------------------------------------- + + /** + * Fetch user's presence information REST API operation. + */ + PNWhereNowOperation = 'PNWhereNowOperation', + + /** + * Fetch channel's presence information REST API operation. + */ + PNHereNowOperation = 'PNHereNowOperation', + + /** + * Update user's information associated with specified channel REST API operation. + */ + PNSetStateOperation = 'PNSetStateOperation', + + /** + * Fetch user's information associated with the specified channel REST API operation. + */ + PNGetStateOperation = 'PNGetStateOperation', + + /** + * Announce presence on managed channels REST API operation. + */ + PNHeartbeatOperation = 'PNHeartbeatOperation', + + // -------------------------------------------------------- + // ----------------- Message Reaction API ----------------- + // -------------------------------------------------------- + + /** + * Add a reaction to the specified message REST API operation. + */ + PNAddMessageActionOperation = 'PNAddActionOperation', + + /** + * Remove reaction from the specified message REST API operation. + */ + PNRemoveMessageActionOperation = 'PNRemoveMessageActionOperation', + + /** + * Fetch reactions for specific message REST API operation. + */ + PNGetMessageActionsOperation = 'PNGetMessageActionsOperation', + + PNTimeOperation = 'PNTimeOperation', + + // -------------------------------------------------------- + // ---------------------- Storage API --------------------- + // -------------------------------------------------------- + + /** + * Channel history REST API operation. + */ + PNHistoryOperation = 'PNHistoryOperation', + + /** + * Delete messages from channel history REST API operation. + */ + PNDeleteMessagesOperation = 'PNDeleteMessagesOperation', + + /** + * History for channels REST API operation. + */ + PNFetchMessagesOperation = 'PNFetchMessagesOperation', + + /** + * Number of messages for channels in specified time frame REST API operation. + */ + PNMessageCounts = 'PNMessageCountsOperation', + + // -------------------------------------------------------- + // -------------------- App Context API ------------------- + // -------------------------------------------------------- + + /** + * Fetch users metadata REST API operation. + */ + PNGetAllUUIDMetadataOperation = 'PNGetAllUUIDMetadataOperation', + + /** + * Fetch user metadata REST API operation. + */ + PNGetUUIDMetadataOperation = 'PNGetUUIDMetadataOperation', + + /** + * Set user metadata REST API operation. + */ + PNSetUUIDMetadataOperation = 'PNSetUUIDMetadataOperation', + + /** + * Remove user metadata REST API operation. + */ + PNRemoveUUIDMetadataOperation = 'PNRemoveUUIDMetadataOperation', + + /** + * Fetch channels metadata REST API operation. + */ + PNGetAllChannelMetadataOperation = 'PNGetAllChannelMetadataOperation', + + /** + * Fetch channel metadata REST API operation. + */ + PNGetChannelMetadataOperation = 'PNGetChannelMetadataOperation', + + /** + * Set channel metadata REST API operation. + */ + PNSetChannelMetadataOperation = 'PNSetChannelMetadataOperation', + + /** + * Remove channel metadata REST API operation. + */ + PNRemoveChannelMetadataOperation = 'PNRemoveChannelMetadataOperation', + + /** + * Fetch channel members REST API operation. + */ + PNGetMembersOperation = 'PNGetMembersOperation', + + /** + * Update channel members REST API operation. + */ + PNSetMembersOperation = 'PNSetMembersOperation', + + /** + * Fetch channel memberships REST API operation. + */ + PNGetMembershipsOperation = 'PNGetMembershipsOperation', + + /** + * Update channel memberships REST API operation. + */ + PNSetMembershipsOperation = 'PNSetMembershipsOperation', + + // -------------------------------------------------------- + // -------------------- File Upload API ------------------- + // -------------------------------------------------------- + + /** + * Fetch list of files sent to the channel REST API operation. + */ + PNListFilesOperation = 'PNListFilesOperation', + + /** + * Retrieve file upload URL REST API operation. + */ + PNGenerateUploadUrlOperation = 'PNGenerateUploadUrlOperation', + + /** + * Upload file to the channel REST API operation. + */ + PNPublishFileOperation = 'PNPublishFileOperation', + + /** + * Publish File Message to the channel REST API operation. + */ + PNPublishFileMessageOperation = 'PNPublishFileMessageOperation', + + /** + * Retrieve file download URL REST API operation. + */ + PNGetFileUrlOperation = 'PNGetFileUrlOperation', + + /** + * Download file from the channel REST API operation. + */ + PNDownloadFileOperation = 'PNDownloadFileOperation', + + /** + * Delete file sent to the channel REST API operation. + */ + PNDeleteFileOperation = 'PNDeleteFileOperation', + + // -------------------------------------------------------- + // -------------------- Mobile Push API ------------------- + // -------------------------------------------------------- + + /** + * Register channels with device push notifications REST API operation. + */ + PNAddPushNotificationEnabledChannelsOperation = 'PNAddPushNotificationEnabledChannelsOperation', + + /** + * Unregister channels with device push notifications REST API operation. + */ + PNRemovePushNotificationEnabledChannelsOperation = 'PNRemovePushNotificationEnabledChannelsOperation', + + /** + * Fetch list of channels with enabled push notifications for device REST API operation. + */ + PNPushNotificationEnabledChannelsOperation = 'PNPushNotificationEnabledChannelsOperation', + + /** + * Disable push notifications for device REST API operation. + */ + PNRemoveAllPushNotificationsOperation = 'PNRemoveAllPushNotificationsOperation', + + // -------------------------------------------------------- + // ------------------ Channel Groups API ------------------ + // -------------------------------------------------------- + + /** + * Fetch channels groups list REST API operation. + */ + PNChannelGroupsOperation = 'PNChannelGroupsOperation', + + /** + * Remove specified channel group REST API operation. + */ + PNRemoveGroupOperation = 'PNRemoveGroupOperation', + + /** + * Fetch list of channels for the specified channel group REST API operation. + */ + PNChannelsForGroupOperation = 'PNChannelsForGroupOperation', + + /** + * Add list of channels to the specified channel group REST API operation. + */ + PNAddChannelsToGroupOperation = 'PNAddChannelsToGroupOperation', + + /** + * Remove list of channels from the specified channel group REST API operation. + */ + PNRemoveChannelsFromGroupOperation = 'PNRemoveChannelsFromGroupOperation', + + // -------------------------------------------------------- + // ----------------------- PAM API ------------------------ + // -------------------------------------------------------- + + /** + * Generate authorized token REST API operation. + */ + PNAccessManagerGrant = 'PNAccessManagerGrant', + + /** + * Generate authorized token REST API operation. + */ + PNAccessManagerGrantToken = 'PNAccessManagerGrantToken', + + PNAccessManagerAudit = 'PNAccessManagerAudit', + + /** + * Revoke authorized token REST API operation. + */ + PNAccessManagerRevokeToken = 'PNAccessManagerRevokeToken', + // + + // -------------------------------------------------------- + // ---------------- Subscription Utility ------------------ + // -------------------------------------------------------- + + PNHandshakeOperation = 'PNHandshakeOperation', + PNReceiveMessagesOperation = 'PNReceiveMessagesOperation', +} + +export default RequestOperation; diff --git a/src/core/endpoints/access_manager/audit.js b/src/core/endpoints/access_manager/audit.js deleted file mode 100644 index dcbab0a74..000000000 --- a/src/core/endpoints/access_manager/audit.js +++ /dev/null @@ -1,49 +0,0 @@ -/* */ - -import operationConstants from '../../constants/operations'; - -export function getOperation() { - return operationConstants.PNAccessManagerAudit; -} - -export function validateParams(modules) { - const { config } = modules; - - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules) { - const { config } = modules; - return `/v2/auth/audit/sub-key/${config.subscribeKey}`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return false; -} - -export function prepareParams(modules, incomingParams) { - const { channel, channelGroup, authKeys = [] } = incomingParams; - const params = {}; - - if (channel) { - params.channel = channel; - } - - if (channelGroup) { - params['channel-group'] = channelGroup; - } - - if (authKeys.length > 0) { - params.auth = authKeys.join(','); - } - - return params; -} - -export function handleResponse(modules, serverResponse) { - return serverResponse.payload; -} diff --git a/src/core/endpoints/access_manager/audit.ts b/src/core/endpoints/access_manager/audit.ts new file mode 100644 index 000000000..49ce52065 --- /dev/null +++ b/src/core/endpoints/access_manager/audit.ts @@ -0,0 +1,108 @@ +/** + * PAM Audit REST API module. + */ + +import { createValidationError, PubNubError } from '../../../models/PubNubError'; +import { TransportResponse } from '../../types/transport-response'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import * as PAM from '../../types/api/access-panager'; +import { KeySet, Query } from '../../types/api'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Auth keys for which permissions should be audited. + */ +const AUTH_KEYS: string[] = []; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = PAM.AuditParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Permissions audit human-readable result. + */ + message: string; + + /** + * Retrieved permissions information. + */ + payload: PAM.PermissionsResponse; + + /** + * Name of the service which provided response. + */ + service: string; +}; +// endregion + +/** + * Permissions audit request. + */ +export class AuditRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + + // Apply default request parameters. + this.parameters.authKeys ??= AUTH_KEYS; + } + + operation(): RequestOperation { + return RequestOperation.PNAccessManagerAudit; + } + + validate(): string | undefined { + if (!this.parameters.keySet.subscribeKey) return 'Missing Subscribe Key'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return serviceResponse.payload; + } + + protected get path(): string { + return `/v2/auth/audit/sub-key/${this.parameters.keySet.subscribeKey}`; + } + + protected get queryParameters(): Query { + const { channel, channelGroup, authKeys } = this.parameters; + + return { + ...(channel ? { channel } : {}), + ...(channelGroup ? { 'channel-group': channelGroup } : {}), + ...(authKeys && authKeys.length ? { auth: authKeys.join(',') } : {}), + }; + } +} diff --git a/src/core/endpoints/access_manager/grant.js b/src/core/endpoints/access_manager/grant.js deleted file mode 100644 index 9d63f84a8..000000000 --- a/src/core/endpoints/access_manager/grant.js +++ /dev/null @@ -1,84 +0,0 @@ -/* */ -import operationConstants from '../../constants/operations'; - -export function getOperation() { - return operationConstants.PNAccessManagerGrant; -} - -export function validateParams(modules, incomingParams) { - const { config } = modules; - - if (!config.subscribeKey) return 'Missing Subscribe Key'; - if (!config.publishKey) return 'Missing Publish Key'; - if (!config.secretKey) return 'Missing Secret Key'; - if (incomingParams.uuids != null && !incomingParams.authKeys) { - return 'authKeys are required for grant request on uuids'; - } - if (incomingParams.uuids != null && (incomingParams.channels != null || incomingParams.channelGroups != null)) { - return 'Both channel/channelgroup and uuid cannot be used in the same request'; - } -} - -export function getURL(modules) { - const { config } = modules; - return `/v2/auth/grant/sub-key/${config.subscribeKey}`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return false; -} - -export function prepareParams(modules, incomingParams) { - const { - channels = [], - channelGroups = [], - uuids = [], - ttl, - read = false, - write = false, - manage = false, - get = false, - join = false, - update = false, - authKeys = [], - } = incomingParams; - const deleteParam = incomingParams.delete; - const params = {}; - - params.r = read ? '1' : '0'; - params.w = write ? '1' : '0'; - params.m = manage ? '1' : '0'; - params.d = deleteParam ? '1' : '0'; - params.g = get ? '1' : '0'; - params.j = join ? '1' : '0'; - params.u = update ? '1' : '0'; - - if (channels.length > 0) { - params.channel = channels.join(','); - } - - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); - } - - if (authKeys.length > 0) { - params.auth = authKeys.join(','); - } - - if (uuids.length > 0) { - params['target-uuid'] = uuids.join(','); - } - - if (ttl || ttl === 0) { - params.ttl = ttl; - } - return params; -} - -export function handleResponse() { - return {}; -} diff --git a/src/core/endpoints/access_manager/grant.ts b/src/core/endpoints/access_manager/grant.ts new file mode 100644 index 000000000..c3eeac172 --- /dev/null +++ b/src/core/endpoints/access_manager/grant.ts @@ -0,0 +1,184 @@ +/** + * PAM Grant REST API module. + */ + +import { createValidationError, PubNubError } from '../../../models/PubNubError'; +import { TransportResponse } from '../../types/transport-response'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import * as PAM from '../../types/api/access-panager'; +import { KeySet, Query } from '../../types/api'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Resources `read` permission. + */ +const READ_PERMISSION = false; + +/** + * Resources `write` permission. + */ +const WRITE_PERMISSION = false; + +/** + * Resources `delete` permission. + */ +const DELETE_PERMISSION = false; + +/** + * Resources `get` permission. + */ +const GET_PERMISSION = false; + +/** + * Resources `update` permission. + */ +const UPDATE_PERMISSION = false; + +/** + * Resources `manage` permission. + */ +const MANAGE_PERMISSION = false; + +/** + * Resources `join` permission. + */ +const JOIN_PERMISSION = false; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = PAM.GrantParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Permissions grant human-readable result. + */ + message: string; + + /** + * Granted permissions' information. + */ + payload: PAM.PermissionsResponse; + + /** + * Name of the service which provided response. + */ + service: string; +}; +// endregion + +/** + * Grant permissions request. + */ +export class GrantRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + + // Apply defaults. + this.parameters.channels ??= []; + this.parameters.channelGroups ??= []; + this.parameters.uuids ??= []; + this.parameters.read ??= READ_PERMISSION; + this.parameters.write ??= WRITE_PERMISSION; + this.parameters.delete ??= DELETE_PERMISSION; + this.parameters.get ??= GET_PERMISSION; + this.parameters.update ??= UPDATE_PERMISSION; + this.parameters.manage ??= MANAGE_PERMISSION; + this.parameters.join ??= JOIN_PERMISSION; + } + + operation(): RequestOperation { + return RequestOperation.PNAccessManagerGrant; + } + + validate(): string | undefined { + const { + keySet: { subscribeKey, publishKey, secretKey }, + uuids, + channels, + channelGroups, + } = this.parameters; + + if (!subscribeKey) return 'Missing Subscribe Key'; + if (!publishKey) return 'Missing Publish Key'; + if (!secretKey) return 'Missing Secret Key'; + + if (uuids?.length !== 0 && this.parameters.authKeys?.length === 0) + return 'authKeys are required for grant request on uuids'; + + if (uuids?.length && (channels?.length !== 0 || channelGroups?.length !== 0)) + return 'Both channel/channel group and uuid cannot be used in the same request'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return serviceResponse.payload; + } + + protected get path(): string { + return `/v2/auth/grant/sub-key/${this.parameters.keySet.subscribeKey}`; + } + + protected get queryParameters(): Query { + const { + channels, + channelGroups, + authKeys, + uuids, + read, + write, + manage, + delete: del, + get, + join, + update, + ttl, + } = this.parameters; + + return { + ...(channels && channels?.length > 0 ? { channel: channels.join(',') } : {}), + ...(channelGroups && channelGroups?.length > 0 ? { 'channel-group': channelGroups.join(',') } : {}), + ...(authKeys && authKeys?.length > 0 ? { auth: authKeys.join(',') } : {}), + ...(uuids && uuids?.length > 0 ? { 'target-uuid': uuids.join(',') } : {}), + r: read ? '1' : '0', + w: write ? '1' : '0', + m: manage ? '1' : '0', + d: del ? '1' : '0', + g: get ? '1' : '0', + j: join ? '1' : '0', + u: update ? '1' : '0', + ...(ttl || ttl === 0 ? { ttl } : {}), + }; + } +} diff --git a/src/core/endpoints/access_manager/grant_token.js b/src/core/endpoints/access_manager/grant_token.js deleted file mode 100644 index 1e0ae8e25..000000000 --- a/src/core/endpoints/access_manager/grant_token.js +++ /dev/null @@ -1,299 +0,0 @@ -import operationConstants from '../../constants/operations'; - -export function getOperation() { - return operationConstants.PNAccessManagerGrantToken; -} - -function hasVspTerms(incomingParams) { - const hasAuthorizedUserId = incomingParams?.authorizedUserId !== undefined; - const hasUserResources = incomingParams?.resources?.users !== undefined; - const hasSpaceResources = incomingParams?.resources?.spaces !== undefined; - const hasUserPatterns = incomingParams?.patterns?.users !== undefined; - const hasSpacePatterns = incomingParams?.patterns?.spaces !== undefined; - - return hasUserPatterns || hasUserResources || hasSpacePatterns || hasSpaceResources || hasAuthorizedUserId; -} - -export function extractPermissions(permissions) { - let permissionsResult = 0; - - if (permissions.join) { - permissionsResult |= 128; - } - - if (permissions.update) { - permissionsResult |= 64; - } - - if (permissions.get) { - permissionsResult |= 32; - } - - if (permissions.delete) { - permissionsResult |= 8; - } - - if (permissions.manage) { - permissionsResult |= 4; - } - - if (permissions.write) { - permissionsResult |= 2; - } - - if (permissions.read) { - permissionsResult |= 1; - } - - return permissionsResult; -} - -function prepareMessagePayloadVsp(_modules, { ttl, resources, patterns, meta, authorizedUserId }) { - const params = { - ttl: 0, - permissions: { - resources: { - channels: {}, - groups: {}, - uuids: {}, - users: {}, // not used, needed for api backward compatibility - spaces: {}, // not used, needed for api backward compatibility - }, - patterns: { - channels: {}, - groups: {}, - uuids: {}, - users: {}, // not used, needed for api backward compatibility - spaces: {}, // not used, needed for api backward compatibility - }, - meta: {}, - }, - }; - - if (resources) { - const { users, spaces, groups } = resources; - - if (users) { - Object.keys(users).forEach((userID) => { - params.permissions.resources.uuids[userID] = extractPermissions(users[userID]); - }); - } - - if (spaces) { - Object.keys(spaces).forEach((spaceId) => { - params.permissions.resources.channels[spaceId] = extractPermissions(spaces[spaceId]); - }); - } - - if (groups) { - Object.keys(groups).forEach((group) => { - params.permissions.resources.groups[group] = extractPermissions(groups[group]); - }); - } - } - - if (patterns) { - const { users, spaces, groups } = patterns; - - if (users) { - Object.keys(users).forEach((userId) => { - params.permissions.patterns.uuids[userId] = extractPermissions(users[userId]); - }); - } - - if (spaces) { - Object.keys(spaces).forEach((spaceId) => { - params.permissions.patterns.channels[spaceId] = extractPermissions(spaces[spaceId]); - }); - } - - if (groups) { - Object.keys(groups).forEach((group) => { - params.permissions.patterns.groups[group] = extractPermissions(groups[group]); - }); - } - } - - if (ttl || ttl === 0) { - params.ttl = ttl; - } - - if (meta) { - params.permissions.meta = meta; - } - - if (authorizedUserId) { - params.permissions.uuid = `${authorizedUserId}`; // ensure this is a string - } - - return params; -} - -function prepareMessagePayload(_modules, incomingParams) { - if (hasVspTerms(incomingParams)) { - return prepareMessagePayloadVsp(_modules, incomingParams); - } - - const { ttl, resources, patterns, meta, authorized_uuid } = incomingParams; - - const params = { - ttl: 0, - permissions: { - resources: { - channels: {}, - groups: {}, - uuids: {}, - users: {}, // not used, needed for api backward compatibility - spaces: {}, // not used, needed for api backward compatibility - }, - patterns: { - channels: {}, - groups: {}, - uuids: {}, - users: {}, // not used, needed for api backward compatibility - spaces: {}, // not used, needed for api backward compatibility - }, - meta: {}, - }, - }; - - if (resources) { - const { uuids, channels, groups } = resources; - - if (uuids) { - Object.keys(uuids).forEach((uuid) => { - params.permissions.resources.uuids[uuid] = extractPermissions(uuids[uuid]); - }); - } - - if (channels) { - Object.keys(channels).forEach((channel) => { - params.permissions.resources.channels[channel] = extractPermissions(channels[channel]); - }); - } - - if (groups) { - Object.keys(groups).forEach((group) => { - params.permissions.resources.groups[group] = extractPermissions(groups[group]); - }); - } - } - - if (patterns) { - const { uuids, channels, groups } = patterns; - - if (uuids) { - Object.keys(uuids).forEach((uuid) => { - params.permissions.patterns.uuids[uuid] = extractPermissions(uuids[uuid]); - }); - } - - if (channels) { - Object.keys(channels).forEach((channel) => { - params.permissions.patterns.channels[channel] = extractPermissions(channels[channel]); - }); - } - - if (groups) { - Object.keys(groups).forEach((group) => { - params.permissions.patterns.groups[group] = extractPermissions(groups[group]); - }); - } - } - - if (ttl || ttl === 0) { - params.ttl = ttl; - } - - if (meta) { - params.permissions.meta = meta; - } - - if (authorized_uuid) { - params.permissions.uuid = `${authorized_uuid}`; // ensure this is a string - } - - return params; -} - -export function validateParams(modules, incomingParams) { - const { config } = modules; - - if (!config.subscribeKey) return 'Missing Subscribe Key'; - if (!config.publishKey) return 'Missing Publish Key'; - if (!config.secretKey) return 'Missing Secret Key'; - - if (!incomingParams.resources && !incomingParams.patterns) return 'Missing either Resources or Patterns.'; - - const hasAuthorizedUuid = incomingParams?.authorized_uuid !== undefined; - const hasUuidResources = incomingParams?.resources?.uuids !== undefined; - const hasChannelResources = incomingParams?.resources?.channels !== undefined; - const hasGroupResources = incomingParams?.resources?.groups !== undefined; - const hasUuidPatterns = incomingParams?.patterns?.uuids !== undefined; - const hasChannelPatterns = incomingParams?.patterns?.channels !== undefined; - const hasGroupPatterns = incomingParams?.patterns?.groups !== undefined; - - const hasLegacyTerms = - hasAuthorizedUuid || - hasUuidResources || - hasUuidPatterns || - hasChannelResources || - hasChannelPatterns || - hasGroupResources || - hasGroupPatterns; - - if (hasVspTerms(incomingParams) && hasLegacyTerms) { - return ( - 'Cannot mix `users`, `spaces` and `authorizedUserId` ' + - 'with `uuids`, `channels`, `groups` and `authorized_uuid`' - ); - } - - if ( - (incomingParams.resources && - (!incomingParams.resources.uuids || Object.keys(incomingParams.resources.uuids).length === 0) && - (!incomingParams.resources.channels || Object.keys(incomingParams.resources.channels).length === 0) && - (!incomingParams.resources.groups || Object.keys(incomingParams.resources.groups).length === 0) && - (!incomingParams.resources.users || Object.keys(incomingParams.resources.users).length === 0) && - (!incomingParams.resources.spaces || Object.keys(incomingParams.resources.spaces).length === 0)) || - (incomingParams.patterns && - (!incomingParams.patterns.uuids || Object.keys(incomingParams.patterns.uuids).length === 0) && - (!incomingParams.patterns.channels || Object.keys(incomingParams.patterns.channels).length === 0) && - (!incomingParams.patterns.groups || Object.keys(incomingParams.patterns.groups).length === 0) && - (!incomingParams.patterns.users || Object.keys(incomingParams.patterns.users).length === 0) && - (!incomingParams.patterns.spaces || Object.keys(incomingParams.patterns.spaces).length === 0)) - ) { - return 'Missing values for either Resources or Patterns.'; - } -} - -export function postURL(modules) { - const { config } = modules; - return `/v3/pam/${config.subscribeKey}/grant`; -} - -export function usePost() { - return true; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return false; -} - -export function prepareParams() { - return {}; -} - -export function postPayload(modules, incomingParams) { - return prepareMessagePayload(modules, incomingParams); -} - -export function handleResponse(modules, response) { - const { token } = response.data; - - return token; -} diff --git a/src/core/endpoints/access_manager/grant_token.ts b/src/core/endpoints/access_manager/grant_token.ts new file mode 100644 index 000000000..fd44529cb --- /dev/null +++ b/src/core/endpoints/access_manager/grant_token.ts @@ -0,0 +1,259 @@ +/** + * PAM Grant Token REST API module. + */ + +import { createValidationError, PubNubError } from '../../../models/PubNubError'; +import { TransportResponse } from '../../types/transport-response'; +import { TransportMethod } from '../../types/transport-request'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import * as PAM from '../../types/api/access-panager'; +import { KeySet } from '../../types/api'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = (PAM.GrantTokenParameters | PAM.ObjectsGrantTokenParameters) & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Permissions group payload. + * + * User can configure permissions per-resource or per-resource which match RegExp. + */ +type PermissionPayload = { + /** + * Object containing `uuid` metadata permissions. + */ + uuids?: Record; + + /** + * Object containing `channel` permissions. + */ + channels?: Record; + + /** + * Object containing `channel group` permissions. + */ + groups?: Record; + + /** + * Extra metadata to be published with the request. + * + * **Important:** Values must be scalar only; `arrays` or `objects` aren't supported. + */ + meta?: PAM.Metadata; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Request processing result data. + */ + data: { + /** + * Permissions token grant human-readable result. + */ + message: string; + + /** + * Generate token with requested permissions. + */ + token: string; + }; + + /** + * Name of the service which provided response. + */ + service: string; +}; +// endregion + +/** + * Grant token permissions request. + */ +export class GrantTokenRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super({ method: TransportMethod.POST }); + + // Apply defaults. + this.parameters.resources ??= {}; + this.parameters.patterns ??= {}; + } + + operation(): RequestOperation { + return RequestOperation.PNAccessManagerGrantToken; + } + + validate(): string | undefined { + const { + keySet: { subscribeKey, publishKey, secretKey }, + resources, + patterns, + } = this.parameters; + + if (!subscribeKey) return 'Missing Subscribe Key'; + if (!publishKey) return 'Missing Publish Key'; + if (!secretKey) return 'Missing Secret Key'; + if (!resources && !patterns) return 'Missing either Resources or Patterns'; + + if ( + this.isVspPermissions(this.parameters) && + ('channels' in (this.parameters.resources ?? {}) || + 'uuids' in (this.parameters.resources ?? {}) || + 'groups' in (this.parameters.resources ?? {}) || + 'channels' in (this.parameters.patterns ?? {}) || + 'uuids' in (this.parameters.patterns ?? {}) || + 'groups' in (this.parameters.patterns ?? {})) + ) + return ( + 'Cannot mix `users`, `spaces` and `authorizedUserId` with `uuids`, `channels`,' + + ' `groups` and `authorized_uuid`' + ); + + let permissionsEmpty = true; + [this.parameters.resources, this.parameters.patterns].forEach((refPerm) => { + Object.keys(refPerm ?? {}).forEach((scope) => { + // @ts-expect-error Permissions with backward compatibility. + if (refPerm && permissionsEmpty && Object.keys(refPerm[scope] ?? {}).length > 0) { + permissionsEmpty = false; + } + }); + }); + + if (permissionsEmpty) return 'Missing values for either Resources or Patterns'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return serviceResponse.data.token; + } + + protected get path(): string { + return `/v3/pam/${this.parameters.keySet.subscribeKey}/grant`; + } + + protected get body(): string { + const { ttl, meta } = this.parameters; + const body: Record = { ...(ttl || ttl === 0 ? { ttl } : {}) }; + const uuid = this.isVspPermissions(this.parameters) + ? this.parameters.authorizedUserId + : this.parameters.authorized_uuid; + + const permissions: Record> = {}; + const resourcePermissions: PermissionPayload = {}; + const patternPermissions: PermissionPayload = {}; + const mapPermissions = ( + name: string, + permissionBit: number, + type: keyof PermissionPayload, + permissions: PermissionPayload, + ) => { + if (!permissions[type]) permissions[type] = {}; + permissions[type]![name] = permissionBit; + }; + + const { resources, patterns } = this.parameters; + [resources, patterns].forEach((refPerm, idx) => { + const target = idx === 0 ? resourcePermissions : patternPermissions; + let channelsPermissions: Record = {}; + let channelGroupsPermissions: Record = {}; + let uuidsPermissions: Record = {}; + + if (refPerm) { + // Check whether working with legacy Objects permissions. + if ('spaces' in refPerm || 'users' in refPerm) { + channelsPermissions = refPerm.spaces ?? {}; + uuidsPermissions = refPerm.users ?? {}; + } else if ('channels' in refPerm || 'uuids' in refPerm || 'groups' in refPerm) { + channelsPermissions = refPerm.channels ?? {}; + channelGroupsPermissions = refPerm.groups ?? {}; + uuidsPermissions = refPerm.uuids ?? {}; + } + } + + Object.keys(channelsPermissions).forEach((channel) => + mapPermissions(channel, this.extractPermissions(channelsPermissions[channel]), 'channels', target), + ); + + Object.keys(channelGroupsPermissions).forEach((groups) => + mapPermissions(groups, this.extractPermissions(channelGroupsPermissions[groups]), 'groups', target), + ); + + Object.keys(uuidsPermissions).forEach((uuids) => + mapPermissions(uuids, this.extractPermissions(uuidsPermissions[uuids]), 'uuids', target), + ); + }); + + if (uuid) permissions.uuid = `${uuid}`; + if (meta) permissions.meta = meta; + body.permissions = permissions; + + return JSON.stringify(body); + } + + /** + * Extract permissions bit from permission configuration object. + * + * @param permissions - User provided scope-based permissions. + * + * @returns Permissions bit. + */ + private extractPermissions( + permissions: PAM.UuidTokenPermissions | PAM.ChannelTokenPermissions | PAM.ChannelGroupTokenPermissions, + ): number { + let permissionsResult = 0; + + if ('join' in permissions && permissions.join) permissionsResult |= 128; + if ('update' in permissions && permissions.update) permissionsResult |= 64; + if ('get' in permissions && permissions.get) permissionsResult |= 32; + if ('delete' in permissions && permissions.delete) permissionsResult |= 8; + if ('manage' in permissions && permissions.manage) permissionsResult |= 4; + if ('write' in permissions && permissions.write) permissionsResult |= 2; + if ('read' in permissions && permissions.read) permissionsResult |= 1; + + return permissionsResult; + } + + /** + * Check whether provided parameters is part of legacy VSP access token configuration. + * + * @param parameters - Parameters which should be checked. + * + * @returns VSP request parameters if it is legacy configuration. + */ + private isVspPermissions( + parameters: PAM.GrantTokenParameters | PAM.ObjectsGrantTokenParameters, + ): parameters is PAM.ObjectsGrantTokenParameters { + return ( + 'authorizedUserId' in parameters || + 'spaces' in (parameters.resources ?? {}) || + 'users' in (parameters.resources ?? {}) || + 'spaces' in (parameters.patterns ?? {}) || + 'users' in (parameters.patterns ?? {}) + ); + } +} diff --git a/src/core/endpoints/access_manager/revoke_token.js b/src/core/endpoints/access_manager/revoke_token.js deleted file mode 100644 index ab457f2db..000000000 --- a/src/core/endpoints/access_manager/revoke_token.js +++ /dev/null @@ -1,37 +0,0 @@ -/** */ - -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -const endpoint = { - getOperation: () => operationConstants.PNAccessManagerRevokeToken, - - validateParams: (modules, token) => { - const { secretKey } = modules.config; - if (!secretKey) { - return 'Missing Secret Key'; - } - - if (!token) { - return "token can't be empty"; - } - }, - - getURL: ({ config }, token) => `/v3/pam/${config.subscribeKey}/grant/${utils.encodeString(token)}`, - useDelete: () => true, - - getRequestTimeout: ({ config }) => config.getTransactionTimeout(), - - isAuthSupported: () => false, - - prepareParams: ({ config }) => ({ - uuid: config.getUUID(), - }), - - handleResponse: (_, response) => ({ - status: response.status, - data: response.data, - }), -}; - -export default endpoint; diff --git a/src/core/endpoints/access_manager/revoke_token.ts b/src/core/endpoints/access_manager/revoke_token.ts new file mode 100644 index 000000000..b95c405f3 --- /dev/null +++ b/src/core/endpoints/access_manager/revoke_token.ts @@ -0,0 +1,89 @@ +/** + * PAM Revoke Token REST API module. + */ + +import { createValidationError, PubNubError } from '../../../models/PubNubError'; +import { TransportResponse } from '../../types/transport-response'; +import { TransportMethod } from '../../types/transport-request'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import * as PAM from '../../types/api/access-panager'; +import { encodeString } from '../../utils'; +import { KeySet } from '../../types/api'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = PAM.RevokeParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Request processing result data. + */ + data: Record; + + /** + * Name of the service which provided response. + */ + service: string; +}; +// endregion + +/** + * Access token revoke request. + * + * Invalidate token and permissions which has been granted for it. + */ +export class RevokeTokenRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super({ method: TransportMethod.DELETE }); + } + + operation(): RequestOperation { + return RequestOperation.PNAccessManagerRevokeToken; + } + + validate(): string | undefined { + if (!this.parameters.keySet.secretKey) return 'Missing Secret Key'; + if (!this.parameters.token) return "token can't be empty"; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return {}; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + token, + } = this.parameters; + + return `/v3/pam/${subscribeKey}/grant/${encodeString(token)}`; + } +} diff --git a/src/core/endpoints/actions/add_message_action.js b/src/core/endpoints/actions/add_message_action.js deleted file mode 100644 index e07ebb6cc..000000000 --- a/src/core/endpoints/actions/add_message_action.js +++ /dev/null @@ -1,56 +0,0 @@ -/* */ - -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -export function getOperation() { - return operationConstants.PNAddMessageActionOperation; -} - -export function validateParams({ config }, incomingParams) { - const { action, channel, messageTimetoken } = incomingParams; - - if (!messageTimetoken) return 'Missing message timetoken'; - if (!config.subscribeKey) return 'Missing Subscribe Key'; - if (!channel) return 'Missing message channel'; - if (!action) return 'Missing Action'; - if (!action.value) return 'Missing Action.value'; - if (!action.type) return 'Missing Action.type'; - if (action.type.length > 15) return 'Action.type value exceed maximum length of 15'; -} - -export function usePost() { - return true; -} - -export function postURL({ config }, incomingParams) { - const { channel, messageTimetoken } = incomingParams; - - return `/v1/message-actions/${config.subscribeKey}/channel/${utils.encodeString( - channel, - )}/message/${messageTimetoken}`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function getRequestHeaders() { - return { 'Content-Type': 'application/json' }; -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams() { - return {}; -} - -export function postPayload(modules, incomingParams) { - return incomingParams.action; -} - -export function handleResponse(modules, addMessageActionResponse) { - return { data: addMessageActionResponse.data }; -} diff --git a/src/core/endpoints/actions/add_message_action.ts b/src/core/endpoints/actions/add_message_action.ts new file mode 100644 index 000000000..59d229964 --- /dev/null +++ b/src/core/endpoints/actions/add_message_action.ts @@ -0,0 +1,103 @@ +/** + * Add Message Action REST API module. + */ + +import { createValidationError, PubNubError } from '../../../models/PubNubError'; +import { TransportResponse } from '../../types/transport-response'; +import { TransportMethod } from '../../types/transport-request'; +import * as MessageAction from '../../types/api/message-action'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import { encodeString } from '../../utils'; +import { KeySet } from '../../types/api'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = MessageAction.AddMessageActionParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Request processing result data. + */ + data: MessageAction.MessageAction; +}; +// endregion + +/** + * Add Message Reaction request. + */ +export class AddMessageActionRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super({ method: TransportMethod.POST }); + } + + operation(): RequestOperation { + return RequestOperation.PNAddMessageActionOperation; + } + + validate(): string | undefined { + const { + keySet: { subscribeKey }, + action, + channel, + messageTimetoken, + } = this.parameters; + + if (!subscribeKey) return 'Missing Subscribe Key'; + if (!channel) return 'Missing message channel'; + if (!messageTimetoken) return 'Missing message timetoken'; + if (!action) return 'Missing Action.value'; + if (!action.value) return 'Missing Action.value'; + if (!action.type) return 'Missing Action.type'; + if (action.type.length > 15) return 'Action.type value exceed maximum length of 15'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return { data: serviceResponse.data }; + } + + protected get headers(): Record | undefined { + return { 'Content-Type': 'application/json' }; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channel, + messageTimetoken, + } = this.parameters; + + return `/v1/message-actions/${subscribeKey}/channel/${encodeString(channel)}/message/${messageTimetoken}`; + } + + protected get body(): ArrayBuffer | string | undefined { + return JSON.stringify(this.parameters.action); + } +} diff --git a/src/core/endpoints/actions/get_message_actions.js b/src/core/endpoints/actions/get_message_actions.js deleted file mode 100644 index ebe4fbb7d..000000000 --- a/src/core/endpoints/actions/get_message_actions.js +++ /dev/null @@ -1,51 +0,0 @@ -/* */ -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -export function getOperation() { - return operationConstants.PNGetMessageActionsOperation; -} - -export function validateParams({ config }, incomingParams) { - const { channel } = incomingParams; - - if (!config.subscribeKey) return 'Missing Subscribe Key'; - if (!channel) return 'Missing message channel'; -} - -export function getURL({ config }, incomingParams) { - const { channel } = incomingParams; - - return `/v1/message-actions/${config.subscribeKey}/channel/${utils.encodeString(channel)}`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams(modules, incomingParams) { - const { limit, start, end } = incomingParams; - const outgoingParams = {}; - - if (limit) outgoingParams.limit = limit; - if (start) outgoingParams.start = start; - if (end) outgoingParams.end = end; - - return outgoingParams; -} - -export function handleResponse(modules, getMessageActionsResponse) { - /** @type GetMessageActionsResponse */ - const response = { data: getMessageActionsResponse.data, start: null, end: null }; - - if (response.data.length) { - response.end = response.data[response.data.length - 1].actionTimetoken; - response.start = response.data[0].actionTimetoken; - } - - return response; -} diff --git a/src/core/endpoints/actions/get_message_actions.ts b/src/core/endpoints/actions/get_message_actions.ts new file mode 100644 index 000000000..80c523412 --- /dev/null +++ b/src/core/endpoints/actions/get_message_actions.ts @@ -0,0 +1,109 @@ +/** + * Get Message Actions REST API module. + */ + +import { createValidationError, PubNubError } from '../../../models/PubNubError'; +import { TransportResponse } from '../../types/transport-response'; +import * as MessageAction from '../../types/api/message-action'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import { KeySet, Query } from '../../types/api'; +import { encodeString } from '../../utils'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = MessageAction.GetMessageActionsParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Retrieved list of message actions. + */ + data: MessageAction.MessageAction[]; + + /** + * More message actions fetch information. + */ + more?: MessageAction.MoreMessageActions; +}; +// endregion + +/** + * Fetch channel message actions request. + */ +export class GetMessageActionsRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + } + + operation(): RequestOperation { + return RequestOperation.PNGetMessageActionsOperation; + } + + validate(): string | undefined { + if (!this.parameters.keySet.subscribeKey) return 'Missing Subscribe Key'; + if (!this.parameters.channel) return 'Missing message channel'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + let start: string | null = null; + let end: string | null = null; + + if (serviceResponse.data.length > 0) { + start = serviceResponse.data[0].actionTimetoken; + end = serviceResponse.data[serviceResponse.data.length - 1].actionTimetoken; + } + + return { + data: serviceResponse.data, + more: serviceResponse.more, + start, + end, + }; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channel, + } = this.parameters; + + return `/v1/message-actions/${subscribeKey}/channel/${encodeString(channel)}`; + } + + protected get queryParameters(): Query { + const { limit, start, end } = this.parameters; + + return { + ...(start ? { start } : {}), + ...(end ? { end } : {}), + ...(limit ? { limit } : {}), + }; + } +} diff --git a/src/core/endpoints/actions/remove_message_action.js b/src/core/endpoints/actions/remove_message_action.js deleted file mode 100644 index 479cfb2e6..000000000 --- a/src/core/endpoints/actions/remove_message_action.js +++ /dev/null @@ -1,45 +0,0 @@ -/* */ - -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -export function getOperation() { - return operationConstants.PNRemoveMessageActionOperation; -} - -export function validateParams({ config }, incomingParams) { - const { channel, actionTimetoken, messageTimetoken } = incomingParams; - - if (!messageTimetoken) return 'Missing message timetoken'; - if (!actionTimetoken) return 'Missing action timetoken'; - if (!config.subscribeKey) return 'Missing Subscribe Key'; - if (!channel) return 'Missing message channel'; -} - -export function useDelete() { - return true; -} - -export function getURL({ config }, incomingParams) { - const { channel, actionTimetoken, messageTimetoken } = incomingParams; - - return `/v1/message-actions/${config.subscribeKey}/channel/${utils.encodeString( - channel, - )}/message/${messageTimetoken}/action/${actionTimetoken}`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams() { - return {}; -} - -export function handleResponse(modules, removeMessageActionResponse) { - return { data: removeMessageActionResponse.data }; -} diff --git a/src/core/endpoints/actions/remove_message_action.ts b/src/core/endpoints/actions/remove_message_action.ts new file mode 100644 index 000000000..3ecb58dc9 --- /dev/null +++ b/src/core/endpoints/actions/remove_message_action.ts @@ -0,0 +1,95 @@ +/** + * Remove Message Action REST API module. + */ + +import { createValidationError, PubNubError } from '../../../models/PubNubError'; +import { TransportResponse } from '../../types/transport-response'; +import { TransportMethod } from '../../types/transport-request'; +import * as MessageAction from '../../types/api/message-action'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import { encodeString } from '../../utils'; +import { KeySet } from '../../types/api'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = MessageAction.RemoveMessageActionParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Request processing result data. + */ + data: Record; +}; +// endregion + +/** + * Remove specific message action request. + */ +export class RemoveMessageAction extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super({ method: TransportMethod.DELETE }); + } + + operation(): RequestOperation { + return RequestOperation.PNRemoveMessageActionOperation; + } + + validate(): string | undefined { + const { + keySet: { subscribeKey }, + channel, + messageTimetoken, + actionTimetoken, + } = this.parameters; + + if (!subscribeKey) return 'Missing Subscribe Key'; + if (!channel) return 'Missing message action channel'; + if (!messageTimetoken) return 'Missing message timetoken'; + if (!actionTimetoken) return 'Missing action timetoken'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return { data: serviceResponse.data }; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channel, + actionTimetoken, + messageTimetoken, + } = this.parameters; + + return `/v1/message-actions/${subscribeKey}/channel/${encodeString( + channel, + )}/message/${messageTimetoken}/action/${actionTimetoken}`; + } +} diff --git a/src/core/endpoints/channel_groups/add_channels.js b/src/core/endpoints/channel_groups/add_channels.js deleted file mode 100644 index 804decdf6..000000000 --- a/src/core/endpoints/channel_groups/add_channels.js +++ /dev/null @@ -1,42 +0,0 @@ -/* */ -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -export function getOperation() { - return operationConstants.PNAddChannelsToGroupOperation; -} - -export function validateParams(modules, incomingParams) { - const { channels, channelGroup } = incomingParams; - const { config } = modules; - - if (!channelGroup) return 'Missing Channel Group'; - if (!channels || channels.length === 0) return 'Missing Channels'; - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules, incomingParams) { - const { channelGroup } = incomingParams; - const { config } = modules; - return `/v1/channel-registration/sub-key/${config.subscribeKey}/channel-group/${utils.encodeString(channelGroup)}`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams(modules, incomingParams) { - const { channels = [] } = incomingParams; - - return { - add: channels.join(','), - }; -} - -export function handleResponse() { - return {}; -} diff --git a/src/core/endpoints/channel_groups/add_channels.ts b/src/core/endpoints/channel_groups/add_channels.ts new file mode 100644 index 000000000..02621a3cd --- /dev/null +++ b/src/core/endpoints/channel_groups/add_channels.ts @@ -0,0 +1,102 @@ +/** + * Add channel group channels REST API module. + */ + +import { createValidationError, PubNubError } from '../../../models/PubNubError'; +import { TransportResponse } from '../../types/transport-response'; +import * as ChannelGroups from '../../types/api/channel-groups'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import { KeySet, Query } from '../../types/api'; +import { encodeString } from '../../utils'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = ChannelGroups.ManageChannelGroupChannelsParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Channel group channels addition human-readable result. + */ + message: string; + + /** + * Name of the service which provided response. + */ + service: string; + + /** + * Whether response represent service error or not. + */ + error: boolean; +}; +// endregion + +/** + * Add channel group channels request. + */ +export class AddChannelGroupChannelsRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + } + + operation(): RequestOperation { + return RequestOperation.PNAddChannelsToGroupOperation; + } + + validate(): string | undefined { + const { + keySet: { subscribeKey }, + channels, + channelGroup, + } = this.parameters; + + if (!subscribeKey) return 'Missing Subscribe Key'; + if (!channelGroup) return 'Missing Channel Group'; + if (!channels) return 'Missing channels'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return {}; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channelGroup, + } = this.parameters; + + return `/v1/channel-registration/sub-key/${subscribeKey}/channel-group/${encodeString(channelGroup)}`; + } + + protected get queryParameters(): Query { + return { add: this.parameters.channels.join(',') }; + } +} diff --git a/src/core/endpoints/channel_groups/delete_group.js b/src/core/endpoints/channel_groups/delete_group.js deleted file mode 100644 index 1dff624d6..000000000 --- a/src/core/endpoints/channel_groups/delete_group.js +++ /dev/null @@ -1,40 +0,0 @@ -/* */ - -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -export function getOperation() { - return operationConstants.PNRemoveGroupOperation; -} - -export function validateParams(modules, incomingParams) { - const { channelGroup } = incomingParams; - const { config } = modules; - - if (!channelGroup) return 'Missing Channel Group'; - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules, incomingParams) { - const { channelGroup } = incomingParams; - const { config } = modules; - return `/v1/channel-registration/sub-key/${config.subscribeKey}/channel-group/${utils.encodeString( - channelGroup, - )}/remove`; -} - -export function isAuthSupported() { - return true; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function prepareParams() { - return {}; -} - -export function handleResponse() { - return {}; -} diff --git a/src/core/endpoints/channel_groups/delete_group.ts b/src/core/endpoints/channel_groups/delete_group.ts new file mode 100644 index 000000000..3a4f2ba08 --- /dev/null +++ b/src/core/endpoints/channel_groups/delete_group.ts @@ -0,0 +1,91 @@ +/** + * Delete channel group REST API module. + */ + +import { createValidationError, PubNubError } from '../../../models/PubNubError'; +import { TransportResponse } from '../../types/transport-response'; +import * as ChannelGroups from '../../types/api/channel-groups'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import { KeySet } from '../../types/api'; +import { encodeString } from '../../utils'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = ChannelGroups.DeleteChannelGroupParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Delete channel group human-readable result. + */ + message: string; + + /** + * Name of the service which provided response. + */ + service: string; + + /** + * Whether response represent service error or not. + */ + error: boolean; +}; +// endregion + +/** + * Channel group delete request. + */ +export class DeleteChannelGroupRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + } + + operation(): RequestOperation { + return RequestOperation.PNRemoveGroupOperation; + } + + validate(): string | undefined { + if (!this.parameters.keySet.subscribeKey) return 'Missing Subscribe Key'; + if (!this.parameters.channelGroup) return 'Missing Channel Group'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return {}; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channelGroup, + } = this.parameters; + + return `/v1/channel-registration/sub-key/${subscribeKey}/channel-group/${encodeString(channelGroup)}/remove`; + } +} diff --git a/src/core/endpoints/channel_groups/list_channels.js b/src/core/endpoints/channel_groups/list_channels.js deleted file mode 100644 index 245857d5e..000000000 --- a/src/core/endpoints/channel_groups/list_channels.js +++ /dev/null @@ -1,39 +0,0 @@ -/* */ -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -export function getOperation() { - return operationConstants.PNChannelsForGroupOperation; -} - -export function validateParams(modules, incomingParams) { - const { channelGroup } = incomingParams; - const { config } = modules; - - if (!channelGroup) return 'Missing Channel Group'; - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules, incomingParams) { - const { channelGroup } = incomingParams; - const { config } = modules; - return `/v1/channel-registration/sub-key/${config.subscribeKey}/channel-group/${utils.encodeString(channelGroup)}`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams() { - return {}; -} - -export function handleResponse(modules, serverResponse) { - return { - channels: serverResponse.payload.channels, - }; -} diff --git a/src/core/endpoints/channel_groups/list_channels.ts b/src/core/endpoints/channel_groups/list_channels.ts new file mode 100644 index 000000000..1dbd83c97 --- /dev/null +++ b/src/core/endpoints/channel_groups/list_channels.ts @@ -0,0 +1,106 @@ +/** + * List channel group channels REST API module. + */ + +import { createValidationError, PubNubError } from '../../../models/PubNubError'; +import { TransportResponse } from '../../types/transport-response'; +import * as ChannelGroups from '../../types/api/channel-groups'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import { encodeString } from '../../utils'; +import { KeySet } from '../../types/api'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = ChannelGroups.ListChannelGroupChannelsParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * List channel group channels human-readable result. + */ + message: string; + + /** + * Name of the service which provided response. + */ + service: string; + + /** + * Whether response represent service error or not. + */ + error: boolean; + + /** + * Retrieved registered channels information. + */ + payload: { + /** + * Channel group for which channels has been received. + */ + group: string; + + /** + * List of channels registered in channel {@link group}. + */ + channels: string[]; + }; +}; +// endregion + +/** + * List Channel Group Channels request. + */ +export class ListChannelGroupChannels extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + } + + operation(): RequestOperation { + return RequestOperation.PNChannelsForGroupOperation; + } + + validate(): string | undefined { + if (!this.parameters.keySet.subscribeKey) return 'Missing Subscribe Key'; + if (!this.parameters.channelGroup) return 'Missing Channel Group'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return { channels: serviceResponse.payload.channels }; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channelGroup, + } = this.parameters; + + return `/v1/channel-registration/sub-key/${subscribeKey}/channel-group/${encodeString(channelGroup)}`; + } +} diff --git a/src/core/endpoints/channel_groups/list_groups.js b/src/core/endpoints/channel_groups/list_groups.js deleted file mode 100644 index 8642f397f..000000000 --- a/src/core/endpoints/channel_groups/list_groups.js +++ /dev/null @@ -1,36 +0,0 @@ -/* */ - -import operationConstants from '../../constants/operations'; - -export function getOperation() { - return operationConstants.PNChannelGroupsOperation; -} - -export function validateParams(modules) { - const { config } = modules; - - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules) { - const { config } = modules; - return `/v1/channel-registration/sub-key/${config.subscribeKey}/channel-group`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams() { - return {}; -} - -export function handleResponse(modules, serverResponse) { - return { - groups: serverResponse.payload.groups, - }; -} diff --git a/src/core/endpoints/channel_groups/list_groups.ts b/src/core/endpoints/channel_groups/list_groups.ts new file mode 100644 index 000000000..63d97c0ac --- /dev/null +++ b/src/core/endpoints/channel_groups/list_groups.ts @@ -0,0 +1,99 @@ +/** + * List All Channel Groups REST API module. + */ + +import { createValidationError, PubNubError } from '../../../models/PubNubError'; +import { TransportResponse } from '../../types/transport-response'; +import * as ChannelGroups from '../../types/api/channel-groups'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import { KeySet } from '../../types/api'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * List all channel groups human-readable result. + */ + message: string; + + /** + * Name of the service which provided response. + */ + service: string; + + /** + * Whether response represent service error or not. + */ + error: boolean; + + /** + * Retrieved registered channels information. + */ + payload: { + /** + * Subscription key for which list of channel groups has been received. + */ + sub_key: string; + + /** + * List of channel groups created for {@link sub_key}. + */ + groups: string[]; + }; +}; +// endregion + +/** + * List all channel groups request. + */ +export class ListChannelGroupsRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + } + + operation(): RequestOperation { + return RequestOperation.PNChannelGroupsOperation; + } + + validate(): string | undefined { + if (!this.parameters.keySet.subscribeKey) return 'Missing Subscribe Key'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return { groups: serviceResponse.payload.groups }; + } + + protected get path(): string { + return `/v1/channel-registration/sub-key/${this.parameters.keySet.subscribeKey}/channel-group`; + } +} diff --git a/src/core/endpoints/channel_groups/remove_channels.js b/src/core/endpoints/channel_groups/remove_channels.js deleted file mode 100644 index 54c664f55..000000000 --- a/src/core/endpoints/channel_groups/remove_channels.js +++ /dev/null @@ -1,42 +0,0 @@ -/* */ -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -export function getOperation() { - return operationConstants.PNRemoveChannelsFromGroupOperation; -} - -export function validateParams(modules, incomingParams) { - const { channels, channelGroup } = incomingParams; - const { config } = modules; - - if (!channelGroup) return 'Missing Channel Group'; - if (!channels || channels.length === 0) return 'Missing Channels'; - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules, incomingParams) { - const { channelGroup } = incomingParams; - const { config } = modules; - return `/v1/channel-registration/sub-key/${config.subscribeKey}/channel-group/${utils.encodeString(channelGroup)}`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams(modules, incomingParams) { - const { channels = [] } = incomingParams; - - return { - remove: channels.join(','), - }; -} - -export function handleResponse() { - return {}; -} diff --git a/src/core/endpoints/channel_groups/remove_channels.ts b/src/core/endpoints/channel_groups/remove_channels.ts new file mode 100644 index 000000000..ba998b6d3 --- /dev/null +++ b/src/core/endpoints/channel_groups/remove_channels.ts @@ -0,0 +1,105 @@ +/** + * Remove channel group channels REST API module. + */ + +import { createValidationError, PubNubError } from '../../../models/PubNubError'; +import { TransportResponse } from '../../types/transport-response'; +import * as ChannelGroups from '../../types/api/channel-groups'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import { KeySet, Query } from '../../types/api'; +import { encodeString } from '../../utils'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = ChannelGroups.ManageChannelGroupChannelsParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Channel group channels manage human-readable result. + */ + message: string; + + /** + * Name of the service which provided response. + */ + service: string; + + /** + * Whether response represent service error or not. + */ + error: boolean; +}; +// endregion + +/** + * Remove channel group channels request. + */ +// prettier-ignore +export class RemoveChannelGroupChannelsRequest extends AbstractRequest< + ChannelGroups.ManageChannelGroupChannelsResponse +> { + constructor(private readonly parameters: RequestParameters) { + super(); + } + + operation(): RequestOperation { + return RequestOperation.PNRemoveChannelsFromGroupOperation; + } + + validate(): string | undefined { + const { + keySet: { subscribeKey }, + channels, + channelGroup, + } = this.parameters; + + if (!subscribeKey) return 'Missing Subscribe Key'; + if (!channelGroup) return 'Missing Channel Group'; + if (!channels) return 'Missing channels'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return {}; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channelGroup, + } = this.parameters; + + return `/v1/channel-registration/sub-key/${subscribeKey}/channel-group/${encodeString(channelGroup)}`; + } + + protected get queryParameters(): Query { + return { remove: this.parameters.channels.join(',') }; + } +} diff --git a/src/core/endpoints/endpoint.js b/src/core/endpoints/endpoint.js deleted file mode 100644 index cead0ebfb..000000000 --- a/src/core/endpoints/endpoint.js +++ /dev/null @@ -1,3 +0,0 @@ -/** */ - -// endpoint definition structure diff --git a/src/core/endpoints/fetch_messages.js b/src/core/endpoints/fetch_messages.js deleted file mode 100644 index bb4c0d3be..000000000 --- a/src/core/endpoints/fetch_messages.js +++ /dev/null @@ -1,127 +0,0 @@ -/* */ -import operationConstants from '../constants/operations'; -import utils from '../utils'; - -function __processMessage(modules, message) { - const result = {}; - if (!modules.cryptoModule) { - result.payload = message; - return result; - } - try { - const decryptedData = modules.cryptoModule.decrypt(message); - const decryptedPayload = - decryptedData instanceof ArrayBuffer ? JSON.parse(new TextDecoder().decode(decryptedData)) : decryptedData; - result.payload = decryptedPayload; - return result; - } catch (e) { - if (modules.config.logVerbosity && console && console.log) console.log('decryption error', e.message); - result.payload = message; - result.error = `Error while decrypting message content: ${e.message}`; - } - return result; -} - -export function getOperation() { - return operationConstants.PNFetchMessagesOperation; -} - -export function validateParams(modules, incomingParams) { - const { channels, includeMessageActions = false } = incomingParams; - const { config } = modules; - - if (!channels || channels.length === 0) return 'Missing channels'; - if (!config.subscribeKey) return 'Missing Subscribe Key'; - - if (includeMessageActions && channels.length > 1) { - throw new TypeError( - 'History can return actions data for a single channel only. ' + - 'Either pass a single channel or disable the includeMessageActions flag.', - ); - } -} - -export function getURL(modules, incomingParams) { - const { channels = [], includeMessageActions = false } = incomingParams; - const { config } = modules; - const endpoint = !includeMessageActions ? 'history' : 'history-with-actions'; - - const stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return `/v3/${endpoint}/sub-key/${config.subscribeKey}/channel/${utils.encodeString(stringifiedChannels)}`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams(modules, incomingParams) { - const { - channels, - start, - end, - includeMessageActions, - count, - stringifiedTimeToken = false, - includeMeta = false, - includeUuid, - includeUUID = true, - includeMessageType = true, - } = incomingParams; - const outgoingParams = {}; - - if (count) { - outgoingParams.max = count; - } else { - outgoingParams.max = channels.length > 1 || includeMessageActions === true ? 25 : 100; - } - if (start) outgoingParams.start = start; - if (end) outgoingParams.end = end; - if (stringifiedTimeToken) outgoingParams.string_message_token = 'true'; - if (includeMeta) outgoingParams.include_meta = 'true'; - if (includeUUID && includeUuid !== false) outgoingParams.include_uuid = 'true'; - if (includeMessageType) outgoingParams.include_message_type = 'true'; - - return outgoingParams; -} - -export function handleResponse(modules, serverResponse) { - const response = { - channels: {}, - }; - - Object.keys(serverResponse.channels || {}).forEach((channelName) => { - response.channels[channelName] = []; - - (serverResponse.channels[channelName] || []).forEach((messageEnvelope) => { - const announce = {}; - const processedMessgeResult = __processMessage(modules, messageEnvelope.message); - announce.channel = channelName; - announce.timetoken = messageEnvelope.timetoken; - announce.message = processedMessgeResult.payload; - announce.messageType = messageEnvelope.message_type; - announce.uuid = messageEnvelope.uuid; - - if (messageEnvelope.actions) { - announce.actions = messageEnvelope.actions; - - // This should be kept for few updates for existing clients consistency. - announce.data = messageEnvelope.actions; - } - if (messageEnvelope.meta) { - announce.meta = messageEnvelope.meta; - } - if (processedMessgeResult.error) announce.error = processedMessgeResult.error; - - response.channels[channelName].push(announce); - }); - }); - if (serverResponse.more) { - response.more = serverResponse.more; - } - - return response; -} diff --git a/src/core/endpoints/fetch_messages.ts b/src/core/endpoints/fetch_messages.ts new file mode 100644 index 000000000..72747c765 --- /dev/null +++ b/src/core/endpoints/fetch_messages.ts @@ -0,0 +1,351 @@ +/** + * Fetch messages REST API module. + */ + +import { createValidationError, PubNubError } from '../../models/PubNubError'; +import { TransportResponse } from '../types/transport-response'; +import { CryptoModule } from '../interfaces/crypto-module'; +import { AbstractRequest } from '../components/request'; +import * as FileSharing from '../types/api/file-sharing'; +import RequestOperation from '../constants/operations'; +import { KeySet, Payload, Query } from '../types/api'; +import * as History from '../types/api/history'; +import { encodeString } from '../utils'; + +// -------------------------------------------------------- +// ---------------------- Defaults ------------------------ +// -------------------------------------------------------- +// region Defaults + +/** + * Whether verbose logging enabled or not. + */ +const LOG_VERBOSITY = false; + +/** + * Whether associated message metadata should be returned or not. + */ +const INCLUDE_METADATA = true; + +/** + * Whether message type should be returned or not. + */ +const INCLUDE_MESSAGE_TYPE = true; + +/** + * Whether timetokens should be returned as strings by default or not. + */ +const STRINGIFY_TIMETOKENS = false; + +/** + * Whether message publisher `uuid` should be returned or not. + */ +const INCLUDE_UUID = true; + +/** + * Default number of messages which can be returned for single channel, and it is maximum as well. + */ +const SINGLE_CHANNEL_MESSAGES_COUNT = 100; + +/** + * Default number of messages which can be returned for multiple channels or when fetched + * message actions. + */ +const MULTIPLE_CHANNELS_MESSAGES_COUNT = 25; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = History.FetchMessagesParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; + + /** + * Published data encryption module. + */ + crypto?: CryptoModule; + + /** + * File download Url generation function. + * + * @param parameters - File download Url request configuration parameters. + * + * @returns File download Url. + */ + getFileUrl: (parameters: FileSharing.FileUrlParameters) => string; + + /** + * Whether verbose logging enabled or not. + * + * @default `false` + */ + logVerbosity?: boolean; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Whether service response represent error or not. + */ + error: boolean; + + /** + * Human-readable error explanation. + */ + error_message: string; + + /** + * List of previously published messages per requested channel. + */ + channels: { + [p: string]: { + /** + * Message payload (decrypted). + */ + message: History.FetchedMessage['message']; + + /** + * When message has been received by PubNub service. + */ + timetoken: string; + + /** + * Message publisher unique identifier. + */ + uuid?: string; + + /** + * PubNub-defined message type. + */ + message_type?: History.PubNubMessageType | null; + + /** + * Additional data which has been published along with message to be used with real-time + * events filter expression. + */ + meta?: Payload; + + /** + * List of message reactions. + */ + actions?: History.Actions; + + /** + * Custom published data type (user-provided). + */ + type?: string; + + /** + * Space in which message has been received. + */ + space_id?: string; + }[]; + }; + + /** + * Additional message actions fetch information. + */ + more?: History.MoreActions; +}; +// endregion + +/** + * Fetch messages from channels request. + */ +export class FetchMessagesRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + + // Apply defaults. + const includeMessageActions = parameters.includeMessageActions ?? false; + const defaultCount = + parameters.channels.length === 1 && includeMessageActions + ? SINGLE_CHANNEL_MESSAGES_COUNT + : MULTIPLE_CHANNELS_MESSAGES_COUNT; + if (!parameters.count) parameters.count = defaultCount; + else parameters.count = Math.min(parameters.count, defaultCount); + + if (parameters.includeUuid) parameters.includeUUID = parameters.includeUuid; + else parameters.includeUUID ??= INCLUDE_UUID; + parameters.stringifiedTimeToken ??= STRINGIFY_TIMETOKENS; + parameters.includeMessageType ??= INCLUDE_MESSAGE_TYPE; + parameters.includeMeta ??= INCLUDE_METADATA; + parameters.logVerbosity ??= LOG_VERBOSITY; + } + + operation(): RequestOperation { + return RequestOperation.PNFetchMessagesOperation; + } + + validate(): string | undefined { + const { + keySet: { subscribeKey }, + channels, + includeMessageActions, + } = this.parameters; + + if (!subscribeKey) return 'Missing Subscribe Key'; + if (!channels) return 'Missing channels'; + if (includeMessageActions! && channels.length > 1) + return ( + 'History can return actions data for a single channel only. Either pass a single channel ' + + 'or disable the includeMessageActions flag.' + ); + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + const responseChannels = serviceResponse.channels ?? {}; + const channels: History.FetchMessagesResponse['channels'] = {}; + + Object.keys(responseChannels).forEach((channel) => { + // Map service response to expected data object type structure. + channels[channel] = responseChannels[channel].map((payload) => { + // `null` message type means regular message. + if (payload.message_type === null) payload.message_type = History.PubNubMessageType.Message; + const processedPayload = this.processPayload(channel, payload); + + const item = { + channel, + timetoken: payload.timetoken, + message: processedPayload.payload, + messageType: payload.message_type, + uuid: payload.uuid, + }; + + if (payload.actions) { + const itemWithActions = item as unknown as History.FetchedMessageWithActions; + itemWithActions.actions = payload.actions; + + // Backward compatibility for existing users. + // TODO: Remove in next release. + itemWithActions.data = payload.actions; + } + + if (payload.meta) (item as History.FetchedMessage).meta = payload.meta; + if (processedPayload.error) (item as History.FetchedMessage).error = processedPayload.error; + + return item as History.FetchedMessage; + }); + }); + + if (serviceResponse.more) + return { channels: responseChannels, more: serviceResponse.more } as History.FetchMessagesWithActionsResponse; + + return { channels: responseChannels } as History.FetchMessagesResponse; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channels, + includeMessageActions, + } = this.parameters; + const endpoint = !includeMessageActions! ? 'history' : 'history-with-actions'; + + return `/v3/${endpoint}/sub-key/${subscribeKey}/channel/${encodeString(channels.join(','))}`; + } + + protected get queryParameters(): Query { + const { start, end, count, includeMessageType, includeMeta, includeUUID, stringifiedTimeToken } = this.parameters; + + return { + max: count!, + ...(start ? { start } : {}), + ...(end ? { end } : {}), + ...(stringifiedTimeToken! ? { string_message_token: 'true' } : {}), + ...(includeMeta! ? { include_meta: 'true' } : {}), + ...(includeUUID! ? { include_uuid: 'true' } : {}), + ...(includeMessageType! ? { include_message_type: 'true' } : {}), + }; + } + + /** + * Parse single channel data entry. + * + * @param channel - Channel for which {@link payload} should be processed. + * @param payload - Source payload which should be processed and parsed to expected type. + * + * @returns + */ + private processPayload( + channel: string, + payload: ServiceResponse['channels'][string][number], + ): { + payload: History.FetchedMessage['message']; + error?: string; + } { + const { crypto, logVerbosity } = this.parameters; + if (!crypto || typeof payload.message !== 'string') return { payload: payload.message }; + + let decryptedPayload: History.FetchedMessage['message']; + let error: string | undefined; + + try { + const decryptedData = crypto.decrypt(payload.message); + decryptedPayload = + decryptedData instanceof ArrayBuffer + ? JSON.parse(FetchMessagesRequest.decoder.decode(decryptedData)) + : decryptedData; + } catch (err) { + if (logVerbosity!) console.log(`decryption error`, (err as Error).message); + decryptedPayload = payload.message; + error = `Error while decrypting message content: ${(err as Error).message}`; + } + + if ( + !error && + decryptedPayload && + payload.message_type == History.PubNubMessageType.Files && + typeof decryptedPayload === 'object' && + this.isFileMessage(decryptedPayload) + ) { + const fileMessage = decryptedPayload; + return { + payload: { + message: fileMessage.message, + file: { + ...fileMessage.file, + url: this.parameters.getFileUrl({ channel, id: fileMessage.file.id, name: fileMessage.file.name }), + }, + }, + error, + }; + } + + return { payload: decryptedPayload, error }; + } + + /** + * Check whether `payload` potentially represents file message. + * + * @param payload - Fetched message payload. + * + * @returns `true` if payload can be {@link History#FileMessage|FileMessage}. + */ + private isFileMessage(payload: History.FetchedMessage['message']): payload is History.FileMessage['message'] { + return (payload as History.FileMessage['message']).file !== undefined; + } +} diff --git a/src/core/endpoints/file_upload/delete_file.js b/src/core/endpoints/file_upload/delete_file.js deleted file mode 100644 index 3d3d8f88a..000000000 --- a/src/core/endpoints/file_upload/delete_file.js +++ /dev/null @@ -1,39 +0,0 @@ -/** */ - -import operationConstants from '../../constants/operations'; - -import utils from '../../utils'; - -const endpoint = { - getOperation: () => operationConstants.PNListFilesOperation, - - validateParams: (_, params) => { - if (!params?.channel) { - return "channel can't be empty"; - } - - if (!params?.id) { - return "file id can't be empty"; - } - - if (!params?.name) { - return "file name can't be empty"; - } - }, - - useDelete: () => true, - getURL: ({ config }, params) => - `/v1/files/${config.subscribeKey}/channels/${utils.encodeString(params.channel)}/files/${params.id}/${params.name}`, - - getRequestTimeout: ({ config }) => config.getTransactionTimeout(), - - isAuthSupported: () => true, - - prepareParams: () => ({}), - - handleResponse: (_, response) => ({ - status: response.status, - }), -}; - -export default endpoint; diff --git a/src/core/endpoints/file_upload/delete_file.ts b/src/core/endpoints/file_upload/delete_file.ts new file mode 100644 index 000000000..f3c21deea --- /dev/null +++ b/src/core/endpoints/file_upload/delete_file.ts @@ -0,0 +1,82 @@ +/** + * Delete file REST API module. + */ + +import { createValidationError, PubNubError } from '../../../models/PubNubError'; +import { TransportResponse } from '../../types/transport-response'; +import { TransportMethod } from '../../types/transport-request'; +import { AbstractRequest } from '../../components/request'; +import * as FileSharing from '../../types/api/file-sharing'; +import RequestOperation from '../../constants/operations'; +import { encodeString } from '../../utils'; +import { KeySet } from '../../types/api'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = FileSharing.DeleteFileParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request processing result status code. + */ + status: number; +}; +// endregion + +/** + * Delete File request. + */ +export class DeleteFileRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super({ method: TransportMethod.DELETE }); + } + + operation(): RequestOperation { + return RequestOperation.PNDeleteFileOperation; + } + + validate(): string | undefined { + const { channel, id, name } = this.parameters; + + if (!channel) return "channel can't be empty"; + if (!id) return "file id can't be empty"; + if (!name) return "file name can't be empty"; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return serviceResponse; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + id, + channel, + name, + } = this.parameters; + + return `/v1/files/${subscribeKey}/channels/${encodeString(channel)}/files/${id}/${name}`; + } +} diff --git a/src/core/endpoints/file_upload/download_file.js b/src/core/endpoints/file_upload/download_file.js deleted file mode 100644 index 3668f6336..000000000 --- a/src/core/endpoints/file_upload/download_file.js +++ /dev/null @@ -1,56 +0,0 @@ -// Download_file.js - -/** */ - -import operationConstants from '../../constants/operations'; - -import utils from '../../utils'; - -const endpoint = { - getOperation: () => operationConstants.PNDownloadFileOperation, - - validateParams: (_, params) => { - if (!params?.channel) { - return "channel can't be empty"; - } - - if (!params?.name) { - return "name can't be empty"; - } - - if (!params?.id) { - return "id can't be empty"; - } - }, - - useGetFile: () => true, - - getFileURL: ({ config }, params) => - `/v1/files/${config.subscribeKey}/channels/${utils.encodeString(params.channel)}/files/${params.id}/${params.name}`, - - getRequestTimeout: ({ config }) => config.getTransactionTimeout(), - - isAuthSupported: () => true, - ignoreBody: () => true, - forceBuffered: () => true, - - prepareParams: () => ({}), - - handleResponse: async ({ PubNubFile, config, cryptography, cryptoModule }, res, params) => { - let { body } = res.response; - if (PubNubFile.supportsEncryptFile && (params.cipherKey || cryptoModule)) { - body = - params.cipherKey == null - ? (await cryptoModule.decryptFile(PubNubFile.create({ data: body, name: params.name }), PubNubFile)).data - : await cryptography.decrypt(params.cipherKey ?? config.cipherKey, body); - } - - return PubNubFile.create({ - data: body, - name: res.response.name ?? params.name, - mimeType: res.response.type, - }); - }, -}; - -export default endpoint; diff --git a/src/core/endpoints/file_upload/download_file.ts b/src/core/endpoints/file_upload/download_file.ts new file mode 100644 index 000000000..6f91ec76a --- /dev/null +++ b/src/core/endpoints/file_upload/download_file.ts @@ -0,0 +1,101 @@ +/** + * Download File REST API module. + */ + +import { PubNubBasicFileParameters, PubNubFileConstructor, PubNubFileInterface } from '../../types/file'; +import { TransportResponse } from '../../types/transport-response'; +import { CryptoModule } from '../../interfaces/crypto-module'; +import { Cryptography } from '../../interfaces/cryptography'; +import { AbstractRequest } from '../../components/request'; +import * as FileSharing from '../../types/api/file-sharing'; +import RequestOperation from '../../constants/operations'; +import { encodeString } from '../../utils'; +import { KeySet } from '../../types/api'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = FileSharing.DownloadFileParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; + + /** + * File object constructor. + */ + PubNubFile: PubNubFileConstructor; + + /** + * Send file decryption module. + */ + crypto?: CryptoModule; + + /** + * Legacy cryptography module. + */ + cryptography?: Cryptography; +}; +// endregion + +/** + * Download File request. + */ +export class DownloadFileRequest< + PlatformFile extends Partial = Record, +> extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + } + + operation(): RequestOperation { + return RequestOperation.PNDownloadFileOperation; + } + + validate(): string | undefined { + const { channel, id, name } = this.parameters; + + if (!channel) return "channel can't be empty"; + if (!id) return "file id can't be empty"; + if (!name) return "file name can't be empty"; + } + + async parse(response: TransportResponse): Promise { + const { cipherKey, crypto, cryptography, name, PubNubFile } = this.parameters; + const mimeType = response.headers['content-type']; + let decryptedFile: PubNubFileInterface | undefined; + let body = response.body!; + + if (PubNubFile.supportsEncryptFile && (cipherKey || crypto)) { + if (cipherKey && cryptography) body = await cryptography.decrypt(cipherKey, body); + else if (!cipherKey && crypto) + decryptedFile = await crypto.decryptFile(PubNubFile.create({ data: body, name: name, mimeType }), PubNubFile); + } + + return ( + decryptedFile + ? decryptedFile + : PubNubFile.create({ + data: body, + name, + mimeType, + }) + ) as PlatformFile; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channel, + id, + name, + } = this.parameters; + + return `/v1/files/${subscribeKey}/channels/${encodeString(channel)}/files/${id}/${name}`; + } +} diff --git a/src/core/endpoints/file_upload/generate_upload_url.js b/src/core/endpoints/file_upload/generate_upload_url.js deleted file mode 100644 index cb7861978..000000000 --- a/src/core/endpoints/file_upload/generate_upload_url.js +++ /dev/null @@ -1,41 +0,0 @@ -/** */ - -import operationConstants from '../../constants/operations'; - -import utils from '../../utils'; - -const endpoint = { - getOperation: () => operationConstants.PNGenerateUploadUrlOperation, - - validateParams: (_, params) => { - if (!params?.channel) { - return "channel can't be empty"; - } - - if (!params?.name) { - return "name can't be empty"; - } - }, - - usePost: () => true, - postURL: ({ config }, params) => - `/v1/files/${config.subscribeKey}/channels/${utils.encodeString(params.channel)}/generate-upload-url`, - - postPayload: (_, params) => ({ - name: params.name, - }), - - getRequestTimeout: ({ config }) => config.getTransactionTimeout(), - - isAuthSupported: () => true, - - prepareParams: () => ({}), - - handleResponse: (_, response) => ({ - status: response.status, - data: response.data, - file_upload_request: response.file_upload_request, - }), -}; - -export default endpoint; diff --git a/src/core/endpoints/file_upload/generate_upload_url.ts b/src/core/endpoints/file_upload/generate_upload_url.ts new file mode 100644 index 000000000..d1d6d2744 --- /dev/null +++ b/src/core/endpoints/file_upload/generate_upload_url.ts @@ -0,0 +1,146 @@ +/** + * Generate file upload URL REST API request. + */ + +import { createValidationError, PubNubError } from '../../../models/PubNubError'; +import { TransportResponse } from '../../types/transport-response'; +import { TransportMethod } from '../../types/transport-request'; +import { AbstractRequest } from '../../components/request'; +import * as FileSharing from '../../types/api/file-sharing'; +import RequestOperation from '../../constants/operations'; +import { encodeString } from '../../utils'; +import { KeySet } from '../../types/api'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = FileSharing.GenerateFileUploadUrlParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * File upload URL generation result status code. + */ + status: number; + + /** + * PubNub Service response. + */ + data: { + /** + * Unique file identifier. + * + * Unique file identifier, and it's {@link name} can be used to download file from the channel + * later. + */ + id: string; + + /** + * Actual file name under which file has been stored. + * + * File name and unique {@link id} can be used to download file from the channel later. + * + * **Note:** Actual file name may be different from the one which has been used during file + * upload. + */ + name: string; + }; + + /** + * PubNub service response extension. + */ + file_upload_request: { + /** + * Pre-signed URL for file upload. + */ + url: string; + + /** + * HTTP method which should be used for file upload. + */ + method: string; + + /** + * Expiration date (ISO 8601 format) for the pre-signed upload request. + */ + expiration_date: string; + + /** + * An array of form fields to be used in the pre-signed POST request. + * + * **Important:** Form data fields should be passed in exact same order as received from + * the PubNub service. + */ + form_fields: { + /** + * Form data field name. + */ + name: string; + /** + * Form data field value. + */ + value: string; + }[]; + }; +}; +// endregion + +/** + * Generate File Upload Url request. + */ +export class GenerateFileUploadUrlRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super({ method: TransportMethod.POST }); + } + + operation(): RequestOperation { + return RequestOperation.PNGenerateUploadUrlOperation; + } + + validate(): string | undefined { + if (!this.parameters.channel) return "channel can't be empty"; + if (!this.parameters.name) return "'name' can't be empty"; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return { + id: serviceResponse.data.id, + name: serviceResponse.data.name, + url: serviceResponse.file_upload_request.url, + formFields: serviceResponse.file_upload_request.form_fields, + }; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channel, + } = this.parameters; + + return `/v1/files/${subscribeKey}/channels/${encodeString(channel)}/generate-upload-url`; + } + + protected get body(): ArrayBuffer | string | undefined { + return JSON.stringify({ name: this.parameters.name }); + } +} diff --git a/src/core/endpoints/file_upload/get_file_url.js b/src/core/endpoints/file_upload/get_file_url.js deleted file mode 100644 index 01169563b..000000000 --- a/src/core/endpoints/file_upload/get_file_url.js +++ /dev/null @@ -1,63 +0,0 @@ -/** */ - -import { PubNubError, createValidationError, signRequest, generatePNSDK } from '../../components/endpoint'; - -import utils from '../../utils'; - -export default (modules, { channel, id, name }) => { - const { config, networking, tokenManager } = modules; - - if (!channel) { - throw new PubNubError( - 'Validation failed, check status for details', - createValidationError("channel can't be empty"), - ); - } - - if (!id) { - throw new PubNubError( - 'Validation failed, check status for details', - createValidationError("file id can't be empty"), - ); - } - - if (!name) { - throw new PubNubError( - 'Validation failed, check status for details', - createValidationError("file name can't be empty"), - ); - } - - const url = `/v1/files/${config.subscribeKey}/channels/${utils.encodeString(channel)}/files/${id}/${name}`; - const params = {}; - - params.uuid = config.getUUID(); - params.pnsdk = generatePNSDK(config); - - const tokenOrKey = tokenManager.getToken() || config.getAuthKey(); - if (tokenOrKey) { - params.auth = tokenOrKey; - } - - if (config.secretKey) { - signRequest( - modules, - url, - params, - {}, - { - getOperation: () => 'PubNubGetFileUrlOperation', - }, - ); - } - - const queryParams = Object.keys(params) - .map((key) => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`) - .join('&'); - - if (queryParams !== '') { - return `${networking.getStandardOrigin()}${url}?${queryParams}`; - } - - return `${networking.getStandardOrigin()}${url}`; -}; diff --git a/src/core/endpoints/file_upload/get_file_url.ts b/src/core/endpoints/file_upload/get_file_url.ts new file mode 100644 index 000000000..300ed96d6 --- /dev/null +++ b/src/core/endpoints/file_upload/get_file_url.ts @@ -0,0 +1,70 @@ +/** + * File sharing REST API module. + */ + +import { TransportResponse } from '../../types/transport-response'; +import { TransportMethod } from '../../types/transport-request'; +import { AbstractRequest } from '../../components/request'; +import * as FileSharing from '../../types/api/file-sharing'; +import RequestOperation from '../../constants/operations'; +import { encodeString } from '../../utils'; +import { KeySet } from '../../types/api'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = FileSharing.FileUrlParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; +// endregion + +/** + * File download Url generation request. + * + * Local request which generates Url to download shared file from the specific channel. + */ +export class GetFileDownloadUrlRequest extends AbstractRequest { + /** + * Construct file download Url generation request. + * + * @param parameters - Request configuration. + */ + constructor(private readonly parameters: RequestParameters) { + super({ method: TransportMethod.LOCAL }); + } + + operation(): RequestOperation { + return RequestOperation.PNGetFileUrlOperation; + } + + validate(): string | undefined { + const { channel, id, name } = this.parameters; + + if (!channel) return "channel can't be empty"; + if (!id) return "file id can't be empty"; + if (!name) return "file name can't be empty"; + } + + async parse(response: TransportResponse): Promise { + return response.url; + } + + protected get path(): string { + const { + channel, + id, + name, + keySet: { subscribeKey }, + } = this.parameters; + + return `/v1/files/${subscribeKey}/channels/${encodeString(channel)}/files/${id}/${name}`; + } +} diff --git a/src/core/endpoints/file_upload/list_files.js b/src/core/endpoints/file_upload/list_files.js deleted file mode 100644 index 5a04502c6..000000000 --- a/src/core/endpoints/file_upload/list_files.js +++ /dev/null @@ -1,45 +0,0 @@ -/** */ - -import operationConstants from '../../constants/operations'; - -import utils from '../../utils'; - -const endpoint = { - getOperation: () => operationConstants.PNListFilesOperation, - - validateParams: (_, params) => { - if (!params?.channel) { - return "channel can't be empty"; - } - }, - - getURL: ({ config }, params) => - `/v1/files/${config.subscribeKey}/channels/${utils.encodeString(params.channel)}/files`, - - getRequestTimeout: ({ config }) => config.getTransactionTimeout(), - - isAuthSupported: () => true, - - prepareParams: (_, params) => { - const outParams = {}; - - if (params.limit) { - outParams.limit = params.limit; - } - - if (params.next) { - outParams.next = params.next; - } - - return outParams; - }, - - handleResponse: (_, response) => ({ - status: response.status, - data: response.data, - next: response.next, - count: response.count, - }), -}; - -export default endpoint; diff --git a/src/core/endpoints/file_upload/list_files.ts b/src/core/endpoints/file_upload/list_files.ts new file mode 100644 index 000000000..0134f068e --- /dev/null +++ b/src/core/endpoints/file_upload/list_files.ts @@ -0,0 +1,110 @@ +/** + * List Files REST API module. + */ + +import { createValidationError, PubNubError } from '../../../models/PubNubError'; +import { TransportResponse } from '../../types/transport-response'; +import { AbstractRequest } from '../../components/request'; +import * as FileSharing from '../../types/api/file-sharing'; +import RequestOperation from '../../constants/operations'; +import { KeySet, Query } from '../../types/api'; +import { encodeString } from '../../utils'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Number of files to return in response. + */ +const LIMIT = 100; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = FileSharing.ListFilesParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request processing result status code. + */ + status: number; + + /** + * List of shared files for specified channel. + */ + data: FileSharing.SharedFile[]; + + /** + * Next files list page token. + */ + next: string; + + /** + * Number of returned files. + */ + count: number; +}; +// endregion + +/** + * Files List request. + */ +export class FilesListRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + + // Apply default request parameters. + this.parameters.limit ??= LIMIT; + } + + operation(): RequestOperation { + return RequestOperation.PNListFilesOperation; + } + + validate(): string | undefined { + if (!this.parameters.channel) return "channel can't be empty"; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return serviceResponse; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channel, + } = this.parameters; + + return `/v1/files/${subscribeKey}/channels/${encodeString(channel)}/files`; + } + + protected get queryParameters(): Query { + const { limit, next } = this.parameters; + + return { limit: limit!, ...(next ? { next } : {}) }; + } +} diff --git a/src/core/endpoints/file_upload/publish_file.js b/src/core/endpoints/file_upload/publish_file.js deleted file mode 100644 index 3a111935f..000000000 --- a/src/core/endpoints/file_upload/publish_file.js +++ /dev/null @@ -1,79 +0,0 @@ -/** */ - -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; -import { encode } from '../../components/base64_codec'; - -const preparePayload = (modules, payload) => { - let stringifiedPayload = JSON.stringify(payload); - if (modules.cryptoModule) { - const encrypted = modules.cryptoModule.encrypt(stringifiedPayload); - stringifiedPayload = typeof encrypted === 'string' ? encrypted : encode(encrypted); - stringifiedPayload = JSON.stringify(stringifiedPayload); - } - return stringifiedPayload || ''; -}; - -const endpoint = { - getOperation: () => operationConstants.PNPublishFileOperation, - - validateParams: (_, params) => { - if (!params?.channel) { - return "channel can't be empty"; - } - - if (!params?.fileId) { - return "file id can't be empty"; - } - - if (!params?.fileName) { - return "file name can't be empty"; - } - }, - - getURL: (modules, params) => { - const { publishKey, subscribeKey } = modules.config; - - const message = { - message: params.message, - file: { - name: params.fileName, - id: params.fileId, - }, - }; - - const payload = preparePayload(modules, message); - - return `/v1/files/publish-file/${publishKey}/${subscribeKey}/0/${utils.encodeString( - params.channel, - )}/0/${utils.encodeString(payload)}`; - }, - - getRequestTimeout: ({ config }) => config.getTransactionTimeout(), - - isAuthSupported: () => true, - - prepareParams: (_, params) => { - const outParams = {}; - - if (params.ttl) { - outParams.ttl = params.ttl; - } - - if (params.storeInHistory !== undefined) { - outParams.store = params.storeInHistory ? '1' : '0'; - } - - if (params.meta && typeof params.meta === 'object') { - outParams.meta = JSON.stringify(params.meta); - } - - return outParams; - }, - - handleResponse: (_, response) => ({ - timetoken: response['2'], - }), -}; - -export default endpoint; diff --git a/src/core/endpoints/file_upload/publish_file.ts b/src/core/endpoints/file_upload/publish_file.ts new file mode 100644 index 000000000..9e01aaf18 --- /dev/null +++ b/src/core/endpoints/file_upload/publish_file.ts @@ -0,0 +1,134 @@ +/** + * Publish File Message REST API module. + */ + +import { createValidationError, PubNubError } from '../../../models/PubNubError'; +import { TransportResponse } from '../../types/transport-response'; +import { CryptoModule } from '../../interfaces/crypto-module'; +import { AbstractRequest } from '../../components/request'; +import * as FileSharing from '../../types/api/file-sharing'; +import RequestOperation from '../../constants/operations'; +import { KeySet, Payload, Query } from '../../types/api'; +import { encode } from '../../components/base64_codec'; +import { encodeString } from '../../utils'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Whether published file messages should be stored in the channel's history. + */ +const STORE_IN_HISTORY = true; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = FileSharing.PublishFileMessageParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; + + /** + * Published data encryption module. + */ + crypto?: CryptoModule; +}; + +/** + * Service success response. + */ +type ServiceResponse = [0 | 1, string, string]; +// endregion + +export class PublishFileMessageRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + + // Apply default request parameters. + this.parameters.storeInHistory ??= STORE_IN_HISTORY; + } + + operation(): RequestOperation { + return RequestOperation.PNPublishFileMessageOperation; + } + + validate(): string | undefined { + const { channel, fileId, fileName } = this.parameters; + + if (!channel) return "channel can't be empty"; + if (!fileId) return "file id can't be empty"; + if (!fileName) return "file name can't be empty"; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return { timetoken: serviceResponse[2] }; + } + + protected get path(): string { + const { + message, + channel, + keySet: { publishKey, subscribeKey }, + fileId, + fileName, + } = this.parameters; + + const fileMessage = { + file: { + name: fileName, + id: fileId, + }, + ...(message ? { message } : {}), + }; + + return `/v1/files/publish-file/${publishKey}/${subscribeKey}/0/${encodeString(channel)}/0/${encodeString( + this.prepareMessagePayload(fileMessage), + )}`; + } + + protected get queryParameters(): Query { + const { storeInHistory, ttl, meta } = this.parameters; + return { + store: storeInHistory! ? '1' : '0', + ...(ttl ? { ttl } : {}), + ...(meta && typeof meta === 'object' ? { meta: JSON.stringify(meta) } : {}), + }; + } + + /** + * Pre-process provided data. + * + * Data will be "normalized" and encrypted if `cryptoModule` has been provided. + * + * @param payload - User-provided data which should be pre-processed before use. + * + * @returns Payload which can be used as part of request URL or body. + * + * @throws {Error} in case if provided `payload` or results of `encryption` can't be stringified. + */ + private prepareMessagePayload(payload: Payload): string { + const { crypto } = this.parameters; + if (!crypto) return JSON.stringify(payload) || ''; + + const encrypted = crypto.encrypt(JSON.stringify(payload)); + + return JSON.stringify(typeof encrypted === 'string' ? encrypted : encode(encrypted)); + } +} diff --git a/src/core/endpoints/file_upload/send_file.js b/src/core/endpoints/file_upload/send_file.js deleted file mode 100644 index ad69fbdbd..000000000 --- a/src/core/endpoints/file_upload/send_file.js +++ /dev/null @@ -1,131 +0,0 @@ -import { PubNubError, createValidationError } from '../../components/endpoint'; -import { FileInterface } from '../../interfaces/file'; - -const sendFile = function ({ - generateUploadUrl, - publishFile, - modules: { PubNubFile, config, cryptography, cryptoModule, networking }, -}) { - return async ({ channel, file: input, message, cipherKey, meta, ttl, storeInHistory }) => { - if (!channel) { - throw new PubNubError( - 'Validation failed, check status for details', - createValidationError("channel can't be empty"), - ); - } - - if (!input) { - throw new PubNubError( - 'Validation failed, check status for details', - createValidationError("file can't be empty"), - ); - } - - let file = PubNubFile.create(input); - - const { - file_upload_request: { url, form_fields: formFields }, - data: { id, name }, - } = await generateUploadUrl({ channel, name: file.name }); - - if (PubNubFile.supportsEncryptFile && (cipherKey || cryptoModule)) { - file = - cipherKey == null - ? await cryptoModule.encryptFile(file, PubNubFile) - : await cryptography.encryptFile(cipherKey, file, PubNubFile); - } - - let formFieldsWithMimeType = formFields; - - if (file.mimeType) { - formFieldsWithMimeType = formFields.map((entry) => { - if (entry.key === 'Content-Type') return { key: entry.key, value: file.mimeType }; - return entry; - }); - } - - let result; - - try { - if (PubNubFile.supportsFileUri && input.uri) { - result = await networking.POSTFILE(url, formFieldsWithMimeType, await file.toFileUri()); - } else if (PubNubFile.supportsFile) { - result = await networking.POSTFILE(url, formFieldsWithMimeType, await file.toFile()); - } else if (PubNubFile.supportsBuffer) { - result = await networking.POSTFILE(url, formFieldsWithMimeType, await file.toBuffer()); - } else if (PubNubFile.supportsBlob) { - result = await networking.POSTFILE(url, formFieldsWithMimeType, await file.toBlob()); - } else { - throw new Error('Unsupported environment'); - } - } catch (e) { - if (e.response && typeof e.response.text === 'string') { - const errorBody = e.response.text; - const reason = /(.*)<\/Message>/gi.exec(errorBody); - throw new PubNubError(reason ? `Upload to bucket failed: ${reason[1]}` : 'Upload to bucket failed.', e); - } else { - throw new PubNubError('Upload to bucket failed.', e); - } - } - - if (result.status !== 204) { - throw new PubNubError('Upload to bucket was unsuccessful', result); - } - - let retries = config.fileUploadPublishRetryLimit; - let wasSuccessful = false; - - let publishResult = { timetoken: '0' }; - - do { - try { - /* eslint-disable-next-line no-await-in-loop */ - publishResult = await publishFile({ - channel, - message, - fileId: id, - fileName: name, - meta, - storeInHistory, - ttl, - }); - - wasSuccessful = true; - } catch (e) { - retries -= 1; - } - } while (!wasSuccessful && retries > 0); - - if (!wasSuccessful) { - throw new PubNubError( - 'Publish failed. You may want to execute that operation manually using pubnub.publishFile', - { - channel, - id, - name, - }, - ); - } else { - return { - timetoken: publishResult.timetoken, - id, - name, - }; - } - }; -}; - -export default (deps) => { - const f = sendFile(deps); - - return (params, cb) => { - const resultP = f(params); - - if (typeof cb === 'function') { - resultP.then((result) => cb(null, result)).catch((error) => cb(error, null)); - - return resultP; - } - return resultP; - }; -}; diff --git a/src/core/endpoints/file_upload/send_file.ts b/src/core/endpoints/file_upload/send_file.ts new file mode 100644 index 000000000..86992294e --- /dev/null +++ b/src/core/endpoints/file_upload/send_file.ts @@ -0,0 +1,173 @@ +import { PubNubFileConstructor, PubNubFileInterface } from '../../types/file'; +import { GenerateFileUploadUrlRequest } from './generate_upload_url'; +import { CryptoModule } from '../../interfaces/crypto-module'; +import { Cryptography } from '../../interfaces/cryptography'; +import { AbstractRequest } from '../../components/request'; +import * as FileSharing from '../../types/api/file-sharing'; +import { PubNubError } from '../../../models/PubNubError'; +import RequestOperation from '../../constants/operations'; +import { KeySet, PubNubAPIError } from '../../types/api'; +import { UploadFileRequest } from './upload-file'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = FileSharing.SendFileParameters & { + /** + * How many times should retry file message publish. + */ + fileUploadPublishRetryLimit: number; + + /** + * PubNub REST API access key set. + */ + keySet: KeySet; + + /** + * {@link PubNub} File object constructor. + */ + PubNubFile: PubNubFileConstructor; + + /** + * Request sending method. + * + * @param request - Request which should be processed. + */ + sendRequest: (request: AbstractRequest) => Promise; + + /** + * File message publish method. + * + * @param parameters - File message request parameters. + */ + publishFile: ( + parameters: FileSharing.PublishFileMessageParameters, + ) => Promise; + + /** + * If passed, will encrypt the payloads. + * + * @deprecated Pass it to {@link crypto} module instead. + */ + cipherKey?: string; + + /** + * Published data encryption module. + */ + crypto?: CryptoModule; + + /** + * Legacy cryptography module. + */ + cryptography?: Cryptography; +}; +// endregion + +/** + * Send file composed request. + */ +export class SendFileRequest { + /** + * File object for upload. + */ + private file?: PubNubFileInterface; + + constructor(private readonly parameters: RequestParameters) { + this.file = this.parameters.PubNubFile?.create(parameters.file); + + if (!this.file) throw new Error('File upload error: unable to create File object.'); + } + + /** + * Process user-input and upload file. + * + * @returns File upload request response. + */ + public async process(): Promise { + let fileName: string | undefined; + let fileId: string | undefined; + + return this.generateFileUploadUrl() + .then((result) => { + fileName = result.name; + fileId = result.id; + return this.uploadFile(result); + }) + .then(() => this.publishFileMessage(fileId!, fileName!)) + .catch((error: Error) => { + const errorStatus = PubNubAPIError.create(error).toStatus(RequestOperation.PNPublishFileOperation); + throw new PubNubError('File upload error.', errorStatus); + }); + } + + /** + * Generate pre-signed file upload Url. + * + * @returns File upload credentials. + */ + private async generateFileUploadUrl(): Promise { + const request = new GenerateFileUploadUrlRequest({ + ...this.parameters, + name: this.file!.name, + keySet: this.parameters.keySet, + }); + + return this.parameters.sendRequest(request); + } + + /** + * Prepare and upload {@link PubNub} File object to remote storage. + * + * @param uploadParameters - File upload request parameters. + * + * @returns + */ + private async uploadFile(uploadParameters: FileSharing.GenerateFileUploadUrlResponse) { + const { cipherKey, PubNubFile, crypto, cryptography } = this.parameters; + const { id, name, url, formFields } = uploadParameters; + + // Encrypt file if possible. + if (this.parameters.PubNubFile!.supportsEncryptFile) { + if (!cipherKey && crypto) this.file = (await crypto.encryptFile(this.file!, PubNubFile!))!; + else if (cipherKey && cryptography) + this.file = (await cryptography.encryptFile(cipherKey, this.file!, PubNubFile!))!; + } + + return this.parameters.sendRequest( + new UploadFileRequest({ + fileId: id, + fileName: name, + file: this.file!, + uploadUrl: url, + formFields, + }), + ); + } + + private async publishFileMessage(fileId: string, fileName: string): Promise { + let result: FileSharing.PublishFileMessageResponse = { timetoken: '0' }; + let retries = this.parameters.fileUploadPublishRetryLimit; + let wasSuccessful = false; + + do { + try { + result = await this.parameters.publishFile({ ...this.parameters, fileId, fileName }); + wasSuccessful = true; + } catch (_) { + retries -= 1; + } + } while (!wasSuccessful && retries > 0); + + if (!wasSuccessful) { + throw new PubNubError( + 'Publish failed. You may want to execute that operation manually using pubnub.publishFile', + { error: true, channel: this.parameters.channel, id: fileId, name: fileName }, + ); + } else return { status: 200, timetoken: result.timetoken, id: fileId, name: fileName }; + } +} diff --git a/src/core/endpoints/file_upload/types.js b/src/core/endpoints/file_upload/types.js deleted file mode 100644 index 0975b9062..000000000 --- a/src/core/endpoints/file_upload/types.js +++ /dev/null @@ -1 +0,0 @@ -/** */ diff --git a/src/core/endpoints/file_upload/upload-file.ts b/src/core/endpoints/file_upload/upload-file.ts new file mode 100644 index 000000000..ed461c4f6 --- /dev/null +++ b/src/core/endpoints/file_upload/upload-file.ts @@ -0,0 +1,62 @@ +/** + * Upload file REST API request. + */ + +import { TransportResponse } from '../../types/transport-response'; +import { TransportRequest } from '../../types/transport-request'; +import { AbstractRequest } from '../../components/request'; +import * as FileSharing from '../../types/api/file-sharing'; +import RequestOperation from '../../constants/operations'; +import { PubNubFileInterface } from '../../types/file'; + +/** + * File Upload request. + */ +export class UploadFileRequest extends AbstractRequest { + constructor(private readonly parameters: FileSharing.UploadFileParameters) { + super(); + + // Use file's actual mime type if available. + const mimeType = parameters.file.mimeType; + if (mimeType) { + parameters.formFields = parameters.formFields.map((entry) => { + if (entry.name === 'Content-Type') return { name: entry.name, value: mimeType }; + return entry; + }); + } + } + + operation(): RequestOperation { + return RequestOperation.PNPublishFileOperation; + } + + validate(): string | undefined { + const { fileId, fileName, file, uploadUrl } = this.parameters; + + if (!fileId) return "Validation failed: file 'id' can't be empty"; + if (!fileName) return "Validation failed: file 'name' can't be empty"; + if (!file) return "Validation failed: 'file' can't be empty"; + if (!uploadUrl) return "Validation failed: file upload 'url' can't be empty"; + } + + async parse(response: TransportResponse): Promise { + return { + status: response.status, + message: response.body ? UploadFileRequest.decoder.decode(response.body) : 'OK', + }; + } + + request(): TransportRequest { + return { ...super.request(), origin: new URL(this.parameters.uploadUrl).origin }; + } + + protected get path(): string { + const { pathname, search } = new URL(this.parameters.uploadUrl); + + return `${pathname}${search}`; + } + + protected get body(): ArrayBuffer | PubNubFileInterface | string | undefined { + return this.parameters.file; + } +} diff --git a/src/core/endpoints/history/delete_messages.js b/src/core/endpoints/history/delete_messages.js deleted file mode 100644 index aaf8b12d7..000000000 --- a/src/core/endpoints/history/delete_messages.js +++ /dev/null @@ -1,50 +0,0 @@ -/* */ - -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -export function getOperation() { - return operationConstants.PNDeleteMessagesOperation; -} - -export function validateParams(modules, incomingParams) { - const { channel } = incomingParams; - const { config } = modules; - - if (!channel) return 'Missing channel'; - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function useDelete() { - return true; -} - -export function getURL(modules, incomingParams) { - const { channel } = incomingParams; - const { config } = modules; - - return `/v3/history/sub-key/${config.subscribeKey}/channel/${utils.encodeString(channel)}`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams(modules, incomingParams) { - const { start, end } = incomingParams; - - const outgoingParams = {}; - - if (start) outgoingParams.start = start; - if (end) outgoingParams.end = end; - - return outgoingParams; -} - -export function handleResponse(modules, serverResponse) { - return serverResponse.payload; -} diff --git a/src/core/endpoints/history/delete_messages.ts b/src/core/endpoints/history/delete_messages.ts new file mode 100644 index 000000000..6b7b1745b --- /dev/null +++ b/src/core/endpoints/history/delete_messages.ts @@ -0,0 +1,96 @@ +/** + * Delete messages REST API module. + */ + +import { createValidationError, PubNubError } from '../../../models/PubNubError'; +import type { TransportResponse } from '../../types/transport-response'; +import { TransportMethod } from '../../types/transport-request'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import * as History from '../../types/api/history'; +import { KeySet, Query } from '../../types/api'; +import { encodeString } from '../../utils'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = History.DeleteMessagesParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Whether service response represent error or not. + */ + error: boolean; + + /** + * Human-readable error explanation. + */ + error_message: string; +}; +// endregion + +/** + * Delete messages from channel history. + */ +export class DeleteMessageRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super({ method: TransportMethod.DELETE }); + } + + operation(): RequestOperation { + return RequestOperation.PNDeleteMessagesOperation; + } + + validate(): string | undefined { + if (!this.parameters.keySet.subscribeKey) return 'Missing Subscribe Key'; + if (!this.parameters.channel) return 'Missing channel'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return {}; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channel, + } = this.parameters; + + return `/v3/history/sub-key/${subscribeKey}/channel/${encodeString(channel)}`; + } + + protected get queryParameters(): Query { + const { start, end } = this.parameters; + + return { + ...(start ? { start } : {}), + ...(end ? { end } : {}), + }; + } +} diff --git a/src/core/endpoints/history/get_history.js b/src/core/endpoints/history/get_history.js deleted file mode 100644 index bf76c52a2..000000000 --- a/src/core/endpoints/history/get_history.js +++ /dev/null @@ -1,92 +0,0 @@ -/* */ -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -function __processMessage(modules, message) { - const result = {}; - if (!modules.cryptoModule) { - result.payload = message; - return result; - } - try { - const decryptedData = modules.cryptoModule.decrypt(message); - const decryptedPayload = - decryptedData instanceof ArrayBuffer ? JSON.parse(new TextDecoder().decode(decryptedData)) : decryptedData; - result.payload = decryptedPayload; - return result; - } catch (e) { - if (modules.config.logVerbosity && console && console.log) console.log('decryption error', e.message); - result.payload = message; - result.error = `Error while decrypting message content: ${e.message}`; - } - return result; -} - -export function getOperation() { - return operationConstants.PNHistoryOperation; -} - -export function validateParams(modules, incomingParams) { - const { channel } = incomingParams; - const { config } = modules; - - if (!channel) return 'Missing channel'; - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules, incomingParams) { - const { channel } = incomingParams; - const { config } = modules; - return `/v2/history/sub-key/${config.subscribeKey}/channel/${utils.encodeString(channel)}`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams(modules, incomingParams) { - const { start, end, reverse, count = 100, stringifiedTimeToken = false, includeMeta = false } = incomingParams; - const outgoingParams = { - include_token: 'true', - }; - - outgoingParams.count = count; - if (start) outgoingParams.start = start; - if (end) outgoingParams.end = end; - if (stringifiedTimeToken) outgoingParams.string_message_token = 'true'; - if (reverse != null) outgoingParams.reverse = reverse.toString(); - if (includeMeta) outgoingParams.include_meta = 'true'; - - return outgoingParams; -} - -export function handleResponse(modules, serverResponse) { - const response = { - messages: [], - startTimeToken: serverResponse[1], - endTimeToken: serverResponse[2], - }; - - if (Array.isArray(serverResponse[0])) { - serverResponse[0].forEach((serverHistoryItem) => { - const processedMessgeResult = __processMessage(modules, serverHistoryItem.message); - const item = { - timetoken: serverHistoryItem.timetoken, - entry: processedMessgeResult.payload, - }; - - if (serverHistoryItem.meta) { - item.meta = serverHistoryItem.meta; - } - if (processedMessgeResult.error) item.error = processedMessgeResult.error; - - response.messages.push(item); - }); - } - - return response; -} diff --git a/src/core/endpoints/history/get_history.ts b/src/core/endpoints/history/get_history.ts new file mode 100644 index 000000000..07da89761 --- /dev/null +++ b/src/core/endpoints/history/get_history.ts @@ -0,0 +1,210 @@ +/** + * Get history REST API module. + */ + +import { createValidationError, PubNubError } from '../../../models/PubNubError'; +import { TransportResponse } from '../../types/transport-response'; +import { CryptoModule } from '../../interfaces/crypto-module'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import { KeySet, Payload, Query } from '../../types/api'; +import * as History from '../../types/api/history'; +import { encodeString } from '../../utils'; + +// -------------------------------------------------------- +// ---------------------- Defaults ------------------------ +// -------------------------------------------------------- +// region Defaults + +/** + * Whether verbose logging enabled or not. + */ +const LOG_VERBOSITY = false; + +/** + * Whether associated message metadata should be returned or not. + */ +const INCLUDE_METADATA = false; + +/** + * Whether timetokens should be returned as strings by default or not. + */ +const STRINGIFY_TIMETOKENS = false; + +/** + * Default and maximum number of messages which should be returned. + */ +const MESSAGES_COUNT = 100; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = History.GetHistoryParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; + + /** + * Published data encryption module. + */ + crypto?: CryptoModule; + + /** + * Whether verbose logging enabled or not. + * + * @default `false` + */ + logVerbosity?: boolean; +}; + +/** + * Service success response. + */ +type ServiceResponse = [ + /** + * List of previously published messages. + */ + { + /** + * Message payload (decrypted). + */ + message: Payload; + + /** + * When message has been received by PubNub service. + */ + timetoken: string | number; + + /** + * Additional data which has been published along with message to be used with real-time + * events filter expression. + */ + meta?: Payload; + }[], + + /** + * Received messages timeline start. + */ + string | number, + + /** + * Received messages timeline end. + */ + string | number, +]; +// endregion + +/** + * Get single channel messages request. + */ +export class GetHistoryRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + + // Apply defaults. + if (parameters.count) parameters.count = Math.min(parameters.count, MESSAGES_COUNT); + else parameters.count = MESSAGES_COUNT; + + parameters.stringifiedTimeToken ??= STRINGIFY_TIMETOKENS; + parameters.includeMeta ??= INCLUDE_METADATA; + parameters.logVerbosity ??= LOG_VERBOSITY; + } + + operation(): RequestOperation { + return RequestOperation.PNHistoryOperation; + } + + validate(): string | undefined { + if (!this.parameters.keySet.subscribeKey) return 'Missing Subscribe Key'; + if (!this.parameters.channel) return 'Missing channel'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + const messages = serviceResponse[0]; + const startTimeToken = serviceResponse[1]; + const endTimeToken = serviceResponse[2]; + + // Handle malformed get history response. + if (!Array.isArray(messages)) return { messages: [], startTimeToken, endTimeToken }; + + return { + messages: messages.map((payload) => { + const processedPayload = this.processPayload(payload.message); + const item: History.GetHistoryResponse['messages'][number] = { + entry: processedPayload.payload, + timetoken: payload.timetoken, + }; + + if (processedPayload.error) item.error = processedPayload.error; + if (payload.meta) item.meta = payload.meta; + + return item; + }), + startTimeToken, + endTimeToken, + }; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channel, + } = this.parameters; + + return `/v2/history/sub-key/${subscribeKey}/channel/${encodeString(channel)}`; + } + + protected get queryParameters(): Query { + const { start, end, reverse, count, stringifiedTimeToken, includeMeta } = this.parameters; + + return { + count: count!, + include_token: 'true', + ...(start ? { start } : {}), + ...(end ? { end } : {}), + ...(stringifiedTimeToken! ? { string_message_token: 'true' } : {}), + ...(reverse !== undefined && reverse !== null ? { reverse: reverse.toString() } : {}), + ...(includeMeta! ? { include_meta: 'true' } : {}), + }; + } + + private processPayload(payload: Payload): { payload: Payload; error?: string } { + const { crypto, logVerbosity } = this.parameters; + if (!crypto || typeof payload !== 'string') return { payload }; + + let decryptedPayload: string; + let error: string | undefined; + + try { + const decryptedData = crypto.decrypt(payload); + decryptedPayload = + decryptedData instanceof ArrayBuffer + ? JSON.parse(GetHistoryRequest.decoder.decode(decryptedData)) + : decryptedData; + } catch (err) { + if (logVerbosity!) console.log(`decryption error`, (err as Error).message); + decryptedPayload = payload; + error = `Error while decrypting message content: ${(err as Error).message}`; + } + + return { + payload: decryptedPayload, + error, + }; + } +} diff --git a/src/core/endpoints/history/message_counts.js b/src/core/endpoints/history/message_counts.js deleted file mode 100644 index 6e00cfcc7..000000000 --- a/src/core/endpoints/history/message_counts.js +++ /dev/null @@ -1,55 +0,0 @@ -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -export function getOperation() { - return operationConstants.PNMessageCounts; -} - -export function validateParams(modules, incomingParams) { - const { channels, timetoken, channelTimetokens } = incomingParams; - const { config } = modules; - - if (!channels) return 'Missing channel'; - if (timetoken && channelTimetokens) return 'timetoken and channelTimetokens are incompatible together'; - if (channelTimetokens && channelTimetokens.length > 1 && channels.length !== channelTimetokens.length) { - return 'Length of channelTimetokens and channels do not match'; - } - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules, incomingParams) { - const { channels } = incomingParams; - const { config } = modules; - - const stringifiedChannels = channels.join(','); - - return `/v3/history/sub-key/${config.subscribeKey}/message-counts/${utils.encodeString(stringifiedChannels)}`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams(modules, incomingParams) { - const { timetoken, channelTimetokens } = incomingParams; - const outgoingParams = {}; - - if (channelTimetokens && channelTimetokens.length === 1) { - const [tt] = channelTimetokens; - outgoingParams.timetoken = tt; - } else if (channelTimetokens) { - outgoingParams.channelsTimetoken = channelTimetokens.join(','); - } else if (timetoken) { - outgoingParams.timetoken = timetoken; - } - - return outgoingParams; -} - -export function handleResponse(modules, serverResponse) { - return { channels: serverResponse.channels }; -} diff --git a/src/core/endpoints/history/message_counts.ts b/src/core/endpoints/history/message_counts.ts new file mode 100644 index 000000000..9ef525ac9 --- /dev/null +++ b/src/core/endpoints/history/message_counts.ts @@ -0,0 +1,122 @@ +/** + * Messages count REST API module. + */ + +import { createValidationError, PubNubError } from '../../../models/PubNubError'; +import { TransportResponse } from '../../types/transport-response'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import * as History from '../../types/api/history'; +import { KeySet, Query } from '../../types/api'; +import { encodeString } from '../../utils'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = History.MessageCountParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Whether service response represent error or not. + */ + error: boolean; + + /** + * Human-readable error explanation. + */ + error_message: string; + + /** + * Map of channel names to the number of counted messages. + */ + channels: Record; + + /** + * Map of channel names to pre-computed REST API paths to fetch more. + */ + more: { + [p: string]: { + /** + * Pre-computed message count REST API url to fetch more information. + */ + url: string; + /** + * Whether there is more information available or not. + */ + is_more: boolean; + }; + }; +}; +// endregion + +export class MessageCountRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + } + + operation(): RequestOperation { + return RequestOperation.PNMessageCounts; + } + + validate(): string | undefined { + const { + keySet: { subscribeKey }, + channels, + timetoken, + channelTimetokens, + } = this.parameters; + + if (!subscribeKey) return 'Missing Subscribe Key'; + if (!channels) return 'Missing channels'; + if (timetoken && channelTimetokens) return '`timetoken` and `channelTimetokens` are incompatible together'; + if (!timetoken && !channelTimetokens) return '`timetoken` or `channelTimetokens` need to be set'; + if (channelTimetokens && channelTimetokens.length && channelTimetokens.length !== channels.length) + return 'Length of `channelTimetokens` and `channels` do not match'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return { channels: serviceResponse.channels }; + } + + protected get path(): string { + return `/v3/history/sub-key/${this.parameters.keySet.subscribeKey}/message-counts/${encodeString( + this.parameters.channels.join(','), + )}`; + } + + protected get queryParameters(): Query { + let { channelTimetokens } = this.parameters; + if (this.parameters.timetoken) channelTimetokens = [this.parameters.timetoken]; + + return { + ...(channelTimetokens!.length === 1 ? { timetoken: channelTimetokens![0] } : {}), + ...(channelTimetokens!.length > 1 ? { channelsTimetoken: channelTimetokens!.join(',') } : {}), + }; + } +} diff --git a/src/core/endpoints/objects/channel/get.js b/src/core/endpoints/objects/channel/get.js deleted file mode 100644 index e5f6f6fb2..000000000 --- a/src/core/endpoints/objects/channel/get.js +++ /dev/null @@ -1,40 +0,0 @@ -import operationConstants from '../../../constants/operations'; - -import utils from '../../../utils'; - -const endpoint = { - getOperation: () => operationConstants.PNGetChannelMetadataOperation, - - validateParams: (_, params) => { - if (!params?.channel) { - return 'Channel cannot be empty'; - } - }, - - getURL: ({ config }, params) => `/v2/objects/${config.subscribeKey}/channels/${utils.encodeString(params.channel)}`, - - getRequestTimeout: ({ config }) => config.getTransactionTimeout(), - - isAuthSupported: () => true, - - prepareParams: (_, params) => { - const queryParams = {}; - queryParams.include = ['status', 'type', 'custom']; - - if (params?.include) { - if (params.include?.customFields === false) { - queryParams.include.pop(); - } - } - queryParams.include = queryParams.include.join(','); - - return queryParams; - }, - - handleResponse: (_, response) => ({ - status: response.status, - data: response.data, - }), -}; - -export default endpoint; diff --git a/src/core/endpoints/objects/channel/get.ts b/src/core/endpoints/objects/channel/get.ts new file mode 100644 index 000000000..a175cf182 --- /dev/null +++ b/src/core/endpoints/objects/channel/get.ts @@ -0,0 +1,89 @@ +/** + * Get Channel Metadata REST API module. + */ + +import { createValidationError, PubNubError } from '../../../../models/PubNubError'; +import { TransportResponse } from '../../../types/transport-response'; +import { AbstractRequest } from '../../../components/request'; +import RequestOperation from '../../../constants/operations'; +import * as AppContext from '../../../types/api/app-context'; +import { KeySet, Query } from '../../../types/api'; +import { encodeString } from '../../../utils'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Whether `Channel` custom field should be included by default or not. + */ +const INCLUDE_CUSTOM_FIELDS = true; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = AppContext.GetChannelMetadataParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; +// endregion + +/** + * Get Channel Metadata request. + */ +export class GetChannelMetadataRequest< + Response extends AppContext.GetChannelMetadataResponse, + Custom extends AppContext.CustomData = AppContext.CustomData, +> extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + + // Apply default request parameters. + parameters.include ??= {}; + parameters.include.customFields ??= INCLUDE_CUSTOM_FIELDS; + } + + operation(): RequestOperation { + return RequestOperation.PNGetChannelMetadataOperation; + } + + validate(): string | undefined { + if (!this.parameters.channel) return 'Channel cannot be empty'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return serviceResponse; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channel, + } = this.parameters; + + return `/v2/objects/${subscribeKey}/channels/${encodeString(channel)}`; + } + + protected get queryParameters(): Query { + return { + include: ['status', 'type', ...(this.parameters.include!.customFields ? ['custom'] : [])].join(','), + }; + } +} diff --git a/src/core/endpoints/objects/channel/get_all.js b/src/core/endpoints/objects/channel/get_all.js deleted file mode 100644 index 79ced13ef..000000000 --- a/src/core/endpoints/objects/channel/get_all.js +++ /dev/null @@ -1,66 +0,0 @@ -import operationConstants from '../../../constants/operations'; - -const endpoint = { - getOperation: () => operationConstants.PNGetAllChannelMetadataOperation, - - validateParams: () => { - // No required parameters. - }, - - getURL: ({ config }) => `/v2/objects/${config.subscribeKey}/channels`, - - getRequestTimeout: ({ config }) => config.getTransactionTimeout(), - - isAuthSupported: () => true, - - prepareParams: (_modules, params) => { - const queryParams = {}; - queryParams.include = ['status', 'type']; - - if (params?.include) { - if (params.include?.customFields) { - queryParams.include.push('custom'); - } - } - queryParams.include = queryParams.include.join(','); - - if (params?.include?.totalCount) { - queryParams.count = params.include?.totalCount; - } - - if (params?.page?.next) { - queryParams.start = params.page?.next; - } - - if (params?.page?.prev) { - queryParams.end = params.page?.prev; - } - - if (params?.filter) { - queryParams.filter = params.filter; - } - - queryParams.limit = params?.limit ?? 100; - - if (params?.sort) { - queryParams.sort = Object.entries(params.sort ?? {}).map(([key, value]) => { - if (value === 'asc' || value === 'desc') { - return `${key}:${value}`; - } - return key; - }); - } - - return queryParams; - }, - - handleResponse: (_, response) => ({ - status: response.status, - data: response.data, - totalCount: response.totalCount, - prev: response.prev, - next: response.next, - }), -}; - -export default endpoint; diff --git a/src/core/endpoints/objects/channel/get_all.ts b/src/core/endpoints/objects/channel/get_all.ts new file mode 100644 index 000000000..e6b298187 --- /dev/null +++ b/src/core/endpoints/objects/channel/get_all.ts @@ -0,0 +1,102 @@ +/** + * Get All Channel Metadata REST API module. + */ + +import { createValidationError, PubNubError } from '../../../../models/PubNubError'; +import { TransportResponse } from '../../../types/transport-response'; +import { AbstractRequest } from '../../../components/request'; +import RequestOperation from '../../../constants/operations'; +import * as AppContext from '../../../types/api/app-context'; +import { KeySet, Query } from '../../../types/api'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Whether `Channel` custom fields should be included in response or not. + */ +const INCLUDE_CUSTOM_FIELDS = false; + +/** + * Whether total number of channels should be included in response or not. + */ +const INCLUDE_TOTAL_COUNT = false; + +/** + * Number of objects to return in response. + */ +const LIMIT = 100; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- + +// region Types +/** + * Request configuration parameters. + */ +type RequestParameters = AppContext.GetAllMetadataParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; +// endregion + +/** + * Get All Channels Metadata request. + */ +export class GetAllChannelsMetadataRequest< + Response extends AppContext.GetAllChannelMetadataResponse, + Custom extends AppContext.CustomData = AppContext.CustomData, +> extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + + // Apply default request parameters. + parameters.include ??= {}; + parameters.include.customFields ??= INCLUDE_CUSTOM_FIELDS; + parameters.include.totalCount ??= INCLUDE_TOTAL_COUNT; + parameters.limit ??= LIMIT; + } + + operation(): RequestOperation { + return RequestOperation.PNGetAllChannelMetadataOperation; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return serviceResponse; + } + + protected get path(): string { + return `/v2/objects/${this.parameters.keySet.subscribeKey}/channels`; + } + + protected get queryParameters(): Query { + const { include, page, filter, sort, limit } = this.parameters; + const sorting = Object.entries(sort ?? {}).map(([option, order]) => + order !== null ? `${option}:${order}` : option, + ); + + return { + include: ['status', 'type', ...(include!.customFields ? ['custom'] : [])].join(','), + count: `${include!.totalCount!}`, + ...(filter ? { filter } : {}), + ...(page?.next ? { start: page.next } : {}), + ...(page?.prev ? { end: page.prev } : {}), + ...(limit ? { limit } : {}), + ...(sorting.length ? { sort: sorting } : {}), + }; + } +} diff --git a/src/core/endpoints/objects/channel/remove.js b/src/core/endpoints/objects/channel/remove.js deleted file mode 100644 index a05026494..000000000 --- a/src/core/endpoints/objects/channel/remove.js +++ /dev/null @@ -1,31 +0,0 @@ -/** */ - -import operationConstants from '../../../constants/operations'; - -import utils from '../../../utils'; - -const endpoint = { - getOperation: () => operationConstants.PNRemoveChannelMetadataOperation, - - validateParams: (_, params) => { - if (!params?.channel) { - return 'Channel cannot be empty'; - } - }, - - getURL: ({ config }, params) => `/v2/objects/${config.subscribeKey}/channels/${utils.encodeString(params.channel)}`, - useDelete: () => true, - - getRequestTimeout: ({ config }) => config.getTransactionTimeout(), - - isAuthSupported: () => true, - - prepareParams: () => ({}), - - handleResponse: (_, response) => ({ - status: response.status, - data: response.data, - }), -}; - -export default endpoint; diff --git a/src/core/endpoints/objects/channel/remove.ts b/src/core/endpoints/objects/channel/remove.ts new file mode 100644 index 000000000..9c85f0045 --- /dev/null +++ b/src/core/endpoints/objects/channel/remove.ts @@ -0,0 +1,68 @@ +/** + * Remove Channel Metadata REST API module. + */ + +import { createValidationError, PubNubError } from '../../../../models/PubNubError'; +import { TransportResponse } from '../../../types/transport-response'; +import { TransportMethod } from '../../../types/transport-request'; +import { AbstractRequest } from '../../../components/request'; +import RequestOperation from '../../../constants/operations'; +import * as AppContext from '../../../types/api/app-context'; +import { encodeString } from '../../../utils'; +import { KeySet } from '../../../types/api'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = AppContext.RemoveChannelMetadataParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; +// endregion + +/** + * Remove Channel Metadata request. + */ +export class RemoveChannelMetadataRequest< + Response extends AppContext.RemoveChannelMetadataResponse, +> extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super({ method: TransportMethod.DELETE }); + } + + operation(): RequestOperation { + return RequestOperation.PNRemoveChannelMetadataOperation; + } + + validate(): string | undefined { + if (!this.parameters.channel) return 'Channel cannot be empty'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return serviceResponse; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channel, + } = this.parameters; + + return `/v2/objects/${subscribeKey}/channels/${encodeString(channel)}`; + } +} diff --git a/src/core/endpoints/objects/channel/set.js b/src/core/endpoints/objects/channel/set.js deleted file mode 100644 index 7f3d4f78c..000000000 --- a/src/core/endpoints/objects/channel/set.js +++ /dev/null @@ -1,49 +0,0 @@ -/** */ - -import operationConstants from '../../../constants/operations'; - -import utils from '../../../utils'; - -const endpoint = { - getOperation: () => operationConstants.PNSetChannelMetadataOperation, - - validateParams: (_, params) => { - if (!params?.channel) { - return 'Channel cannot be empty'; - } - - if (!params?.data) { - return 'Data cannot be empty'; - } - }, - - usePatch: () => true, - - patchURL: ({ config }, params) => `/v2/objects/${config.subscribeKey}/channels/${utils.encodeString(params.channel)}`, - - patchPayload: (_, params) => params.data, - - getRequestTimeout: ({ config }) => config.getTransactionTimeout(), - - isAuthSupported: () => true, - - prepareParams: (_, params) => { - const queryParams = {}; - queryParams.include = ['status', 'type', 'custom']; - - if (params?.include) { - if (params.include?.customFields === false) { - queryParams.include.pop(); - } - } - queryParams.include = queryParams.include.join(','); - return queryParams; - }, - - handleResponse: (_, response) => ({ - status: response.status, - data: response.data, - }), -}; - -export default endpoint; diff --git a/src/core/endpoints/objects/channel/set.ts b/src/core/endpoints/objects/channel/set.ts new file mode 100644 index 000000000..80cace4ed --- /dev/null +++ b/src/core/endpoints/objects/channel/set.ts @@ -0,0 +1,95 @@ +/** + * Set Channel Metadata REST API module. + */ + +import { createValidationError, PubNubError } from '../../../../models/PubNubError'; +import { TransportResponse } from '../../../types/transport-response'; +import { TransportMethod } from '../../../types/transport-request'; +import { AbstractRequest } from '../../../components/request'; +import RequestOperation from '../../../constants/operations'; +import * as AppContext from '../../../types/api/app-context'; +import { KeySet, Query } from '../../../types/api'; +import { encodeString } from '../../../utils'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Whether `Channel` custom field should be included by default or not. + */ +const INCLUDE_CUSTOM_FIELDS = true; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = AppContext.SetChannelMetadataParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; +// endregion + +/** + * Set Channel Metadata request. + */ +export class SetChannelMetadataRequest< + Response extends AppContext.SetChannelMetadataResponse, + Custom extends AppContext.CustomData = AppContext.CustomData, +> extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super({ method: TransportMethod.PATCH }); + + // Apply default request parameters. + parameters.include ??= {}; + parameters.include.customFields ??= INCLUDE_CUSTOM_FIELDS; + } + + operation(): RequestOperation { + return RequestOperation.PNSetChannelMetadataOperation; + } + + validate(): string | undefined { + if (!this.parameters.channel) return 'Channel cannot be empty'; + if (!this.parameters.data) return 'Data cannot be empty'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return serviceResponse; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channel, + } = this.parameters; + + return `/v2/objects/${subscribeKey}/channels/${encodeString(channel)}`; + } + + protected get queryParameters(): Query { + return { + include: ['status', 'type', ...(this.parameters.include!.customFields ? ['custom'] : [])].join(','), + }; + } + + protected get body(): ArrayBuffer | string | undefined { + return JSON.stringify(this.parameters.data); + } +} diff --git a/src/core/endpoints/objects/member/get.js b/src/core/endpoints/objects/member/get.js deleted file mode 100644 index 5ce830599..000000000 --- a/src/core/endpoints/objects/member/get.js +++ /dev/null @@ -1,93 +0,0 @@ -/** */ - -import operationConstants from '../../../constants/operations'; - -import utils from '../../../utils'; - -const endpoint = { - getOperation: () => operationConstants.PNGetMembersOperation, - - validateParams: (_, params) => { - if (!params?.channel) { - return 'channel cannot be empty'; - } - }, - - getURL: ({ config }, params) => - `/v2/objects/${config.subscribeKey}/channels/${utils.encodeString(params.channel)}/uuids`, - - getRequestTimeout: ({ config }) => config.getTransactionTimeout(), - - isAuthSupported: () => true, - - prepareParams: (_modules, params) => { - const queryParams = {}; - queryParams.include = []; - - if (params?.include) { - if (params.include?.statusField) { - queryParams.include.push('status'); - } - - if (params.include?.customFields) { - queryParams.include.push('custom'); - } - - if (params.include?.UUIDFields) { - queryParams.include.push('uuid'); - } - - if (params.include?.customUUIDFields) { - queryParams.include.push('uuid.custom'); - } - - if (params.include?.UUIDStatusField) { - queryParams.include.push('uuid.status'); - } - - if (params.include?.UUIDTypeField) { - queryParams.include.push('uuid.type'); - } - } - queryParams.include = queryParams.include.join(','); - - if (params?.include?.totalCount) { - queryParams.count = params.include?.totalCount; - } - - if (params?.page?.next) { - queryParams.start = params.page?.next; - } - - if (params?.page?.prev) { - queryParams.end = params.page?.prev; - } - - if (params?.filter) { - queryParams.filter = params.filter; - } - - queryParams.limit = params?.limit ?? 100; - - if (params?.sort) { - queryParams.sort = Object.entries(params.sort ?? {}).map(([key, value]) => { - if (value === 'asc' || value === 'desc') { - return `${key}:${value}`; - } - return key; - }); - } - - return queryParams; - }, - - handleResponse: (_, response) => ({ - status: response.status, - data: response.data, - totalCount: response.totalCount, - prev: response.prev, - next: response.next, - }), -}; - -export default endpoint; diff --git a/src/core/endpoints/objects/member/get.ts b/src/core/endpoints/objects/member/get.ts new file mode 100644 index 000000000..baf2d0cf1 --- /dev/null +++ b/src/core/endpoints/objects/member/get.ts @@ -0,0 +1,151 @@ +/** + * Get Channel Members REST API module. + */ + +import { createValidationError, PubNubError } from '../../../../models/PubNubError'; +import { TransportResponse } from '../../../types/transport-response'; +import { AbstractRequest } from '../../../components/request'; +import RequestOperation from '../../../constants/operations'; +import * as AppContext from '../../../types/api/app-context'; +import { KeySet, Query } from '../../../types/api'; +import { encodeString } from '../../../utils'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Whether `Member` custom field should be included in response or not. + */ +const INCLUDE_CUSTOM_FIELDS = false; + +/** + * Whether member's status field should be included in response or not. + */ +const INCLUDE_STATUS = false; + +/** + * Whether total number of members should be included in response or not. + */ +const INCLUDE_TOTAL_COUNT = false; + +/** + * Whether `UUID` fields should be included in response or not. + */ +const INCLUDE_UUID_FIELDS = false; + +/** + * Whether `UUID` status field should be included in response or not. + */ +const INCLUDE_UUID_STATUS_FIELD = false; + +/** + * Whether `UUID` type field should be included in response or not. + */ +const INCLUDE_UUID_TYPE_FIELD = false; + +/** + * Whether `UUID` custom field should be included in response or not. + */ +const INCLUDE_UUID_CUSTOM_FIELDS = false; + +/** + * Number of objects to return in response. + */ +const LIMIT = 100; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = AppContext.GetMembersParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; +// endregion + +/** + * Get Channel Members request. + */ +export class GetChannelMembersRequest< + Response extends AppContext.GetMembersResponse, + MembersCustom extends AppContext.CustomData = AppContext.CustomData, + UUIDCustom extends AppContext.CustomData = AppContext.CustomData, +> extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + + // Apply default request parameters. + parameters.include ??= {}; + parameters.include.customFields ??= INCLUDE_CUSTOM_FIELDS; + parameters.include.totalCount ??= INCLUDE_TOTAL_COUNT; + parameters.include.statusField ??= INCLUDE_STATUS; + parameters.include.UUIDFields ??= INCLUDE_UUID_FIELDS; + parameters.include.customUUIDFields ??= INCLUDE_UUID_CUSTOM_FIELDS; + parameters.include.UUIDStatusField ??= INCLUDE_UUID_STATUS_FIELD; + parameters.include.UUIDTypeField ??= INCLUDE_UUID_TYPE_FIELD; + parameters.limit ??= LIMIT; + } + + operation(): RequestOperation { + return RequestOperation.PNSetMembersOperation; + } + + validate(): string | undefined { + if (!this.parameters.channel) return 'Channel cannot be empty'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return serviceResponse; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channel, + } = this.parameters; + + return `/v2/objects/${subscribeKey}/channels/${encodeString(channel)}/uuids`; + } + + protected get queryParameters(): Query { + const { include, page, filter, sort, limit } = this.parameters; + const sorting = Object.entries(sort ?? {}).map(([option, order]) => + order !== null ? `${option}:${order}` : option, + ); + const includeFlags: string[] = []; + + if (include!.statusField) includeFlags.push('status'); + if (include!.customFields) includeFlags.push('custom'); + if (include!.UUIDFields) includeFlags.push('uuid'); + if (include!.UUIDStatusField) includeFlags.push('uuid.status'); + if (include!.UUIDTypeField) includeFlags.push('uuid.type'); + if (include!.customUUIDFields) includeFlags.push('uuid.custom'); + + return { + count: `${include!.totalCount!}`, + ...(includeFlags.length > 0 ? { include: includeFlags.join(',') } : {}), + ...(filter ? { filter } : {}), + ...(page?.next ? { start: page.next } : {}), + ...(page?.prev ? { end: page.prev } : {}), + ...(limit ? { limit } : {}), + ...(sorting.length ? { sort: sorting } : {}), + }; + } +} diff --git a/src/core/endpoints/objects/member/set.js b/src/core/endpoints/objects/member/set.js deleted file mode 100644 index e80f3163e..000000000 --- a/src/core/endpoints/objects/member/set.js +++ /dev/null @@ -1,107 +0,0 @@ -import operationConstants from '../../../constants/operations'; - -import utils from '../../../utils'; - -const endpoint = { - getOperation: () => operationConstants.PNSetMembersOperation, - - validateParams: (_, params) => { - if (!params?.channel) { - return 'Channel cannot be empty'; - } - - if (!params?.uuids || params?.uuids.length === 0) { - return 'UUIDs cannot be empty'; - } - }, - - usePatch: () => true, - - patchURL: ({ config }, params) => - `/v2/objects/${config.subscribeKey}/channels/${utils.encodeString(params.channel)}/uuids`, - - patchPayload: (_, params) => ({ - set: [], - delete: [], - [params.type]: params.uuids.map((uuid) => { - if (typeof uuid === 'string') { - return { - uuid: { - id: uuid, - }, - }; - } - return { - uuid: { id: uuid.id }, - custom: uuid.custom, - status: uuid.status, - }; - }), - }), - - getRequestTimeout: ({ config }) => config.getTransactionTimeout(), - - isAuthSupported: () => true, - - prepareParams: (_modules, params) => { - const queryParams = {}; - queryParams.include = ['uuid.status', 'uuid.type', 'type']; - - if (params?.include) { - if (params.include?.customFields) { - queryParams.include.push('custom'); - } - - if (params.include?.customUUIDFields) { - queryParams.include.push('uuid.custom'); - } - - if (params.include?.UUIDFields) { - queryParams.include.push('uuid'); - } - } - - queryParams.include = queryParams.include.join(','); - - if (params?.include?.totalCount) { - queryParams.count = true; - } - - if (params?.page?.next) { - queryParams.start = params.page?.next; - } - - if (params?.page?.prev) { - queryParams.end = params.page?.prev; - } - - if (params?.filter) { - queryParams.filter = params.filter; - } - - if (params.limit != null) { - queryParams.limit = params.limit; - } - - if (params?.sort) { - queryParams.sort = Object.entries(params.sort ?? {}).map(([key, value]) => { - if (value === 'asc' || value === 'desc') { - return `${key}:${value}`; - } - return key; - }); - } - - return queryParams; - }, - - handleResponse: (_, response) => ({ - status: response.status, - data: response.data, - totalCount: response.totalCount, - prev: response.prev, - next: response.next, - }), -}; - -export default endpoint; diff --git a/src/core/endpoints/objects/member/set.ts b/src/core/endpoints/objects/member/set.ts new file mode 100644 index 000000000..2095edecb --- /dev/null +++ b/src/core/endpoints/objects/member/set.ts @@ -0,0 +1,152 @@ +/** + * Set Channel Members REST API module. + */ + +import { createValidationError, PubNubError } from '../../../../models/PubNubError'; +import { TransportResponse } from '../../../types/transport-response'; +import { TransportMethod } from '../../../types/transport-request'; +import { AbstractRequest } from '../../../components/request'; +import RequestOperation from '../../../constants/operations'; +import * as AppContext from '../../../types/api/app-context'; +import { KeySet, Query } from '../../../types/api'; +import { encodeString } from '../../../utils'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Whether `Member` custom field should be included in response or not. + */ +const INCLUDE_CUSTOM_FIELDS = false; + +/** + * Whether total number of members should be included in response or not. + */ +const INCLUDE_TOTAL_COUNT = false; + +/** + * Whether `UUID` fields should be included in response or not. + */ +const INCLUDE_UUID_FIELDS = false; + +/** + * Whether `UUID` custom field should be included in response or not. + */ +const INCLUDE_UUID_CUSTOM_FIELDS = false; + +/** + * Number of objects to return in response. + */ +const LIMIT = 100; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = AppContext.SetChannelMembersParameters & { + /** + * Type of change in channel members list. + */ + type: 'set' | 'delete'; + + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; +// endregion + +/** + * Set Channel Members request. + */ +export class SetChannelMembersRequest< + Response extends AppContext.SetChannelMembersParameters, + Custom extends AppContext.CustomData = AppContext.CustomData, +> extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super({ method: TransportMethod.PATCH }); + + // Apply default request parameters. + parameters.include ??= {}; + parameters.include.customFields ??= INCLUDE_CUSTOM_FIELDS; + parameters.include.totalCount ??= INCLUDE_TOTAL_COUNT; + parameters.include.UUIDFields ??= INCLUDE_UUID_FIELDS; + parameters.include.customUUIDFields ??= INCLUDE_UUID_CUSTOM_FIELDS; + parameters.limit ??= LIMIT; + } + + operation(): RequestOperation { + return RequestOperation.PNSetMembersOperation; + } + + validate(): string | undefined { + const { channel, uuids } = this.parameters; + + if (!channel) return 'Channel cannot be empty'; + if (!uuids || uuids.length === 0) return 'UUIDs cannot be empty'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return serviceResponse; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channel, + } = this.parameters; + + return `/v2/objects/${subscribeKey}/channels/${encodeString(channel)}/uuids`; + } + + protected get queryParameters(): Query { + const { include, page, filter, sort, limit } = this.parameters; + const sorting = Object.entries(sort ?? {}).map(([option, order]) => + order !== null ? `${option}:${order}` : option, + ); + const includeFlags: string[] = ['uuid.status', 'uuid.type', 'type']; + + if (include!.customFields) includeFlags.push('custom'); + if (include!.UUIDFields) includeFlags.push('uuid'); + if (include!.customUUIDFields) includeFlags.push('uuid.custom'); + + return { + count: `${include!.totalCount!}`, + ...(includeFlags.length > 0 ? { include: includeFlags.join(',') } : {}), + ...(filter ? { filter } : {}), + ...(page?.next ? { start: page.next } : {}), + ...(page?.prev ? { end: page.prev } : {}), + ...(limit ? { limit } : {}), + ...(sorting.length ? { sort: sorting } : {}), + }; + } + + protected get body(): string { + const { uuids, type } = this.parameters; + + return JSON.stringify({ + [`${type}`]: uuids.map((uuid) => { + if (typeof uuid === 'string') { + return { uuid: { id: uuid } }; + } else { + return { uuid: { id: uuid.id }, status: uuid.status, custom: uuid.custom }; + } + }), + }); + } +} diff --git a/src/core/endpoints/objects/membership/get.js b/src/core/endpoints/objects/membership/get.js deleted file mode 100644 index 3f3dc94dd..000000000 --- a/src/core/endpoints/objects/membership/get.js +++ /dev/null @@ -1,89 +0,0 @@ -import operationConstants from '../../../constants/operations'; - -import utils from '../../../utils'; - -const endpoint = { - getOperation: () => operationConstants.PNGetMembershipsOperation, - - validateParams: () => { - // No required parameters. - }, - - getURL: ({ config }, params) => - `/v2/objects/${config.subscribeKey}/uuids/${utils.encodeString(params?.uuid ?? config.getUUID())}/channels`, - - getRequestTimeout: ({ config }) => config.getTransactionTimeout(), - - isAuthSupported: () => true, - - prepareParams: (_modules, params) => { - const queryParams = {}; - queryParams.include = []; - - if (params?.include) { - if (params.include?.statusField) { - queryParams.include.push('status'); - } - - if (params.include?.customFields) { - queryParams.include.push('custom'); - } - - if (params.include?.channelFields) { - queryParams.include.push('channel'); - } - - if (params.include?.customChannelFields) { - queryParams.include.push('channel.custom'); - } - - if (params.include?.channelStatusField) { - queryParams.include.push('channel.status'); - } - - if (params.include?.channelTypeField) { - queryParams.include.push('channel.type'); - } - } - queryParams.include = queryParams.include.join(','); - - if (params?.include?.totalCount) { - queryParams.count = params.include?.totalCount; - } - - if (params?.page?.next) { - queryParams.start = params.page?.next; - } - - if (params?.page?.prev) { - queryParams.end = params.page?.prev; - } - - if (params?.filter) { - queryParams.filter = params.filter; - } - - queryParams.limit = params?.limit ?? 100; - - if (params?.sort) { - queryParams.sort = Object.entries(params.sort ?? {}).map(([key, value]) => { - if (value === 'asc' || value === 'desc') { - return `${key}:${value}`; - } - return key; - }); - } - - return queryParams; - }, - - handleResponse: (_, response) => ({ - status: response.status, - data: response.data, - totalCount: response.totalCount, - prev: response.prev, - next: response.next, - }), -}; - -export default endpoint; diff --git a/src/core/endpoints/objects/membership/get.ts b/src/core/endpoints/objects/membership/get.ts new file mode 100644 index 000000000..4d5d2b8a1 --- /dev/null +++ b/src/core/endpoints/objects/membership/get.ts @@ -0,0 +1,154 @@ +/** + * Get UUID Memberships REST API module. + */ + +import { createValidationError, PubNubError } from '../../../../models/PubNubError'; +import { TransportResponse } from '../../../types/transport-response'; +import { AbstractRequest } from '../../../components/request'; +import RequestOperation from '../../../constants/operations'; +import * as AppContext from '../../../types/api/app-context'; +import { KeySet, Query } from '../../../types/api'; +import { encodeString } from '../../../utils'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Whether `Membership` custom field should be included in response or not. + */ +const INCLUDE_CUSTOM_FIELDS = false; + +/** + * Whether membership's status field should be included in response or not. + */ +const INCLUDE_STATUS = false; + +/** + * Whether total number of memberships should be included in response or not. + */ +const INCLUDE_TOTAL_COUNT = false; + +/** + * Whether `Channel` fields should be included in response or not. + */ +const INCLUDE_CHANNEL_FIELDS = false; + +/** + * Whether `Channel` status field should be included in response or not. + */ +const INCLUDE_CHANNEL_STATUS_FIELD = false; + +/** + * Whether `Channel` type field should be included in response or not. + */ +const INCLUDE_CHANNEL_TYPE_FIELD = false; + +/** + * Whether `Channel` custom field should be included in response or not. + */ +const INCLUDE_CHANNEL_CUSTOM_FIELDS = false; + +/** + * Number of objects to return in response. + */ +const LIMIT = 100; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = AppContext.GetMembershipsParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; +// endregion + +/** + * Get UUID Memberships request. + */ +export class GetUUIDMembershipsRequest< + Response extends AppContext.GetMembershipsResponse, + MembersCustom extends AppContext.CustomData = AppContext.CustomData, + UUIDCustom extends AppContext.CustomData = AppContext.CustomData, +> extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + + // Apply default request parameters. + parameters.include ??= {}; + parameters.include.customFields ??= INCLUDE_CUSTOM_FIELDS; + parameters.include.totalCount ??= INCLUDE_TOTAL_COUNT; + parameters.include.statusField ??= INCLUDE_STATUS; + parameters.include.channelFields ??= INCLUDE_CHANNEL_FIELDS; + parameters.include.customChannelFields ??= INCLUDE_CHANNEL_CUSTOM_FIELDS; + parameters.include.channelStatusField ??= INCLUDE_CHANNEL_STATUS_FIELD; + parameters.include.channelTypeField ??= INCLUDE_CHANNEL_TYPE_FIELD; + parameters.limit ??= LIMIT; + + // Remap for backward compatibility. + if (this.parameters.userId) this.parameters.uuid = this.parameters.userId; + } + + operation(): RequestOperation { + return RequestOperation.PNGetMembershipsOperation; + } + + validate(): string | undefined { + if (!this.parameters.uuid) return "'uuid' cannot be empty"; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return serviceResponse; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + uuid, + } = this.parameters; + + return `/v2/objects/${subscribeKey}/uuids/${encodeString(uuid!)}/channels`; + } + + protected get queryParameters(): Query { + const { include, page, filter, sort, limit } = this.parameters; + const sorting = Object.entries(sort ?? {}).map(([option, order]) => + order !== null ? `${option}:${order}` : option, + ); + const includeFlags: string[] = []; + + if (include!.statusField) includeFlags.push('status'); + if (include!.customFields) includeFlags.push('custom'); + if (include!.channelFields) includeFlags.push('channel'); + if (include!.channelStatusField) includeFlags.push('channel.status'); + if (include!.channelTypeField) includeFlags.push('channel.type'); + if (include!.customChannelFields) includeFlags.push('channel.custom'); + + return { + count: `${include!.totalCount!}`, + ...(includeFlags.length > 0 ? { include: includeFlags.join(',') } : {}), + ...(filter ? { filter } : {}), + ...(page?.next ? { start: page.next } : {}), + ...(page?.prev ? { end: page.prev } : {}), + ...(limit ? { limit } : {}), + ...(sorting.length ? { sort: sorting } : {}), + }; + } +} diff --git a/src/core/endpoints/objects/membership/set.js b/src/core/endpoints/objects/membership/set.js deleted file mode 100644 index f801d7c2a..000000000 --- a/src/core/endpoints/objects/membership/set.js +++ /dev/null @@ -1,105 +0,0 @@ -/** */ - -import operationConstants from '../../../constants/operations'; - -import utils from '../../../utils'; - -const endpoint = { - getOperation: () => operationConstants.PNSetMembershipsOperation, - - validateParams: (_, params) => { - if (!params?.channels || params?.channels.length === 0) { - return 'Channels cannot be empty'; - } - }, - - usePatch: () => true, - - patchURL: ({ config }, params) => - `/v2/objects/${config.subscribeKey}/uuids/${utils.encodeString(params.uuid ?? config.getUUID())}/channels`, - - patchPayload: (_, params) => ({ - set: [], - delete: [], - [params.type]: params.channels.map((channel) => { - if (typeof channel === 'string') { - return { - channel: { - id: channel, - }, - }; - } - return { - channel: { id: channel.id }, - custom: channel.custom, - status: channel.status, - }; - }), - }), - - getRequestTimeout: ({ config }) => config.getTransactionTimeout(), - - isAuthSupported: () => true, - - prepareParams: (_modules, params) => { - const queryParams = {}; - queryParams.include = ['channel.status', 'channel.type', 'status']; - - if (params?.include) { - if (params.include?.customFields) { - queryParams.include.push('custom'); - } - - if (params.include?.customChannelFields) { - queryParams.include.push('channel.custom'); - } - - if (params.include?.channelFields) { - queryParams.include.push('channel'); - } - } - - queryParams.include = queryParams.include.join(','); - - if (params?.include?.totalCount) { - queryParams.count = true; - } - - if (params?.page?.next) { - queryParams.start = params.page?.next; - } - - if (params?.page?.prev) { - queryParams.end = params.page?.prev; - } - - if (params?.filter) { - queryParams.filter = params.filter; - } - - if (params.limit != null) { - queryParams.limit = params.limit; - } - - if (params?.sort) { - queryParams.sort = Object.entries(params.sort ?? {}).map(([key, value]) => { - if (value === 'asc' || value === 'desc') { - return `${key}:${value}`; - } - return key; - }); - } - - return queryParams; - }, - - handleResponse: (_, response) => ({ - status: response.status, - data: response.data, - totalCount: response.totalCount, - prev: response.prev, - next: response.next, - }), -}; - -export default endpoint; diff --git a/src/core/endpoints/objects/membership/set.ts b/src/core/endpoints/objects/membership/set.ts new file mode 100644 index 000000000..ddca5f6f2 --- /dev/null +++ b/src/core/endpoints/objects/membership/set.ts @@ -0,0 +1,156 @@ +/** + * Set UUID Memberships REST API module. + */ + +import { createValidationError, PubNubError } from '../../../../models/PubNubError'; +import { TransportResponse } from '../../../types/transport-response'; +import { TransportMethod } from '../../../types/transport-request'; +import { AbstractRequest } from '../../../components/request'; +import RequestOperation from '../../../constants/operations'; +import * as AppContext from '../../../types/api/app-context'; +import { KeySet, Query } from '../../../types/api'; +import { encodeString } from '../../../utils'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Whether `Membership` custom field should be included in response or not. + */ +const INCLUDE_CUSTOM_FIELDS = false; + +/** + * Whether total number of memberships should be included in response or not. + */ +const INCLUDE_TOTAL_COUNT = false; + +/** + * Whether `Channel` fields should be included in response or not. + */ +const INCLUDE_CHANNEL_FIELDS = false; + +/** + * Whether `Channel` custom field should be included in response or not. + */ +const INCLUDE_CHANNEL_CUSTOM_FIELDS = false; + +/** + * Number of objects to return in response. + */ +const LIMIT = 100; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = AppContext.SetMembershipsParameters & { + /** + * Type of change in UUID memberships list. + */ + type: 'set' | 'delete'; + + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; +// endregion + +/** + * Set UUID Memberships request. + */ +export class SetUUIDMembershipsRequest< + Response extends AppContext.SetMembershipsResponse, + MembersCustom extends AppContext.CustomData = AppContext.CustomData, + UUIDCustom extends AppContext.CustomData = AppContext.CustomData, +> extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super({ method: TransportMethod.PATCH }); + + // Apply default request parameters. + parameters.include ??= {}; + parameters.include.customFields ??= INCLUDE_CUSTOM_FIELDS; + parameters.include.totalCount ??= INCLUDE_TOTAL_COUNT; + parameters.include.channelFields ??= INCLUDE_CHANNEL_FIELDS; + parameters.include.customChannelFields ??= INCLUDE_CHANNEL_CUSTOM_FIELDS; + parameters.limit ??= LIMIT; + + // Remap for backward compatibility. + if (this.parameters.userId) this.parameters.uuid = this.parameters.userId; + } + + operation(): RequestOperation { + return RequestOperation.PNSetMembershipsOperation; + } + + validate(): string | undefined { + const { uuid, channels } = this.parameters; + + if (!uuid) return "'uuid' cannot be empty"; + if (!channels || channels.length === 0) return 'Channels cannot be empty'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return serviceResponse; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + uuid, + } = this.parameters; + + return `/v2/objects/${subscribeKey}/uuids/${encodeString(uuid!)}/channels`; + } + + protected get queryParameters(): Query { + const { include, page, filter, sort, limit } = this.parameters; + const sorting = Object.entries(sort ?? {}).map(([option, order]) => + order !== null ? `${option}:${order}` : option, + ); + const includeFlags: string[] = ['channel.status', 'channel.type', 'status']; + + if (include!.customFields) includeFlags.push('custom'); + if (include!.channelFields) includeFlags.push('channel'); + if (include!.customChannelFields) includeFlags.push('channel.custom'); + + return { + count: `${include!.totalCount!}`, + ...(includeFlags.length > 0 ? { include: includeFlags.join(',') } : {}), + ...(filter ? { filter } : {}), + ...(page?.next ? { start: page.next } : {}), + ...(page?.prev ? { end: page.prev } : {}), + ...(limit ? { limit } : {}), + ...(sorting.length ? { sort: sorting } : {}), + }; + } + + protected get body(): string { + const { channels, type } = this.parameters; + + return JSON.stringify({ + [`${type}`]: channels.map((channel) => { + if (typeof channel === 'string') { + return { channel: { id: channel } }; + } else { + return { channel: { id: channel.id }, status: channel.status, custom: channel.custom }; + } + }), + }); + } +} diff --git a/src/core/endpoints/objects/uuid/get.js b/src/core/endpoints/objects/uuid/get.js deleted file mode 100644 index 1721489d8..000000000 --- a/src/core/endpoints/objects/uuid/get.js +++ /dev/null @@ -1,44 +0,0 @@ -/** */ - -import operationConstants from '../../../constants/operations'; - -import utils from '../../../utils'; - -const endpoint = { - getOperation: () => operationConstants.PNGetUUIDMetadataOperation, - - validateParams: () => { - // No required parameters. - }, - - getURL: ({ config }, params) => - `/v2/objects/${config.subscribeKey}/uuids/${utils.encodeString(params?.uuid ?? config.getUUID())}`, - - getRequestTimeout: ({ config }) => config.getTransactionTimeout(), - - isAuthSupported: () => true, - - prepareParams: ({ config }, params) => { - const queryParams = {}; - - queryParams.uuid = params?.uuid ?? config.getUUID(); - queryParams.include = ['status', 'type', 'custom']; - - if (params?.include) { - if (params.include?.customFields === false) { - queryParams.include.pop(); - } - } - - queryParams.include = queryParams.include.join(','); - - return queryParams; - }, - - handleResponse: (_, response) => ({ - status: response.status, - data: response.data, - }), -}; - -export default endpoint; diff --git a/src/core/endpoints/objects/uuid/get.ts b/src/core/endpoints/objects/uuid/get.ts new file mode 100644 index 000000000..ca44f8aa3 --- /dev/null +++ b/src/core/endpoints/objects/uuid/get.ts @@ -0,0 +1,95 @@ +/** + * Get UUID Metadata REST API module. + */ + +import { createValidationError, PubNubError } from '../../../../models/PubNubError'; +import { TransportResponse } from '../../../types/transport-response'; +import { AbstractRequest } from '../../../components/request'; +import RequestOperation from '../../../constants/operations'; +import * as AppContext from '../../../types/api/app-context'; +import { KeySet, Query } from '../../../types/api'; +import { encodeString } from '../../../utils'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Whether UUID custom field should be included by default or not. + */ +const INCLUDE_CUSTOM_FIELDS = true; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = AppContext.GetUUIDMetadataParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; +// endregion + +/** + * Get UUID Metadata request. + */ +export class GetUUIDMetadataRequest< + Response extends AppContext.GetUUIDMetadataResponse, + Custom extends AppContext.CustomData = AppContext.CustomData, +> extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + + // Apply default request parameters. + parameters.include ??= {}; + parameters.include.customFields ??= INCLUDE_CUSTOM_FIELDS; + + // Remap for backward compatibility. + if (this.parameters.userId) this.parameters.uuid = this.parameters.userId; + } + + operation(): RequestOperation { + return RequestOperation.PNGetUUIDMetadataOperation; + } + + validate(): string | undefined { + if (!this.parameters.uuid) return "'uuid' cannot be empty"; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return serviceResponse; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + uuid, + } = this.parameters; + + return `/v2/objects/${subscribeKey}/uuids/${encodeString(uuid!)}`; + } + + protected get queryParameters(): Query { + const { uuid, include } = this.parameters; + + return { + uuid: uuid!, + include: ['status', 'type', ...(this.parameters.include!.customFields ? ['custom'] : [])].join(','), + }; + } +} diff --git a/src/core/endpoints/objects/uuid/get_all.js b/src/core/endpoints/objects/uuid/get_all.js deleted file mode 100644 index 1c3ef9d86..000000000 --- a/src/core/endpoints/objects/uuid/get_all.js +++ /dev/null @@ -1,67 +0,0 @@ -import operationConstants from '../../../constants/operations'; - -const endpoint = { - getOperation: () => operationConstants.PNGetAllUUIDMetadataOperation, - - validateParams: () => { - // No required parameters. - }, - - getURL: ({ config }) => `/v2/objects/${config.subscribeKey}/uuids`, - - getRequestTimeout: ({ config }) => config.getTransactionTimeout(), - - isAuthSupported: () => true, - - prepareParams: (_modules, params) => { - const queryParams = {}; - queryParams.include = ['status', 'type']; - - if (params?.include) { - if (params.include?.customFields) { - queryParams.include.push('custom'); - } - } - - queryParams.include = queryParams.include.join(','); - - if (params?.include?.totalCount) { - queryParams.count = params.include?.totalCount; - } - - if (params?.page?.next) { - queryParams.start = params.page?.next; - } - - if (params?.page?.prev) { - queryParams.end = params.page?.prev; - } - - if (params?.filter) { - queryParams.filter = params.filter; - } - - queryParams.limit = params?.limit ?? 100; - - if (params?.sort) { - queryParams.sort = Object.entries(params.sort ?? {}).map(([key, value]) => { - if (value === 'asc' || value === 'desc') { - return `${key}:${value}`; - } - return key; - }); - } - - return queryParams; - }, - - handleResponse: (_, response) => ({ - status: response.status, - data: response.data, - totalCount: response.totalCount, - next: response.next, - prev: response.prev, - }), -}; - -export default endpoint; diff --git a/src/core/endpoints/objects/uuid/get_all.ts b/src/core/endpoints/objects/uuid/get_all.ts new file mode 100644 index 000000000..009ee4fff --- /dev/null +++ b/src/core/endpoints/objects/uuid/get_all.ts @@ -0,0 +1,99 @@ +/** + * Get All UUID Metadata REST API module. + */ + +import { createValidationError, PubNubError } from '../../../../models/PubNubError'; +import { TransportResponse } from '../../../types/transport-response'; +import { AbstractRequest } from '../../../components/request'; +import RequestOperation from '../../../constants/operations'; +import * as AppContext from '../../../types/api/app-context'; +import { KeySet, Query } from '../../../types/api'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Whether `Channel` custom field should be included by default or not. + */ +const INCLUDE_CUSTOM_FIELDS = false; + +/** + * Whether to fetch total count or not. + */ +const INCLUDE_TOTAL_COUNT = false; + +/** + * Number of objects to return in response. + */ +const LIMIT = 100; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = AppContext.GetAllMetadataParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; +// endregion + +export class GetAllUUIDMetadataRequest< + Response extends AppContext.GetAllUUIDMetadataResponse, + Custom extends AppContext.CustomData = AppContext.CustomData, +> extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + + // Apply default request parameters. + parameters.include ??= {}; + parameters.include.customFields ??= INCLUDE_CUSTOM_FIELDS; + parameters.include.totalCount ??= INCLUDE_TOTAL_COUNT; + parameters.limit ??= LIMIT; + } + + operation(): RequestOperation { + return RequestOperation.PNGetAllUUIDMetadataOperation; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return serviceResponse; + } + + protected get path(): string { + return `/v2/objects/${this.parameters.keySet.subscribeKey}/uuids`; + } + + protected get queryParameters(): Query { + const { include, page, filter, sort, limit } = this.parameters; + const sorting = Object.entries(sort ?? {}).map(([option, order]) => + order !== null ? `${option}:${order}` : option, + ); + + return { + include: ['status', 'type', ...(include!.customFields ? ['custom'] : [])].join(','), + count: `${include!.totalCount!}`, + ...(filter ? { filter } : {}), + ...(page?.next ? { start: page.next } : {}), + ...(page?.prev ? { end: page.prev } : {}), + ...(limit ? { limit } : {}), + ...(sorting.length ? { sort: sorting } : {}), + }; + } +} diff --git a/src/core/endpoints/objects/uuid/remove.js b/src/core/endpoints/objects/uuid/remove.js deleted file mode 100644 index a441c92db..000000000 --- a/src/core/endpoints/objects/uuid/remove.js +++ /dev/null @@ -1,32 +0,0 @@ -/** */ - -import operationConstants from '../../../constants/operations'; - -import utils from '../../../utils'; - -const endpoint = { - getOperation: () => operationConstants.PNRemoveUUIDMetadataOperation, - - validateParams: () => { - // No required parameters. - }, - - getURL: ({ config }, params) => - `/v2/objects/${config.subscribeKey}/uuids/${utils.encodeString(params?.uuid ?? config.getUUID())}`, - useDelete: () => true, - - getRequestTimeout: ({ config }) => config.getTransactionTimeout(), - - isAuthSupported: () => true, - - prepareParams: ({ config }, params) => ({ - uuid: params?.uuid ?? config.getUUID(), - }), - - handleResponse: (_, response) => ({ - status: response.status, - data: response.data, - }), -}; - -export default endpoint; diff --git a/src/core/endpoints/objects/uuid/remove.ts b/src/core/endpoints/objects/uuid/remove.ts new file mode 100644 index 000000000..2442c2b5f --- /dev/null +++ b/src/core/endpoints/objects/uuid/remove.ts @@ -0,0 +1,71 @@ +/** + * Remove UUID Metadata REST API module. + */ + +import { createValidationError, PubNubError } from '../../../../models/PubNubError'; +import { TransportResponse } from '../../../types/transport-response'; +import { TransportMethod } from '../../../types/transport-request'; +import { AbstractRequest } from '../../../components/request'; +import RequestOperation from '../../../constants/operations'; +import * as AppContext from '../../../types/api/app-context'; +import { KeySet } from '../../../types/api'; +import { encodeString } from '../../../utils'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = AppContext.RemoveUUIDMetadataParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; +// endregion + +/** + * Remove UUID Metadata request. + */ +export class RemoveUUIDMetadataRequest< + Response extends AppContext.RemoveUUIDMetadataResponse, +> extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super({ method: TransportMethod.DELETE }); + + // Remap for backward compatibility. + if (this.parameters.userId) this.parameters.uuid = this.parameters.userId; + } + + operation(): RequestOperation { + return RequestOperation.PNRemoveUUIDMetadataOperation; + } + + validate(): string | undefined { + if (!this.parameters.uuid) return "'uuid' cannot be empty"; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return serviceResponse; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + uuid, + } = this.parameters; + + return `/v2/objects/${subscribeKey}/uuids/${encodeString(uuid!)}`; + } +} diff --git a/src/core/endpoints/objects/uuid/set.js b/src/core/endpoints/objects/uuid/set.js deleted file mode 100644 index ca111373c..000000000 --- a/src/core/endpoints/objects/uuid/set.js +++ /dev/null @@ -1,50 +0,0 @@ -/** */ - -import operationConstants from '../../../constants/operations'; - -import utils from '../../../utils'; - -const endpoint = { - getOperation: () => operationConstants.PNSetUUIDMetadataOperation, - - validateParams: (_, params) => { - if (!params?.data) { - return 'Data cannot be empty'; - } - }, - - usePatch: () => true, - - patchURL: ({ config }, params) => - `/v2/objects/${config.subscribeKey}/uuids/${utils.encodeString(params.uuid ?? config.getUUID())}`, - - patchPayload: (_, params) => params.data, - - getRequestTimeout: ({ config }) => config.getTransactionTimeout(), - - isAuthSupported: () => true, - - prepareParams: ({ config }, params) => { - const queryParams = {}; - - queryParams.uuid = params?.uuid ?? config.getUUID(); - queryParams.include = ['status', 'type', 'custom']; - - if (params?.include) { - if (params.include?.customFields === false) { - queryParams.include.pop(); - } - } - - queryParams.include = queryParams.include.join(','); - - return queryParams; - }, - - handleResponse: (_, response) => ({ - status: response.status, - data: response.data, - }), -}; - -export default endpoint; diff --git a/src/core/endpoints/objects/uuid/set.ts b/src/core/endpoints/objects/uuid/set.ts new file mode 100644 index 000000000..2c6cf5098 --- /dev/null +++ b/src/core/endpoints/objects/uuid/set.ts @@ -0,0 +1,98 @@ +/** + * Set UUID Metadata REST API module. + */ + +import { createValidationError, PubNubError } from '../../../../models/PubNubError'; +import { TransportResponse } from '../../../types/transport-response'; +import { TransportMethod } from '../../../types/transport-request'; +import { AbstractRequest } from '../../../components/request'; +import RequestOperation from '../../../constants/operations'; +import * as AppContext from '../../../types/api/app-context'; +import { KeySet, Query } from '../../../types/api'; +import { encodeString } from '../../../utils'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Whether `Channel` custom field should be included by default or not. + */ +const INCLUDE_CUSTOM_FIELDS = true; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = AppContext.SetUUIDMetadataParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; +// endregion + +/** + * Set UUID Metadata request. + */ +export class SetUUIDMetadataRequest< + Response extends AppContext.SetUUIDMetadataResponse, + Custom extends AppContext.CustomData = AppContext.CustomData, +> extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super({ method: TransportMethod.PATCH }); + + // Apply default request parameters. + parameters.include ??= {}; + parameters.include.customFields ??= INCLUDE_CUSTOM_FIELDS; + + // Remap for backward compatibility. + if (this.parameters.userId) this.parameters.uuid = this.parameters.userId; + } + + operation(): RequestOperation { + return RequestOperation.PNSetUUIDMetadataOperation; + } + + validate(): string | undefined { + if (!this.parameters.uuid) return "'uuid' cannot be empty"; + if (!this.parameters.data) return 'Data cannot be empty'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return serviceResponse; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + uuid, + } = this.parameters; + + return `/v2/objects/${subscribeKey}/uuids/${encodeString(uuid!)}`; + } + + protected get queryParameters(): Query { + return { + include: ['status', 'type', ...(this.parameters.include!.customFields ? ['custom'] : [])].join(','), + }; + } + + protected get body(): ArrayBuffer | string | undefined { + return JSON.stringify(this.parameters.data); + } +} diff --git a/src/core/endpoints/presence/get_state.js b/src/core/endpoints/presence/get_state.js deleted file mode 100644 index c75caa82a..000000000 --- a/src/core/endpoints/presence/get_state.js +++ /dev/null @@ -1,53 +0,0 @@ -/* */ - -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -export function getOperation() { - return operationConstants.PNGetStateOperation; -} - -export function validateParams(modules) { - const { config } = modules; - - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules, incomingParams) { - const { config } = modules; - const { uuid = config.UUID, channels = [] } = incomingParams; - const stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return `/v2/presence/sub-key/${config.subscribeKey}/channel/${utils.encodeString(stringifiedChannels)}/uuid/${uuid}`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams(modules, incomingParams) { - const { channelGroups = [] } = incomingParams; - const params = {}; - - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); - } - - return params; -} - -export function handleResponse(modules, serverResponse, incomingParams) { - const { channels = [], channelGroups = [] } = incomingParams; - let channelsResponse = {}; - - if (channels.length === 1 && channelGroups.length === 0) { - channelsResponse[channels[0]] = serverResponse.payload; - } else { - channelsResponse = serverResponse.payload; - } - - return { channels: channelsResponse }; -} diff --git a/src/core/endpoints/presence/get_state.ts b/src/core/endpoints/presence/get_state.ts new file mode 100644 index 000000000..49bf53eb8 --- /dev/null +++ b/src/core/endpoints/presence/get_state.ts @@ -0,0 +1,122 @@ +/** + * Get Presence State REST API module. + */ + +import { createValidationError, PubNubError } from '../../../models/PubNubError'; +import { TransportResponse } from '../../types/transport-response'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import { KeySet, Payload, Query } from '../../types/api'; +import * as Presence from '../../types/api/presence'; +import { encodeString } from '../../utils'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = Presence.GetPresenceStateParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Get presence state human-readable result. + */ + message: string; + + /** + * Name of the service which provided response. + */ + service: string; + + /** + * Whether response represent service error or not. + */ + uuid: string; + + /** + * Retrieved {@link uuid} per-channel associated presence state. + */ + payload: Record | Payload; +}; +// endregion + +/** + * Get `uuid` presence state request. + */ +export class GetPresenceStateRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + + // Apply defaults. + this.parameters.channels ??= []; + this.parameters.channelGroups ??= []; + } + + operation(): RequestOperation { + return RequestOperation.PNGetStateOperation; + } + + validate(): string | undefined { + const { + keySet: { subscribeKey }, + channels, + channelGroups, + } = this.parameters; + + if (!subscribeKey) return 'Missing Subscribe Key'; + if (channels && channels.length > 0 && channelGroups && channelGroups.length > 0) + return 'Only `channels` or `channelGroups` can be specified at once.'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + const { channels, channelGroups } = this.parameters; + const state: { channels: Record } = { channels: {} }; + + if (channels?.length === 1 && channelGroups?.length === 0) state.channels[channels[0]] = serviceResponse.payload; + else state.channels = serviceResponse.payload as Record; + + return state; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + uuid, + channels, + } = this.parameters; + const stringifiedChannels = channels && channels.length > 0 ? encodeString(channels.join(',')) : ','; + + return `/v2/presence/sub-key/${subscribeKey}/channel/${stringifiedChannels}/uuid/${uuid}`; + } + + protected get queryParameters(): Query { + const { channelGroups } = this.parameters; + if (!channelGroups || channelGroups.length === 0) return {}; + + return { 'channel-group': channelGroups.join(',') }; + } +} diff --git a/src/core/endpoints/presence/heartbeat.js b/src/core/endpoints/presence/heartbeat.js deleted file mode 100644 index b5b0b7627..000000000 --- a/src/core/endpoints/presence/heartbeat.js +++ /dev/null @@ -1,49 +0,0 @@ -/* */ - -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -export function getOperation() { - return operationConstants.PNHeartbeatOperation; -} - -export function validateParams(modules) { - const { config } = modules; - - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules, incomingParams) { - const { config } = modules; - const { channels = [] } = incomingParams; - const stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return `/v2/presence/sub-key/${config.subscribeKey}/channel/${utils.encodeString(stringifiedChannels)}/heartbeat`; -} - -export function isAuthSupported() { - return true; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function prepareParams(modules, incomingParams) { - const { channelGroups = [], state } = incomingParams; - const { config } = modules; - const params = {}; - - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); - } - - if (state) { - params.state = JSON.stringify(state); - } - params.heartbeat = config.getPresenceTimeout(); - return params; -} - -export function handleResponse() { - return {}; -} diff --git a/src/core/endpoints/presence/heartbeat.ts b/src/core/endpoints/presence/heartbeat.ts new file mode 100644 index 000000000..411a37b0d --- /dev/null +++ b/src/core/endpoints/presence/heartbeat.ts @@ -0,0 +1,101 @@ +/** + * Announce heartbeat REST API module. + */ + +import { createValidationError, PubNubError } from '../../../models/PubNubError'; +import { TransportResponse } from '../../types/transport-response'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import * as Presence from '../../types/api/presence'; +import { KeySet, Query } from '../../types/api'; +import { encodeString } from '../../utils'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = Presence.PresenceHeartbeatParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Presence heartbeat announce human-readable result. + */ + message: string; + + /** + * Name of the service which provided response. + */ + service: string; +}; +// endregion + +export class HeartbeatRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + } + + operation(): RequestOperation { + return RequestOperation.PNHeartbeatOperation; + } + + validate(): string | undefined { + const { + keySet: { subscribeKey }, + channels, + channelGroups, + } = this.parameters; + + if (!subscribeKey) return 'Missing Subscribe Key'; + if (channels?.length === 0 && channelGroups?.length === 0) + return 'Please provide a list of channels and/or channel-groups'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return {}; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channels, + } = this.parameters; + const stringifiedChannels = channels && channels.length > 0 ? encodeString(channels.join(',')) : ','; + + return `/v2/presence/sub-key/${subscribeKey}/channel/${stringifiedChannels}/heartbeat`; + } + + protected get queryParameters(): Query { + const { channelGroups, state, heartbeat } = this.parameters; + const query: Record = { heartbeat: `${heartbeat}` }; + + if (channelGroups && channelGroups.length === 0) query['channel-group'] = channelGroups.join(','); + if (state) query.state = JSON.stringify(state); + + return query; + } +} diff --git a/src/core/endpoints/presence/here_now.js b/src/core/endpoints/presence/here_now.js deleted file mode 100644 index 53d707c1e..000000000 --- a/src/core/endpoints/presence/here_now.js +++ /dev/null @@ -1,133 +0,0 @@ -/* */ -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -export function getOperation() { - return operationConstants.PNHereNowOperation; -} - -export function validateParams(modules) { - const { config } = modules; - - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules, incomingParams) { - const { config } = modules; - const { channels = [], channelGroups = [] } = incomingParams; - let baseURL = `/v2/presence/sub-key/${config.subscribeKey}`; - - if (channels.length > 0 || channelGroups.length > 0) { - const stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - baseURL += `/channel/${utils.encodeString(stringifiedChannels)}`; - } - - return baseURL; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams(modules, incomingParams) { - const { channelGroups = [], includeUUIDs = true, includeState = false, queryParameters = {} } = incomingParams; - let params = {}; - - if (!includeUUIDs) params.disable_uuids = 1; - if (includeState) params.state = 1; - - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); - } - - params = { ...params, ...queryParameters }; - - return params; -} - -export function handleResponse(modules, serverResponse, incomingParams) { - const { channels = [], channelGroups = [], includeUUIDs = true, includeState = false } = incomingParams; - - const prepareSingularChannel = () => { - const response = {}; - const occupantsList = []; - response.totalChannels = 1; - response.totalOccupancy = serverResponse.occupancy; - response.channels = {}; - response.channels[channels[0]] = { - occupants: occupantsList, - name: channels[0], - occupancy: serverResponse.occupancy, - }; - - // We have had issues in the past with server returning responses - // that contain no uuids array - if (includeUUIDs && serverResponse.uuids) { - serverResponse.uuids.forEach((uuidEntry) => { - if (includeState) { - occupantsList.push({ state: uuidEntry.state, uuid: uuidEntry.uuid }); - } else { - occupantsList.push({ state: null, uuid: uuidEntry }); - } - }); - } - - return response; - }; - - const prepareMultipleChannel = () => { - const response = {}; - response.totalChannels = serverResponse.payload.total_channels; - response.totalOccupancy = serverResponse.payload.total_occupancy; - response.channels = {}; - - Object.keys(serverResponse.payload.channels).forEach((channelName) => { - const channelEntry = serverResponse.payload.channels[channelName]; - const occupantsList = []; - response.channels[channelName] = { - occupants: occupantsList, - name: channelName, - occupancy: channelEntry.occupancy, - }; - - if (includeUUIDs) { - channelEntry.uuids.forEach((uuidEntry) => { - if (includeState) { - occupantsList.push({ - state: uuidEntry.state, - uuid: uuidEntry.uuid, - }); - } else { - occupantsList.push({ state: null, uuid: uuidEntry }); - } - }); - } - - return response; - }); - - return response; - }; - - let response; - if (channels.length > 1 || channelGroups.length > 0 || (channelGroups.length === 0 && channels.length === 0)) { - response = prepareMultipleChannel(); - } else { - response = prepareSingularChannel(); - } - - return response; -} - -export function handleError(modules, params, status) { - if (status.statusCode === 402 && !this.getURL(modules, params).includes('channel')) { - status.errorData.message = - 'You have tried to perform a Global Here Now operation, ' + - 'your keyset configuration does not support that. Please provide a channel, ' + - 'or enable the Global Here Now feature from the Portal.'; - } -} diff --git a/src/core/endpoints/presence/here_now.ts b/src/core/endpoints/presence/here_now.ts new file mode 100644 index 000000000..54c81331c --- /dev/null +++ b/src/core/endpoints/presence/here_now.ts @@ -0,0 +1,211 @@ +/** + * Channels / channel groups presence REST API module. + */ + +import { createValidationError, PubNubError } from '../../../models/PubNubError'; +import { TransportResponse } from '../../types/transport-response'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import { KeySet, Payload, Query } from '../../types/api'; +import * as Presence from '../../types/api/presence'; +import { encodeString } from '../../utils'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Whether `uuid` should be included in response or not. + */ +const INCLUDE_UUID = true; + +/** + * Whether state associated with `uuid` should be included in response or not. + */ +const INCLUDE_STATE = false; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = Presence.HereNowParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type BasicServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Here now human-readable result. + */ + message: string; + + /** + * Name of the service which provided response. + */ + service: string; +}; + +/** + * Single channel here now service response. + */ +type SingleChannelServiceResponse = BasicServiceResponse & { + /** + * List of received channel subscribers. + * + * **Note:** Field is missing if `uuid` and `state` not included. + */ + uuids?: (string | { uuid: string; state?: Payload })[]; + + /** + * Total number of active subscribers. + */ + occupancy: number; +}; + +/** + * Multiple channels / channel groups here now service response. + */ +type MultipleChannelServiceResponse = BasicServiceResponse & { + /** + * Retrieved channels' presence. + */ + payload: { + /** + * Total number of channels for which presence information received. + */ + total_channels: number; + + /** + * Total occupancy for all retrieved channels. + */ + total_occupancy: number; + + /** + * List of channels to which `uuid` currently subscribed. + */ + channels?: { + [p: string]: { + /** + * List of received channel subscribers. + * + * **Note:** Field is missing if `uuid` and `state` not included. + */ + uuids: (string | { uuid: string; state?: Payload })[]; + + /** + * Total number of active subscribers in single channel. + */ + occupancy: number; + }; + }; + }; +}; + +/** + * Here now REST API service success response. + */ +type ServiceResponse = SingleChannelServiceResponse | MultipleChannelServiceResponse; +// endregion + +export class HereNowRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + + // Apply defaults. + this.parameters.queryParameters ??= {}; + this.parameters.includeUUIDs ??= INCLUDE_UUID; + this.parameters.includeState ??= INCLUDE_STATE; + } + + operation(): RequestOperation { + return RequestOperation.PNHereNowOperation; + } + + validate(): string | undefined { + if (!this.parameters.keySet.subscribeKey) return 'Missing Subscribe Key'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + // Extract general presence information. + const totalChannels = 'occupancy' in serviceResponse ? 1 : serviceResponse.payload.total_channels; + const totalOccupancy = + 'occupancy' in serviceResponse ? serviceResponse.occupancy : serviceResponse.payload.total_channels; + const channelsPresence: Presence.HereNowResponse['channels'] = {}; + let channels: Required['channels'] = {}; + + // Remap single channel presence to multiple channels presence response. + if ('occupancy' in serviceResponse) { + const channel = this.parameters.channels![0]; + channels[channel] = { uuids: serviceResponse.uuids ?? [], occupancy: totalOccupancy }; + } else channels = serviceResponse.payload.channels ?? {}; + + Object.keys(channels).forEach((channel) => { + const channelEntry = channels[channel]; + channelsPresence[channel] = { + occupants: channelEntry.uuids.map((uuid) => { + if (typeof uuid === 'string') return { uuid, state: null }; + return uuid; + }), + name: channel, + occupancy: channelEntry.occupancy, + }; + }); + + return { + totalChannels, + totalOccupancy, + channels: channelsPresence, + }; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channels, + channelGroups, + } = this.parameters; + let path = `/v2/presence/sub-key/${subscribeKey}`; + + if ((channels && channels.length > 0) || (channelGroups && channelGroups.length > 0)) { + const stringifiedChannels = channels && channels.length > 0 ? encodeString(channels.join(',')) : ','; + path += `/channel/${stringifiedChannels}`; + } + + return path; + } + + protected get queryParameters(): Query { + const { channelGroups, includeUUIDs, includeState, queryParameters } = this.parameters; + + return { + ...(!includeUUIDs! ? { disable_uuids: '1' } : {}), + ...(includeState ?? false ? { state: '1' } : {}), + ...(channelGroups && channelGroups.length > 0 ? { 'channel-group': channelGroups.join(',') } : {}), + ...queryParameters!, + }; + } +} diff --git a/src/core/endpoints/presence/leave.js b/src/core/endpoints/presence/leave.js deleted file mode 100644 index ed8962603..000000000 --- a/src/core/endpoints/presence/leave.js +++ /dev/null @@ -1,44 +0,0 @@ -/* */ - -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -export function getOperation() { - return operationConstants.PNUnsubscribeOperation; -} - -export function validateParams(modules) { - const { config } = modules; - - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules, incomingParams) { - const { config } = modules; - const { channels = [] } = incomingParams; - const stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return `/v2/presence/sub-key/${config.subscribeKey}/channel/${utils.encodeString(stringifiedChannels)}/leave`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams(modules, incomingParams) { - const { channelGroups = [] } = incomingParams; - const params = {}; - - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); - } - - return params; -} - -export function handleResponse() { - return {}; -} diff --git a/src/core/endpoints/presence/leave.ts b/src/core/endpoints/presence/leave.ts new file mode 100644 index 000000000..002f9cd31 --- /dev/null +++ b/src/core/endpoints/presence/leave.ts @@ -0,0 +1,103 @@ +/** + * Announce leave REST API module. + */ + +import { createValidationError, PubNubError } from '../../../models/PubNubError'; +import { TransportResponse } from '../../types/transport-response'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import * as Presence from '../../types/api/presence'; +import { KeySet, Query } from '../../types/api'; +import { encodeString } from '../../utils'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = Presence.PresenceLeaveParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Leave presence human-readable result. + */ + message: string; + + /** + * Performed presence action. + */ + action: 'leave'; + + /** + * Name of the service which provided response. + */ + service: string; +}; +// endregion + +export class PresenceLeaveRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + } + + operation(): RequestOperation { + return RequestOperation.PNUnsubscribeOperation; + } + + validate(): string | undefined { + const { + keySet: { subscribeKey }, + channels, + channelGroups, + } = this.parameters; + + if (!subscribeKey) return 'Missing Subscribe Key'; + if (channels?.length === 0 && channelGroups?.length === 0) + return 'At least one `channel` or `channel group` should be provided.'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return {}; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channels, + } = this.parameters; + const stringifiedChannels = channels && channels.length > 0 ? encodeString(channels.join(',')) : ','; + + return `/v2/presence/sub-key/${subscribeKey}/channel/${stringifiedChannels}/leave`; + } + + protected get queryParameters(): Query { + const { channelGroups } = this.parameters; + if (!channelGroups || channelGroups.length === 0) return {}; + + return { 'channel-group': channelGroups.join(',') }; + } +} diff --git a/src/core/endpoints/presence/set_state.js b/src/core/endpoints/presence/set_state.js deleted file mode 100644 index 53f419a5d..000000000 --- a/src/core/endpoints/presence/set_state.js +++ /dev/null @@ -1,50 +0,0 @@ -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -export function getOperation() { - return operationConstants.PNSetStateOperation; -} - -export function validateParams(modules, incomingParams) { - const { config } = modules; - const { state, channels = [], channelGroups = [] } = incomingParams; - - if (!state) return 'Missing State'; - if (!config.subscribeKey) return 'Missing Subscribe Key'; - if (channels.length === 0 && channelGroups.length === 0) { - return 'Please provide a list of channels and/or channel-groups'; - } -} - -export function getURL(modules, incomingParams) { - const { config } = modules; - const { channels = [] } = incomingParams; - const stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return `/v2/presence/sub-key/${config.subscribeKey}/channel/${utils.encodeString( - stringifiedChannels, - )}/uuid/${utils.encodeString(config.UUID)}/data`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams(modules, incomingParams) { - const { state, channelGroups = [] } = incomingParams; - const params = {}; - - params.state = JSON.stringify(state); - - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); - } - return params; -} - -export function handleResponse(modules, serverResponse) { - return { state: serverResponse.payload }; -} diff --git a/src/core/endpoints/presence/set_state.ts b/src/core/endpoints/presence/set_state.ts new file mode 100644 index 000000000..f700d428a --- /dev/null +++ b/src/core/endpoints/presence/set_state.ts @@ -0,0 +1,116 @@ +/** + * Set Presence State REST API module. + */ + +import { createValidationError, PubNubError } from '../../../models/PubNubError'; +import { TransportResponse } from '../../types/transport-response'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import { KeySet, Payload, Query } from '../../types/api'; +import * as Presence from '../../types/api/presence'; +import { encodeString } from '../../utils'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = Presence.SetPresenceStateParameters & { + /** + * The subscriber uuid to associate state with. + */ + uuid: string; + + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Set presence state human-readable result. + */ + message: string; + + /** + * Name of the service which provided response. + */ + service: string; + + /** + * Associated presence state. + */ + payload: Payload; +}; +// endregion + +/** + * Set `uuid` presence state request. + */ +export class SetPresenceStateRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + } + + operation(): RequestOperation { + return RequestOperation.PNSetStateOperation; + } + + validate(): string | undefined { + const { + keySet: { subscribeKey }, + state, + channels, + channelGroups, + } = this.parameters; + + if (!subscribeKey) return 'Missing Subscribe Key'; + if (!state) return 'Missing State'; + if (channels?.length === 0 && channelGroups?.length === 0) + return 'Please provide a list of channels and/or channel-groups'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return { state: serviceResponse.payload }; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + uuid, + channels, + } = this.parameters; + const stringifiedChannels = channels && channels.length > 0 ? encodeString(channels.join(',')) : ','; + + return `/v2/presence/sub-key/${subscribeKey}/channel/${stringifiedChannels}/uuid/${uuid}/data`; + } + + protected get queryParameters(): Query { + const { channelGroups, state } = this.parameters; + const query: Query = { state: JSON.stringify(state) }; + + if (channelGroups && channelGroups.length === 0) query['channel-group'] = channelGroups.join(','); + + return query; + } +} diff --git a/src/core/endpoints/presence/where_now.js b/src/core/endpoints/presence/where_now.js deleted file mode 100644 index bc6daeb93..000000000 --- a/src/core/endpoints/presence/where_now.js +++ /dev/null @@ -1,40 +0,0 @@ -/* */ -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -export function getOperation() { - return operationConstants.PNWhereNowOperation; -} - -export function validateParams(modules) { - const { config } = modules; - - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules, incomingParams) { - const { config } = modules; - const { uuid = config.UUID } = incomingParams; - return `/v2/presence/sub-key/${config.subscribeKey}/uuid/${utils.encodeString(uuid)}`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams() { - return {}; -} - -export function handleResponse(modules, serverResponse) { - // This is a quick fix for when the server does not include a payload - // in where now responses - if (!serverResponse.payload) { - return { channels: [] }; - } - return { channels: serverResponse.payload.channels }; -} diff --git a/src/core/endpoints/presence/where_now.ts b/src/core/endpoints/presence/where_now.ts new file mode 100644 index 000000000..a271540df --- /dev/null +++ b/src/core/endpoints/presence/where_now.ts @@ -0,0 +1,93 @@ +/** + * `uuid` presence REST API module. + */ + +import { createValidationError, PubNubError } from '../../../models/PubNubError'; +import { TransportResponse } from '../../types/transport-response'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import * as Presence from '../../types/api/presence'; +import { encodeString } from '../../utils'; +import { KeySet } from '../../types/api'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = Required & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = { + /** + * Request result status code. + */ + status: number; + + /** + * Where now human-readable result. + */ + message: string; + + /** + * Retrieved channels with `uuid` subscriber. + */ + payload?: { + /** + * List of channels to which `uuid` currently subscribed. + */ + channels: string[]; + }; + + /** + * Name of the service which provided response. + */ + service: string; +}; +// endregion + +export class WhereNowRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + } + + operation(): RequestOperation { + return RequestOperation.PNWhereNowOperation; + } + + validate(): string | undefined { + if (!this.parameters.keySet.subscribeKey) return 'Missing Subscribe Key'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + if (!serviceResponse.payload) return { channels: [] }; + + return { channels: serviceResponse.payload.channels }; + } + protected get path(): string { + const { + keySet: { subscribeKey }, + uuid, + } = this.parameters; + + return `/v2/presence/sub-key/${subscribeKey}/uuid/${encodeString(uuid)}`; + } +} diff --git a/src/core/endpoints/publish.js b/src/core/endpoints/publish.js deleted file mode 100644 index 5fddd7d21..000000000 --- a/src/core/endpoints/publish.js +++ /dev/null @@ -1,91 +0,0 @@ -/* */ -import operationConstants from '../constants/operations'; -import utils from '../utils'; -import { encode } from '../components/base64_codec'; - -function prepareMessagePayload(modules, messagePayload) { - let stringifiedPayload = JSON.stringify(messagePayload); - - if (modules.cryptoModule) { - const encrypted = modules.cryptoModule.encrypt(stringifiedPayload); - stringifiedPayload = typeof encrypted === 'string' ? encrypted : encode(encrypted); - stringifiedPayload = JSON.stringify(stringifiedPayload); - } - return stringifiedPayload || ''; -} - -export function getOperation() { - return operationConstants.PNPublishOperation; -} - -export function validateParams({ config }, incomingParams) { - const { message, channel } = incomingParams; - - if (!channel) return 'Missing Channel'; - if (!message) return 'Missing Message'; - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function usePost(modules, incomingParams) { - const { sendByPost = false } = incomingParams; - return sendByPost; -} - -export function getURL(modules, incomingParams) { - const { config } = modules; - const { channel, message } = incomingParams; - const stringifiedPayload = prepareMessagePayload(modules, message); - return `/publish/${config.publishKey}/${config.subscribeKey}/0/${utils.encodeString(channel)}/0/${utils.encodeString( - stringifiedPayload, - )}`; -} - -export function postURL(modules, incomingParams) { - const { config } = modules; - const { channel } = incomingParams; - return `/publish/${config.publishKey}/${config.subscribeKey}/0/${utils.encodeString(channel)}/0`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function postPayload(modules, incomingParams) { - const { message } = incomingParams; - return prepareMessagePayload(modules, message); -} - -export function prepareParams(modules, incomingParams) { - const { meta, replicate = true, storeInHistory, ttl } = incomingParams; - const params = {}; - - if (storeInHistory != null) { - if (storeInHistory) { - params.store = '1'; - } else { - params.store = '0'; - } - } - - if (ttl) { - params.ttl = ttl; - } - - if (replicate === false) { - params.norep = 'true'; - } - - if (meta && typeof meta === 'object') { - params.meta = JSON.stringify(meta); - } - - return params; -} - -export function handleResponse(modules, serverResponse) { - return { timetoken: serverResponse[2] }; -} diff --git a/src/core/endpoints/publish.ts b/src/core/endpoints/publish.ts new file mode 100644 index 000000000..fd59e0046 --- /dev/null +++ b/src/core/endpoints/publish.ts @@ -0,0 +1,229 @@ +/** + * Publish REST API module. + */ + +import { createValidationError, PubNubError } from '../../models/PubNubError'; +import { TransportResponse } from '../types/transport-response'; +import { TransportMethod } from '../types/transport-request'; +import { CryptoModule } from '../interfaces/crypto-module'; +import { AbstractRequest } from '../components/request'; +import RequestOperation from '../constants/operations'; +import { KeySet, Payload, Query } from '../types/api'; +import { encode } from '../components/base64_codec'; +import { encodeString } from '../utils'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Whether published data should be stored in history or not. + */ +const STORE_IN_HISTORY = true; + +/** + * Whether data is published used `POST` body or not. + */ +const SEND_BY_POST = false; + +/** + * Whether published data should be replicated across all data centers or not. + */ +const SHOULD_REPLICATE = true; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +export type PublishParameters = { + /** + * Channel name to publish messages to. + */ + channel: string; + + /** + * Data which should be sent to the `channel`. + * + * The message may be any valid JSON type including objects, arrays, strings, and numbers. + */ + message: Payload; + + /** + * Whether published data should be available with `Storage API` later or not. + * + * @default `true` + */ + storeInHistory?: boolean; + + /** + * Whether message should be sent as part of request POST body or not. + * + * @default `false` + */ + sendByPost?: boolean; + + /** + * Metadata, which should be associated with published data. + * + * Associated metadata can be utilized by message filtering feature. + */ + meta?: Payload; + + /** + * Specify duration during which data will be available with `Storage API`. + * + * - If `storeInHistory` = `true`, and `ttl` = `0`, the `message` is stored with no expiry time. + * - If `storeInHistory` = `true` and `ttl` = `X` (`X` is an Integer value), the `message` is + * stored with an expiry time of `X` hours. + * - If `storeInHistory` = `false`, the `ttl` parameter is ignored. + * - If `ttl` is not specified, then expiration of the `message` defaults back to the expiry value + * for the key. + */ + ttl?: number; + + /** + * Whether published data should be replicated across all data centers or not. + * + * @default `true` + * @deprecated + */ + replicate?: boolean; + + /** + * Indexed signature for deprecated parameters. + */ + [key: string]: string | number | boolean | undefined | Payload | CryptoModule; +}; + +/** + * Service success response. + */ +export type PublishResponse = { + /** + * High-precision time when published data has been received by the PubNub service. + */ + timetoken: string; +}; + +/** + * Request configuration parameters. + */ +type RequestParameters = PublishParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; + + /** + * Published data encryption module. + */ + crypto?: CryptoModule; +}; + +/** + * Service success response. + */ +type ServiceResponse = [0 | 1, string, string]; +// endregion + +/** + * Data publish request. + * + * Request will normalize and encrypt (if required) provided data and push it to the specified + * channel. + */ +export class PublishRequest extends AbstractRequest { + /** + * Construct data publish request. + * + * @param parameters - Request configuration. + */ + constructor(private readonly parameters: RequestParameters) { + super({ method: parameters.sendByPost ? TransportMethod.POST : TransportMethod.GET }); + + // Apply default request parameters. + this.parameters.storeInHistory ??= STORE_IN_HISTORY; + this.parameters.sendByPost ??= SEND_BY_POST; + + // Apply defaults to the deprecated parameter. + this.parameters.replicate ??= SHOULD_REPLICATE; + } + + operation(): RequestOperation { + return RequestOperation.PNPublishOperation; + } + + validate(): string | undefined { + const { + message, + channel, + keySet: { publishKey }, + } = this.parameters; + + if (!channel) return "Missing 'channel''"; + if (!message) return "Missing 'message'"; + if (!publishKey) return "Missing 'publishKey'"; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return { timetoken: serviceResponse[2] }; + } + + protected get path(): string { + const { message, channel, keySet } = this.parameters; + const stringifiedPayload = this.prepareMessagePayload(message); + + return `/publish/${keySet.publishKey}/${keySet.subscribeKey}/0/${encodeString(channel)}/0${ + !this.parameters.sendByPost ? `/${encodeString(stringifiedPayload)}` : '' + }`; + } + + protected get queryParameters(): Query { + const { meta, replicate, storeInHistory, ttl } = this.parameters; + + return { + store: storeInHistory ? '1' : '0', + ...(ttl !== undefined ? { ttl } : {}), + ...(!replicate ? { norep: 'true' } : {}), + ...(meta && typeof meta === 'object' ? { meta: JSON.stringify(meta) } : {}), + }; + } + + protected get body(): ArrayBuffer | string | undefined { + return this.prepareMessagePayload(this.parameters.message); + } + + /** + * Pre-process provided data. + * + * Data will be "normalized" and encrypted if `cryptoModule` has been provided. + * + * @param payload - User-provided data which should be pre-processed before use. + * + * @returns Payload which can be used as part of request URL or body. + * + * @throws {Error} in case if provided `payload` or results of `encryption` can't be stringified. + */ + private prepareMessagePayload(payload: Payload): string { + const { crypto } = this.parameters; + if (!crypto) return JSON.stringify(payload) || ''; + + const encrypted = crypto.encrypt(JSON.stringify(payload)); + + return JSON.stringify(typeof encrypted === 'string' ? encrypted : encode(encrypted)); + } +} diff --git a/src/core/endpoints/push/add_push_channels.js b/src/core/endpoints/push/add_push_channels.js deleted file mode 100644 index 759a8ce63..000000000 --- a/src/core/endpoints/push/add_push_channels.js +++ /dev/null @@ -1,53 +0,0 @@ -/* */ - -import operationConstants from '../../constants/operations'; - -export function getOperation() { - return operationConstants.PNPushNotificationEnabledChannelsOperation; -} - -export function validateParams(modules, incomingParams) { - const { device, pushGateway, channels, topic } = incomingParams; - const { config } = modules; - - if (!device) return 'Missing Device ID (device)'; - if (!pushGateway) return 'Missing GW Type (pushGateway: gcm, apns or apns2)'; - if (pushGateway === 'apns2' && !topic) return 'Missing APNS2 topic'; - if (!channels || channels.length === 0) return 'Missing Channels'; - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules, incomingParams) { - const { device, pushGateway } = incomingParams; - const { config } = modules; - - if (pushGateway === 'apns2') { - return `/v2/push/sub-key/${config.subscribeKey}/devices-apns2/${device}`; - } - - return `/v1/push/sub-key/${config.subscribeKey}/devices/${device}`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams(modules, incomingParams) { - const { pushGateway, channels = [], environment = 'development', topic } = incomingParams; - let parameters = { type: pushGateway, add: channels.join(',') }; - - if (pushGateway === 'apns2') { - parameters = { ...parameters, environment, topic }; - delete parameters.type; - } - - return parameters; -} - -export function handleResponse() { - return {}; -} diff --git a/src/core/endpoints/push/add_push_channels.ts b/src/core/endpoints/push/add_push_channels.ts new file mode 100644 index 000000000..fbeaa1c23 --- /dev/null +++ b/src/core/endpoints/push/add_push_channels.ts @@ -0,0 +1,59 @@ +/** + * Register Channels with Device push REST API module. + */ + +import { createValidationError, PubNubError } from '../../../models/PubNubError'; +import { TransportResponse } from '../../types/transport-response'; +import { BasePushNotificationChannelsRequest } from './push'; +import RequestOperation from '../../constants/operations'; +import * as Push from '../../types/api/push'; +import { KeySet } from '../../types/api'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = Push.ManageDeviceChannelsParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = [0 | 1, string]; +// endregion + +/** + * Register channels with device push request. + */ +// prettier-ignore +export class AddDevicePushNotificationChannelsRequest extends BasePushNotificationChannelsRequest< + Push.ManageDeviceChannelsResponse +> { + constructor(parameters: RequestParameters) { + super({ ...parameters, action: 'add' }); + } + + operation(): RequestOperation { + return RequestOperation.PNAddPushNotificationEnabledChannelsOperation; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return {}; + } +} diff --git a/src/core/endpoints/push/list_push_channels.js b/src/core/endpoints/push/list_push_channels.js deleted file mode 100644 index 25e6fc347..000000000 --- a/src/core/endpoints/push/list_push_channels.js +++ /dev/null @@ -1,51 +0,0 @@ -/* */ -import operationConstants from '../../constants/operations'; - -export function getOperation() { - return operationConstants.PNPushNotificationEnabledChannelsOperation; -} - -export function validateParams(modules, incomingParams) { - const { device, pushGateway, topic } = incomingParams; - const { config } = modules; - - if (!device) return 'Missing Device ID (device)'; - if (!pushGateway) return 'Missing GW Type (pushGateway: gcm, apns or apns2)'; - if (pushGateway === 'apns2' && !topic) return 'Missing APNS2 topic'; - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules, incomingParams) { - const { device, pushGateway } = incomingParams; - const { config } = modules; - - if (pushGateway === 'apns2') { - return `/v2/push/sub-key/${config.subscribeKey}/devices-apns2/${device}`; - } - - return `/v1/push/sub-key/${config.subscribeKey}/devices/${device}`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams(modules, incomingParams) { - const { pushGateway, environment = 'development', topic } = incomingParams; - let parameters = { type: pushGateway }; - - if (pushGateway === 'apns2') { - parameters = { ...parameters, environment, topic }; - delete parameters.type; - } - - return parameters; -} - -export function handleResponse(modules, serverResponse) { - return { channels: serverResponse }; -} diff --git a/src/core/endpoints/push/list_push_channels.ts b/src/core/endpoints/push/list_push_channels.ts new file mode 100644 index 000000000..b0904014e --- /dev/null +++ b/src/core/endpoints/push/list_push_channels.ts @@ -0,0 +1,59 @@ +/** + * List Device push enabled channels REST API module. + */ + +import { createValidationError, PubNubError } from '../../../models/PubNubError'; +import { TransportResponse } from '../../types/transport-response'; +import { BasePushNotificationChannelsRequest } from './push'; +import RequestOperation from '../../constants/operations'; +import * as Push from '../../types/api/push'; +import { KeySet } from '../../types/api'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = Push.ListDeviceChannelsParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = string[]; +// endregion + +/** + * List device push enabled channels request. + */ +// prettier-ignore +export class ListDevicePushNotificationChannelsRequest extends BasePushNotificationChannelsRequest< + Push.ListDeviceChannelsResponse +> { + constructor(parameters: RequestParameters) { + super({ ...parameters, action: 'list' }); + } + + operation(): RequestOperation { + return RequestOperation.PNPushNotificationEnabledChannelsOperation; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return { channels: serviceResponse }; + } +} diff --git a/src/core/endpoints/push/push.ts b/src/core/endpoints/push/push.ts new file mode 100644 index 000000000..20e231d62 --- /dev/null +++ b/src/core/endpoints/push/push.ts @@ -0,0 +1,121 @@ +/** + * Manage channels enabled for device push REST API module. + */ + +import { TransportResponse } from '../../types/transport-response'; +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import { KeySet, Query } from '../../types/api'; +import * as Push from '../../types/api/push'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults + +/** + * Environment for which APNS2 notifications + */ +const ENVIRONMENT = 'development'; + +/** + * Maximum number of channels in `list` response. + */ +const MAX_COUNT = 1000; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = (Push.ManageDeviceChannelsParameters | Push.RemoveDeviceParameters) & { + /** + * Action which should be performed. + */ + action: 'add' | 'remove' | 'remove-device' | 'list'; + + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; +// endregion + +/** + * Base push notification request. + */ +export class BasePushNotificationChannelsRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + + // Apply request defaults + if (this.parameters.pushGateway === 'apns2') this.parameters.environment ??= ENVIRONMENT; + if (this.parameters.count && this.parameters.count > MAX_COUNT) this.parameters.count = MAX_COUNT; + } + + operation(): RequestOperation { + throw Error('Should be implemented in subclass.'); + } + + validate(): string | undefined { + const { + keySet: { subscribeKey }, + action, + device, + pushGateway, + } = this.parameters; + + if (!subscribeKey) return 'Missing Subscribe Key'; + if (!device) return 'Missing Device ID (device)'; + if ( + (action === 'add' || action === 'remove') && + (!('channels' in this.parameters) || this.parameters.channels.length === 0) + ) + return 'Missing Channels'; + + if (!pushGateway) return 'Missing GW Type (pushGateway: gcm or apns2)'; + if (this.parameters.pushGateway === 'apns2' && !this.parameters.topic) return 'Missing APNS2 topic'; + } + + async parse(_response: TransportResponse): Promise { + throw Error('Should be implemented in subclass.'); + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + action, + device, + pushGateway, + } = this.parameters; + + let path = + pushGateway === 'apns2' + ? `/v2/push/sub-key/${subscribeKey}/devices-apns2/${device}` + : `/v1/push/sub-key/${subscribeKey}/devices/${device}`; + if (action === 'remove-device') path = `${path}/remove`; + + return path; + } + + protected get queryParameters(): Query { + const { start, count } = this.parameters; + let query: Query = { + type: this.parameters.pushGateway, + ...(start ? { start } : {}), + ...(count && count > 0 ? { count } : {}), + }; + + if ('channels' in this.parameters) query[this.parameters.action] = this.parameters.channels.join(','); + if (this.parameters.pushGateway === 'apns2') { + const { environment, topic } = this.parameters; + query = { ...query, environment: environment!, topic }; + } + + return query; + } +} diff --git a/src/core/endpoints/push/remove_device.js b/src/core/endpoints/push/remove_device.js deleted file mode 100644 index 1f1d350fb..000000000 --- a/src/core/endpoints/push/remove_device.js +++ /dev/null @@ -1,52 +0,0 @@ -/* */ - -import operationConstants from '../../constants/operations'; - -export function getOperation() { - return operationConstants.PNRemoveAllPushNotificationsOperation; -} - -export function validateParams(modules, incomingParams) { - const { device, pushGateway, topic } = incomingParams; - const { config } = modules; - - if (!device) return 'Missing Device ID (device)'; - if (!pushGateway) return 'Missing GW Type (pushGateway: gcm, apns or apns2)'; - if (pushGateway === 'apns2' && !topic) return 'Missing APNS2 topic'; - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules, incomingParams) { - const { device, pushGateway } = incomingParams; - const { config } = modules; - - if (pushGateway === 'apns2') { - return `/v2/push/sub-key/${config.subscribeKey}/devices-apns2/${device}/remove`; - } - - return `/v1/push/sub-key/${config.subscribeKey}/devices/${device}/remove`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams(modules, incomingParams) { - const { pushGateway, environment = 'development', topic } = incomingParams; - let parameters = { type: pushGateway }; - - if (pushGateway === 'apns2') { - parameters = { ...parameters, environment, topic }; - delete parameters.type; - } - - return parameters; -} - -export function handleResponse() { - return {}; -} diff --git a/src/core/endpoints/push/remove_device.ts b/src/core/endpoints/push/remove_device.ts new file mode 100644 index 000000000..f660a4073 --- /dev/null +++ b/src/core/endpoints/push/remove_device.ts @@ -0,0 +1,59 @@ +/** + * Unregister Device push REST API module. + */ + +import { createValidationError, PubNubError } from '../../../models/PubNubError'; +import { TransportResponse } from '../../types/transport-response'; +import { BasePushNotificationChannelsRequest } from './push'; +import RequestOperation from '../../constants/operations'; +import * as Push from '../../types/api/push'; +import { KeySet } from '../../types/api'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = Push.RemoveDeviceParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = [0 | 1, string]; +// endregion + +/** + * Unregister device push notifications request. + */ +// prettier-ignore +export class RemoveDevicePushNotificationRequest extends BasePushNotificationChannelsRequest< + Push.RemoveDeviceResponse +> { + constructor(parameters: RequestParameters) { + super({ ...parameters, action: 'remove-device' }); + } + + operation(): RequestOperation { + return RequestOperation.PNRemoveAllPushNotificationsOperation; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return {}; + } +} diff --git a/src/core/endpoints/push/remove_push_channels.js b/src/core/endpoints/push/remove_push_channels.js deleted file mode 100644 index 16cc9bcfd..000000000 --- a/src/core/endpoints/push/remove_push_channels.js +++ /dev/null @@ -1,53 +0,0 @@ -/* */ - -import operationConstants from '../../constants/operations'; - -export function getOperation() { - return operationConstants.PNPushNotificationEnabledChannelsOperation; -} - -export function validateParams(modules, incomingParams) { - const { device, pushGateway, channels, topic } = incomingParams; - const { config } = modules; - - if (!device) return 'Missing Device ID (device)'; - if (!pushGateway) return 'Missing GW Type (pushGateway: gcm, apns or apns2)'; - if (pushGateway === 'apns2' && !topic) return 'Missing APNS2 topic'; - if (!channels || channels.length === 0) return 'Missing Channels'; - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules, incomingParams) { - const { device, pushGateway } = incomingParams; - const { config } = modules; - - if (pushGateway === 'apns2') { - return `/v2/push/sub-key/${config.subscribeKey}/devices-apns2/${device}`; - } - - return `/v1/push/sub-key/${config.subscribeKey}/devices/${device}`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams(modules, incomingParams) { - const { pushGateway, channels = [], environment = 'development', topic } = incomingParams; - let parameters = { type: pushGateway, remove: channels.join(',') }; - - if (pushGateway === 'apns2') { - parameters = { ...parameters, environment, topic }; - delete parameters.type; - } - - return parameters; -} - -export function handleResponse() { - return {}; -} diff --git a/src/core/endpoints/push/remove_push_channels.ts b/src/core/endpoints/push/remove_push_channels.ts new file mode 100644 index 000000000..fa5e1793e --- /dev/null +++ b/src/core/endpoints/push/remove_push_channels.ts @@ -0,0 +1,59 @@ +/** + * Unregister Channels from Device push REST API module. + */ + +import { createValidationError, PubNubError } from '../../../models/PubNubError'; +import { TransportResponse } from '../../types/transport-response'; +import { BasePushNotificationChannelsRequest } from './push'; +import RequestOperation from '../../constants/operations'; +import * as Push from '../../types/api/push'; +import { KeySet } from '../../types/api'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +type RequestParameters = Push.ManageDeviceChannelsParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = [0 | 1, string]; +// endregion + +/** + * Unregister channels from device push request. + */ +// prettier-ignore +export class RemoveDevicePushNotificationChannelsRequest extends BasePushNotificationChannelsRequest< + Push.ManageDeviceChannelsResponse +> { + constructor(parameters: RequestParameters) { + super({ ...parameters, action: 'remove' }); + } + + operation(): RequestOperation { + return RequestOperation.PNRemovePushNotificationEnabledChannelsOperation; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return {}; + } +} diff --git a/src/core/endpoints/signal.js b/src/core/endpoints/signal.js deleted file mode 100644 index ff7aa4802..000000000 --- a/src/core/endpoints/signal.js +++ /dev/null @@ -1,49 +0,0 @@ -/* */ - -import operationConstants from '../constants/operations'; -import utils from '../utils'; - -function prepareMessagePayload(modules, messagePayload) { - const stringifiedPayload = JSON.stringify(messagePayload); - - return stringifiedPayload; -} - -export function getOperation() { - return operationConstants.PNSignalOperation; -} - -export function validateParams({ config }, incomingParams) { - const { message, channel } = incomingParams; - - if (!channel) return 'Missing Channel'; - if (!message) return 'Missing Message'; - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules, incomingParams) { - const { config } = modules; - const { channel, message } = incomingParams; - const stringifiedPayload = prepareMessagePayload(modules, message); - return `/signal/${config.publishKey}/${config.subscribeKey}/0/${utils.encodeString(channel)}/0/${utils.encodeString( - stringifiedPayload, - )}`; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams() { - const params = {}; - - return params; -} - -export function handleResponse(modules, serverResponse) { - return { timetoken: serverResponse[2] }; -} diff --git a/src/core/endpoints/signal.ts b/src/core/endpoints/signal.ts new file mode 100644 index 000000000..850a5dfcf --- /dev/null +++ b/src/core/endpoints/signal.ts @@ -0,0 +1,103 @@ +/** + * Signal REST API module. + */ + +import { createValidationError, PubNubError } from '../../models/PubNubError'; +import { TransportResponse } from '../types/transport-response'; +import { AbstractRequest } from '../components/request'; +import RequestOperation from '../constants/operations'; +import { KeySet, Payload } from '../types/api'; +import { encodeString } from '../utils'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Request configuration parameters. + */ +export type SignalParameters = { + /** + * Channel name to publish signal to. + */ + channel: string; + + /** + * Data which should be sent to the `channel`. + * + * The message may be any valid JSON type including objects, arrays, strings, and numbers. + */ + message: Payload; +}; + +/** + * Service success response. + */ +export type SignalResponse = { + /** + * High-precision time when published data has been received by the PubNub service. + */ + timetoken: string; +}; + +/** + * Request configuration parameters. + */ +type RequestParameters = SignalParameters & { + /** + * PubNub REST API access key set. + */ + keySet: KeySet; +}; + +/** + * Service success response. + */ +type ServiceResponse = [0 | 1, string, string]; +// endregion + +export class SignalRequest extends AbstractRequest { + constructor(private readonly parameters: RequestParameters) { + super(); + } + + operation(): RequestOperation { + return RequestOperation.PNSignalOperation; + } + + validate(): string | undefined { + const { + message, + channel, + keySet: { publishKey }, + } = this.parameters; + + if (!channel) return "Missing 'channel''"; + if (!message) return "Missing 'message'"; + if (!publishKey) return "Missing 'publishKey'"; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return { timetoken: serviceResponse[2] }; + } + + protected get path(): string { + const { + keySet: { publishKey, subscribeKey }, + channel, + message, + } = this.parameters; + const stringifiedPayload = JSON.stringify(message); + + return `/signal/${publishKey}/${subscribeKey}/0/${encodeString(channel)}/0/${encodeString(stringifiedPayload)}`; + } +} diff --git a/src/core/endpoints/subscribe.js b/src/core/endpoints/subscribe.js deleted file mode 100644 index faf6d1306..000000000 --- a/src/core/endpoints/subscribe.js +++ /dev/null @@ -1,89 +0,0 @@ -/* */ -import operationConstants from '../constants/operations'; -import utils from '../utils'; - -export function getOperation() { - return operationConstants.PNSubscribeOperation; -} - -export function validateParams(modules) { - const { config } = modules; - - if (!config.subscribeKey) return 'Missing Subscribe Key'; -} - -export function getURL(modules, incomingParams) { - const { config } = modules; - const { channels = [] } = incomingParams; - const stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return `/v2/subscribe/${config.subscribeKey}/${utils.encodeString(stringifiedChannels)}/0`; -} - -export function getRequestTimeout({ config }) { - return config.getSubscribeTimeout(); -} - -export function isAuthSupported() { - return true; -} - -export function prepareParams({ config }, incomingParams) { - const { state, channelGroups = [], timetoken, filterExpression, region } = incomingParams; - const params = { - heartbeat: config.getPresenceTimeout(), - }; - - if (channelGroups.length > 0) { - params['channel-group'] = channelGroups.join(','); - } - - if (filterExpression && filterExpression.length > 0) { - params['filter-expr'] = filterExpression; - } - - if (Object.keys(state).length) { - params.state = JSON.stringify(state); - } - - if (timetoken) { - params.tt = timetoken; - } - - if (region) { - params.tr = region; - } - - return params; -} - -export function handleResponse(modules, serverResponse) { - const messages = []; - - serverResponse.m.forEach((rawMessage) => { - const publishMetaData = { - publishTimetoken: rawMessage.p.t, - region: rawMessage.p.r, - }; - const parsedMessage = { - shard: parseInt(rawMessage.a, 10), - subscriptionMatch: rawMessage.b, - channel: rawMessage.c, - messageType: rawMessage.e, - payload: rawMessage.d, - flags: rawMessage.f, - issuingClientId: rawMessage.i, - subscribeKey: rawMessage.k, - originationTimetoken: rawMessage.o, - userMetadata: rawMessage.u, - publishMetaData, - }; - messages.push(parsedMessage); - }); - - const metadata = { - timetoken: serverResponse.t.t, - region: serverResponse.t.r, - }; - - return { messages, metadata }; -} diff --git a/src/core/endpoints/subscribe.ts b/src/core/endpoints/subscribe.ts new file mode 100644 index 000000000..2758497b5 --- /dev/null +++ b/src/core/endpoints/subscribe.ts @@ -0,0 +1,838 @@ +/** + * Subscription REST API module. + */ + +import { createValidationError, PubNubError } from '../../models/PubNubError'; +import { TransportResponse } from '../types/transport-response'; +import { CryptoModule } from '../interfaces/crypto-module'; +import * as Subscription from '../types/api/subscription'; +import { AbstractRequest } from '../components/request'; +import * as FileSharing from '../types/api/file-sharing'; +import RequestOperation from '../constants/operations'; +import * as AppContext from '../types/api/app-context'; +import { KeySet, Payload, Query } from '../types/api'; +import { encodeString } from '../utils'; + +// -------------------------------------------------------- +// ---------------------- Defaults ------------------------ +// -------------------------------------------------------- +// region Defaults + +/** + * Whether should subscribe to channels / groups presence announcements or not. + */ +const WITH_PRESENCE = false; + +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * PubNub-defined event types by payload. + */ +export enum PubNubEventType { + /** + * Presence change event. + */ + Presence = -2, + + /** + * Regular message event. + * + * **Note:** This is default type assigned for non-presence events if `e` field is missing. + */ + Message = -1, + + /** + * Signal data event. + */ + Signal = 1, + + /** + * App Context object event. + */ + AppContext, + + /** + * Message reaction event. + */ + MessageAction, + + /** + * Files event. + */ + Files, +} + +/** + * Time cursor. + * + * Cursor used by subscription loop to identify point in time after which updates will be + * delivered. + */ +type SubscriptionCursor = { + /** + * PubNub high-precision timestamp. + * + * Aside of specifying exact time of receiving data / event this token used to catchup / + * follow on real-time updates. + */ + t: string; + + /** + * Data center region for which `timetoken` has been generated. + */ + r: number; +}; + +// endregion + +// region Presence service response +/** + * Periodical presence change service response. + */ +type PresenceIntervalData = { + /** + * Periodical subscribed channels and groups presence change announcement. + */ + action: 'interval'; + + /** + * Unix timestamp when presence event has been triggered. + */ + timestamp: number; + + /** + * The current occupancy after the presence change is updated. + */ + occupancy: number; + + /** + * The list of unique user identifiers that `joined` the channel since the last interval + * presence update. + */ + join?: string[]; + + /** + * The list of unique user identifiers that `left` the channel since the last interval + * presence update. + */ + leave?: string[]; + + /** + * The list of unique user identifiers that `timeout` the channel since the last interval + * presence update. + */ + timeout?: string[]; +}; + +/** + * Subscribed user presence information change service response. + */ +type PresenceChangeData = { + /** + * Change if user's presence. + * + * User's presence may change between: `join`, `leave` and `timeout`. + */ + action: 'join' | 'leave' | 'timeout'; + + /** + * Unix timestamp when presence event has been triggered. + */ + timestamp: number; + + /** + * Unique identification of the user for whom presence information changed. + */ + uuid: string; + + /** + * The user's state associated with the channel has been updated. + * + * @deprecated Use set state methods to specify associated user's data instead of passing to + * subscribe. + */ + data: { [p: string]: Payload }; +}; + +/** + * Associated user presence state change service response. + */ +type PresenceStateChangeData = { + /** + * Subscribed user associated presence state change. + */ + action: 'state-change'; + + /** + * Unix timestamp when presence event has been triggered. + */ + timestamp: number; + + /** + * Unique identification of the user for whom associated presence state has been changed. + */ + uuid: string; + + /** + * The user's state associated with the channel has been updated. + */ + data: { [p: string]: Payload }; +}; + +/** + * Channel presence service response. + */ +export type PresenceData = PresenceIntervalData | PresenceChangeData | PresenceStateChangeData; +// endregion + +// region Message Actions service response +/** + * Message reaction change service response. + */ +export type MessageActionData = { + /** + * The type of event that happened during the message action update. + * + * Possible values are: + * - `added` - action has been added to the message + * - `removed` - action has been removed from message + */ + event: 'added' | 'removed'; + + /** + * Information about message action for which update has been generated. + */ + data: { + /** + * Timetoken of message for which action has been added / removed. + */ + messageTimetoken: string; + + /** + * Timetoken of message action which has been added / removed. + */ + actionTimetoken: string; + + /** + * Message action type. + */ + type: string; + + /** + * Value associated with message action {@link type}. + */ + value: string; + }; + + /** + * Name of service which generated update for message action. + */ + source: string; + + /** + * Version of service which generated update for message action. + */ + version: string; +}; +// endregion + +// region App Context service data +/** + * VSP Objects change events. + */ +type AppContextVSPEvents = 'updated' | 'removed'; + +/** + * App Context Objects change events. + */ +type AppContextEvents = 'set' | 'delete'; + +/** + * Common real-time App Context Object service response. + */ +type ObjectData = { + /** + * The type of event that happened during the object update. + */ + event: Event; + + /** + * App Context object type. + */ + type: Type; + + /** + * App Context object information. + * + * App Context object can be one of: + * - `channel` / `space` + * - `uuid` / `user` + * - `membership` + */ + data: AppContextObject; + + /** + * Name of service which generated update for object. + */ + source: string; + + /** + * Version of service which generated update for object. + */ + version: string; +}; + +/** + * `Channel` object change real-time service response. + */ +type ChannelObjectData = ObjectData< + AppContextEvents, + 'channel', + AppContext.ChannelMetadataObject +>; + +/** + * `Space` object change real-time service response. + */ +export type SpaceObjectData = ObjectData< + AppContextVSPEvents, + 'space', + AppContext.ChannelMetadataObject +>; + +/** + * `Uuid` object change real-time service response. + */ +type UuidObjectData = ObjectData>; + +/** + * `User` object change real-time service response. + */ +export type UserObjectData = ObjectData< + AppContextVSPEvents, + 'user', + AppContext.UUIDMetadataObject +>; + +/** + * `Membership` object change real-time service response. + */ +type MembershipObjectData = ObjectData< + AppContextEvents, + 'membership', + Omit, 'id'> & { + /** + * `Uuid` object which has been used to create relationship with `channel`. + */ + uuid: { + /** + * Unique `user` object identifier. + */ + id: string; + }; + + /** + * `Channel` object which has been used to create relationship with `uuid`. + */ + channel: { + /** + * Unique `channel` object identifier. + */ + id: string; + }; + } +>; + +/** + * VSP `Membership` object change real-time service response. + */ +export type VSPMembershipObjectData = ObjectData< + AppContextVSPEvents, + 'membership', + Omit, 'id'> & { + /** + * `User` object which has been used to create relationship with `space`. + */ + user: { + /** + * Unique `user` object identifier. + */ + id: string; + }; + + /** + * `Space` object which has been used to create relationship with `user`. + */ + space: { + /** + * Unique `channel` object identifier. + */ + id: string; + }; + } +>; + +/** + * App Context service response. + */ +export type AppContextObjectData = ChannelObjectData | UuidObjectData | MembershipObjectData; +// endregion + +// region File service response +/** + * File service response. + */ +export type FileData = { + /** + * Message which has been associated with uploaded file. + */ + message?: Payload; + + /** + * Information about uploaded file. + */ + file: { + /** + * Unique identifier of uploaded file. + */ + id: string; + + /** + * Actual name with which file has been stored. + */ + name: string; + }; +}; +// endregion + +/** + * Service response data envelope. + * + * Each entry from `m` list wrapped into this object. + */ +type Envelope = { + /** + * Shard number on which the event has been stored. + */ + a: string; + + /** + * A numeric representation of enabled debug flags. + */ + f: number; + + /** + * PubNub defined event type. + */ + e?: PubNubEventType; + + /** + * Identifier of client which sent message (set only when Publish REST API endpoint called with + * `uuid`). + */ + i?: string; + + /** + * Sequence number (set only when Publish REST API endpoint called with `seqn`). + */ + s?: number; + + /** + * Event "publish" time. + * + * This is the time when message has been received by {@link https://www.pubnub.com|PubNub} network. + */ + p: SubscriptionCursor; + + /** + * User-defined (local) "publish" time. + */ + o?: SubscriptionCursor; + + /** + * Name of channel where update received. + */ + c: string; + + /** + * Event payload. + * + * **Note:** One more type not mentioned here to keep type system working ({@link Payload}). + */ + d: PresenceData | MessageActionData | AppContextObjectData | FileData | string; + + /** + * Actual name of subscription through which event has been delivered. + * + * PubNub client can be used to subscribe to the group of channels to receive updates and + * (group name will be set for field). With this approach there will be no need to separately + * add *N* number of channels to `subscribe` method call. + */ + b?: string; + + /** + * User-provided metadata during `publish` method usage. + */ + u?: { [p: string]: Payload }; + + /** + * User provided message type (set only when `publish` called with `type`). + */ + mt?: string; + + /** + * Identifier of space into which message has been published (set only when `publish` called + * with `space_id`). + */ + si?: string; +}; + +/** + * Subscribe REST API service success response. + */ +type ServiceResponse = { + /** + * Next subscription cursor. + * + * The cursor contains information about the start of the next real-time update timeframe. + */ + t: SubscriptionCursor; + + /** + * List of updates. + * + * Contains list of real-time updates received using previous subscription cursor. + */ + m: Envelope[]; +}; + +/** + * Request configuration parameters. + */ +export type RequestParameters = Subscription.SubscribeParameters & { + /** + * Timetoken's region identifier. + */ + region?: number; + + /** + * Subscriber `userId` presence timeout. + * + * For how long (in seconds) user will be `online` without sending any new subscribe or + * heartbeat requests. + */ + heartbeat?: number; + + /** + * Real-time events filtering expression. + */ + filterExpression?: string | null; + + /** + * PubNub REST API access key set. + */ + keySet: KeySet; + + /** + * Received data decryption module. + */ + crypto?: CryptoModule; + + /** + * File download Url generation function. + * + * @param id - Unique identifier of the file which should be downloaded. + * @param name - Name with which file has been stored. + * @param channel - Name of the channel from which file should be downloaded. + */ + getFileUrl: (parameters: FileSharing.FileUrlParameters) => string; +}; +// endregion + +/** + * Base subscription request implementation. + * + * Subscription request used in small variations in two cases: + * - subscription manager + * - event engine + */ +export class BaseSubscribeRequest extends AbstractRequest { + constructor(protected readonly parameters: RequestParameters) { + super({ cancellable: true }); + + // Apply default request parameters. + this.parameters.withPresence ??= WITH_PRESENCE; + this.parameters.channelGroups ??= []; + this.parameters.channels ??= []; + } + + operation(): RequestOperation { + return RequestOperation.PNSubscribeOperation; + } + + validate(): string | undefined { + const { + keySet: { subscribeKey }, + channels, + channelGroups, + } = this.parameters; + + if (!subscribeKey) return 'Missing Subscribe Key'; + if (!channels && !channelGroups) return '`channels` and `channelGroups` both should not be empty'; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + const events: Subscription.SubscriptionResponse['messages'] = serviceResponse.m.map((envelope) => { + let { e: eventType } = envelope; + + // Resolve missing event type. + eventType ??= envelope.c.endsWith('-pnpres') ? PubNubEventType.Presence : PubNubEventType.Message; + + // Check whether payload is string (potentially encrypted data). + if (typeof envelope.d === 'string') { + if (eventType == PubNubEventType.Message) { + return { + type: PubNubEventType.Message, + data: this.messageFromEnvelope(envelope), + }; + } + + return { + type: PubNubEventType.Files, + data: this.fileFromEnvelope(envelope), + }; + } else if (eventType === PubNubEventType.Presence) { + return { + type: PubNubEventType.Presence, + data: this.presenceEventFromEnvelope(envelope), + }; + } else if (eventType == PubNubEventType.Signal) { + return { + type: PubNubEventType.Signal, + data: this.signalFromEnvelope(envelope), + }; + } else if (eventType === PubNubEventType.AppContext) { + return { + type: PubNubEventType.AppContext, + data: this.appContextFromEnvelope(envelope), + }; + } else if (eventType === PubNubEventType.MessageAction) { + return { + type: PubNubEventType.MessageAction, + data: this.messageActionFromEnvelope(envelope), + }; + } + + return { + type: PubNubEventType.Files, + data: this.fileFromEnvelope(envelope), + }; + }); + + return { + cursor: { timetoken: serviceResponse.t.t, region: serviceResponse.t.r }, + messages: events, + }; + } + + // -------------------------------------------------------- + // ------------------ Envelope parsing -------------------- + // -------------------------------------------------------- + // region Envelope parsing + + private presenceEventFromEnvelope(envelope: Envelope): Subscription.Presence { + const { d: payload } = envelope; + let [channel, subscription] = this.subscriptionChannelFromEnvelope(envelope); + + // Clean up channel and subscription name from presence suffix. + channel = channel.replace('-pnpres', ''); + if (subscription) subscription = subscription.replace('-pnpres', ''); + + // Backward compatibility with deprecated properties. + const actualChannel = subscription !== null ? channel : null; + const subscribedChannel = subscription !== null ? subscription : channel; + + return { + channel, + subscription, + actualChannel, + subscribedChannel, + timetoken: envelope.p.t, + ...(payload as PresenceData), + }; + } + + private messageFromEnvelope(envelope: Envelope): Subscription.Message { + const [channel, subscription] = this.subscriptionChannelFromEnvelope(envelope); + const [message, decryptionError] = this.decryptedData(envelope.d); + + // Backward compatibility with deprecated properties. + const actualChannel = subscription !== null ? channel : null; + const subscribedChannel = subscription !== null ? subscription : channel; + + // Basic message event payload. + const event: Subscription.Message = { + channel, + subscription, + actualChannel, + subscribedChannel, + timetoken: envelope.p.t, + publisher: envelope.i, + userMetadata: envelope.u, + message, + }; + + if (decryptionError) event.error = decryptionError; + + return event; + } + + private signalFromEnvelope(envelope: Envelope): Subscription.Signal { + const [channel, subscription] = this.subscriptionChannelFromEnvelope(envelope); + + return { + channel, + subscription, + timetoken: envelope.p.t, + publisher: envelope.i, + userMetadata: envelope.u, + message: envelope.d, + }; + } + + private messageActionFromEnvelope(envelope: Envelope): Subscription.MessageAction { + const [channel, subscription] = this.subscriptionChannelFromEnvelope(envelope); + const action = envelope.d as MessageActionData; + + return { + channel, + subscription, + timetoken: envelope.p.t, + publisher: envelope.i, + event: action.event, + data: { + ...action.data, + uuid: envelope.i!, + }, + }; + } + + private appContextFromEnvelope(envelope: Envelope): Subscription.AppContextObject { + const [channel, subscription] = this.subscriptionChannelFromEnvelope(envelope); + const object = envelope.d as AppContextObjectData; + + return { + channel, + subscription, + timetoken: envelope.p.t, + message: object, + }; + } + + private fileFromEnvelope(envelope: Envelope): Subscription.File { + const [channel, subscription] = this.subscriptionChannelFromEnvelope(envelope); + const [file, decryptionError] = this.decryptedData(envelope.d); + let errorMessage = decryptionError; + + // Basic file event payload. + const event: Subscription.File = { + channel, + subscription, + timetoken: envelope.p.t, + publisher: envelope.i, + userMetadata: envelope.u, + }; + + if (!file) errorMessage ??= `File information payload is missing.`; + else if (typeof file === 'string') errorMessage ??= `Unexpected file information payload data type.`; + else { + event.message = file.message; + if (file.file) { + event.file = { + id: file.file.id, + name: file.file.name, + url: this.parameters.getFileUrl({ id: file.file.id, name: file.file.name, channel }), + }; + } + } + + if (errorMessage) event.error = errorMessage; + + return event; + } + // endregion + + private subscriptionChannelFromEnvelope(envelope: Envelope): [string, string | null] { + return [envelope.c, envelope.b === undefined || envelope.b === envelope.c ? null : envelope.b]; + } + + /** + * Decrypt provided `data`. + * + * @param [data] - Message or file information which should be decrypted if possible. + * + * @returns Tuple with decrypted data and decryption error (if any). + */ + private decryptedData(data: Payload): [T, string | undefined] { + if (!this.parameters.crypto || typeof data !== 'string') return [data as T, undefined]; + + let payload: Payload | null; + let error: string | undefined; + + try { + const decryptedData = this.parameters.crypto.decrypt(data); + payload = + decryptedData instanceof ArrayBuffer + ? JSON.parse(SubscribeRequest.decoder.decode(decryptedData)) + : decryptedData; + } catch (err) { + payload = null; + error = `Error while decrypting file message content: ${(err as Error).message}`; + } + + return [(payload ?? data) as T, error]; + } +} + +/** + * Subscribe request. + */ +export class SubscribeRequest extends BaseSubscribeRequest { + protected get path(): string { + const { + keySet: { subscribeKey }, + channels, + } = this.parameters; + + return `/v2/subscribe/${subscribeKey}/${encodeString(channels!.length > 0 ? channels!.join(',') : ',')}/0`; + } + + protected get queryParameters(): Query { + const { channelGroups, filterExpression, state, timetoken, region } = this.parameters; + const query: Query = {}; + + if (channelGroups && channelGroups.length > 0) query['channel-group'] = channelGroups.join(','); + if (filterExpression && filterExpression.length > 0) query['filter-expr'] = filterExpression; + if (state && Object.keys(state).length > 0) query['state'] = JSON.stringify(state); + if (typeof timetoken === 'string') { + if (timetoken && timetoken.length > 0) query['tt'] = timetoken; + } else if (timetoken && timetoken > 0) query['tt'] = timetoken; + + if (region) query['tr'] = region; + + return query; + } +} diff --git a/src/core/endpoints/subscriptionUtils/handshake.js b/src/core/endpoints/subscriptionUtils/handshake.js deleted file mode 100644 index 68487c68d..000000000 --- a/src/core/endpoints/subscriptionUtils/handshake.js +++ /dev/null @@ -1,45 +0,0 @@ -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -const endpoint = { - getOperation: () => operationConstants.PNHandshakeOperation, - - validateParams: (_, params) => { - if (!params?.channels && !params?.channelGroups) { - return 'channels and channleGroups both should not be empty'; - } - }, - - getURL: ({ config }, params) => { - const { channels = [] } = params; - const stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return `/v2/subscribe/${config.subscribeKey}/${utils.encodeString(stringifiedChannels)}/0`; - }, - - getRequestTimeout: ({ config }) => config.getSubscribeTimeout(), - - isAuthSupported: () => true, - - prepareParams: (_, params) => { - const outParams = {}; - if (params.channelGroups && params.channelGroups.length > 0) { - outParams['channel-group'] = params.channelGroups.join(','); - } - outParams.tt = 0; - if (params.state) { - outParams.state = JSON.stringify(params.state); - } - if (params.filterExpression && params.filterExpression.length > 0) { - outParams['filter-expr'] = params.filterExpression; - } - outParams.ee = ''; - return outParams; - }, - - handleResponse: (_, response) => ({ - region: response.t.r, - timetoken: response.t.t, - }), -}; - -export default endpoint; diff --git a/src/core/endpoints/subscriptionUtils/handshake.ts b/src/core/endpoints/subscriptionUtils/handshake.ts new file mode 100644 index 000000000..d70494d80 --- /dev/null +++ b/src/core/endpoints/subscriptionUtils/handshake.ts @@ -0,0 +1,39 @@ +/** + * Handshake subscribe REST API module. + */ + +import RequestOperation from '../../constants/operations'; +import { BaseSubscribeRequest } from '../subscribe'; +import { encodeString } from '../../utils'; +import { Query } from '../../types/api'; + +/** + * Handshake subscribe request. + * + * Separate subscribe request required by Event Engine. + */ +export class HandshakeSubscribeRequest extends BaseSubscribeRequest { + operation(): RequestOperation { + return RequestOperation.PNHandshakeOperation; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channels, + } = this.parameters; + + return `/v2/subscribe/${subscribeKey}/${encodeString(channels!.length > 0 ? channels!.join(',') : ',')}/0`; + } + + protected get queryParameters(): Query { + const { channelGroups, filterExpression, state } = this.parameters; + const query: Query = { tt: 0, ee: '' }; + + if (channelGroups && channelGroups.length > 0) query['channel-group'] = channelGroups.join(','); + if (filterExpression && filterExpression.length > 0) query['filter-expr'] = filterExpression; + if (state && Object.keys(state).length > 0) query['state'] = JSON.stringify(state); + + return query; + } +} diff --git a/src/core/endpoints/subscriptionUtils/receiveMessages.js b/src/core/endpoints/subscriptionUtils/receiveMessages.js deleted file mode 100644 index c85a52ab5..000000000 --- a/src/core/endpoints/subscriptionUtils/receiveMessages.js +++ /dev/null @@ -1,76 +0,0 @@ -import operationConstants from '../../constants/operations'; -import utils from '../../utils'; - -const endpoint = { - getOperation: () => operationConstants.PNReceiveMessagesOperation, - - validateParams: (_, params) => { - if (!params?.channels && !params?.channelGroups) { - return 'channels and channleGroups both should not be empty'; - } - if (!params?.timetoken) { - return 'timetoken can not be empty'; - } - if (!params?.region) { - return 'region can not be empty'; - } - }, - - getURL: ({ config }, params) => { - const { channels = [] } = params; - const stringifiedChannels = channels.length > 0 ? channels.join(',') : ','; - return `/v2/subscribe/${config.subscribeKey}/${utils.encodeString(stringifiedChannels)}/0`; - }, - - getRequestTimeout: ({ config }) => config.getSubscribeTimeout(), - - isAuthSupported: () => true, - - getAbortSignal: (_, params) => params.abortSignal, - - prepareParams: (_, params) => { - const outParams = {}; - if (params.channelGroups && params.channelGroups.length > 0) { - outParams['channel-group'] = params.channelGroups.join(','); - } - if (params.filterExpression && params.filterExpression.length > 0) { - outParams['filter-expr'] = params.filterExpression; - } - outParams.tt = params.timetoken; - outParams.tr = params.region; - outParams.ee = ''; - return outParams; - }, - - handleResponse: (_, response) => { - const parsedMessages = []; - - response.m.forEach((envelope) => { - const parsedMessage = { - shard: parseInt(envelope.a, 10), - subscriptionMatch: envelope.b, - channel: envelope.c, - messageType: envelope.e, - payload: envelope.d, - flags: envelope.f, - issuingClientId: envelope.i, - subscribeKey: envelope.k, - originationTimetoken: envelope.o, - publishMetaData: { - timetoken: envelope.p.t, - region: envelope.p.r, - }, - }; - parsedMessages.push(parsedMessage); - }); - return { - messages: parsedMessages, - metadata: { - region: response.t.r, - timetoken: response.t.t, - }, - }; - }, -}; - -export default endpoint; diff --git a/src/core/endpoints/subscriptionUtils/receiveMessages.ts b/src/core/endpoints/subscriptionUtils/receiveMessages.ts new file mode 100644 index 000000000..c50cb015d --- /dev/null +++ b/src/core/endpoints/subscriptionUtils/receiveMessages.ts @@ -0,0 +1,48 @@ +/** + * Receive messages subscribe REST API module. + */ + +import RequestOperation from '../../constants/operations'; +import { BaseSubscribeRequest } from '../subscribe'; +import { encodeString } from '../../utils'; +import { Query } from '../../types/api'; + +/** + * Receive messages subscribe request. + */ +export class ReceiveMessagesSubscribeRequest extends BaseSubscribeRequest { + operation(): RequestOperation { + return RequestOperation.PNReceiveMessagesOperation; + } + + validate(): string | undefined { + const validationResult = super.validate(); + + if (validationResult) return validationResult; + if (!this.parameters.timetoken) return 'timetoken can not be empty'; + if (!this.parameters.region) return 'region can not be empty'; + } + + protected get path(): string { + const { + keySet: { subscribeKey }, + channels, + } = this.parameters; + + return `/v2/subscribe/${subscribeKey}/${encodeString(channels!.length > 0 ? channels!.join(',') : ',')}/0`; + } + + protected get queryParameters(): Query { + const { channelGroups, filterExpression, timetoken, region } = this.parameters; + const query: Query = { ee: '' }; + + if (channelGroups && channelGroups.length > 0) query['channel-group'] = channelGroups.join(','); + if (filterExpression && filterExpression.length > 0) query['filter-expr'] = filterExpression; + if (typeof timetoken === 'string') { + if (timetoken && timetoken.length > 0) query['tt'] = timetoken; + } else if (timetoken && timetoken > 0) query['tt'] = timetoken; + if (region) query['tr'] = region; + + return query; + } +} diff --git a/src/core/endpoints/time.js b/src/core/endpoints/time.js deleted file mode 100644 index f5996c0e4..000000000 --- a/src/core/endpoints/time.js +++ /dev/null @@ -1,32 +0,0 @@ -/* */ -import operationConstants from '../constants/operations'; - -export function getOperation() { - return operationConstants.PNTimeOperation; -} - -export function getURL() { - return '/time/0'; -} - -export function getRequestTimeout({ config }) { - return config.getTransactionTimeout(); -} - -export function prepareParams() { - return {}; -} - -export function isAuthSupported() { - return false; -} - -export function handleResponse(modules, serverResponse) { - return { - timetoken: serverResponse[0], - }; -} - -export function validateParams() { - // pass -} diff --git a/src/core/endpoints/time.ts b/src/core/endpoints/time.ts new file mode 100644 index 000000000..14880795f --- /dev/null +++ b/src/core/endpoints/time.ts @@ -0,0 +1,55 @@ +/** + * Time REST API module. + */ + +import { createValidationError, PubNubError } from '../../models/PubNubError'; +import { TransportResponse } from '../types/transport-response'; +import { AbstractRequest } from '../components/request'; +import RequestOperation from '../constants/operations'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +/** + * Service success response. + */ +export type TimeResponse = { + /** + * High-precision time when published data has been received by the PubNub service. + */ + timetoken: string; +}; + +/** + * Service success response. + */ +type ServiceResponse = [string]; +// endregion + +export class TimeRequest extends AbstractRequest { + constructor() { + super(); + } + + operation(): RequestOperation { + return RequestOperation.PNTimeOperation; + } + + async parse(response: TransportResponse): Promise { + const serviceResponse = this.deserializeResponse(response); + + if (!serviceResponse) + throw new PubNubError( + 'Service response error, check status for details', + createValidationError('Unable to deserialize service response'), + ); + + return { timetoken: serviceResponse[0] }; + } + + protected get path(): string { + return '/time/0'; + } +} diff --git a/src/core/interfaces/configuration.ts b/src/core/interfaces/configuration.ts index 423c3dde3..7bfaa34b0 100644 --- a/src/core/interfaces/configuration.ts +++ b/src/core/interfaces/configuration.ts @@ -1,35 +1,168 @@ -import { FileConstructor } from './file'; -import { TransportKeepAlive } from './transport'; +/** + * {@link PubNub} client configuration module. + */ + +import { PubNubFileConstructor, PubNubFileInterface } from '../types/file'; +import { RequestRetryPolicy } from '../../event-engine/core/retryPolicy'; +import { CryptoModule } from './crypto-module'; +import { KeySet } from '../types/api'; + +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- + +// region Defaults +/** + * Whether secured connection should be used by or not. + */ +const USE_SSL = true; + +/** + * Whether PubNub client should catch up subscription after network issues. + */ +const RESTORE = false; + +/** + * Whether network availability change should be announced with `PNNetworkDownCategory` and + * `PNNetworkUpCategory` state or not. + */ +const AUTO_NETWORK_DETECTION = false; + +/** + * Whether messages should be de-duplicated before announcement or not. + */ +const DEDUPE_ON_SUBSCRIBE = false; + +/** + * Maximum cache which should be used for message de-duplication functionality. + */ +const DEDUPE_CACHE_SIZE = 100; + +/** + * Maximum number of file message publish retries. + */ +const FILE_PUBLISH_RETRY_LIMIT = 5; + +/** + * Whether subscription event engine should be used or not. + */ +const ENABLE_EVENT_ENGINE = false; + +/** + * Whether configured user presence state should be maintained by the PubNub client or not. + */ +const MAINTAIN_PRESENCE_STATE = true; + +/** + * Whether PubNub client should try to utilize existing TCP connection for new requests or not. + */ +const KEEP_ALIVE = false; + +/** + * Whether verbose logging should be enabled or not. + */ +const USE_VERBOSE_LOGGING = false; + +/** + * Whether leave events should be suppressed or not. + */ +const SUPPRESS_LEAVE_EVENTS = false; + +/** + * Whether heartbeat request failure should be announced or not. + */ +const ANNOUNCE_HEARTBEAT_FAILURE = true; + +/** + * Whether heartbeat request success should be announced or not. + */ +const ANNOUNCE_HEARTBEAT_SUCCESS = false; + +/** + * Whether PubNub client instance id should be added to the requests or not. + */ +const USE_INSTANCE_ID = false; -export type PrivateConfigurationOptions = 'platform' | 'sdkFamily' | 'cbor' | 'networking' | 'PubNubFile'; +/** + * Whether unique identifier should be added to the request or not. + */ +const USE_REQUEST_ID = false; /** - * Base platform-less PubNub client configuration. + * Transactional requests timeout. */ -export interface BaseConfiguration { +const TRANSACTIONAL_REQUEST_TIMEOUT = 15; + +/** + * Subscription request timeout. + */ +const SUBSCRIBE_REQUEST_TIMEOUT = 310; + +/** + * Default user presence timeout. + */ +const PRESENCE_TIMEOUT = 300; + +/** + * Minimum user presence timeout. + */ +const PRESENCE_TIMEOUT_MINIMUM = 20; +// endregion + +/** + * Base user-provided PubNub client configuration. + */ +export type UserConfiguration = { /** * Specifies the `subscribeKey` to be used for subscribing to a channel and message publishing. */ subscribeKey: string; + /** + * Specifies the `subscribe_key` to be used for subscribing to a channel and message publishing. + * + * @deprecated Use the {@link subscribeKey} instead. + */ + subscribe_key?: string; + /** * Specifies the `publishKey` to be used for publishing messages to a channel. */ publishKey?: string; /** - * `userId` to use. You should set a unique `userId` to identify the user or the device that - * connects to PubNub. + * Specifies the `publish_key` to be used for publishing messages to a channel. + * + * @deprecated Use the {@link publishKey} instead. + */ + publish_key?: string; + + /** + * Specifies the `secretKey` to be used for request signatures computation. + */ + secretKey?: string; + + /** + * Specifies the `secret_key` to be used for request signatures computation. + * + * @deprecated Use the {@link secretKey} instead. + */ + secret_key?: string; + + /** + * Unique PubNub client user identifier. + * + * Unique `userId` to identify the user or the device that connects to PubNub. * It's a UTF-8 encoded string of up to 64 alphanumeric characters. * - * If you don't set the userId, you won't be able to connect to PubNub. + * If you don't set the `userId`, you won't be able to connect to PubNub. */ userId: string; /** * If Access Manager enabled, this key will be used on all requests. */ - authKey?: string; + authKey?: string | null; /** * Log HTTP information. @@ -50,7 +183,7 @@ export interface BaseConfiguration { * * @default `ps.pndsn.com` */ - origin?: string; + origin?: string | string[]; /** * How long the server will consider the client alive for presence.The value is in seconds. @@ -66,6 +199,24 @@ export interface BaseConfiguration { */ heartbeatInterval?: number; + /** + * Transactional requests timeout in milliseconds. + * + * Maximum duration for which PubNub client should wait for transactional request completion. + * + * @default `15` seconds + */ + transactionalRequestTimeout?: number; + + /** + * Subscription requests timeout in milliseconds. + * + * Maximum duration for which PubNub client should wait for subscription request completion. + * + * @default `310` seconds + */ + subscribeRequestTimeout?: number; + /** * `true` to allow catch up on the front-end applications. * @@ -74,7 +225,7 @@ export interface BaseConfiguration { restore?: boolean; /** - * Whether or not to include the PubNub object instance ID in outgoing requests. + * Whether to include the PubNub object instance ID in outgoing requests. * * @default `false` */ @@ -124,11 +275,13 @@ export interface BaseConfiguration { * - `PubNub.LinearRetryPolicy({ delay, maximumRetry })` * - `PubNub.ExponentialRetryPolicy({ minimumDelay, maximumDelay, maximumRetry })` * - * For more information, refer to {@link /docs/general/setup/connection-management#reconnection-policy|Reconnection Policy}. JavaScript doesn't support excluding endpoints. + * For more information, refer to + * {@link /docs/general/setup/connection-management#reconnection-policy|Reconnection Policy}. JavaScript doesn't + * support excluding endpoints. * * @default `not set` */ - retryConfiguration?: object; + retryConfiguration?: RequestRetryPolicy; /** * Whether the `state` set using `setState()` should be maintained for the current `userId`. @@ -143,7 +296,7 @@ export interface BaseConfiguration { * connects to PubNub. * If you don't set the `UUID`, you won't be able to connect to PubNub. * - * @deprecated Use `userId` instead. + * @deprecated Use {@link userId} instead. */ uuid?: string; @@ -156,45 +309,462 @@ export interface BaseConfiguration { keepAlive?: boolean; /** - * Set a custom parameters for setting your connection `keepAlive` if this is set to `true`. + * If the SDK is running as part of another SDK built atop of it, allow a custom `pnsdk` with + * name and version. */ - keepAliveSettings?: TransportKeepAlive; + sdkName: string; + /** + * If the SDK is operated by a partner, allow a custom `pnsdk` item for them. + */ + partnerId?: string; +}; + +/** + * Extended client configuration. + * + * Extended configuration contains unannounced configuration options. + */ +export type ExtendedConfiguration = UserConfiguration & { + /** + * PubNub Account key set. + */ + keySet: KeySet; + + /** + * Real-time updates filtering expression. + */ + filterExpression?: string | null; + + /** + * Whether messages should be de-duplicated on subscribe before announcement or not. + * + * @default `false` + */ + dedupeOnSubscribe: boolean; + + /** + * Maximum size of deduplication manager cache. + */ + maximumCacheSize: number; + + /** + * Whether unique request identifier should be used in request query or not. + * + * @default `false` + */ + useRequestId?: boolean; + + /** + * Whether heartbeat request success should be announced or not. + * + * @default `false` + */ + announceSuccessfulHeartbeats: boolean; + + /** + * Whether heartbeat request failure should be announced or not. + * + * @default `true` + */ + announceFailedHeartbeats: boolean; + + /** + * How many times file message publish attempt should be retried. + * + * @default `5` + */ + fileUploadPublishRetryLimit: number; +}; + +/** + * Platform-specific PubNub client configuration. + * + * Part of configuration which is added by platform-specific PubNub client initialization code. + */ +export type PlatformConfiguration = { /** * Track of the SDK family for identifier generator. */ sdkFamily: string; /** - * If the SDK is running as part of another SDK built atop of it, allow a custom pnsdk with - * name and version. + * The cryptography module used for encryption and decryption of messages and files. Takes the + * {@link cipherKey} and {@link useRandomIVs} parameters as arguments. + * + * For more information, refer to the + * {@link /docs/sdks/javascript/api-reference/configuration#cryptomodule|cryptoModule} section. + * + * @default `not set` */ - sdkName: string; + cryptoModule?: CryptoModule; /** - * If the SDK is operated by a partner, allow a custom pnsdk item for them. + * Platform-specific file representation */ - partnerId?: string; + /* eslint-disable @typescript-eslint/no-explicit-any */ + PubNubFile?: PubNubFileConstructor; - // ------------------- Web-specific configuration ------------------- + // region Deprecated parameters + /** + * If passed, will encrypt the payloads. + * + * @deprecated Pass it to `cryptoModule` instead. + */ + cipherKey?: string; /** - * If the browser fails to detect the network changes from WiFi to LAN and vice versa or you - * get reconnection issues, set the flag to `false`. This allows the SDK reconnection logic to - * take over. + * When `true` the initialization vector (IV) is random for all requests (not just for file + * upload). + * When `false` the IV is hard-coded for all requests except for file upload. * * @default `true` + * + * @deprecated Pass it to `cryptoModule` instead. */ - listenToBrowserNetworkEvents?: boolean; + useRandomIVs?: boolean; - // ------------------- Node-specific configuration ------------------- + /** + * Custom data encryption method. + * + * @deprecated Instead use {@link cryptoModule} for data encryption. + */ + customEncrypt?: (data: string) => string; - networking: any; + /** + * Custom data decryption method. + * + * @deprecated Instead use {@link cryptoModule} for data decryption. + */ + customDecrypt?: (data: string) => string; + // endregion +}; - cbor: any; +/** + * User-provided configuration object interface. + * + * Interface contains limited set of settings manipulation and access. + */ +export interface ClientConfiguration { + /** + * Get a PubNub client user identifier. + * + * @returns Current PubNub client user identifier. + */ + getUserId(): string; /** - * Platform-specific file representation + * Change the current PubNub client user identifier. + * + * **Important:** Change won't affect ongoing REST API calls. + * + * @param value - New PubNub client user identifier. + * + * @throws Error empty user identifier has been provided. + */ + setUserId(value: string): void; + + /** + * Change REST API endpoint access authorization key. + * + * @param authKey - New authorization key which should be used with new requests. + */ + setAuthKey(authKey: string | null): void; + + /** + * Real-time updates filtering expression. + * + * @returns Filtering expression. + */ + getFilterExpression(): string | undefined | null; + + /** + * Update real-time updates filtering expression. + * + * @param expression - New expression which should be used or `undefined` to disable filtering. + */ + setFilterExpression(expression: string | null | undefined): void; + + /** + * Change data encryption / decryption key. + * + * @param key - New key which should be used for data encryption / decryption. + */ + setCipherKey(key: string | undefined): void; + + /** + * Get PubNub SDK version. + * + * @returns Current SDK version. + */ + get version(): string; + + /** + * Get PubNub SDK version. + * + * @returns Current SDK version. + */ + getVersion(): string; + + /** + * Add framework's prefix. + * + * @param name - Name of the framework which would want to add own data into `pnsdk` suffix. + * @param suffix - Suffix with information about framework. */ - PubNubFile: FileConstructor; + _addPnsdkSuffix(name: string, suffix: string | number): void; + + // -------------------------------------------------------- + // ---------------------- Deprecated ---------------------- + // -------------------------------------------------------- + // region Deprecated + + /** + * Get a PubNub client user identifier. + * + * @returns Current PubNub client user identifier. + * + * @deprecated Use the {@link getUserId} or {@link userId} getter instead. + */ + getUUID(): string; + + /** + * Change the current PubNub client user identifier. + * + * **Important:** Change won't affect ongoing REST API calls. + * + * @param value - New PubNub client user identifier. + * + * @returns {Configuration} Reference to the configuration instance for easier chaining. + * + * @throws Error empty user identifier has been provided. + * + * @deprecated Use the {@link setUserId} or {@link userId} setter instead. + */ + setUUID(value: string): void; + // endregion } + +/** + * Internal PubNub client configuration object interface. + */ +export interface PrivateClientConfiguration + extends ClientConfiguration, + Omit { + /** + * REST API endpoint access authorization key. + * + * It is required to have `authorization key` with required permissions to access REST API + * endpoints when `PAM` enabled for user key set. + */ + getAuthKey(): string | undefined | null; + + /** + * Data encryption / decryption module. + * + * @returns Data processing crypto module (if set). + */ + get cryptoModule(): CryptoModule | undefined; + + /** + * Retrieve user's presence timeout. + * + * @returns User's presence timeout value. + */ + getPresenceTimeout(): number; + + /** + * Retrieve heartbeat requests interval. + * + * @returns Heartbeat requests interval. + */ + getHeartbeatInterval(): number | undefined; + + /** + * Change heartbeat requests interval. + * + * @param interval - New presence request heartbeat intervals. + */ + setHeartbeatInterval(interval: number): void; + + /** + * Transactional request timeout. + * + * @returns Maximum duration in milliseconds for which PubNub client should wait for + * transactional request completion. + */ + getTransactionTimeout(): number; + + /** + * Subscription requests timeout. + * + * @returns Maximum duration in milliseconds for which PubNub client should wait for + * subscription request completion. + */ + getSubscribeTimeout(): number; + + /** + * PubNub file object constructor. + */ + get PubNubFile(): PubNubFileConstructor | undefined; + + /** + * Get PubNub client instance identifier. + * + * @returns Current PubNub client instance identifier. + */ + get instanceId(): string | undefined; + + /** + * Get SDK family identifier. + * + * @returns Current SDK family identifier. + */ + get sdkFamily(): string; + + /** + * Compose `pnsdk` suffix string. + * + * @param separator - String which will be used to join registered suffixes. + * + * @returns Concatenated `pnsdk` suffix string. + */ + _getPnsdkSuffix(separator: string): string; + + // -------------------------------------------------------- + // ---------------------- Deprecated ---------------------- + // -------------------------------------------------------- + // region Deprecated + + /** + * If passed, will encrypt the payloads. + * + * @deprecated Pass it to `cryptoModule` instead. + */ + get cipherKey(): string | undefined; + + /** + * When `true` the initialization vector (IV) is random for all requests (not just for file + * upload). + * When `false` the IV is hard-coded for all requests except for file upload. + * + * @default `true` + * + * @deprecated Pass it to `cryptoModule` instead. + */ + get useRandomIVs(): boolean | undefined; + + /** + * Custom data encryption method. + * + * @deprecated Instead use {@link cryptoModule} for data encryption. + */ + get customEncrypt(): ((data: string) => string) | undefined; + + /** + * Custom data decryption method. + * + * @deprecated Instead use {@link cryptoModule} for data decryption. + */ + get customDecrypt(): ((data: string) => string) | undefined; + + // endregion +} + +/** + * Apply configuration default values. + * + * @param configuration - User-provided configuration. + */ +export const setDefaults = (configuration: UserConfiguration): ExtendedConfiguration => { + // Copy configuration. + const configurationCopy = { ...configuration }; + configurationCopy.logVerbosity ??= USE_VERBOSE_LOGGING; + configurationCopy.ssl ??= USE_SSL; + configurationCopy.transactionalRequestTimeout ??= TRANSACTIONAL_REQUEST_TIMEOUT; + configurationCopy.subscribeRequestTimeout ??= SUBSCRIBE_REQUEST_TIMEOUT; + configurationCopy.restore ??= RESTORE; + configurationCopy.useInstanceId ??= USE_INSTANCE_ID; + configurationCopy.suppressLeaveEvents ??= SUPPRESS_LEAVE_EVENTS; + configurationCopy.requestMessageCountThreshold ??= DEDUPE_CACHE_SIZE; + configurationCopy.autoNetworkDetection ??= AUTO_NETWORK_DETECTION; + configurationCopy.enableEventEngine ??= ENABLE_EVENT_ENGINE; + configurationCopy.maintainPresenceState ??= MAINTAIN_PRESENCE_STATE; + configurationCopy.keepAlive ??= KEEP_ALIVE; + + // Generate default origin subdomains. + if (!configurationCopy.origin) + configurationCopy.origin = Array.from({ length: 20 }, (_, i) => `ps${i + 1}.pndsn.com`); + + const keySet: KeySet = { + subscribeKey: configurationCopy.subscribeKey, + publishKey: configurationCopy.publishKey, + secretKey: configurationCopy.secretKey, + }; + + if (configurationCopy.presenceTimeout && configurationCopy.presenceTimeout < PRESENCE_TIMEOUT_MINIMUM) { + configurationCopy.presenceTimeout = PRESENCE_TIMEOUT_MINIMUM; + // eslint-disable-next-line no-console + console.log('WARNING: Presence timeout is less than the minimum. Using minimum value: ', PRESENCE_TIMEOUT_MINIMUM); + } + if (configurationCopy.presenceTimeout) { + configurationCopy.heartbeatInterval = configurationCopy.presenceTimeout / 2 - 1; + } else configurationCopy.presenceTimeout = PRESENCE_TIMEOUT; + + // Apply extended configuration defaults. + let announceSuccessfulHeartbeats = ANNOUNCE_HEARTBEAT_SUCCESS; + let announceFailedHeartbeats = ANNOUNCE_HEARTBEAT_FAILURE; + let fileUploadPublishRetryLimit = FILE_PUBLISH_RETRY_LIMIT; + let dedupeOnSubscribe = DEDUPE_ON_SUBSCRIBE; + const maximumCacheSize = DEDUPE_CACHE_SIZE; + let useRequestId = USE_REQUEST_ID; + + // @ts-expect-error Not documented legacy configuration options. + if (configurationCopy.dedupeOnSubscribe && typeof configurationCopy.dedupeOnSubscribe === 'boolean') { + // @ts-expect-error Not documented legacy configuration options. + dedupeOnSubscribe = configurationCopy.dedupeOnSubscribe; + } + + // @ts-expect-error Not documented legacy configuration options. + if (configurationCopy.useRequestId && typeof configurationCopy.useRequestId === 'boolean') { + // @ts-expect-error Not documented legacy configuration options. + useRequestId = configurationCopy.useRequestId; + } + + if ( + // @ts-expect-error Not documented legacy configuration options. + configurationCopy.announceSuccessfulHeartbeats && + // @ts-expect-error Not documented legacy configuration options. + typeof configurationCopy.announceSuccessfulHeartbeats === 'boolean' + ) { + // @ts-expect-error Not documented legacy configuration options. + announceSuccessfulHeartbeats = configurationCopy.announceSuccessfulHeartbeats; + } + + // @ts-expect-error Not documented legacy configuration options. + if (configurationCopy.announceFailedHeartbeats && typeof configurationCopy.announceFailedHeartbeats === 'boolean') { + // @ts-expect-error Not documented legacy configuration options. + announceFailedHeartbeats = configurationCopy.announceFailedHeartbeats; + } + + if ( + // @ts-expect-error Not documented legacy configuration options. + configurationCopy.fileUploadPublishRetryLimit && + // @ts-expect-error Not documented legacy configuration options. + typeof configurationCopy.fileUploadPublishRetryLimit === 'number' + ) { + // @ts-expect-error Not documented legacy configuration options. + fileUploadPublishRetryLimit = configurationCopy.fileUploadPublishRetryLimit; + } + + return { + ...configurationCopy, + keySet, + dedupeOnSubscribe, + maximumCacheSize, + useRequestId, + announceSuccessfulHeartbeats, + announceFailedHeartbeats, + fileUploadPublishRetryLimit, + }; +}; diff --git a/src/core/interfaces/crypto-module.ts b/src/core/interfaces/crypto-module.ts index 8f5aec34c..74e21341e 100644 --- a/src/core/interfaces/crypto-module.ts +++ b/src/core/interfaces/crypto-module.ts @@ -1,3 +1,13 @@ +/** + * Crypto module. + */ + +import { PubNubFileConstructor, PubNubFileInterface } from '../types/file'; +import { Payload } from '../types/api'; + +/** + * Crypto module configuration. + */ export type CryptoModuleConfiguration = { default: C; cryptors?: C[]; @@ -7,31 +17,128 @@ export type CryptorConfiguration = { /** * Data encryption / decryption key. */ - cipherKey: string; + cipherKey?: string; + + /** + * Request sign secret key. + */ + secretKey?: string; /** * Whether random initialization vector should be used or not. + * + * @default `true` */ useRandomIVs?: boolean; + + /** + * Custom data encryption method. + * + * @deprecated Instead use {@link cryptoModule} for data encryption. + */ + get customEncrypt(): ((data: string) => string) | undefined; + + /** + * Custom data decryption method. + * + * @deprecated Instead use {@link cryptoModule} for data decryption. + */ + get customDecrypt(): ((data: string) => string) | undefined; }; -export abstract class CryptoModule { +/** + * Base crypto module interface. + */ +export interface CryptoModule { + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + // region Encryption + + /** + * Encrypt data. + * + * @param data - Data which should be encrypted using `CryptoModule`. + * + * @returns Data encryption result. + */ + encrypt(data: ArrayBuffer | string): ArrayBuffer | string; + + /** + * Encrypt file object. + * + * @param file - File object with data for encryption. + * @param File - File object constructor to create instance for encrypted data representation. + * + * @returns Asynchronous file encryption result. + */ + encryptFile( + file: PubNubFileInterface, + /* eslint-disable @typescript-eslint/no-explicit-any */ + File: PubNubFileConstructor, + ): Promise; + // endregion + + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + // region Decryption + + /** + * Encrypt data. + * + * @param data - Dta which should be encrypted using `CryptoModule`. + * + * @returns Data decryption result. + */ + decrypt(data: ArrayBuffer | string): ArrayBuffer | Payload | null; + + /** + * Decrypt file object. + * + * @param file - Encrypted file object with data for decryption. + * @param File - File object constructor to create instance for decrypted data representation. + * + * @returns Asynchronous file decryption result. + */ + decryptFile( + file: PubNubFileInterface, + /* eslint-disable @typescript-eslint/no-explicit-any */ + File: PubNubFileConstructor, + ): Promise; + // endregion +} + +export abstract class AbstractCryptoModule implements CryptoModule { + /** + * `String` to {@link ArrayBuffer} response decoder. + */ + protected static encoder = new TextEncoder(); + + /** + * {@link ArrayBuffer} to {@link string} decoder. + */ + protected static decoder = new TextDecoder(); + defaultCryptor: C; cryptors: C[]; - protected constructor(configuration: CryptoModuleConfiguration) { - this.defaultCryptor = configuration.default; - this.cryptors = configuration.cryptors ?? []; - } + // -------------------------------------------------------- + // --------------- Convenience functions ------------------ + // -------------------------------------------------------- + // region Convenience functions /** * Construct crypto module with legacy cryptor for encryption and both legacy and AES-CBC * cryptors for decryption. * * @param config Cryptors configuration options. - * @returns {CryptoModule} Crypto module which encrypts data using legacy cryptor. + * + * @returns Crypto module which encrypts data using legacy cryptor. + * + * @throws Error if `config.cipherKey` not set. */ - static legacyCryptoModule(config: CryptorConfiguration): CryptoModule { + static legacyCryptoModule(config: CryptorConfiguration): CryptoModule { throw new Error('Should be implemented by concrete crypto module implementation.'); } @@ -40,23 +147,89 @@ export abstract class CryptoModule { * cryptors for decryption. * * @param config Cryptors configuration options. - * @returns {CryptoModule} Crypto module which encrypts data using AES-CBC cryptor. + * + * @returns Crypto module which encrypts data using AES-CBC cryptor. + * + * @throws Error if `config.cipherKey` not set. */ - static aesCbcCryptoModule(config: CryptorConfiguration): CryptoModule { + static aesCbcCryptoModule(config: CryptorConfiguration): CryptoModule { throw new Error('Should be implemented by concrete crypto module implementation.'); } + // endregion - static withDefaultCryptor(cryptor: C): CryptoModule { - throw new Error('Should be implemented by concrete crypto module implementation.'); + constructor(configuration: CryptoModuleConfiguration) { + this.defaultCryptor = configuration.default; + this.cryptors = configuration.cryptors ?? []; } - abstract encrypt(data: ArrayBuffer | string); + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + // region Encryption + + /** + * Encrypt data. + * + * @param data - Data which should be encrypted using {@link CryptoModule}. + * + * @returns Data encryption result. + */ + abstract encrypt(data: ArrayBuffer | string): ArrayBuffer | string; + + /** + * Encrypt file object. + * + * @param file - File object with data for encryption. + * @param File - File object constructor to create instance for encrypted data representation. + * + * @returns Asynchronous file encryption result. + */ + abstract encryptFile( + file: PubNubFileInterface, + /* eslint-disable @typescript-eslint/no-explicit-any */ + File: PubNubFileConstructor, + ): Promise; + // endregion + + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + // region Decryption + + /** + * Encrypt data. + * + * @param data - Dta which should be encrypted using `CryptoModule`. + * + * @returns Data decryption result. + */ + abstract decrypt(data: ArrayBuffer | string): ArrayBuffer | Payload | null; + + /** + * Decrypt file object. + * + * @param file - Encrypted file object with data for decryption. + * @param File - File object constructor to create instance for decrypted data representation. + * + * @returns Asynchronous file decryption result. + */ + abstract decryptFile( + file: PubNubFileInterface, + /* eslint-disable @typescript-eslint/no-explicit-any */ + File: PubNubFileConstructor, + ): Promise; + // endregion + + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + // region Helpers /** * Retrieve list of module's cryptors. - * @protected */ protected getAllCryptors() { return [this.defaultCryptor, ...this.cryptors]; } + // endregion } diff --git a/src/core/interfaces/cryptography.ts b/src/core/interfaces/cryptography.ts new file mode 100644 index 000000000..5e859c656 --- /dev/null +++ b/src/core/interfaces/cryptography.ts @@ -0,0 +1,70 @@ +/** + * Legacy Cryptography module interface. + */ + +import { PubNubFileConstructor, PubNubFileInterface } from '../types/file'; + +export interface Cryptography { + // region Encryption + /** + * Encrypt provided source data using specific encryption {@link key}. + * + * @param key - Data encryption key.
**Note:** Same key should be used to `decrypt` data. + * @param input - Source data for encryption. + * + * @returns Encrypted data as object or stream (depending on from source data type). + * + * @throws Error if unknown data type has been passed. + */ + encrypt(key: string, input: Types): Promise; + + /** + * Decrypt provided encrypted data using specific decryption {@link key}. + * + * @param key - Data decryption key.
**Note:** Should be the same as used to `encrypt` data. + * @param input - Encrypted data for decryption. + * + * @returns Decrypted data as object or stream (depending on from encrypted data type). + * + * @throws Error if unknown data type has been passed. + */ + decrypt(key: string, input: Types): Promise; + + /** + * Encrypt provided `PubNub` File object using specific encryption {@link key}. + * + * @param key - Key for `PubNub` File object encryption.
**Note:** Same key should be + * used to `decrypt` data. + * @param file - Source `PubNub` File object for encryption. + * @param File - Class constructor for `PubNub` File object. + * + * @returns Encrypted data as `PubNub` File object. + * + * @throws Error if file is empty or contains unsupported data type. + */ + encryptFile( + key: string, + file: PubNubFileInterface, + /* eslint-disable @typescript-eslint/no-explicit-any */ + File: PubNubFileConstructor, + ): Promise; + + /** + * Decrypt provided `PubNub` File object using specific decryption {@link key}. + * + * @param key - Key for `PubNub` File object decryption.
**Note:** Should be the same + * as used to `encrypt` data. + * @param file - Encrypted `PubNub` File object for decryption. + * @param File - Class constructor for `PubNub` File object. + * + * @returns Decrypted data as `PubNub` File object. + * + * @throws Error if file is empty or contains unsupported data type. + */ + decryptFile( + key: string, + file: PubNubFileInterface, + /* eslint-disable @typescript-eslint/no-explicit-any */ + File: PubNubFileConstructor, + ): Promise; +} diff --git a/src/core/interfaces/file.ts b/src/core/interfaces/file.ts deleted file mode 100644 index 89e9335aa..000000000 --- a/src/core/interfaces/file.ts +++ /dev/null @@ -1,137 +0,0 @@ -// Placeholder for Node.js-specific types, defaulting to `unknown` if not available -type NodeReadable = 'Readable' extends keyof typeof import('stream') ? import('stream').Readable : unknown; -type NodeBuffer = 'Buffer' extends keyof typeof import('buffer') ? import('buffer').Buffer : unknown; - -// Placeholder for web-specific types, defaulting to `unknown` if not available -type MaybeTypedArray = typeof Uint8Array !== 'undefined' ? Uint8Array : unknown; -type WebArrayBuffer = typeof ArrayBuffer extends undefined ? unknown : ArrayBuffer; -type WebBlob = typeof Blob extends undefined ? unknown : Blob; -type WebFile = typeof File extends undefined ? unknown : File; - -export type FileObject = - | WebFile - | { data: (ArrayBufferView | WebArrayBuffer | WebBlob | string)[]; name: string; mimeType?: string } - | { stream?: NodeReadable; data?: NodeBuffer | string, encoding: string; name: string, mimeType?: string }; - -/** - * Represents a class definition for creating file representation objects. - * @typedef {Object} FileConstructor - * @property {function} new - File representation object constructor. - */ -export type FileConstructor = { - /** - * Create file representation object. - * - * @param file - User-provided data for file object. - * @returns Initialized file object instance. - */ - new (file: FileObject): FileInterface; -}; - -/** - * File representation interface. - */ -export interface FileInterface { - /** - * Whether platform natively supports `File`. - */ - supportsFile(): boolean; - - /** - * Whether platform natively supports `Blob`. - */ - supportsBlob(): boolean; - - /** - * Whether platform natively supports `ArrayBuffer`. - */ - supportsArrayBuffer(): boolean; - - /** - * Whether platform natively supports `Buffer`. - */ - supportsBuffer(): boolean; - - /** - * Whether platform natively supports `Stream`. - */ - supportsStream(): boolean; - - /** - * Whether platform natively supports `String`. - */ - supportsString(): boolean; - - /** - * Whether platform supports file encryption. - */ - supportsEncryptFile(): boolean; - - /** - * Whether platform natively supports file `Uri`. - */ - supportsFileUri(): boolean; - - /** - * Represent file object content as `buffer`. - * - * @throws Error if feature not supported on the target platform. - * - * @returns File content as `buffer`. - */ - toBuffer(): Promise; - - /** - * Represent file object content as `stream`. - * - * @throws Error if feature not supported on the target platform. - * - * @returns File content as `stream`. - */ - toStream(): Promise; - - /** - * Represent file object content as file `Uri`. - * - * @throws Error if feature not supported on the target platform. - * - * @returns File content as file `Uri`. - */ - toFileUri(): Promise; - - /** - * Represent file object content as `Blob`. - * - * @throws Error if feature not supported on the target platform. - * - * @returns File content as `Blob`. - */ - toBlob(): Promise; - - /** - * Represent file object content as `ArrayBuffer`. - * - * @throws Error if feature not supported on the target platform. - * - * @returns File content as `ArrayBuffer`. - */ - toArrayBuffer(): Promise; - - /** - * Represent file object content as `string`. - * - * @throws Error if feature not supported on the target platform. - * - * @returns File content as `string`. - */ - toString(): Promise; - - /** - * Represent file object content as `File`. - * - * @throws Error if feature not supported on the target platform. - * - * @returns File content as `File`. - */ - toFile(): Promise; -} diff --git a/src/core/interfaces/request.ts b/src/core/interfaces/request.ts new file mode 100644 index 000000000..77168006f --- /dev/null +++ b/src/core/interfaces/request.ts @@ -0,0 +1,38 @@ +import { TransportResponse } from '../types/transport-response'; +import { TransportRequest } from '../types/transport-request'; +import RequestOperation from '../constants/operations'; + +/** + * General REST API call request interface. + */ +export interface Request { + /** + * Type of request operation. + * + * PubNub REST API endpoint which will be called with request. + */ + operation(): RequestOperation; + + /** + * Validate provided request parameters. + * + * @returns Error message if request can't be sent without missing or malformed parameters. + */ + validate(): string | undefined; + + /** + * Compile all parameters into transparent data type. + * + * @returns Transport request which can be processed by the network layer. + */ + request(): TransportRequest; + + /** + * Process service response. + * + * @param [response] Successful request response from the service. + * + * @returns Service response mapped to the expected data type or `undefined` in case of error. + */ + parse(response: TransportResponse): Promise; +} diff --git a/src/core/interfaces/transport.ts b/src/core/interfaces/transport.ts index ca88c4850..701053900 100644 --- a/src/core/interfaces/transport.ts +++ b/src/core/interfaces/transport.ts @@ -1,5 +1,5 @@ -import {TransportRequest} from "../types/transport-request"; -import {TransportResponse} from "../types/transport-response"; +import { CancellationController, TransportRequest } from '../types/transport-request'; +import { TransportResponse } from '../types/transport-response'; /** * Represents the configuration options for keeping the transport connection alive. @@ -32,7 +32,7 @@ export type TransportKeepAlive = { * @default 30000 */ timeout?: number; -} +}; /** * This interface is used to send requests to the PubNub API. @@ -44,10 +44,24 @@ export type TransportKeepAlive = { */ export interface Transport { /** - * Async send method for handling transport requests. + * Make request sendable. * * @param req - The transport request to be processed. - * @returns - A promise that resolves to a transport response. + * + * @returns - A promise that resolves to a transport response and request cancellation + * controller (if required). */ - send(req: TransportRequest): Promise; -} \ No newline at end of file + makeSendable(req: TransportRequest): [Promise, CancellationController | undefined]; + + /** + * Pre-processed request. + * + * Transport implementation may pre-process original transport requests before making + * platform-specific request objects from it. + * + * @param req - Transport request provided by the PubNub client. + * + * @returns Transport request with updated properties (if it was required). + */ + request(req: TransportRequest): TransportRequest; +} diff --git a/src/core/pubnub-channel-groups.ts b/src/core/pubnub-channel-groups.ts new file mode 100644 index 000000000..ea50e1ea1 --- /dev/null +++ b/src/core/pubnub-channel-groups.ts @@ -0,0 +1,222 @@ +/** + * PubNub Channel Groups API module. + */ + +import { RemoveChannelGroupChannelsRequest } from './endpoints/channel_groups/remove_channels'; +import { KeySet, ResultCallback, SendRequestFunction, StatusCallback } from './types/api'; +import { AddChannelGroupChannelsRequest } from './endpoints/channel_groups/add_channels'; +import { ListChannelGroupChannels } from './endpoints/channel_groups/list_channels'; +import { DeleteChannelGroupRequest } from './endpoints/channel_groups/delete_group'; +import { ListChannelGroupsRequest } from './endpoints/channel_groups/list_groups'; +import * as ChannelGroups from './types/api/channel-groups'; + +export default class PubnubChannelGroups { + constructor( + private readonly keySet: KeySet, + /* eslint-disable @typescript-eslint/no-explicit-any */ + private readonly sendRequest: SendRequestFunction, + ) {} + + // -------------------------------------------------------- + // ---------------------- Audit API ----------------------- + // -------------------------------------------------------- + // region Audit API + + /** + * Fetch channel group channels. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public listChannels( + parameters: ChannelGroups.ListChannelGroupChannelsParameters, + callback: ResultCallback, + ): void; + + /** + * Fetch channel group channels. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous get channel group channels response. + */ + public async listChannels( + parameters: ChannelGroups.ListChannelGroupChannelsParameters, + ): Promise; + + /** + * Fetch channel group channels. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get channel group channels response or `void` in case if `callback` + * provided. + */ + public async listChannels( + parameters: ChannelGroups.ListChannelGroupChannelsParameters, + callback?: ResultCallback, + ): Promise { + const request = new ListChannelGroupChannels({ ...parameters, keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + + // region Deprecated + /** + * Fetch all channel groups. + * + * @param callback - Request completion handler callback. + * + * @deprecated + */ + public listGroups(callback: ResultCallback): void; + + /** + * Fetch all channel groups. + * + * @returns Asynchronous get all channel groups response. + * + * @deprecated + */ + public async listGroups(): Promise; + + /** + * Fetch all channel groups. + * + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get all channel groups response or `void` in case if `callback` provided. + * + * @deprecated + */ + public async listGroups( + callback?: ResultCallback, + ): Promise { + const request = new ListChannelGroupsRequest({ keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + // endregion + + // -------------------------------------------------------- + // ---------------------- Manage API ---------------------- + // -------------------------------------------------------- + // region Manage API + + /** + * Add channels to the channel group. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public addChannels(parameters: ChannelGroups.ManageChannelGroupChannelsParameters, callback: StatusCallback): void; + + /** + * Add channels to the channel group. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous add channels to the channel group response. + */ + public async addChannels( + parameters: ChannelGroups.ManageChannelGroupChannelsParameters, + ): Promise>; + + /** + * Add channels to the channel group. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous add channels to the channel group response or `void` in case if + * `callback` provided. + */ + public async addChannels( + parameters: ChannelGroups.ManageChannelGroupChannelsParameters, + callback?: StatusCallback, + ): Promise | void> { + const request = new AddChannelGroupChannelsRequest({ ...parameters, keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + + /** + * Remove channels from the channel group. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public removeChannels(parameters: ChannelGroups.ManageChannelGroupChannelsParameters, callback: StatusCallback): void; + + /** + * Remove channels from the channel group. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous remove channels from the channel group response. + */ + public async removeChannels( + parameters: ChannelGroups.ManageChannelGroupChannelsParameters, + ): Promise>; + + /** + * Remove channels from the channel group. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous remove channels from the channel group response or `void` in + * case if `callback` provided. + */ + public async removeChannels( + parameters: ChannelGroups.ManageChannelGroupChannelsParameters, + callback?: StatusCallback, + ): Promise | void> { + const request = new RemoveChannelGroupChannelsRequest({ ...parameters, keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + + /** + * Remove channel group. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public deleteGroup(parameters: ChannelGroups.DeleteChannelGroupParameters, callback: StatusCallback): void; + + /** + * Remove channel group. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous remove channel group response. + */ + public async deleteGroup(parameters: ChannelGroups.DeleteChannelGroupParameters): Promise>; + + /** + * Remove channel group. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous remove channel group response or `void` in case if `callback` provided. + */ + public async deleteGroup( + parameters: ChannelGroups.DeleteChannelGroupParameters, + callback?: StatusCallback, + ): Promise | void> { + const request = new DeleteChannelGroupRequest({ ...parameters, keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + + // endregion +} diff --git a/src/core/pubnub-common.js b/src/core/pubnub-common.js deleted file mode 100644 index 3aa12932e..000000000 --- a/src/core/pubnub-common.js +++ /dev/null @@ -1,847 +0,0 @@ -import Config from './components/config'; -import Crypto from './components/cryptography/index'; -import { encode } from './components/base64_codec'; -import SubscriptionManager from './components/subscription_manager'; -import TelemetryManager from './components/telemetry_manager'; -import NotificationsPayload from './components/push_payload'; -import ListenerManager from './components/listener_manager'; -import TokenManager from './components/token_manager'; - -import endpointCreator from './components/endpoint'; - -import * as addChannelsChannelGroupConfig from './endpoints/channel_groups/add_channels'; -import * as removeChannelsChannelGroupConfig from './endpoints/channel_groups/remove_channels'; -import * as deleteChannelGroupConfig from './endpoints/channel_groups/delete_group'; -import * as listChannelGroupsConfig from './endpoints/channel_groups/list_groups'; -import * as listChannelsInChannelGroupConfig from './endpoints/channel_groups/list_channels'; - -import * as addPushChannelsConfig from './endpoints/push/add_push_channels'; -import * as removePushChannelsConfig from './endpoints/push/remove_push_channels'; -import * as listPushChannelsConfig from './endpoints/push/list_push_channels'; -import * as removeDevicePushConfig from './endpoints/push/remove_device'; - -import * as presenceLeaveEndpointConfig from './endpoints/presence/leave'; -import * as presenceWhereNowEndpointConfig from './endpoints/presence/where_now'; -import * as presenceHeartbeatEndpointConfig from './endpoints/presence/heartbeat'; -import * as presenceGetStateConfig from './endpoints/presence/get_state'; -import * as presenceSetStateConfig from './endpoints/presence/set_state'; -import * as presenceHereNowConfig from './endpoints/presence/here_now'; - -// Actions API - -import * as addMessageActionEndpointConfig from './endpoints/actions/add_message_action'; -import * as removeMessageActionEndpointConfig from './endpoints/actions/remove_message_action'; -import * as getMessageActionEndpointConfig from './endpoints/actions/get_message_actions'; - -// File Upload API v1 - -import listFilesEndpointConfig from './endpoints/file_upload/list_files'; -import generateUploadUrlEndpointConfig from './endpoints/file_upload/generate_upload_url'; -import publishFileEndpointConfig from './endpoints/file_upload/publish_file'; -import sendFileFunction from './endpoints/file_upload/send_file'; -import getFileUrlFunction from './endpoints/file_upload/get_file_url'; -import downloadFileEndpointConfig from './endpoints/file_upload/download_file'; -import deleteFileEndpointConfig from './endpoints/file_upload/delete_file'; - -// Object API v2 -import getAllUUIDMetadataEndpointConfig from './endpoints/objects/uuid/get_all'; - -import getUUIDMetadataEndpointConfig from './endpoints/objects/uuid/get'; - -import setUUIDMetadataEndpointConfig from './endpoints/objects/uuid/set'; - -import removeUUIDMetadataEndpointConfig from './endpoints/objects/uuid/remove'; - -import getAllChannelMetadataEndpointConfig from './endpoints/objects/channel/get_all'; - -import getChannelMetadataEndpointConfig from './endpoints/objects/channel/get'; - -import setChannelMetadataEndpointConfig from './endpoints/objects/channel/set'; - -import removeChannelMetadataEndpointConfig from './endpoints/objects/channel/remove'; - -import getMembersV2EndpointConfig from './endpoints/objects/member/get'; - -import setMembersV2EndpointConfig from './endpoints/objects/member/set'; - -import getMembershipsV2EndpointConfig from './endpoints/objects/membership/get'; - -import setMembershipsV2EndpointConfig from './endpoints/objects/membership/set'; - -import * as auditEndpointConfig from './endpoints/access_manager/audit'; -import * as grantEndpointConfig from './endpoints/access_manager/grant'; -import * as grantTokenEndpointConfig from './endpoints/access_manager/grant_token'; -import revokeTokenEndpointConfig from './endpoints/access_manager/revoke_token'; - -import * as publishEndpointConfig from './endpoints/publish'; -import * as signalEndpointConfig from './endpoints/signal'; -import * as historyEndpointConfig from './endpoints/history/get_history'; -import * as deleteMessagesEndpointConfig from './endpoints/history/delete_messages'; -import * as messageCountsEndpointConfig from './endpoints/history/message_counts'; -import * as fetchMessagesEndpointConfig from './endpoints/fetch_messages'; -import * as timeEndpointConfig from './endpoints/time'; -import * as subscribeEndpointConfig from './endpoints/subscribe'; - -// subscription utilities -import handshakeEndpointConfig from './endpoints/subscriptionUtils/handshake'; -import receiveMessagesConfig from './endpoints/subscriptionUtils/receiveMessages'; - -import OPERATIONS from './constants/operations'; -import CATEGORIES from './constants/categories'; - -import uuidGenerator from './components/uuid'; -import { EventEngine } from '../event-engine'; -import { PresenceEventEngine } from '../event-engine/presence/presence'; -import { RetryPolicy } from '../event-engine/core/retryPolicy'; -import EventEmitter from './components/eventEmitter'; - -import { Channel } from '../entities/Channel'; -import { ChannelGroup } from '../entities/ChannelGroup'; -import { ChannelMetadata } from '../entities/ChannelMetadata'; -import { UserMetadata } from '../entities/UserMetadata'; -import { SubscriptionSet } from '../entities/SubscriptionSet'; - -export default class { - _config; - - _telemetryManager; - - _listenerManager; - - _tokenManager; - - // tell flow about the mounted endpoint - time; - - publish; - - fire; - - history; - - deleteMessages; - - messageCounts; - - fetchMessages; - - // - channelGroups; - - // - push; - - // - hereNow; - - whereNow; - - getState; - - setState; - // presence utility methods - iAmHere; - iAmAway; - setPresenceState; - - // subscription utility methods - handshake; - receiveMessages; - - // - grant; - - grantToken; - - audit; - - revokeToken; - - // - subscribe; - - signal; - - presence; - - unsubscribe; - - unsubscribeAll; - - // Actions API - addMessageAction; - - removeMessageAction; - - getMessageActions; - - // File Upload API v1 - - File; - - encryptFile; - - decryptFile; - - listFiles; - - sendFile; - - downloadFile; - - getFileUrl; - - deleteFile; - - publishFile; - - // Objects API v2 - - objects; - - // User - createUser; - - updateUser; - - fetchUser; - - removeUser; - - fetchUsers; - - // Space - createSpace; - - updateSpace; - - fetchSpace; - - removeSpace; - - fetchSpaces; - - // Membership - addMemberships; - - updateMemberships; - - fetchMemberships; - - removeMemberships; - - disconnect; - - reconnect; - - destroy; - - stop; - - getSubscribedChannels; - - getSubscribedChannelGroups; - - addListener; - - removeListener; - - removeAllListeners; - - parseToken; - - setToken; - - getToken; - - getAuthKey; - - setAuthKey; - - setCipherKey; - - setUUID; - - getUUID; - - setUserId; - - getUserId; - - getFilterExpression; - - setFilterExpression; - - setHeartbeatInterval; - - setProxy; - - encrypt; - - decrypt; - - _eventEmitter; - - constructor(setup) { - const { networking, cbor } = setup; - - const config = new Config({ setup }); - this._config = config; - const crypto = new Crypto({ config }); // LEGACY - - const { cryptography } = setup; - - networking.init(config); - - const tokenManager = new TokenManager(config, cbor); - this._tokenManager = tokenManager; - - const telemetryManager = new TelemetryManager({ - maximumSamplesCount: 60000, - }); - - this._telemetryManager = telemetryManager; - const cryptoModule = this._config.cryptoModule; - - const modules = { - config, - networking, - crypto, - cryptography, - tokenManager, - telemetryManager, - PubNubFile: setup.PubNubFile, - cryptoModule: cryptoModule, - }; - - this.File = setup.PubNubFile; - - this.encryptFile = function (key, file) { - if (arguments.length == 1 && typeof key != 'string' && modules.cryptoModule) { - file = key; - return modules.cryptoModule.encryptFile(file, this.File); - } - return cryptography.encryptFile(key, file, this.File); - }; - this.decryptFile = function (key, file) { - if (arguments.length == 1 && typeof key != 'string' && modules.cryptoModule) { - file = key; - return modules.cryptoModule.decryptFile(file, this.File); - } - return cryptography.decryptFile(key, file, this.File); - }; - - const timeEndpoint = endpointCreator.bind(this, modules, timeEndpointConfig); - const leaveEndpoint = endpointCreator.bind(this, modules, presenceLeaveEndpointConfig); - const heartbeatEndpoint = endpointCreator.bind(this, modules, presenceHeartbeatEndpointConfig); - const setStateEndpoint = endpointCreator.bind(this, modules, presenceSetStateConfig); - const subscribeEndpoint = endpointCreator.bind(this, modules, subscribeEndpointConfig); - - // managers - const listenerManager = new ListenerManager(); - this._listenerManager = listenerManager; - - this.iAmHere = endpointCreator.bind(this, modules, presenceHeartbeatEndpointConfig); - this.iAmAway = endpointCreator.bind(this, modules, presenceLeaveEndpointConfig); - this.setPresenceState = endpointCreator.bind(this, modules, presenceSetStateConfig); - this.handshake = endpointCreator.bind(this, modules, handshakeEndpointConfig); - this.receiveMessages = endpointCreator.bind(this, modules, receiveMessagesConfig); - - this._eventEmitter = new EventEmitter({ - modules: modules, - listenerManager: this._listenerManager, - getFileUrl: (params) => getFileUrlFunction(modules, params), - }); - if (config.enableEventEngine === true) { - if (config.maintainPresenceState) { - this.presenceState = {}; - this.setState = (args) => { - args.channels?.forEach((channel) => (this.presenceState[channel] = args.state)); - args.channelGroups?.forEach((group) => (this.presenceState[group] = args.state)); - return this.setPresenceState({ - channels: args.channels, - channelGroups: args.channelGroups, - state: this.presenceState, - }); - }; - } - - if (config.getHeartbeatInterval()) { - const presenceEventEngine = new PresenceEventEngine({ - heartbeat: this.iAmHere, - leave: this.iAmAway, - heartbeatDelay: () => - new Promise((resolve) => setTimeout(resolve, modules.config.getHeartbeatInterval() * 1000)), - retryDelay: (amount) => new Promise((resolve) => setTimeout(resolve, amount)), - config: modules.config, - presenceState: this.presenceState, - emitStatus: (status) => { - listenerManager.announceStatus(status); - }, - }); - this.presenceEventEngine = presenceEventEngine; - this.join = this.presenceEventEngine.join.bind(presenceEventEngine); - this.leave = this.presenceEventEngine.leave.bind(presenceEventEngine); - this.leaveAll = this.presenceEventEngine.leaveAll.bind(presenceEventEngine); - } - const eventEngine = new EventEngine({ - handshake: this.handshake, - receiveMessages: this.receiveMessages, - delay: (amount) => new Promise((resolve) => setTimeout(resolve, amount)), - join: this.join, - leave: this.leave, - leaveAll: this.leaveAll, - presenceState: this.presenceState, - config: modules.config, - emitMessages: (events) => { - for (const event of events) { - this._eventEmitter.emitEvent(event); - } - }, - emitStatus: (status) => { - listenerManager.announceStatus(status); - }, - }); - - this.subscribe = eventEngine.subscribe.bind(eventEngine); - this.unsubscribe = eventEngine.unsubscribe.bind(eventEngine); - this.unsubscribeAll = eventEngine.unsubscribeAll.bind(eventEngine); - this.reconnect = eventEngine.reconnect.bind(eventEngine); - this.disconnect = eventEngine.disconnect.bind(eventEngine); - this.destroy = eventEngine.dispose.bind(eventEngine); - this.getSubscribedChannels = eventEngine.getSubscribedChannels.bind(eventEngine); - this.getSubscribedChannelGroups = eventEngine.getSubscribedChannelGroups.bind(eventEngine); - this.eventEngine = eventEngine; - } else { - const subscriptionManager = new SubscriptionManager({ - timeEndpoint, - leaveEndpoint, - heartbeatEndpoint, - setStateEndpoint, - subscribeEndpoint, - crypto: modules.crypto, - config: modules.config, - listenerManager, - getFileUrl: (params) => getFileUrlFunction(modules, params), - cryptoModule: modules.cryptoModule, - eventEmitter: this._eventEmitter, - }); - - this.subscribe = subscriptionManager.adaptSubscribeChange.bind(subscriptionManager); - this.unsubscribe = subscriptionManager.adaptUnsubscribeChange.bind(subscriptionManager); - this.disconnect = subscriptionManager.disconnect.bind(subscriptionManager); - this.reconnect = subscriptionManager.reconnect.bind(subscriptionManager); - this.unsubscribeAll = subscriptionManager.unsubscribeAll.bind(subscriptionManager); - this.getSubscribedChannels = subscriptionManager.getSubscribedChannels.bind(subscriptionManager); - this.getSubscribedChannelGroups = subscriptionManager.getSubscribedChannelGroups.bind(subscriptionManager); - - this.setState = subscriptionManager.adaptStateChange.bind(subscriptionManager); - this.presence = subscriptionManager.adaptPresenceChange.bind(subscriptionManager); - - this.destroy = (isOffline) => { - subscriptionManager.unsubscribeAll(isOffline); - subscriptionManager.disconnect(); - }; - } - - this.addListener = this._eventEmitter.addListener.bind(this._eventEmitter); - this.removeListener = this._eventEmitter.removeListener.bind(this._eventEmitter); - this.removeAllListeners = this._eventEmitter.removeAllListeners.bind(this._eventEmitter); - - this.parseToken = tokenManager.parseToken.bind(tokenManager); - this.setToken = tokenManager.setToken.bind(tokenManager); - this.getToken = tokenManager.getToken.bind(tokenManager); - - /* channel groups */ - this.channelGroups = { - listGroups: endpointCreator.bind(this, modules, listChannelGroupsConfig), - listChannels: endpointCreator.bind(this, modules, listChannelsInChannelGroupConfig), - addChannels: endpointCreator.bind(this, modules, addChannelsChannelGroupConfig), - removeChannels: endpointCreator.bind(this, modules, removeChannelsChannelGroupConfig), - deleteGroup: endpointCreator.bind(this, modules, deleteChannelGroupConfig), - }; - /* push */ - this.push = { - addChannels: endpointCreator.bind(this, modules, addPushChannelsConfig), - removeChannels: endpointCreator.bind(this, modules, removePushChannelsConfig), - deleteDevice: endpointCreator.bind(this, modules, removeDevicePushConfig), - listChannels: endpointCreator.bind(this, modules, listPushChannelsConfig), - }; - /* presence */ - this.hereNow = endpointCreator.bind(this, modules, presenceHereNowConfig); - this.whereNow = endpointCreator.bind(this, modules, presenceWhereNowEndpointConfig); - this.getState = endpointCreator.bind(this, modules, presenceGetStateConfig); - /* PAM */ - this.grant = endpointCreator.bind(this, modules, grantEndpointConfig); - this.grantToken = endpointCreator.bind(this, modules, grantTokenEndpointConfig); - this.audit = endpointCreator.bind(this, modules, auditEndpointConfig); - this.revokeToken = endpointCreator.bind(this, modules, revokeTokenEndpointConfig); - this.publish = endpointCreator.bind(this, modules, publishEndpointConfig); - - this.fire = (args, callback) => { - args.replicate = false; - args.storeInHistory = false; - return this.publish(args, callback); - }; - - this.signal = endpointCreator.bind(this, modules, signalEndpointConfig); - - this.history = endpointCreator.bind(this, modules, historyEndpointConfig); - this.deleteMessages = endpointCreator.bind(this, modules, deleteMessagesEndpointConfig); - this.messageCounts = endpointCreator.bind(this, modules, messageCountsEndpointConfig); - this.fetchMessages = endpointCreator.bind(this, modules, fetchMessagesEndpointConfig); - - // Actions API - - this.addMessageAction = endpointCreator.bind(this, modules, addMessageActionEndpointConfig); - - this.removeMessageAction = endpointCreator.bind(this, modules, removeMessageActionEndpointConfig); - - this.getMessageActions = endpointCreator.bind(this, modules, getMessageActionEndpointConfig); - - // File Upload API v1 - - this.listFiles = endpointCreator.bind(this, modules, listFilesEndpointConfig); - - const generateUploadUrl = endpointCreator.bind(this, modules, generateUploadUrlEndpointConfig); - this.publishFile = endpointCreator.bind(this, modules, publishFileEndpointConfig); - - this.sendFile = sendFileFunction({ - generateUploadUrl, - publishFile: this.publishFile, - modules, - }); - - this.getFileUrl = (params) => getFileUrlFunction(modules, params); - - this.downloadFile = endpointCreator.bind(this, modules, downloadFileEndpointConfig); - - this.deleteFile = endpointCreator.bind(this, modules, deleteFileEndpointConfig); - - // entities - - this.channel = (name) => new Channel(name, this._eventEmitter, this); - this.channelGroup = (name) => new ChannelGroup(name, this._eventEmitter, this); - this.channelMetadata = (id) => new ChannelMetadata(id, this._eventEmitter, this); - this.userMetadata = (id) => new UserMetadata(id, this._eventEmitter, this); - this.subscriptionSet = (args) => - new SubscriptionSet({ - channels: args.channels, - channelGroups: args.channelGroups, - subscriptionOptions: args.subscriptionOptions, - eventEmitter: this._eventEmitter, - pubnub: this, - }); - - // Objects API v2 - - this.objects = { - getAllUUIDMetadata: endpointCreator.bind(this, modules, getAllUUIDMetadataEndpointConfig), - getUUIDMetadata: endpointCreator.bind(this, modules, getUUIDMetadataEndpointConfig), - setUUIDMetadata: endpointCreator.bind(this, modules, setUUIDMetadataEndpointConfig), - removeUUIDMetadata: endpointCreator.bind(this, modules, removeUUIDMetadataEndpointConfig), - - getAllChannelMetadata: endpointCreator.bind(this, modules, getAllChannelMetadataEndpointConfig), - getChannelMetadata: endpointCreator.bind(this, modules, getChannelMetadataEndpointConfig), - setChannelMetadata: endpointCreator.bind(this, modules, setChannelMetadataEndpointConfig), - removeChannelMetadata: endpointCreator.bind(this, modules, removeChannelMetadataEndpointConfig), - - getChannelMembers: endpointCreator.bind(this, modules, getMembersV2EndpointConfig), - setChannelMembers: (parameters, ...rest) => - endpointCreator.call( - this, - modules, - setMembersV2EndpointConfig, - { - type: 'set', - ...parameters, - }, - ...rest, - ), - removeChannelMembers: (parameters, ...rest) => - endpointCreator.call( - this, - modules, - setMembersV2EndpointConfig, - { - type: 'delete', - ...parameters, - }, - ...rest, - ), - - getMemberships: endpointCreator.bind(this, modules, getMembershipsV2EndpointConfig), - setMemberships: (parameters, ...rest) => - endpointCreator.call( - this, - modules, - setMembershipsV2EndpointConfig, - { - type: 'set', - ...parameters, - }, - ...rest, - ), - removeMemberships: (parameters, ...rest) => - endpointCreator.call( - this, - modules, - setMembershipsV2EndpointConfig, - { - type: 'delete', - ...parameters, - }, - ...rest, - ), - }; - - // User Apis - this.createUser = (args) => - this.objects.setUUIDMetadata({ - uuid: args.userId, - data: args.data, - include: args.include, - }); - - this.updateUser = this.createUser; - - this.removeUser = (args) => - this.objects.removeUUIDMetadata({ - uuid: args?.userId, - }); - - this.fetchUser = (args) => - this.objects.getUUIDMetadata({ - uuid: args?.userId, - include: args?.include, - }); - - this.fetchUsers = this.objects.getAllUUIDMetadata; - - // Space apis - this.createSpace = (args) => - this.objects.setChannelMetadata({ - channel: args.spaceId, - data: args.data, - include: args.include, - }); - - this.updateSpace = this.createSpace; - - this.removeSpace = (args) => - this.objects.removeChannelMetadata({ - channel: args.spaceId, - }); - - this.fetchSpace = (args) => - this.objects.getChannelMetadata({ - channel: args.spaceId, - include: args.include, - }); - - this.fetchSpaces = this.objects.getAllChannelMetadata; - - // Membership apis - this.addMemberships = (parameters) => { - if (typeof parameters.spaceId === 'string') { - return this.objects.setChannelMembers({ - channel: parameters.spaceId, - uuids: parameters.users?.map((user) => { - if (typeof user === 'string') { - return user; - } - return { - id: user.userId, - custom: user.custom, - status: user.status, - }; - }), - limit: 0, - }); - } else { - return this.objects.setMemberships({ - uuid: parameters.userId, - channels: parameters.spaces?.map((space) => { - if (typeof space === 'string') { - return space; - } - return { - id: space.spaceId, - custom: space.custom, - status: space.status, - }; - }), - limit: 0, - }); - } - }; - - this.updateMemberships = this.addMemberships; - - this.removeMemberships = (parameters) => { - if (typeof parameters.spaceId === 'string') { - return this.objects.removeChannelMembers({ - channel: parameters.spaceId, - uuids: parameters.userIds, - limit: 0, - }); - } else { - return this.objects.removeMemberships({ - uuid: parameters.userId, - channels: parameters.spaceIds, - limit: 0, - }); - } - }; - - this.fetchMemberships = (params) => { - if (typeof params.spaceId === 'string') { - return this.objects - .getChannelMembers({ - channel: params.spaceId, - filter: params.filter, - limit: params.limit, - page: params.page, - include: { - customFields: params.include.customFields, - UUIDFields: params.include.userFields, - customUUIDFields: params.include.customUserFields, - statusField: params.include.statusField, - UUIDStatusField: params.include.userStatusField, - UUIDTypeField: params.include.userTypeField, - totalCount: params.include.totalCount, - }, - sort: - params.sort != null - ? Object.fromEntries(Object.entries(params.sort).map(([k, v]) => [k.replace('user', 'uuid'), v])) - : null, - }) - .then((res) => { - res.data = res.data?.map((m) => { - return { - user: m.uuid, - custom: m.custom, - updated: m.updated, - eTag: m.eTag, - }; - }); - return res; - }); - } else { - return this.objects - .getMemberships({ - uuid: params.userId, - filter: params.filter, - limit: params.limit, - page: params.page, - include: { - customFields: params.include.customFields, - channelFields: params.include.spaceFields, - customChannelFields: params.include.customSpaceFields, - statusField: params.include.statusField, - channelStatusField: params.include.spaceStatusField, - channelTypeField: params.include.spaceTypeField, - totalCount: params.include.totalCount, - }, - sort: - params.sort != null - ? Object.fromEntries(Object.entries(params.sort).map(([k, v]) => [k.replace('space', 'channel'), v])) - : null, - }) - .then((res) => { - res.data = res.data?.map((m) => { - return { - space: m.channel, - custom: m.custom, - updated: m.updated, - eTag: m.eTag, - }; - }); - return res; - }); - } - }; - - this.time = timeEndpoint; - - // --- deprecated ------------------ - this.stop = this.destroy; // -------- - // --- deprecated ------------------ - - // mount crypto - this.encrypt = function (data, key) { - if (typeof key === 'undefined' && modules.cryptoModule) { - const encrypted = modules.cryptoModule.encrypt(data); - return typeof encrypted === 'string' ? encrypted : encode(encrypted); - } else { - return crypto.encrypt(data, key); - } - }; - this.decrypt = function (data, key) { - if (typeof key === 'undefined' && cryptoModule) { - const decrypted = modules.cryptoModule.decrypt(data); - return decrypted instanceof ArrayBuffer ? JSON.parse(new TextDecoder().decode(decrypted)) : decrypted; - } else { - return crypto.decrypt(data, key); - } - }; - - /* config */ - this.getAuthKey = modules.config.getAuthKey.bind(modules.config); - this.setAuthKey = modules.config.setAuthKey.bind(modules.config); - this.getUUID = modules.config.getUUID.bind(modules.config); - this.setUUID = modules.config.setUUID.bind(modules.config); - this.getUserId = modules.config.getUserId.bind(modules.config); - this.setUserId = modules.config.setUserId.bind(modules.config); - this.getFilterExpression = modules.config.getFilterExpression.bind(modules.config); - this.setFilterExpression = modules.config.setFilterExpression.bind(modules.config); - this.setCipherKey = (key) => modules.config.setCipherKey(key, setup, modules); - this.setHeartbeatInterval = modules.config.setHeartbeatInterval.bind(modules.config); - - if (networking.hasModule('proxy')) { - this.setProxy = (proxy) => { - modules.config.setProxy(proxy); - this.reconnect(); - }; - } - } - - getVersion() { - return this._config.getVersion(); - } - - _addPnsdkSuffix(name, suffix) { - this._config._addPnsdkSuffix(name, suffix); - } - - // network hooks to indicate network changes - networkDownDetected() { - this._listenerManager.announceNetworkDown(); - - if (this._config.restore) { - this.disconnect(); - } else { - this.destroy(true); - } - } - - networkUpDetected() { - this._listenerManager.announceNetworkUp(); - this.reconnect(); - } - - static notificationPayload(title, body) { - return new NotificationsPayload(title, body); - } - - static generateUUID() { - return uuidGenerator.createUUID(); - } - - static OPERATIONS = OPERATIONS; - - static CATEGORIES = CATEGORIES; - - static LinearRetryPolicy = RetryPolicy.LinearRetryPolicy; - static ExponentialRetryPolicy = RetryPolicy.ExponentialRetryPolicy; -} diff --git a/src/core/pubnub-common.ts b/src/core/pubnub-common.ts new file mode 100644 index 000000000..101cfb0ef --- /dev/null +++ b/src/core/pubnub-common.ts @@ -0,0 +1,3215 @@ +// region Imports +// region Components +import { Listener, ListenerManager } from './components/listener_manager'; +import { SubscriptionManager } from './components/subscription-manager'; +import NotificationsPayload from './components/push_payload'; +import { AbstractRequest } from './components/request'; +import TokenManager from './components/token_manager'; +import Crypto from './components/cryptography/index'; +import EventEmitter from './components/eventEmitter'; +import { encode } from './components/base64_codec'; +import uuidGenerator from './components/uuid'; +// endregion + +// region Types +import { ResultCallback, StatusCallback, Payload, Status, PubNubAPIError } from './types/api'; +// endregion + +// region Component Interfaces +import { ClientConfiguration, PrivateClientConfiguration } from './interfaces/configuration'; +import { Cryptography } from './interfaces/cryptography'; +import { Transport } from './interfaces/transport'; +// endregion + +// region Constants +import RequestOperation from './constants/operations'; +import StatusCategory from './constants/categories'; +// endregion + +import { createValidationError, PubNubError } from '../models/PubNubError'; + +// region Event Engine +import { PresenceEventEngine } from '../event-engine/presence/presence'; +import { RetryPolicy } from '../event-engine/core/retryPolicy'; +import { EventEngine } from '../event-engine'; +// endregion + +// region Publish & Signal +import * as Publish from './endpoints/publish'; +import * as Signal from './endpoints/signal'; +// endregion + +// region Subscription +import { RequestParameters as SubscribeRequestParameters, SubscribeRequest } from './endpoints/subscribe'; +import { ReceiveMessagesSubscribeRequest } from './endpoints/subscriptionUtils/receiveMessages'; +import { HandshakeSubscribeRequest } from './endpoints/subscriptionUtils/handshake'; +import * as Subscription from './types/api/subscription'; +// endregion + +// region Presence +import { GetPresenceStateRequest } from './endpoints/presence/get_state'; +import { SetPresenceStateRequest } from './endpoints/presence/set_state'; +import { HeartbeatRequest } from './endpoints/presence/heartbeat'; +import { PresenceLeaveRequest } from './endpoints/presence/leave'; +import { WhereNowRequest } from './endpoints/presence/where_now'; +import { HereNowRequest } from './endpoints/presence/here_now'; +import * as Presence from './types/api/presence'; +// endregion + +// region Message Storage +import { DeleteMessageRequest } from './endpoints/history/delete_messages'; +import { MessageCountRequest } from './endpoints/history/message_counts'; +import { GetHistoryRequest } from './endpoints/history/get_history'; +import { FetchMessagesRequest } from './endpoints/fetch_messages'; +import * as History from './types/api/history'; +// endregion + +// region Message Actions +import { GetMessageActionsRequest } from './endpoints/actions/get_message_actions'; +import { AddMessageActionRequest } from './endpoints/actions/add_message_action'; +import { RemoveMessageAction } from './endpoints/actions/remove_message_action'; +import * as MessageAction from './types/api/message-action'; +// endregion + +// region File sharing +import { PublishFileMessageRequest } from './endpoints/file_upload/publish_file'; +import { GetFileDownloadUrlRequest } from './endpoints/file_upload/get_file_url'; +import { DeleteFileRequest } from './endpoints/file_upload/delete_file'; +import { FilesListRequest } from './endpoints/file_upload/list_files'; +import { SendFileRequest } from './endpoints/file_upload/send_file'; +import * as FileSharing from './types/api/file-sharing'; +import { PubNubFileInterface } from './types/file'; +// endregion + +// region PubNub Access Manager +import { RevokeTokenRequest } from './endpoints/access_manager/revoke_token'; +import { GrantTokenRequest } from './endpoints/access_manager/grant_token'; +import { GrantRequest } from './endpoints/access_manager/grant'; +import { AuditRequest } from './endpoints/access_manager/audit'; +import * as PAM from './types/api/access-panager'; +// endregion + +// region Entities +import { SubscriptionOptions } from '../entities/commonTypes'; +import { ChannelMetadata } from '../entities/ChannelMetadata'; +import { SubscriptionSet } from '../entities/SubscriptionSet'; +import { ChannelGroup } from '../entities/ChannelGroup'; +import { UserMetadata } from '../entities/UserMetadata'; +import { Channel } from '../entities/Channel'; +// endregion + +// region Channel Groups +import PubNubChannelGroups from './pubnub-channel-groups'; +// endregion + +// region Push Notifications +import PubNubPushNotifications from './pubnub-push'; +// endregion + +// region App Context +import * as AppContext from './types/api/app-context'; +import PubNubObjects from './pubnub-objects'; +// endregion + +// region Time +import * as Time from './endpoints/time'; +// endregion + +import { encodeString } from './utils'; +import { DownloadFileRequest } from './endpoints/file_upload/download_file'; +// endregion + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- +// region Types + +type ClientInstanceConfiguration = { + /** + * Client-provided configuration. + */ + configuration: PrivateClientConfiguration; + + /** + * Transport provider for requests execution. + */ + transport: Transport; + + /** + * REST API endpoints access tokens manager. + */ + tokenManager: TokenManager; + + /** + * Legacy crypto module implementation. + */ + cryptography?: Cryptography; + + /** + * Legacy crypto (legacy data encryption / decryption and request signature support). + */ + crypto?: Crypto; +}; +// endregion + +/** + * Platform-agnostic PubNub client core. + */ +export class PubNubCore< + CryptographyTypes, + FileConstructorParameters, + PlatformFile extends Partial = Record, +> { + /** + * PubNub client configuration. + */ + protected readonly _configuration: PrivateClientConfiguration; + + /** + * Subscription loop manager. + * + * **Note:** Manager created when EventEngine is off. + */ + private readonly subscriptionManager?: SubscriptionManager; + + /** + * Transport for network requests processing. + */ + protected readonly transport: Transport; + + /** + * REST API endpoints access tokens manager. + */ + private readonly tokenManager: TokenManager; + + /** + * Legacy crypto module implementation. + */ + private readonly cryptography?: Cryptography; + + /** + * Legacy crypto (legacy data encryption / decryption and request signature support). + */ + private readonly crypto?: Crypto; + + /** + * Real-time event listeners manager. + */ + protected readonly listenerManager: ListenerManager; + + /** + * User's presence event engine. + */ + private presenceEventEngine?: PresenceEventEngine; + + /** + * Subscription event engine. + */ + private readonly eventEngine?: EventEngine; + + /** + * Client-managed presence information. + */ + private readonly presenceState?: Record; + + /** + * Real-time events emitter. + */ + private readonly eventEmitter: EventEmitter; + + /** + * PubNub App Context REST API entry point. + */ + private readonly _objects: PubNubObjects; + + /** + * PubNub Channel Group REST API entry point. + */ + private readonly _channelGroups: PubNubChannelGroups; + + /** + * PubNub Push Notification REST API entry point. + */ + private readonly _push: PubNubPushNotifications; + + // -------------------------------------------------------- + // ----------------------- Static ------------------------- + // -------------------------------------------------------- + + // region Static + /** + * Type of REST API endpoint which reported status. + */ + static OPERATIONS = RequestOperation; + + /** + * API call status category. + */ + static CATEGORIES = StatusCategory; + + /** + * Exponential retry policy constructor. + */ + static ExponentialRetryPolicy = RetryPolicy.ExponentialRetryPolicy; + + /** + * Linear retry policy constructor. + */ + static LinearRetryPolicy = RetryPolicy.LinearRetryPolicy; + + /** + * Construct notification payload which will trigger push notification. + * + * @param title - Title which will be shown on notification. + * @param body - Payload which will be sent as part of notification. + * + * @returns Pre-formatted message payload which will trigger push notification. + */ + static notificationPayload(title: string, body: Payload) { + return new NotificationsPayload(title, body); + } + + /** + * Generate unique identifier. + * + * @returns Unique identifier. + */ + static generateUUID() { + return uuidGenerator.createUUID(); + } + // endregion + + constructor(configuration: ClientInstanceConfiguration) { + this._configuration = configuration.configuration; + this.cryptography = configuration.cryptography; + this.tokenManager = configuration.tokenManager; + this.transport = configuration.transport; + this.crypto = configuration.crypto; + + // API group entry points initialization. + this._objects = new PubNubObjects(this._configuration, this.sendRequest); + this._channelGroups = new PubNubChannelGroups(this._configuration.keySet, this.sendRequest); + this._push = new PubNubPushNotifications(this._configuration.keySet, this.sendRequest); + + // Prepare for real-time events announcement. + this.listenerManager = new ListenerManager(); + this.eventEmitter = new EventEmitter(this.listenerManager); + + if (this._configuration.enableEventEngine) { + let heartbeatInterval = this._configuration.getHeartbeatInterval(); + this.presenceState = {}; + + if (heartbeatInterval) { + this.presenceEventEngine = new PresenceEventEngine({ + heartbeat: this.heartbeat, + leave: this.unsubscribe, + heartbeatDelay: () => + new Promise((resolve, reject) => { + heartbeatInterval = this._configuration.getHeartbeatInterval(); + if (!heartbeatInterval) reject(new PubNubError('Heartbeat interval has been reset.')); + else setTimeout(resolve, heartbeatInterval * 1000); + }), + retryDelay: (amount) => new Promise((resolve) => setTimeout(resolve, amount)), + emitStatus: (status) => this.listenerManager.announceStatus(status), + config: this._configuration, + presenceState: this.presenceState, + }); + } + + this.eventEngine = new EventEngine({ + handshake: this.subscribeHandshake, + receiveMessages: this.subscribeReceiveMessages, + delay: (amount) => new Promise((resolve) => setTimeout(resolve, amount)), + join: this.presenceEventEngine?.join, + leave: this.presenceEventEngine?.leave, + leaveAll: this.presenceEventEngine?.leaveAll, + presenceState: this.presenceState, + config: this._configuration, + emitMessages: (events) => events.forEach((event) => this.eventEmitter.emitEvent(event)), + emitStatus: (status) => this.listenerManager.announceStatus(status), + }); + } else { + this.subscriptionManager = new SubscriptionManager( + this._configuration, + this.listenerManager, + this.eventEmitter, + this.makeSubscribe, + this.heartbeat, + this.makeUnsubscribe, + this.time, + ); + } + } + + // -------------------------------------------------------- + // -------------------- Configuration ---------------------- + // -------------------------------------------------------- + // region Configuration + + /** + * PubNub client configuration. + * + * @returns Currently user PubNub client configuration. + */ + public get configuration(): ClientConfiguration { + return this._configuration; + } + + /** + * Current PubNub client configuration. + * + * @returns Currently user PubNub client configuration. + * + * @deprecated Use {@link configuration} getter instead. + */ + public get _config(): ClientConfiguration { + return this.configuration; + } + + /** + * REST API endpoint access authorization key. + * + * It is required to have `authorization key` with required permissions to access REST API + * endpoints when `PAM` enabled for user key set. + */ + get authKey(): string | undefined { + return this._configuration.authKey ?? undefined; + } + + /** + * REST API endpoint access authorization key. + * + * It is required to have `authorization key` with required permissions to access REST API + * endpoints when `PAM` enabled for user key set. + */ + getAuthKey(): string | undefined { + return this.authKey; + } + + /** + * Change REST API endpoint access authorization key. + * + * @param authKey - New authorization key which should be used with new requests. + */ + setAuthKey(authKey: string): void { + this._configuration.setAuthKey(authKey); + } + + /** + * Get a PubNub client user identifier. + * + * @returns Current PubNub client user identifier. + */ + get userId(): string { + return this._configuration.userId; + } + + /** + * Change the current PubNub client user identifier. + * + * **Important:** Change won't affect ongoing REST API calls. + * + * @param value - New PubNub client user identifier. + * + * @throws Error empty user identifier has been provided. + */ + set userId(value: string) { + this._configuration.userId = value; + } + + /** + * Get a PubNub client user identifier. + * + * @returns Current PubNub client user identifier. + */ + getUserId(): string { + return this._configuration.userId; + } + + /** + * Change the current PubNub client user identifier. + * + * **Important:** Change won't affect ongoing REST API calls. + * + * @param value - New PubNub client user identifier. + * + * @throws Error empty user identifier has been provided. + */ + setUserId(value: string): void { + this._configuration.userId = value; + } + + /** + * Real-time updates filtering expression. + * + * @returns Filtering expression. + */ + get filterExpression(): string | undefined { + return this._configuration.getFilterExpression() ?? undefined; + } + + /** + * Real-time updates filtering expression. + * + * @returns Filtering expression. + */ + getFilterExpression(): string | undefined { + return this.filterExpression; + } + + /** + * Update real-time updates filtering expression. + * + * @param expression - New expression which should be used or `undefined` to disable filtering. + */ + set filterExpression(expression: string | null | undefined) { + this._configuration.setFilterExpression(expression); + } + + /** + * Update real-time updates filtering expression. + * + * @param expression - New expression which should be used or `undefined` to disable filtering. + */ + setFilterExpression(expression: string | null): void { + this.filterExpression = expression; + } + + /** + * Dta encryption / decryption key. + * + * @returns Currently used key for data encryption / decryption. + */ + get cipherKey(): string | undefined { + return this._configuration.cipherKey; + } + + /** + * Change data encryption / decryption key. + * + * @param key - New key which should be used for data encryption / decryption. + */ + set cipherKey(key: string | undefined) { + this._configuration.setCipherKey(key); + } + + /** + * Change data encryption / decryption key. + * + * @param key - New key which should be used for data encryption / decryption. + */ + setCipherKey(key: string): void { + this.cipherKey = key; + } + + /** + * Change heartbeat requests interval. + * + * @param interval - New presence request heartbeat intervals. + */ + set heartbeatInterval(interval: number) { + this._configuration.setHeartbeatInterval(interval); + } + + /** + * Change heartbeat requests interval. + * + * @param interval - New presence request heartbeat intervals. + */ + setHeartbeatInterval(interval: number): void { + this.heartbeatInterval = interval; + } + + /** + * Get PubNub SDK version. + * + * @returns Current SDK version. + */ + getVersion(): string { + return this._configuration.version; + } + + /** + * Add framework's prefix. + * + * @param name - Name of the framework which would want to add own data into `pnsdk` suffix. + * @param suffix - Suffix with information about framework. + */ + _addPnsdkSuffix(name: string, suffix: string | number) { + this._configuration._addPnsdkSuffix(name, suffix); + } + + // -------------------------------------------------------- + // ---------------------- Deprecated ---------------------- + // -------------------------------------------------------- + // region Deprecated + + /** + * Get a PubNub client user identifier. + * + * @returns Current PubNub client user identifier. + * + * @deprecated Use the {@link getUserId} or {@link userId} getter instead. + */ + getUUID(): string { + return this.userId; + } + + /** + * Change the current PubNub client user identifier. + * + * **Important:** Change won't affect ongoing REST API calls. + * + * @param value - New PubNub client user identifier. + * + * @throws Error empty user identifier has been provided. + * + * @deprecated Use the {@link PubNubCore#setUserId} or {@link PubNubCore#userId} setter instead. + */ + setUUID(value: string) { + this.userId = value; + } + + /** + * Custom data encryption method. + * + * @deprecated Instead use {@link cryptoModule} for data encryption. + */ + get customEncrypt(): ((data: string) => string) | undefined { + return this._configuration.customEncrypt; + } + + /** + * Custom data decryption method. + * + * @deprecated Instead use {@link cryptoModule} for data decryption. + */ + get customDecrypt(): ((data: string) => string) | undefined { + return this._configuration.customDecrypt; + } + // endregion + // endregion + + // -------------------------------------------------------- + // ---------------------- Entities ------------------------ + // -------------------------------------------------------- + // region Entities + + /** + * Create a `Channel` entity. + * + * Entity can be used for the interaction with the following API: + * - `subscribe` + * + * @param name - Unique channel name. + * @returns `Channel` entity. + */ + public channel(name: string): Channel { + return new Channel(name, this.eventEmitter, this); + } + + /** + * Create a `ChannelGroup` entity. + * + * Entity can be used for the interaction with the following API: + * - `subscribe` + * + * @param name - Unique channel group name. + * @returns `ChannelGroup` entity. + */ + public channelGroup(name: string): ChannelGroup { + return new ChannelGroup(name, this.eventEmitter, this); + } + + /** + * Create a `ChannelMetadata` entity. + * + * Entity can be used for the interaction with the following API: + * - `subscribe` + * + * @param id - Unique channel metadata object identifier. + * @returns `ChannelMetadata` entity. + */ + public channelMetadata(id: string): ChannelMetadata { + return new ChannelMetadata(id, this.eventEmitter, this); + } + + /** + * Create a `UserMetadata` entity. + * + * Entity can be used for the interaction with the following API: + * - `subscribe` + * + * @param id - Unique user metadata object identifier. + * @returns `UserMetadata` entity. + */ + public userMetadata(id: string): UserMetadata { + return new UserMetadata(id, this.eventEmitter, this); + } + + /** + * Create subscriptions set object. + * + * @param parameters - Subscriptions set configuration parameters. + */ + public subscriptionSet(parameters: { + channels: string[]; + channelGroups: string[]; + subscriptionOptions: SubscriptionOptions; + }): SubscriptionSet { + return new SubscriptionSet({ ...parameters, eventEmitter: this.eventEmitter, pubnub: this }); + } + // endregion + + // -------------------------------------------------------- + // ----------------------- Common ------------------------- + // -------------------------------------------------------- + + // region Common + /** + * Schedule request execution. + * + * @param request - REST API request. + * @param callback - Request completion handler callback. + * + * @returns Asynchronous request execution and response parsing result. + */ + private sendRequest( + request: AbstractRequest, + callback: ResultCallback, + ): void; + + /** + * Schedule request execution. + * + * @param request - REST API request. + * + * @returns Asynchronous request execution and response parsing result. + */ + private async sendRequest(request: AbstractRequest): Promise; + + /** + * Schedule request execution. + * + * @param request - REST API request. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous request execution and response parsing result or `void` in case if + * `callback` provided. + * + * @throws PubNubError in case of request processing error. + */ + private async sendRequest( + request: AbstractRequest, + callback?: ResultCallback, + ): Promise { + // Validate user-input. + const validationResult = request.validate(); + if (validationResult) { + if (callback) return callback(createValidationError(validationResult), null); + throw new PubNubError('Validation failed, check status for details', createValidationError(validationResult)); + } + + // Complete request configuration. + const transportRequest = request.request(); + if ( + transportRequest.body && + typeof transportRequest.body === 'object' && + 'toArrayBuffer' in transportRequest.body + ) { + // Set 300 seconds file upload request delay. + transportRequest.timeout = 300; + } else { + if (request.operation() === RequestOperation.PNSubscribeOperation) + transportRequest.timeout = this._configuration.getSubscribeTimeout(); + else transportRequest.timeout = this._configuration.getTransactionTimeout(); + } + + // API request processing status. + const status: Status = { + error: false, + operation: request.operation(), + statusCode: 0, + }; + + const [sendableRequest, cancellationController] = this.transport.makeSendable(transportRequest); + + /** + * **Important:** Because of multiple environments where JS SDK can be used control over + * cancellation had to be inverted to let transport provider solve request cancellation task + * more efficiently. As result, cancellation controller can be retrieved and used only after + * request will be scheduled by transport provider. + */ + request.cancellationController = cancellationController ? cancellationController : null; + + return sendableRequest + .then((response) => { + status.statusCode = response.status; + + return request.parse(response); + }) + .then((parsed) => { + // Notify callback (if possible). + if (callback) return callback(status, parsed); + + return parsed; + }) + .catch((error: PubNubAPIError) => { + console.log(`~~~~~~~> WHAT HERE?:`, error); + if (error instanceof PubNubError) { + console.log(`~~~~~~> OH, WE ARE REGULAR PUBNUB ERROR`); + // @ts-expect-error I allow this for debug + console.log(`~~~~~~~~> WHAT IN STATUS?: `, error['status']); + } + // const errorStatus = error.toStatus(request.operation()); + const errorStatus = { error: true }; + // Notify callback (if possible). + if (callback) callback(errorStatus, null); + + throw new PubNubError('REST API request processing error, check status for details', errorStatus); + }); + } + + /** + * Unsubscribe from all channels and groups. + * + * @param isOffline - Whether `offline` presence should be notified or not. + */ + public destroy(isOffline: boolean): void { + if (this.subscriptionManager) { + this.subscriptionManager.unsubscribeAll(isOffline); + this.subscriptionManager.disconnect(); + } else if (this.eventEngine) this.eventEngine.dispose(); + } + // endregion + + // -------------------------------------------------------- + // ----------------------- Listener ----------------------- + // -------------------------------------------------------- + // region Listener + + /** + * Register real-time events listener. + * + * @param listener - Listener with event callbacks to handle different types of events. + */ + public addListener(listener: Listener): void { + this.listenerManager.addListener(listener); + } + + /** + * Remove real-time event listener. + * + * @param listener - Event listeners which should be removed. + */ + public removeListener(listener: Listener): void { + this.listenerManager.removeListener(listener); + } + + /** + * Clear all real-time event listeners. + */ + public removeAllListeners(): void { + this.listenerManager.removeAllListeners(); + } + + // endregion + + // -------------------------------------------------------- + // ---------------------- Publish API --------------------- + // -------------------------------------------------------- + // region Publish API + + /** + * Publish data to a specific channel. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public publish(parameters: Publish.PublishParameters, callback: ResultCallback): void; + + /** + * Publish data to a specific channel. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous publish data response. + */ + public async publish(parameters: Publish.PublishParameters): Promise; + + /** + * Publish data to a specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous publish data response or `void` in case if `callback` provided. + */ + async publish( + parameters: Publish.PublishParameters, + callback?: ResultCallback, + ): Promise { + const request = new Publish.PublishRequest({ + ...parameters, + keySet: this._configuration.keySet, + crypto: this._configuration.cryptoModule, + }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // -------------------------------------------------------- + // ---------------------- Signal API ---------------------- + // -------------------------------------------------------- + // region Signal API + + /** + * Signal data to a specific channel. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public signal(parameters: Signal.SignalParameters, callback: ResultCallback): void; + + /** + * Signal data to a specific channel. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous signal data response. + */ + public async signal(parameters: Signal.SignalParameters): Promise; + + /** + * Signal data to a specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous signal data response or `void` in case if `callback` provided. + */ + async signal( + parameters: Signal.SignalParameters, + callback?: ResultCallback, + ): Promise { + const request = new Signal.SignalRequest({ + ...parameters, + keySet: this._configuration.keySet, + }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // -------------------------------------------------------- + // ----------------------- Fire API ---------------------- + // -------------------------------------------------------- + // region Fire API + + /** + * `Fire` a data to a specific channel. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link publish} method instead. + */ + public fire(parameters: Publish.PublishParameters, callback: ResultCallback): void; + + /** + * `Fire` a data to a specific channel. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous signal data response. + * + * @deprecated Use {@link publish} method instead. + */ + public async fire(parameters: Publish.PublishParameters): Promise; + + /** + * `Fire` a data to a specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous signal data response or `void` in case if `callback` provided. + * + * @deprecated Use {@link publish} method instead. + */ + async fire( + parameters: Publish.PublishParameters, + callback?: ResultCallback, + ): Promise { + callback ??= () => {}; + return this.publish({ ...parameters, replicate: false, storeInHistory: false }, callback); + } + // endregion + + // -------------------------------------------------------- + // -------------------- Subscribe API --------------------- + // -------------------------------------------------------- + // region Subscribe API + + /** + * Get list of channels on which PubNub client currently subscribed. + * + * @returns List of active channels. + */ + public getSubscribedChannels(): string[] { + if (this.subscriptionManager) return this.subscriptionManager.subscribedChannels; + else if (this.eventEngine) return this.eventEngine.getSubscribedChannels(); + + return []; + } + + /** + * Get list of channel groups on which PubNub client currently subscribed. + * + * @returns List of active channel groups. + */ + public getSubscribedChannelGroups(): string[] { + if (this.subscriptionManager) return this.subscriptionManager.subscribedChannelGroups; + else if (this.eventEngine) return this.eventEngine.getSubscribedChannelGroups(); + + return []; + } + + /** + * Subscribe to specified channels and groups real-time events. + * + * @param parameters - Request configuration parameters. + */ + public subscribe(parameters: Subscription.SubscribeParameters): void { + if (this.subscriptionManager) this.subscriptionManager.subscribe(parameters); + else if (this.eventEngine) this.eventEngine.subscribe(parameters); + } + + /** + * Perform subscribe request. + * + * **Note:** Method passed into managers to let them use it when required. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + private makeSubscribe( + parameters: Omit, + callback: ResultCallback, + ): void { + const request = new SubscribeRequest({ + ...parameters, + keySet: this._configuration.keySet, + getFileUrl: this.getFileUrl, + }); + + this.sendRequest(request, (status, result) => { + if (this.subscriptionManager && this.subscriptionManager.abort === request.abort) + this.subscriptionManager.abort = null; + + callback(status, result); + }); + + /** + * Allow subscription cancellation. + * + * **Note:** Had to be done after scheduling because transport provider return cancellation + * controller only when schedule new request. + */ + if (this.subscriptionManager) this.subscriptionManager.abort = request.abort; + } + + /** + * Unsubscribe from specified channels and groups real-time events. + * + * @param parameters - Request configuration parameters. + */ + public unsubscribe(parameters: Presence.PresenceLeaveParameters): void { + if (this.subscriptionManager) this.subscriptionManager.unsubscribe(parameters); + else if (this.eventEngine) this.eventEngine.unsubscribe(parameters); + } + + /** + * Perform unsubscribe request. + * + * **Note:** Method passed into managers to let them use it when required. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + private makeUnsubscribe(parameters: Presence.PresenceLeaveParameters, callback: StatusCallback): void { + this.sendRequest( + new PresenceLeaveRequest({ + ...parameters, + keySet: this._configuration.keySet, + }), + callback, + ); + } + + /** + * Unsubscribe from all channels and groups. + */ + public unsubscribeAll() { + if (this.subscriptionManager) this.subscriptionManager.unsubscribeAll(); + else if (this.eventEngine) this.eventEngine.unsubscribeAll(); + } + + /** + * Temporarily disconnect from real-time events stream. + */ + public disconnect(): void { + if (this.subscriptionManager) this.subscriptionManager.disconnect(); + else if (this.eventEngine) this.eventEngine.disconnect(); + } + + /** + * Restore connection to the real-time events stream. + * + * @param parameters - Reconnection catch up configuration. **Note:** available only with + * enabled event engine. + */ + public reconnect(parameters?: { timetoken?: string; region?: number }): void { + if (this.subscriptionManager) this.subscriptionManager.reconnect(); + else if (this.eventEngine) this.eventEngine.reconnect(parameters ?? {}); + } + + /** + * Event engine handshake subscribe. + * + * @param parameters - Request configuration parameters. + */ + private async subscribeHandshake(parameters: Subscription.CancelableSubscribeParameters) { + const request = new HandshakeSubscribeRequest({ + ...parameters, + keySet: this._configuration.keySet, + crypto: this._configuration.cryptoModule, + getFileUrl: this.getFileUrl, + }); + + const abortUnsubscribe = parameters.abortSignal.subscribe(request.abort); + + /** + * Allow subscription cancellation. + * + * **Note:** Had to be done after scheduling because transport provider return cancellation + * controller only when schedule new request. + */ + const handshakeResponse = this.sendRequest(request); + return handshakeResponse.then((response) => { + abortUnsubscribe(); + return response.cursor; + }); + } + + /** + * Event engine receive messages subscribe. + * + * @param parameters - Request configuration parameters. + */ + private async subscribeReceiveMessages(parameters: Subscription.CancelableSubscribeParameters) { + const request = new ReceiveMessagesSubscribeRequest({ + ...parameters, + keySet: this._configuration.keySet, + crypto: this._configuration.cryptoModule, + getFileUrl: this.getFileUrl, + }); + + const abortUnsubscribe = parameters.abortSignal.subscribe(request.abort); + + /** + * Allow subscription cancellation. + * + * **Note:** Had to be done after scheduling because transport provider return cancellation + * controller only when schedule new request. + */ + const handshakeResponse = this.sendRequest(request); + return handshakeResponse.then((response) => { + abortUnsubscribe(); + return response; + }); + } + // endregion + + // -------------------------------------------------------- + // ------------------ Message Action API ------------------ + // -------------------------------------------------------- + // region Message Action API + + // region List + /** + * Get reactions to a specific message. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public getMessageActions( + parameters: MessageAction.GetMessageActionsParameters, + callback: ResultCallback, + ): void; + + /** + * Get reactions to a specific message. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous get reactions response. + */ + public async getMessageActions( + parameters: MessageAction.GetMessageActionsParameters, + ): Promise; + + /** + * Get reactions to a specific message. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get reactions response or `void` in case if `callback` provided. + */ + async getMessageActions( + parameters: MessageAction.GetMessageActionsParameters, + callback?: ResultCallback, + ): Promise { + const request = new GetMessageActionsRequest({ ...parameters, keySet: this._configuration.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Add + /** + * Add a reaction to a specific message. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public addMessageAction( + parameters: MessageAction.AddMessageActionParameters, + callback: ResultCallback, + ): void; + + /** + * Add a reaction to a specific message. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous add a reaction response. + */ + public async addMessageAction( + parameters: MessageAction.AddMessageActionParameters, + ): Promise; + + /** + * Add a reaction to a specific message. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous add a reaction response or `void` in case if `callback` provided. + */ + async addMessageAction( + parameters: MessageAction.AddMessageActionParameters, + callback?: ResultCallback, + ): Promise { + const request = new AddMessageActionRequest({ ...parameters, keySet: this._configuration.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Remove + /** + * Remove a reaction from a specific message. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public removeMessageAction( + parameters: MessageAction.RemoveMessageActionParameters, + callback: ResultCallback, + ): void; + + /** + * Remove a reaction from a specific message. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous remove a reaction response. + */ + public async removeMessageAction( + parameters: MessageAction.RemoveMessageActionParameters, + ): Promise; + + /** + * Remove a reaction from a specific message. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous remove a reaction response or `void` in case if `callback` provided. + */ + async removeMessageAction( + parameters: MessageAction.RemoveMessageActionParameters, + callback?: ResultCallback, + ): Promise { + const request = new RemoveMessageAction({ ...parameters, keySet: this._configuration.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + // endregion + + // -------------------------------------------------------- + // --------------- Message Persistence API ---------------- + // -------------------------------------------------------- + // region Message Persistence API + + // region Fetch Messages + /** + * Fetch messages history for channels. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + * + * @deprecated + */ + public fetchMessages( + parameters: History.FetchMessagesParameters, + callback: ResultCallback, + ): void; + + /** + * Fetch messages history for channels. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous fetch messages response. + * + * @deprecated + */ + public async fetchMessages(parameters: History.FetchMessagesParameters): Promise; + + /** + * Fetch messages history for channels. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous fetch messages response or `void` in case if `callback` provided. + * + * @deprecated + */ + async fetchMessages( + parameters: History.FetchMessagesParameters, + callback?: ResultCallback, + ): Promise { + const request = new FetchMessagesRequest({ + ...parameters, + keySet: this._configuration.keySet, + crypto: this._configuration.cryptoModule, + getFileUrl: this.getFileUrl, + }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Delete Messages + /** + * Delete messages from the channel history. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + * + * @deprecated + */ + public deleteMessages( + parameters: History.DeleteMessagesParameters, + callback: ResultCallback, + ): void; + + /** + * Delete messages from the channel history. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous delete messages response. + * + * @deprecated + */ + public async deleteMessages(parameters: History.DeleteMessagesParameters): Promise; + + /** + * Delete messages from the channel history. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous delete messages response or `void` in case if `callback` provided. + * + * @deprecated + */ + async deleteMessages( + parameters: History.DeleteMessagesParameters, + callback?: ResultCallback, + ): Promise { + const request = new DeleteMessageRequest({ ...parameters, keySet: this._configuration.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Count Messages + /** + * Count messages from the channels' history. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + * + * @deprecated + */ + public messageCounts( + parameters: History.MessageCountParameters, + callback: ResultCallback, + ): void; + + /** + * Count messages from the channels' history. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous count messages response. + * + * @deprecated + */ + public async messageCounts(parameters: History.MessageCountParameters): Promise; + + /** + * Count messages from the channels' history. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous count messages response or `void` in case if `callback` provided. + * + * @deprecated + */ + async messageCounts( + parameters: History.MessageCountParameters, + callback?: ResultCallback, + ): Promise { + const request = new MessageCountRequest({ ...parameters, keySet: this._configuration.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Deprecated + // region Fetch History + /** + * Fetch single channel history. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + * + * @deprecated + */ + public history(parameters: History.GetHistoryParameters, callback: ResultCallback): void; + + /** + * Fetch single channel history. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous fetch channel history response. + * + * @deprecated + */ + public async history(parameters: History.GetHistoryParameters): Promise; + + /** + * Fetch single channel history. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous fetch channel history response or `void` in case if `callback` provided. + * + * @deprecated + */ + async history( + parameters: History.GetHistoryParameters, + callback?: ResultCallback, + ): Promise { + const request = new GetHistoryRequest({ + ...parameters, + keySet: this._configuration.keySet, + crypto: this._configuration.cryptoModule, + }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + // endregion + // endregion + + // -------------------------------------------------------- + // --------------------- Presence API --------------------- + // -------------------------------------------------------- + // region Presence API + + // region Here Now + /** + * Get channel's presence information. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public hereNow(parameters: Presence.HereNowParameters, callback: ResultCallback): void; + + /** + * Get channel presence information. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous get channel's presence response. + */ + public async hereNow(parameters: Presence.HereNowParameters): Promise; + + /** + * Get channel's presence information. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get channel's presence response or `void` in case if `callback` provided. + */ + async hereNow( + parameters: Presence.HereNowParameters, + callback?: ResultCallback, + ): Promise { + const request = new HereNowRequest({ ...parameters, keySet: this._configuration.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Where Now + /** + * Get user's presence information. + * + * Get list of channels to which `uuid` currently subscribed. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public whereNow(parameters: Presence.WhereNowParameters, callback: ResultCallback): void; + + /** + * Get user's presence information. + * + * Get list of channels to which `uuid` currently subscribed. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous get user's presence response. + */ + public async whereNow(parameters: Presence.WhereNowParameters): Promise; + + /** + * Get user's presence information. + * + * Get list of channels to which `uuid` currently subscribed. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get user's presence response or `void` in case if `callback` provided. + */ + async whereNow( + parameters: Presence.WhereNowParameters, + callback?: ResultCallback, + ): Promise { + const request = new WhereNowRequest({ + uuid: parameters.uuid ?? this._configuration.userId, + keySet: this._configuration.keySet, + }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Get Presence State + /** + * Get associated user's data for channels and groups. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public getState( + parameters: Presence.GetPresenceStateParameters, + callback: ResultCallback, + ): void; + + /** + * Get associated user's data for channels and groups. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous get associated user's data response. + */ + public async getState(parameters: Presence.GetPresenceStateParameters): Promise; + + /** + * Get associated user's data for channels and groups. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get user's data response or `void` in case if `callback` provided. + */ + async getState( + parameters: Presence.GetPresenceStateParameters, + callback?: ResultCallback, + ): Promise { + const request = new GetPresenceStateRequest({ + ...parameters, + uuid: parameters.uuid ?? this._configuration.userId, + keySet: this._configuration.keySet, + }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Set Presence State + /** + * Set associated user's data for channels and groups. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public setState( + parameters: Presence.SetPresenceStateParameters | Presence.SetPresenceStateWithHeartbeatParameters, + callback: ResultCallback, + ): void; + + /** + * Set associated user's data for channels and groups. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous set associated user's data response. + */ + public async setState( + parameters: Presence.SetPresenceStateParameters | Presence.SetPresenceStateWithHeartbeatParameters, + ): Promise; + + /** + * Set associated user's data for channels and groups. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous set user's data response or `void` in case if `callback` provided. + */ + async setState( + parameters: Presence.SetPresenceStateParameters | Presence.SetPresenceStateWithHeartbeatParameters, + callback?: ResultCallback, + ): Promise { + const { keySet, userId: uuid } = this._configuration; + const heartbeat = this._configuration.getPresenceTimeout(); + let request: AbstractRequest; + + // Maintain presence information (if required). + if (this._configuration.enableEventEngine && this.presenceState) { + const presenceState = this.presenceState; + parameters.channels?.forEach((channel) => (presenceState[channel] = parameters.state)); + + if ('channelGroups' in parameters) { + parameters.channelGroups?.forEach((group) => (presenceState[group] = parameters.state)); + } + } + + // Check whether state should be set with heartbeat or not. + if ('withHeartbeat' in parameters) { + request = new HeartbeatRequest({ ...parameters, keySet, heartbeat }); + } else { + request = new SetPresenceStateRequest({ ...parameters, keySet, uuid }); + } + + // Update state used by subscription manager. + if (this.subscriptionManager) this.subscriptionManager.setState(parameters); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Change presence state + /** + * Manual presence management. + * + * @param parameters - Desired presence state for provided list of channels and groups. + */ + public presence(parameters: { connected: boolean; channels?: string[]; channelGroups?: string[] }) { + this.subscriptionManager?.changePresence(parameters); + } + // endregion + + // region Heartbeat + /** + * Announce user presence + * + * @param parameters - Desired presence state for provided list of channels and groups. + */ + private async heartbeat(parameters: Presence.PresenceHeartbeatParameters) { + // Manual presence management possible only with subscription manager. + if (!this.subscriptionManager) return; + + const request = new HeartbeatRequest({ + ...parameters, + keySet: this._configuration.keySet, + }); + + return this.sendRequest(request); + } + // endregion + // endregion + + // -------------------------------------------------------- + // ------------------------ PAM API ----------------------- + // -------------------------------------------------------- + // region PAM API + + // region Grant + /** + * Grant token permission. + * + * Generate access token with requested permissions. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public grantToken(parameters: PAM.GrantTokenParameters, callback: ResultCallback): void; + + /** + * Grant token permission. + * + * Generate access token with requested permissions. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous grant token response. + */ + public async grantToken(parameters: PAM.GrantTokenParameters): Promise; + + /** + * Grant token permission. + * + * Generate access token with requested permissions. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous grant token response or `void` in case if `callback` provided. + */ + async grantToken( + parameters: PAM.GrantTokenParameters, + callback?: ResultCallback, + ): Promise { + const request = new GrantTokenRequest({ ...parameters, keySet: this._configuration.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Revoke + /** + * Revoke token permission. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public revokeToken(parameters: PAM.RevokeParameters, callback: ResultCallback): void; + + /** + * Revoke token permission. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous revoke token response. + */ + public async revokeToken(parameters: PAM.RevokeParameters): Promise; + + /** + * Revoke token permission. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous revoke token response or `void` in case if `callback` provided. + */ + async revokeToken( + parameters: PAM.RevokeParameters, + callback?: ResultCallback, + ): Promise { + const request = new RevokeTokenRequest({ ...parameters, keySet: this._configuration.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Token Manipulation + /** + * Get current access token. + * + * @returns Previously configured access token using {@link setToken} method. + */ + public get token(): string | undefined { + return this.tokenManager.getToken(); + } + + /** + * Get current access token. + * + * @returns Previously configured access token using {@link setToken} method. + */ + public getToken(): string | undefined { + return this.token; + } + + /** + * Set current access token. + * + * @param token - New access token which should be used with next REST API endpoint calls. + */ + public set token(token: string | undefined) { + this.tokenManager.setToken(token); + } + + /** + * Set current access token. + * + * @param token - New access token which should be used with next REST API endpoint calls. + */ + public setToken(token: string | undefined): void { + this.token = token; + } + + /** + * Parse access token. + * + * Parse token to see what permissions token owner has. + * + * @param token - Token which should be parsed. + * + * @returns Token's permissions information for the resources. + */ + public parseToken(token: string) { + return this.tokenManager.parseToken(token); + } + // endregion + + // region Deprecated + // region Grant Auth Permissions + /** + * Grant auth key(s) permission. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link grantToken} and {@link setToken} methods instead. + */ + public grant(parameters: PAM.GrantParameters, callback: ResultCallback): void; + + /** + * Grant auth key(s) permission. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous grant auth key(s) permissions response. + * + * @deprecated Use {@link grantToken} and {@link setToken} methods instead. + */ + public async grant(parameters: PAM.GrantParameters): Promise; + + /** + * Grant auth key(s) permission. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous grant auth key(s) permissions or `void` in case if `callback` provided. + * + * @deprecated Use {@link grantToken} and {@link setToken} methods instead. + */ + async grant( + parameters: PAM.GrantParameters, + callback?: ResultCallback, + ): Promise { + const request = new GrantRequest({ ...parameters, keySet: this._configuration.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Audit Permissions + /** + * Audit auth key(s) permission. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + * + * @deprecated + */ + public audit(parameters: PAM.AuditParameters, callback: ResultCallback): void; + + /** + * Audit auth key(s) permission. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous audit auth key(s) permissions response. + * + * @deprecated + */ + public async audit(parameters: PAM.AuditParameters): Promise; + + /** + * Audit auth key(s) permission. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @deprecated + * + * @deprecated Use {@link grantToken} and {@link setToken} methods instead. + */ + async audit( + parameters: PAM.AuditParameters, + callback?: ResultCallback, + ): Promise { + const request = new AuditRequest({ ...parameters, keySet: this._configuration.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + // endregion + // endregion + + // -------------------------------------------------------- + // ------------------- App Context API -------------------- + // -------------------------------------------------------- + // region App Context API + + /** + * PubNub App Context API group. + */ + get objects(): PubNubObjects { + return this._objects; + } + + // region Deprecated API + /** + * Fetch a paginated list of User objects. + * + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link PubNubCore#objects.getAllUUIDMetadata} method instead. + */ + public fetchUsers( + callback: ResultCallback>, + ): void; + + /** + * Fetch a paginated list of User objects. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link PubNubCore#objects.getAllUUIDMetadata} method instead. + */ + public fetchUsers( + parameters: AppContext.GetAllMetadataParameters, + callback: ResultCallback>, + ): void; + + /** + * Fetch a paginated list of User objects. + * + * @param [parameters] - Request configuration parameters. + * + * @returns Asynchronous get all User objects response. + * + * @deprecated Use {@link PubNubCore#objects.getAllUUIDMetadata} method instead. + */ + public async fetchUsers( + parameters?: AppContext.GetAllMetadataParameters, + ): Promise>; + + /** + Fetch a paginated list of User objects. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get all User objects response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.getAllUUIDMetadata} method instead. + */ + public async fetchUsers( + parametersOrCallback?: + | AppContext.GetAllMetadataParameters + | ResultCallback>, + callback?: ResultCallback>, + ): Promise | void> { + return this.objects._getAllUUIDMetadata(parametersOrCallback, callback); + } + + /** + * Fetch User object for currently configured PubNub client `uuid`. + * + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link PubNubCore#objects.getUUIDMetadata} method instead. + */ + public fetchUser( + callback: ResultCallback>, + ): void; + + /** + * Fetch User object for currently configured PubNub client `uuid`. + * + * @param parameters - Request configuration parameters. Will fetch User object for currently + * configured PubNub client `uuid` if not set. + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link PubNubCore#objects.getUUIDMetadata} method instead. + */ + public fetchUser( + parameters: AppContext.GetUUIDMetadataParameters, + callback: ResultCallback>, + ): void; + + /** + * Fetch User object for currently configured PubNub client `uuid`. + * + * @param [parameters] - Request configuration parameters. Will fetch User object for currently + * configured PubNub client `uuid` if not set. + * + * @returns Asynchronous get User object response. + * + * @deprecated Use {@link PubNubCore#objects.getUUIDMetadata} method instead. + */ + public async fetchUser( + parameters?: AppContext.GetUUIDMetadataParameters, + ): Promise>; + + /** + * Fetch User object for currently configured PubNub client `uuid`. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get User object response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.getUUIDMetadata} method instead. + */ + async fetchUser( + parametersOrCallback?: + | AppContext.GetUUIDMetadataParameters + | ResultCallback>, + callback?: ResultCallback>, + ): Promise | void> { + return this.objects._getUUIDMetadata(parametersOrCallback, callback); + } + + /** + * Create User object. + * + * @param parameters - Request configuration parameters. Will create User object for currently + * configured PubNub client `uuid` if not set. + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link PubNubCore#objects.setUUIDMetadata} method instead. + */ + public createUser( + parameters: AppContext.SetUUIDMetadataParameters, + callback: ResultCallback>, + ): void; + + /** + * Create User object. + * + * @param parameters - Request configuration parameters. Will create User object for currently + * configured PubNub client `uuid` if not set. + * + * @returns Asynchronous create User object response. + * + * @deprecated Use {@link PubNubCore#objects.setUUIDMetadata} method instead. + */ + public async createUser( + parameters: AppContext.SetUUIDMetadataParameters, + ): Promise>; + + /** + * Create User object. + * + * @param parameters - Request configuration parameters. Will create User object for currently + * configured PubNub client `uuid` if not set. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous create User object response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.setUUIDMetadata} method instead. + */ + async createUser( + parameters: AppContext.SetUUIDMetadataParameters, + callback?: ResultCallback>, + ): Promise | void> { + return this.objects._setUUIDMetadata(parameters, callback); + } + + /** + * Update User object. + * + * @param parameters - Request configuration parameters. Will update User object for currently + * configured PubNub client `uuid` if not set. + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link PubNubCore#objects.setUUIDMetadata} method instead. + */ + public updateUser( + parameters: AppContext.SetUUIDMetadataParameters, + callback: ResultCallback>, + ): void; + + /** + * Update User object. + * + * @param parameters - Request configuration parameters. Will update User object for currently + * configured PubNub client `uuid` if not set. + * + * @returns Asynchronous update User object response. + * + * @deprecated Use {@link PubNubCore#objects.setUUIDMetadata} method instead. + */ + public async updateUser( + parameters: AppContext.SetUUIDMetadataParameters, + ): Promise>; + + /** + * Update User object. + * + * @param parameters - Request configuration parameters. Will update User object for currently + * configured PubNub client `uuid` if not set. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous update User object response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.setUUIDMetadata} method instead. + */ + async updateUser( + parameters: AppContext.SetUUIDMetadataParameters, + callback?: ResultCallback>, + ): Promise | void> { + return this.objects._setUUIDMetadata(parameters, callback); + } + + /** + * Remove a specific User object. + * + * @param callback - Request completion handler callback. Will remove User object for currently + * configured PubNub client `uuid` if not set. + * + * @deprecated Use {@link PubNubCore#objects.removeUUIDMetadata} method instead. + */ + public removeUser(callback: ResultCallback): void; + + /** + * Remove a specific User object. + * + * @param parameters - Request configuration parameters. Will remove User object for currently + * configured PubNub client `uuid` if not set. + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link PubNubCore#objects.removeUUIDMetadata} method instead. + */ + public removeUser( + parameters: AppContext.RemoveUUIDMetadataParameters, + callback: ResultCallback, + ): void; + + /** + * Remove a specific User object. + * + * @param [parameters] - Request configuration parameters. Will remove User object for currently + * configured PubNub client `uuid` if not set. + * + * @returns Asynchronous User object remove response. + * + * @deprecated Use {@link PubNubCore#objects.removeUUIDMetadata} method instead. + */ + public async removeUser( + parameters?: AppContext.RemoveUUIDMetadataParameters, + ): Promise; + + /** + * Remove a specific User object. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous User object remove response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.removeUUIDMetadata} method instead. + */ + public async removeUser( + parametersOrCallback?: + | AppContext.RemoveUUIDMetadataParameters + | ResultCallback, + callback?: ResultCallback, + ): Promise { + return this.objects._removeUUIDMetadata(parametersOrCallback, callback); + } + + /** + * Fetch a paginated list of Space objects. + * + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link PubNubCore#objects.getAllChannelMetadata} method instead. + */ + public fetchSpaces( + callback: ResultCallback>, + ): void; + + /** + * Fetch a paginated list of Space objects. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link PubNubCore#objects.getAllChannelMetadata} method instead. + */ + public fetchSpaces( + parameters: AppContext.GetAllMetadataParameters, + callback: ResultCallback>, + ): void; + + /** + * Fetch a paginated list of Space objects. + * + * @param [parameters] - Request configuration parameters. + * + * @returns Asynchronous get all Space objects response. + * + * @deprecated Use {@link PubNubCore#objects.getAllChannelMetadata} method instead. + */ + public async fetchSpaces( + parameters?: AppContext.GetAllMetadataParameters, + ): Promise>; + + /** + * Fetch a paginated list of Space objects. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get all Space objects response or `void` in case if `callback` + * provided. + * + * @deprecated Use {@link PubNubCore#objects.getAllChannelMetadata} method instead. + */ + async fetchSpaces( + parametersOrCallback?: + | AppContext.GetAllMetadataParameters + | ResultCallback>, + callback?: ResultCallback>, + ): Promise | void> { + return this.objects._getAllChannelMetadata(parametersOrCallback, callback); + } + + /** + * Fetch a specific Space object. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link PubNubCore#objects.getChannelMetadata} method instead. + */ + public fetchSpace( + parameters: AppContext.GetChannelMetadataParameters, + callback: ResultCallback>, + ): void; + + /** + * Fetch a specific Space object. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous get Channel metadata response. + * + * @deprecated Use {@link PubNubCore#objects.getChannelMetadata} method instead. + */ + public async fetchSpace( + parameters: AppContext.GetChannelMetadataParameters, + ): Promise>; + + /** + * Fetch a specific Space object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get Space object response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.getChannelMetadata} method instead. + */ + async fetchSpace( + parameters: AppContext.GetChannelMetadataParameters, + callback?: ResultCallback>, + ): Promise | void> { + return this.objects._getChannelMetadata(parameters, callback); + } + + /** + * Create specific Space object. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link PubNubCore#objects.setChannelMetadata} method instead. + */ + public createSpace( + parameters: AppContext.SetChannelMetadataParameters, + callback: ResultCallback>, + ): void; + + /** + * Create specific Space object. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous create Space object response. + * + * @deprecated Use {@link PubNubCore#objects.setChannelMetadata} method instead. + */ + public async createSpace( + parameters: AppContext.SetChannelMetadataParameters, + ): Promise>; + + /** + * Create specific Space object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous create Space object response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.setChannelMetadata} method instead. + */ + async createSpace( + parameters: AppContext.SetChannelMetadataParameters, + callback?: ResultCallback>, + ): Promise | void> { + return this.objects._setChannelMetadata(parameters, callback); + } + + /** + * Update specific Space object. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link PubNubCore#objects.setChannelMetadata} method instead. + */ + public updateSpace( + parameters: AppContext.SetChannelMetadataParameters, + callback: ResultCallback>, + ): void; + + /** + * Update specific Space object. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous update Space object response. + * + * @deprecated Use {@link PubNubCore#objects.setChannelMetadata} method instead. + */ + public async updateSpace( + parameters: AppContext.SetChannelMetadataParameters, + ): Promise>; + + /** + * Update specific Space object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous update Space object response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.setChannelMetadata} method instead. + */ + async updateSpace( + parameters: AppContext.SetChannelMetadataParameters, + callback?: ResultCallback>, + ): Promise | void> { + return this.objects._setChannelMetadata(parameters, callback); + } + + /** + * Remove Space object. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link PubNubCore#objects.removeChannelMetadata} method instead. + */ + public removeSpace( + parameters: AppContext.RemoveChannelMetadataParameters, + callback: ResultCallback, + ): void; + + /** + * Remove a specific Space object. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous Space object remove response. + * + * @deprecated Use {@link PubNubCore#objects.removeChannelMetadata} method instead. + */ + public async removeSpace( + parameters: AppContext.RemoveChannelMetadataParameters, + ): Promise; + + /** + * Remove a specific Space object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous Space object remove response or `void` in case if `callback` + * provided. + * + * @deprecated Use {@link PubNubCore#objects.removeChannelMetadata} method instead. + */ + async removeSpace( + parameters: AppContext.RemoveChannelMetadataParameters, + callback?: ResultCallback, + ): Promise { + return this.objects._removeChannelMetadata(parameters, callback); + } + + /** + * Fetch paginated list of specific Space members or specific User memberships. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link PubNubCore#objects.getChannelMembers} or {@link PubNubCore#objects.getMemberships} + * methods instead. + */ + public fetchMemberships< + RelationCustom extends AppContext.CustomData = AppContext.CustomData, + MetadataCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.GetMembershipsParameters | AppContext.GetMembersParameters, + callback: ResultCallback< + | AppContext.SpaceMembershipsResponse + | AppContext.UserMembersResponse + >, + ): void; + + /** + * Fetch paginated list of specific Space members or specific User memberships. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous get specific Space members or specific User memberships response. + * + * @deprecated Use {@link PubNubCore#objects.getChannelMembers} or {@link PubNubCore#objects.getMemberships} + * methods instead. + */ + public async fetchMemberships< + RelationCustom extends AppContext.CustomData = AppContext.CustomData, + MetadataCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.GetMembershipsParameters | AppContext.GetMembersParameters, + ): Promise< + | AppContext.SpaceMembershipsResponse + | AppContext.UserMembersResponse + >; + + /** + * Fetch paginated list of specific Space members or specific User memberships. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get specific Space members or specific User memberships response or + * `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.getChannelMembers} or {@link PubNubCore#objects.getMemberships} + * methods instead. + */ + public async fetchMemberships< + RelationCustom extends AppContext.CustomData = AppContext.CustomData, + MetadataCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.GetMembershipsParameters | AppContext.GetMembersParameters, + callback?: ResultCallback< + | AppContext.SpaceMembershipsResponse + | AppContext.UserMembersResponse + >, + ): Promise< + | AppContext.SpaceMembershipsResponse + | AppContext.UserMembersResponse + | void + > { + return this.objects.fetchMemberships(parameters, callback); + } + + /** + * Add members to specific Space or memberships specific User. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link PubNubCore#objects.setChannelMembers} or {@link PubNubCore#objects.setMemberships} + * methods instead. + */ + public addMemberships< + Custom extends AppContext.CustomData = AppContext.CustomData, + MetadataCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.SetMembershipsParameters | AppContext.SetChannelMembersParameters, + callback: ResultCallback< + AppContext.SetMembershipsResponse | AppContext.SetMembersResponse + >, + ): void; + + /** + * Add members to specific Space or memberships specific User. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous add members to specific Space or memberships specific User response. + * + * @deprecated Use {@link PubNubCore#objects.setChannelMembers} or {@link PubNubCore#objects.setMemberships} + * methods instead. + */ + public async addMemberships< + Custom extends AppContext.CustomData = AppContext.CustomData, + MetadataCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.SetMembershipsParameters | AppContext.SetChannelMembersParameters, + ): Promise< + AppContext.SetMembershipsResponse | AppContext.SetMembersResponse + >; + + /** + * Add members to specific Space or memberships specific User. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous add members to specific Space or memberships specific User response or + * `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.setChannelMembers} or {@link PubNubCore#objects.setMemberships} + * methods instead. + */ + async addMemberships< + Custom extends AppContext.CustomData = AppContext.CustomData, + MetadataCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.SetMembershipsParameters | AppContext.SetChannelMembersParameters, + callback?: ResultCallback< + AppContext.SetMembershipsResponse | AppContext.SetMembersResponse + >, + ) { + return this.objects.addMemberships(parameters, callback); + } + + /** + * Update specific Space members or User memberships. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link PubNubCore#objects.setChannelMembers} or {@link PubNubCore#objects.setMemberships} + * methods instead. + */ + public updateMemberships< + Custom extends AppContext.CustomData = AppContext.CustomData, + MetadataCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.SetMembershipsParameters | AppContext.SetChannelMembersParameters, + callback: ResultCallback< + AppContext.SetMembershipsResponse | AppContext.SetMembersResponse + >, + ): void; + + /** + * Update specific Space members or User memberships. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous update Space members or User memberships response. + * + * @deprecated Use {@link PubNubCore#objects.setChannelMembers} or {@link PubNubCore#objects.setMemberships} + * methods instead. + */ + public async updateMemberships< + Custom extends AppContext.CustomData = AppContext.CustomData, + MetadataCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.SetMembershipsParameters | AppContext.SetChannelMembersParameters, + ): Promise< + AppContext.SetMembershipsResponse | AppContext.SetMembersResponse + >; + + /** + * Update specific Space members or User memberships. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous update Space members or User memberships response or `void` in case + * if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.setChannelMembers} or {@link PubNubCore#objects.setMemberships} + * methods instead. + */ + async updateMemberships< + Custom extends AppContext.CustomData = AppContext.CustomData, + MetadataCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.SetMembershipsParameters | AppContext.SetChannelMembersParameters, + callback?: ResultCallback< + AppContext.SetMembershipsResponse | AppContext.SetMembersResponse + >, + ) { + return this.objects.addMemberships(parameters, callback); + } + + /** + * Remove User membership. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + * + * @deprecated Use {@link PubNubCore#objects.removeMemberships} or {@link PubNubCore#objects.removeChannelMembers} + * methods instead + * from `objects` API group.. + */ + public removeMemberships< + RelationCustom extends AppContext.CustomData = AppContext.CustomData, + MetadataCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.RemoveMembersParameters | AppContext.RemoveMembershipsParameters, + callback: ResultCallback< + | AppContext.RemoveMembersResponse + | AppContext.RemoveMembershipsResponse + >, + ): void; + + /** + * Remove User membership. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous memberships modification response. + * + * @deprecated Use {@link PubNubCore#objects.removeMemberships} or {@link PubNubCore#objects.removeChannelMembers} + * methods instead + * from `objects` API group.. + */ + public async removeMemberships< + RelationCustom extends AppContext.CustomData = AppContext.CustomData, + MetadataCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.RemoveMembersParameters | AppContext.RemoveMembershipsParameters, + ): Promise>; + + /** + * Remove User membership. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous memberships modification response or `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubCore#objects.removeMemberships} or {@link PubNubCore#objects.removeChannelMembers} + * methods instead + * from `objects` API group.. + */ + public async removeMemberships< + RelationCustom extends AppContext.CustomData = AppContext.CustomData, + MetadataCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.RemoveMembersParameters | AppContext.RemoveMembershipsParameters, + callback?: ResultCallback< + | AppContext.RemoveMembersResponse + | AppContext.RemoveMembershipsResponse + >, + ): Promise< + | AppContext.RemoveMembersResponse + | AppContext.RemoveMembershipsResponse + | void + > { + if ('spaceId' in parameters) { + const spaceParameters = parameters as AppContext.RemoveMembersParameters; + const requestParameters = { + channel: spaceParameters.spaceId ?? spaceParameters.channel, + uuids: spaceParameters.userIds ?? spaceParameters.uuids, + limit: 0, + }; + if (callback) return this.objects.removeChannelMembers(requestParameters, callback); + return this.objects.removeChannelMembers(requestParameters); + } + + const userParameters = parameters as AppContext.RemoveMembershipsParameters; + const requestParameters = { + uuid: userParameters.userId, + channels: userParameters.spaceIds ?? userParameters.channels, + limit: 0, + }; + if (callback) return this.objects.removeMemberships(requestParameters, callback); + return this.objects.removeMemberships(requestParameters); + } + // endregion + // endregion + + // -------------------------------------------------------- + // ----------------- Channel Groups API ------------------- + // -------------------------------------------------------- + // region Channel Groups API + + /** + * PubNub Channel Groups API group. + */ + get channelGroups(): PubNubChannelGroups { + return this._channelGroups; + } + // endregion + + // -------------------------------------------------------- + // ---------------- Push Notifications API ----------------- + // -------------------------------------------------------- + // region Push Notifications API + + /** + * PubNub Push Notifications API group. + */ + get push(): PubNubPushNotifications { + return this._push; + } + // endregion + + // -------------------------------------------------------- + // ------------------ File sharing API -------------------- + // -------------------------------------------------------- + // region File sharing API + + // region Send + /** + * Share file to a specific channel. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public sendFile( + parameters: FileSharing.SendFileParameters, + callback: ResultCallback, + ): void; + + /** + * Share file to a specific channel. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous file sharing response. + */ + public async sendFile( + parameters: FileSharing.SendFileParameters, + ): Promise; + + /** + * Share file to a specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous file sharing response or `void` in case if `callback` provided. + */ + public async sendFile( + parameters: FileSharing.SendFileParameters, + callback?: ResultCallback, + ): Promise { + if (!this._configuration.PubNubFile) + throw new Error("Validation failed: 'PubNubFile' not configured or file upload not supported by the platform."); + + const sendFileRequest = new SendFileRequest({ + ...parameters, + cipherKey: parameters.cipherKey ?? this._configuration.cipherKey, + keySet: this._configuration.keySet, + PubNubFile: this._configuration.PubNubFile!, + fileUploadPublishRetryLimit: this._configuration.fileUploadPublishRetryLimit, + file: parameters.file, + sendRequest: this.sendRequest, + publishFile: this.publishFile, + crypto: this._configuration.cryptoModule, + cryptography: this.cryptography ? (this.cryptography as Cryptography) : undefined, + }); + + const status: Status = { + error: false, + operation: RequestOperation.PNPublishFileOperation, + statusCode: 0, + }; + + return sendFileRequest + .process() + .then((response) => { + status.statusCode = response.status; + + if (callback) return callback(status, response); + return response; + }) + .catch((error: PubNubAPIError) => { + const errorStatus = error.toStatus(status.operation!); + + // Notify callback (if possible). + if (callback) callback(errorStatus, null); + + throw new PubNubError('REST API request processing error, check status for details', errorStatus); + }); + } + // endregion + + // region Publish File Message + /** + * Publish file message to a specific channel. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public publishFile( + parameters: FileSharing.PublishFileMessageParameters, + callback: ResultCallback, + ): void; + + /** + * Publish file message to a specific channel. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous publish file message response. + */ + public async publishFile( + parameters: FileSharing.PublishFileMessageParameters, + ): Promise; + + /** + * Publish file message to a specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous publish file message response or `void` in case if `callback` provided. + */ + public async publishFile( + parameters: FileSharing.PublishFileMessageParameters, + callback?: ResultCallback, + ): Promise { + if (!this._configuration.PubNubFile) + throw new Error("Validation failed: 'PubNubFile' not configured or file upload not supported by the platform."); + + const request = new PublishFileMessageRequest({ + ...parameters, + keySet: this._configuration.keySet, + crypto: this._configuration.cryptoModule, + }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region List + /** + * Retrieve list of shared files in specific channel. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public listFiles( + parameters: FileSharing.ListFilesParameters, + callback: ResultCallback, + ): void; + + /** + * Retrieve list of shared files in specific channel. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous shared files list response. + */ + public async listFiles(parameters: FileSharing.ListFilesParameters): Promise; + + /** + * Retrieve list of shared files in specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous shared files list response or `void` in case if `callback` provided. + */ + public async listFiles( + parameters: FileSharing.ListFilesParameters, + callback?: ResultCallback, + ): Promise { + const request = new FilesListRequest({ ...parameters, keySet: this._configuration.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Get Download Url + /** + * Get file download Url. + * + * @param parameters - Request configuration parameters. + * + * @returns File download Url. + */ + public getFileUrl(parameters: FileSharing.FileUrlParameters): FileSharing.FileUrlResponse { + const request = this.transport.request( + new GetFileDownloadUrlRequest({ ...parameters, keySet: this._configuration.keySet }).request(), + ); + const query = request.queryParameters ?? {}; + const queryString = Object.keys(query) + .map((key) => { + const queryValue = query[key]; + if (!Array.isArray(queryValue)) return `${key}=${encodeString(queryValue)}`; + + return queryValue.map((value) => `${key}=${encodeString(value)}`).join('&'); + }) + .join('&'); + + return `${request.origin}${request.path}?${queryString}`; + } + // endregion + + // region Download + /** + * Download shared file from specific channel. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public downloadFile(parameters: FileSharing.DownloadFileParameters, callback: ResultCallback): void; + + /** + * Download shared file from specific channel. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous download shared file response. + */ + public async downloadFile(parameters: FileSharing.DownloadFileParameters): Promise; + + /** + * Download shared file from specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous download shared file response or `void` in case if `callback` provided. + */ + public async downloadFile( + parameters: FileSharing.DownloadFileParameters, + callback?: ResultCallback, + ): Promise { + if (!this._configuration.PubNubFile) + throw new Error("Validation failed: 'PubNubFile' not configured or file upload not supported by the platform."); + + const request = new DownloadFileRequest({ + ...parameters, + cipherKey: parameters.cipherKey ?? this._configuration.cipherKey, + keySet: this._configuration.keySet, + PubNubFile: this._configuration.PubNubFile!, + cryptography: this.cryptography ? (this.cryptography as Cryptography) : undefined, + crypto: this._configuration.cryptoModule, + }); + + if (callback) return this.sendRequest(request, callback); + return (await this.sendRequest(request)) as PlatformFile; + } + // endregion + + // region Delete + /** + * Delete shared file from specific channel. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public deleteFile( + parameters: FileSharing.DeleteFileParameters, + callback: ResultCallback, + ): void; + + /** + * Delete shared file from specific channel. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous delete shared file response. + */ + public async deleteFile(parameters: FileSharing.DeleteFileParameters): Promise; + + /** + * Delete shared file from specific channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous delete shared file response or `void` in case if `callback` provided. + */ + public async deleteFile( + parameters: FileSharing.DeleteFileParameters, + callback?: ResultCallback, + ): Promise { + const request = new DeleteFileRequest({ ...parameters, keySet: this._configuration.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + // endregion + + // -------------------------------------------------------- + // ---------------------- Time API ------------------------ + // -------------------------------------------------------- + // region Time API + + /** + Get current high-precision timetoken. + * + * @param callback - Request completion handler callback. + */ + public time(callback: ResultCallback): void; + + /** + * Get current high-precision timetoken. + * + * @returns Asynchronous get current timetoken response. + */ + public async time(): Promise; + + /** + Get current high-precision timetoken. + * + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get current timetoken response or `void` in case if `callback` provided. + */ + async time(callback?: ResultCallback): Promise { + const request = new Time.TimeRequest(); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // -------------------------------------------------------- + // ------------------ Cryptography API -------------------- + // -------------------------------------------------------- + // region Cryptography + // region Common + + /** + * Encrypt data. + * + * @param data - Stringified data which should be encrypted using `CryptoModule`. + * @deprecated + * @param [customCipherKey] - Cipher key which should be used to encrypt data. **Deprecated:** + * use {@link Configuration#cryptoModule|cryptoModule} instead. + * + * @returns Data encryption result as a string. + */ + public encrypt(data: string, customCipherKey?: string): string { + if (typeof customCipherKey === 'undefined' && this._configuration.cryptoModule) { + const encrypted = this._configuration.cryptoModule.encrypt(data); + + return typeof encrypted === 'string' ? encrypted : encode(encrypted); + } + + if (!this.crypto) throw new Error('Encryption error: cypher key not set'); + + return this.crypto.encrypt(data, customCipherKey); + } + + /** + * Decrypt data. + * + * @param data - Stringified data which should be encrypted using `CryptoModule`. + * @param [customCipherKey] - Cipher key which should be used to decrypt data. **Deprecated:** + * use {@link Configuration#cryptoModule|cryptoModule} instead. + * + * @returns Data decryption result as an object. + */ + public decrypt(data: string, customCipherKey?: string): Payload | null { + if (typeof customCipherKey === 'undefined' && this._configuration.cryptoModule) { + const decrypted = this._configuration.cryptoModule.decrypt(data); + + return decrypted instanceof ArrayBuffer ? JSON.parse(new TextDecoder().decode(decrypted)) : decrypted; + } + + if (!this.crypto) throw new Error('Decryption error: cypher key not set'); + + return this.crypto.decrypt(data, customCipherKey); + } + // endregion + + // region File + /** + * Encrypt file content. + * + * @param file - File which should be encrypted using `CryptoModule`. + * + * @returns Asynchronous file encryption result. + * + * @throws Error if source file not provided. + * @throws File constructor not provided. + * @throws Crypto module is missing (if non-legacy flow used). + */ + public async encryptFile(file: PubNubFileInterface): Promise; + + /** + * Encrypt file content. + * + * @param key - Cipher key which should be used to encrypt data. + * @param file - File which should be encrypted using legacy cryptography. + * + * @returns Asynchronous file encryption result. + * + * @throws Error if source file not provided. + * @throws File constructor not provided. + * @throws Crypto module is missing (if non-legacy flow used). + */ + public async encryptFile(key: string, file: PubNubFileInterface): Promise; + + /** + * Encrypt file content. + * + * @param keyOrFile - Cipher key which should be used to encrypt data or file which should be + * encrypted using `CryptoModule`. + * @param [file] - File which should be encrypted using legacy cryptography. + * + * @returns Asynchronous file encryption result. + * + * @throws Error if source file not provided. + * @throws File constructor not provided. + * @throws Crypto module is missing (if non-legacy flow used). + */ + public async encryptFile(keyOrFile: string | PubNubFileInterface, file?: PubNubFileInterface) { + if (typeof keyOrFile !== 'string') file = keyOrFile; + + if (!file) throw new Error('File encryption error. Source file is missing.'); + if (!this._configuration.PubNubFile) throw new Error('File encryption error. File constructor not configured.'); + if (typeof keyOrFile !== 'string' && !this._configuration.cryptoModule) + throw new Error('File encryption error. Crypto module not configured.'); + + if (typeof keyOrFile === 'string') { + if (!this.cryptography) throw new Error('File encryption error. File encryption not available'); + return this.cryptography.encryptFile(keyOrFile, file, this._configuration.PubNubFile); + } + + return this._configuration.cryptoModule?.encryptFile(file, this._configuration.PubNubFile); + } + + /** + * Decrypt file content. + * + * @param file - File which should be decrypted using legacy cryptography. + * + * @returns Asynchronous file decryption result. + * + * @throws Error if source file not provided. + * @throws File constructor not provided. + * @throws Crypto module is missing (if non-legacy flow used). + */ + public async decryptFile(file: PubNubFileInterface): Promise; + + /** + * Decrypt file content. + * + * @param key - Cipher key which should be used to decrypt data. + * @param [file] - File which should be decrypted using legacy cryptography. + * + * @returns Asynchronous file decryption result. + * + * @throws Error if source file not provided. + * @throws File constructor not provided. + * @throws Crypto module is missing (if non-legacy flow used). + */ + public async decryptFile(key: string | PubNubFileInterface, file?: PubNubFileInterface): Promise; + + /** + * Decrypt file content. + * + * @param keyOrFile - Cipher key which should be used to decrypt data or file which should be + * decrypted using `CryptoModule`. + * @param [file] - File which should be decrypted using legacy cryptography. + * + * @returns Asynchronous file decryption result. + * + * @throws Error if source file not provided. + * @throws File constructor not provided. + * @throws Crypto module is missing (if non-legacy flow used). + */ + public async decryptFile(keyOrFile: string | PubNubFileInterface, file?: PubNubFileInterface) { + if (typeof keyOrFile !== 'string') file = keyOrFile; + + if (!file) throw new Error('File encryption error. Source file is missing.'); + if (!this._configuration.PubNubFile) + throw new Error('File decryption error. File constructor' + ' not configured.'); + if (typeof keyOrFile === 'string' && !this._configuration.cryptoModule) + throw new Error('File decryption error. Crypto module not configured.'); + + if (typeof keyOrFile === 'string') { + if (!this.cryptography) throw new Error('File decryption error. File decryption not available'); + return this.cryptography.decryptFile(keyOrFile, file, this._configuration.PubNubFile); + } + + return this._configuration.cryptoModule?.decryptFile(file, this._configuration.PubNubFile); + } + // endregion + // endregion +} diff --git a/src/core/pubnub-objects.ts b/src/core/pubnub-objects.ts new file mode 100644 index 000000000..ff316c600 --- /dev/null +++ b/src/core/pubnub-objects.ts @@ -0,0 +1,1094 @@ +/** + * PubNub Objects API module. + */ + +import { GetAllChannelsMetadataRequest } from './endpoints/objects/channel/get_all'; +import { RemoveChannelMetadataRequest } from './endpoints/objects/channel/remove'; +import { GetUUIDMembershipsRequest } from './endpoints/objects/membership/get'; +import { SetUUIDMembershipsRequest } from './endpoints/objects/membership/set'; +import { GetAllUUIDMetadataRequest } from './endpoints/objects/uuid/get_all'; +import { GetChannelMetadataRequest } from './endpoints/objects/channel/get'; +import { SetChannelMetadataRequest } from './endpoints/objects/channel/set'; +import { RemoveUUIDMetadataRequest } from './endpoints/objects/uuid/remove'; +import { GetChannelMembersRequest } from './endpoints/objects/member/get'; +import { SetChannelMembersRequest } from './endpoints/objects/member/set'; +import { KeySet, ResultCallback, SendRequestFunction } from './types/api'; +import { GetUUIDMetadataRequest } from './endpoints/objects/uuid/get'; +import { PrivateClientConfiguration } from './interfaces/configuration'; +import * as AppContext from './types/api/app-context'; + +export default class PubNubObjects { + /** + * REST API endpoints access credentials. + */ + private readonly keySet: KeySet; + constructor( + private readonly configuration: PrivateClientConfiguration, + /* eslint-disable @typescript-eslint/no-explicit-any */ + private readonly sendRequest: SendRequestFunction, + ) { + this.keySet = configuration.keySet; + } + + // -------------------------------------------------------- + // ----------------------- UUID API ----------------------- + // -------------------------------------------------------- + // region UUID API + // region Get Metadata + + /** + * Fetch a paginated list of UUID Metadata objects. + * + * @param callback - Request completion handler callback. + */ + public getAllUUIDMetadata( + callback: ResultCallback>, + ): void; + + /** + * Fetch a paginated list of UUID Metadata objects. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public getAllUUIDMetadata( + parameters: AppContext.GetAllMetadataParameters, + callback: ResultCallback>, + ): void; + + /** + * Fetch a paginated list of UUID Metadata objects. + * + * @param [parameters] - Request configuration parameters. + * + * @returns Asynchronous get all UUID metadata response. + */ + public async getAllUUIDMetadata( + parameters?: AppContext.GetAllMetadataParameters, + ): Promise>; + + /** + * Fetch a paginated list of UUID Metadata objects. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get all UUID metadata response or `void` in case if `callback` provided. + */ + async getAllUUIDMetadata( + parametersOrCallback?: + | AppContext.GetAllMetadataParameters + | ResultCallback>, + callback?: ResultCallback>, + ): Promise | void> { + return this._getAllUUIDMetadata(parametersOrCallback, callback); + } + + /** + * Fetch a paginated list of UUID Metadata objects. + * + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get all UUID metadata response or `void` in case if `callback` provided. + */ + async _getAllUUIDMetadata( + parametersOrCallback?: + | AppContext.GetAllMetadataParameters + | ResultCallback>, + callback?: ResultCallback>, + ): Promise | void> { + // Get user request parameters. + const parameters: AppContext.GetAllMetadataParameters = + parametersOrCallback && typeof parametersOrCallback !== 'function' ? parametersOrCallback : {}; + callback ??= typeof parametersOrCallback === 'function' ? parametersOrCallback : undefined; + + const request = new GetAllUUIDMetadataRequest({ ...parameters, keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + + /** + * Fetch UUID Metadata object for currently configured PubNub client `uuid`. + * + * @param callback - Request completion handler callback. + */ + public getUUIDMetadata( + callback: ResultCallback>, + ): void; + + /** + * Fetch a specific UUID Metadata object. + * + * @param parameters - Request configuration parameters. Will fetch UUID metadata object for + * currently configured PubNub client `uuid` if not set. + * @param callback - Request completion handler callback. + */ + public getUUIDMetadata( + parameters: AppContext.GetUUIDMetadataParameters, + callback: ResultCallback>, + ): void; + + /** + * Fetch a specific UUID Metadata object. + * + * @param [parameters] - Request configuration parameters. Will fetch UUID Metadata object for + * currently configured PubNub client `uuid` if not set. + * + * @returns Asynchronous get UUID metadata response. + */ + public async getUUIDMetadata( + parameters?: AppContext.GetUUIDMetadataParameters, + ): Promise>; + + /** + * Fetch a specific UUID Metadata object. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get UUID metadata response or `void` in case if `callback` provided. + */ + async getUUIDMetadata( + parametersOrCallback?: + | AppContext.GetUUIDMetadataParameters + | ResultCallback>, + callback?: ResultCallback>, + ): Promise | void> { + return this._getUUIDMetadata(parametersOrCallback, callback); + } + + /** + * Fetch a specific UUID Metadata object. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get UUID metadata response or `void` in case if `callback` provided. + */ + async _getUUIDMetadata( + parametersOrCallback?: + | AppContext.GetUUIDMetadataParameters + | ResultCallback>, + callback?: ResultCallback>, + ): Promise | void> { + // Get user request parameters. + const parameters: AppContext.GetUUIDMetadataParameters = + parametersOrCallback && typeof parametersOrCallback !== 'function' ? parametersOrCallback : {}; + callback ??= typeof parametersOrCallback === 'function' ? parametersOrCallback : undefined; + if (parameters.userId) parameters.uuid = parameters.userId; + parameters.uuid ??= this.configuration.userId; + + const request = new GetUUIDMetadataRequest({ ...parameters, keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Set Metadata + /** + * Update specific UUID Metadata object. + * + * @param parameters - Request configuration parameters. Will set UUID metadata for currently + * configured PubNub client `uuid` if not set. + * @param callback - Request completion handler callback. + */ + public setUUIDMetadata( + parameters: AppContext.SetUUIDMetadataParameters, + callback: ResultCallback>, + ): void; + + /** + * Update specific UUID Metadata object. + * + * @param parameters - Request configuration parameters. Will set UUID metadata for currently + * configured PubNub client `uuid` if not set. + * + * @returns Asynchronous set UUID metadata response. + */ + public async setUUIDMetadata( + parameters: AppContext.SetUUIDMetadataParameters, + ): Promise>; + + /** + * Update specific UUID Metadata object. + * + * @param parameters - Request configuration parameters. Will set UUID metadata for currently + * configured PubNub client `uuid` if not set. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous set UUID metadata response or `void` in case if `callback` provided. + */ + async setUUIDMetadata( + parameters: AppContext.SetUUIDMetadataParameters, + callback?: ResultCallback>, + ): Promise | void> { + return this._setUUIDMetadata(parameters, callback); + } + + /** + * Update specific UUID Metadata object. + * + * @param parameters - Request configuration parameters. Will set UUID metadata for currently + * configured PubNub client `uuid` if not set. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous set UUID metadata response or `void` in case if `callback` provided. + */ + async _setUUIDMetadata( + parameters: AppContext.SetUUIDMetadataParameters, + callback?: ResultCallback>, + ): Promise | void> { + if (parameters.userId) parameters.uuid = parameters.userId; + parameters.uuid ??= this.configuration.userId; + + const request = new GetUUIDMetadataRequest({ ...parameters, keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Remove Metadata + /** + * Remove UUID Metadata object for currently configured PubNub client `uuid`. + * + * @param callback - Request completion handler callback. + */ + public removeUUIDMetadata(callback: ResultCallback): void; + + /** + * Remove a specific UUID Metadata object. + * + * @param parameters - Request configuration parameters. Will remove UUID metadata for currently + * configured PubNub client `uuid` if not set. + * @param callback - Request completion handler callback. + */ + public removeUUIDMetadata( + parameters: AppContext.RemoveUUIDMetadataParameters, + callback: ResultCallback, + ): void; + + /** + * Remove a specific UUID Metadata object. + * + * @param [parameters] - Request configuration parameters. Will remove UUID metadata for currently + * configured PubNub client `uuid` if not set. + * + * @returns Asynchronous UUID metadata remove response. + */ + public async removeUUIDMetadata( + parameters?: AppContext.RemoveUUIDMetadataParameters, + ): Promise; + + /** + * Remove a specific UUID Metadata object. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous UUID metadata remove response or `void` in case if `callback` provided. + */ + public async removeUUIDMetadata( + parametersOrCallback?: + | AppContext.RemoveUUIDMetadataParameters + | ResultCallback, + callback?: ResultCallback, + ): Promise { + return this._removeUUIDMetadata(parametersOrCallback, callback); + } + + /** + * Remove a specific UUID Metadata object. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous UUID metadata remove response or `void` in case if `callback` provided. + */ + public async _removeUUIDMetadata( + parametersOrCallback?: + | AppContext.RemoveUUIDMetadataParameters + | ResultCallback, + callback?: ResultCallback, + ): Promise { + // Get user request parameters. + const parameters: AppContext.RemoveUUIDMetadataParameters = + parametersOrCallback && typeof parametersOrCallback !== 'function' ? parametersOrCallback : {}; + callback ??= typeof parametersOrCallback === 'function' ? parametersOrCallback : undefined; + if (parameters.userId) parameters.uuid = parameters.userId; + parameters.uuid ??= this.configuration.userId; + + const request = new RemoveUUIDMetadataRequest({ ...parameters, keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + // endregion + + // -------------------------------------------------------- + // --------------------- Channel API ---------------------- + // -------------------------------------------------------- + // region Channel API + // region Get Metadata + + /** + * Fetch a paginated list of Channel Metadata objects. + * + * @param callback - Request completion handler callback. + */ + public getAllChannelMetadata( + callback: ResultCallback>, + ): void; + + /** + * Fetch a paginated list of Channel Metadata objects. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public getAllChannelMetadata( + parameters: AppContext.GetAllMetadataParameters, + callback: ResultCallback>, + ): void; + + /** + * Fetch a paginated list of Channel Metadata objects. + * + * @param [parameters] - Request configuration parameters. + * + * @returns Asynchronous get all Channel metadata response. + */ + public async getAllChannelMetadata( + parameters?: AppContext.GetAllMetadataParameters, + ): Promise>; + + /** + * Fetch a paginated list of Channel Metadata objects. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get all Channel metadata response or `void` in case if `callback` + * provided. + */ + async getAllChannelMetadata( + parametersOrCallback?: + | AppContext.GetAllMetadataParameters + | ResultCallback>, + callback?: ResultCallback>, + ): Promise | void> { + return this._getAllChannelMetadata(parametersOrCallback, callback); + } + + /** + * Fetch a paginated list of Channel Metadata objects. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get all Channel metadata response or `void` in case if `callback` + * provided. + */ + async _getAllChannelMetadata( + parametersOrCallback?: + | AppContext.GetAllMetadataParameters + | ResultCallback>, + callback?: ResultCallback>, + ): Promise | void> { + // Get user request parameters. + const parameters: AppContext.GetAllMetadataParameters = + parametersOrCallback && typeof parametersOrCallback !== 'function' ? parametersOrCallback : {}; + callback ??= typeof parametersOrCallback === 'function' ? parametersOrCallback : undefined; + + const request = new GetAllChannelsMetadataRequest({ ...parameters, keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + + /** + * Fetch Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public getChannelMetadata( + parameters: AppContext.GetChannelMetadataParameters, + callback: ResultCallback>, + ): void; + + /** + * Fetch a specific Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous get Channel metadata response. + */ + public async getChannelMetadata( + parameters: AppContext.GetChannelMetadataParameters, + ): Promise>; + + /** + * Fetch Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get Channel metadata response or `void` in case if `callback` provided. + */ + async getChannelMetadata( + parameters: AppContext.GetChannelMetadataParameters, + callback?: ResultCallback>, + ): Promise | void> { + return this._getChannelMetadata(parameters, callback); + } + + /** + * Fetch Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get Channel metadata response or `void` in case if `callback` provided. + */ + async _getChannelMetadata( + parameters: AppContext.GetChannelMetadataParameters, + callback?: ResultCallback>, + ): Promise | void> { + const request = new GetChannelMetadataRequest({ ...parameters, keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Set Metadata + /** + * Update specific Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public setChannelMetadata( + parameters: AppContext.SetChannelMetadataParameters, + callback: ResultCallback>, + ): void; + + /** + * Update specific Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous set Channel metadata response. + */ + public async setChannelMetadata( + parameters: AppContext.SetChannelMetadataParameters, + ): Promise>; + + /** + * Update specific Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous set Channel metadata response or `void` in case if `callback` provided. + */ + async setChannelMetadata( + parameters: AppContext.SetChannelMetadataParameters, + callback?: ResultCallback>, + ): Promise | void> { + return this._setChannelMetadata(parameters, callback); + } + + /** + * Update specific Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous set Channel metadata response or `void` in case if `callback` provided. + */ + async _setChannelMetadata( + parameters: AppContext.SetChannelMetadataParameters, + callback?: ResultCallback>, + ): Promise | void> { + const request = new SetChannelMetadataRequest({ ...parameters, keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Remove Metadata + /** + * Remove Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public removeChannelMetadata( + parameters: AppContext.RemoveChannelMetadataParameters, + callback: ResultCallback, + ): void; + + /** + * Remove a specific Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous Channel metadata remove response. + */ + public async removeChannelMetadata( + parameters: AppContext.RemoveChannelMetadataParameters, + ): Promise; + + /** + * Remove a specific Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous Channel metadata remove response or `void` in case if `callback` + * provided. + */ + async removeChannelMetadata( + parameters: AppContext.RemoveChannelMetadataParameters, + callback?: ResultCallback, + ): Promise { + return this._removeChannelMetadata(parameters, callback); + } + + /** + * Remove a specific Channel Metadata object. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous Channel metadata remove response or `void` in case if `callback` + * provided. + */ + async _removeChannelMetadata( + parameters: AppContext.RemoveChannelMetadataParameters, + callback?: ResultCallback, + ): Promise { + const request = new RemoveChannelMetadataRequest({ ...parameters, keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + // endregion + + // -------------------------------------------------------- + // -------------- Members / Membership API ---------------- + // -------------------------------------------------------- + // region Members API + // region Get Members + + /** + * Fetch a paginated list of Channel Member objects. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public getChannelMembers< + MemberCustom extends AppContext.CustomData = AppContext.CustomData, + UUIDCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.GetMembersParameters, + callback: ResultCallback>, + ): void; + + /** + * Fetch a paginated list of Channel Member objects. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous get Channel Members response. + */ + public async getChannelMembers< + MemberCustom extends AppContext.CustomData = AppContext.CustomData, + UUIDCustom extends AppContext.CustomData = AppContext.CustomData, + >(parameters: AppContext.GetMembersParameters): Promise>; + + /** + * Fetch a paginated list of Channel Member objects. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get Channel Members response or `void` in case if `callback` provided. + */ + async getChannelMembers< + MemberCustom extends AppContext.CustomData = AppContext.CustomData, + UUIDCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.GetMembersParameters, + callback?: ResultCallback>, + ): Promise | void> { + const request = new GetChannelMembersRequest({ ...parameters, keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Set Members + /** + * Update specific Channel Members list. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public setChannelMembers< + MemberCustom extends AppContext.CustomData = AppContext.CustomData, + UUIDCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.SetChannelMembersParameters, + callback: ResultCallback>, + ): void; + + /** + * Update specific Channel Members list. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous update Channel Members list response. + */ + public async setChannelMembers< + MemberCustom extends AppContext.CustomData = AppContext.CustomData, + UUIDCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.SetChannelMembersParameters, + ): Promise>; + + /** + * Update specific Channel Members list. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous update Channel members list response or `void` in case if `callback` + * provided. + */ + async setChannelMembers< + MemberCustom extends AppContext.CustomData = AppContext.CustomData, + UUIDCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.SetChannelMembersParameters, + callback?: ResultCallback>, + ): Promise | void> { + const request = new SetChannelMembersRequest({ ...parameters, type: 'set', keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Remove Members + /** + * Remove Members from the Channel. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public removeChannelMembers< + MemberCustom extends AppContext.CustomData = AppContext.CustomData, + UUIDCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.RemoveMembersParameters, + callback: ResultCallback>, + ): void; + + /** + * Remove Members from the Channel. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous Channel Members remove response. + */ + public async removeChannelMembers< + MemberCustom extends AppContext.CustomData = AppContext.CustomData, + UUIDCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.RemoveMembersParameters, + ): Promise>; + + /** + * Remove Members from the Channel. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous Channel Members remove response or `void` in case if `callback` provided. + */ + async removeChannelMembers< + MemberCustom extends AppContext.CustomData = AppContext.CustomData, + UUIDCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.RemoveMembersParameters, + callback?: ResultCallback>, + ): Promise | void> { + const request = new SetChannelMembersRequest({ ...parameters, type: 'delete', keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + // endregion + + // region Membership API + // region Get Membership + /** + * Fetch a specific UUID Memberships list for currently configured PubNub client `uuid`. + * + * @param callback - Request completion handler callback. + * + * @returns Asynchronous get UUID Memberships list response or `void` in case if `callback` + * provided. + */ + public getMemberships< + MembershipCustom extends AppContext.CustomData = AppContext.CustomData, + ChannelCustom extends AppContext.CustomData = AppContext.CustomData, + >(callback: ResultCallback>): void; + + /** + * Fetch a specific UUID Memberships list. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public getMemberships< + MembershipCustom extends AppContext.CustomData = AppContext.CustomData, + ChannelCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.GetMembershipsParameters, + callback: ResultCallback>, + ): void; + + /** + * Fetch a specific UUID Memberships list. + * + * @param [parameters] - Request configuration parameters. Will fetch UUID Memberships list for + * currently configured PubNub client `uuid` if not set. + * + * @returns Asynchronous get UUID Memberships list response. + */ + public async getMemberships< + MembershipCustom extends AppContext.CustomData = AppContext.CustomData, + ChannelCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters?: AppContext.GetMembershipsParameters, + ): Promise>; + + /** + * Fetch a specific UUID Memberships list. + * + * @param [parametersOrCallback] - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get UUID Memberships response or `void` in case if `callback` provided. + */ + async getMemberships< + MembershipCustom extends AppContext.CustomData = AppContext.CustomData, + ChannelCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parametersOrCallback?: + | AppContext.GetMembershipsParameters + | ResultCallback>, + callback?: ResultCallback>, + ): Promise | void> { + // Get user request parameters. + const parameters: AppContext.GetMembershipsParameters = + parametersOrCallback && typeof parametersOrCallback !== 'function' ? parametersOrCallback : {}; + callback ??= typeof parametersOrCallback === 'function' ? parametersOrCallback : undefined; + if (parameters.userId) parameters.uuid = parameters.userId; + parameters.uuid ??= this.configuration.userId; + + const request = new GetUUIDMembershipsRequest({ ...parameters, keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Set Membership + /** + * Update specific UUID Memberships list. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public setMemberships< + MembershipCustom extends AppContext.CustomData = AppContext.CustomData, + ChannelCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.SetMembershipsParameters, + callback: ResultCallback>, + ): void; + + /** + * Update specific UUID Memberships list. + * + * @param parameters - Request configuration parameters or callback from overload. + * + * @returns Asynchronous update UUID Memberships list response. + */ + public async setMemberships< + MembershipCustom extends AppContext.CustomData = AppContext.CustomData, + ChannelCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.SetMembershipsParameters, + ): Promise>; + + /** + * Update specific UUID Memberships list. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous update UUID Memberships list response or `void` in case if `callback` + * provided. + */ + async setMemberships< + MembershipCustom extends AppContext.CustomData = AppContext.CustomData, + ChannelCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.SetMembershipsParameters, + callback?: ResultCallback>, + ): Promise | void> { + if (parameters.userId) parameters.uuid = parameters.userId; + parameters.uuid ??= this.configuration.userId; + + const request = new SetUUIDMembershipsRequest({ ...parameters, type: 'set', keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // region Remove Membership + /** + * Remove a specific UUID Memberships. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public removeMemberships< + MembershipCustom extends AppContext.CustomData = AppContext.CustomData, + ChannelCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.RemoveMembershipsParameters, + callback: ResultCallback>, + ): void; + + /** + * Remove a specific UUID Memberships. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous UUID Memberships remove response. + */ + public async removeMemberships< + MembershipCustom extends AppContext.CustomData = AppContext.CustomData, + ChannelCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.RemoveMembershipsParameters, + ): Promise>; + + /** + * Remove a specific UUID Memberships. + * + * @param parameters - Request configuration parameters or callback from overload. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous UUID Memberships remove response or `void` in case if `callback` + * provided. + */ + async removeMemberships< + MembershipCustom extends AppContext.CustomData = AppContext.CustomData, + ChannelCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.RemoveMembershipsParameters, + callback?: ResultCallback>, + ): Promise | void> { + if (parameters.userId) parameters.uuid = parameters.userId; + parameters.uuid ??= this.configuration.userId; + + const request = new SetUUIDMembershipsRequest({ ...parameters, type: 'delete', keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + // endregion + + // -------------------------------------------------------- + // --------------------- Deprecated API ------------------- + // -------------------------------------------------------- + // region Deprecated + + /** + * Fetch paginated list of specific Space members or specific User memberships. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get specific Space members or specific User memberships response. + * + * @deprecated Use {@link PubNubObjects#getChannelMembers} or {@link PubNubObjects#getMemberships} methods instead. + */ + public async fetchMemberships< + RelationCustom extends AppContext.CustomData = AppContext.CustomData, + MetadataCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.GetMembershipsParameters | AppContext.GetMembersParameters, + callback?: ResultCallback< + | AppContext.SpaceMembershipsResponse + | AppContext.UserMembersResponse + >, + ): Promise< + | AppContext.SpaceMembershipsResponse + | AppContext.UserMembersResponse + | void + > { + if ('spaceId' in parameters) { + const spaceParameters = parameters as AppContext.GetMembersParameters; + const mappedParameters = { + channel: spaceParameters.spaceId ?? spaceParameters.channel, + filter: spaceParameters.filter, + limit: spaceParameters.limit, + page: spaceParameters.page, + include: { ...spaceParameters.include }, + sort: spaceParameters.sort + ? Object.fromEntries( + Object.entries(spaceParameters.sort).map(([key, value]) => [key.replace('user', 'uuid'), value]), + ) + : undefined, + } as AppContext.GetMembersParameters; + + // Map Members object to the older version. + const mapMembers = (response: AppContext.GetMembersResponse) => + ({ + status: response.status, + data: response.data.map((members) => ({ + user: members.uuid, + custom: members.custom, + updated: members.updated, + eTag: members.eTag, + })), + totalCount: response.totalCount, + next: response.next, + prev: response.prev, + }) as AppContext.UserMembersResponse; + + if (callback) + return this.getChannelMembers(mappedParameters, (status, result) => { + callback(status, result ? mapMembers(result) : result); + }); + return this.getChannelMembers(mappedParameters).then(mapMembers); + } + + const userParameters = parameters as AppContext.GetMembershipsParameters; + const mappedParameters = { + uuid: userParameters.userId ?? userParameters.uuid, + filter: userParameters.filter, + limit: userParameters.limit, + page: userParameters.page, + include: { ...userParameters.include }, + sort: userParameters.sort + ? Object.fromEntries( + Object.entries(userParameters.sort).map(([key, value]) => [key.replace('space', 'channel'), value]), + ) + : undefined, + } as AppContext.GetMembershipsParameters; + + // Map Memberships object to the older version. + const mapMemberships = ( + response: AppContext.GetMembershipsResponse, + ) => + ({ + status: response.status, + data: response.data.map((membership) => ({ + space: membership.channel, + custom: membership.custom, + updated: membership.updated, + eTag: membership.eTag, + })), + totalCount: response.totalCount, + next: response.next, + prev: response.prev, + }) as AppContext.SpaceMembershipsResponse; + + if (callback) + return this.getMemberships(mappedParameters, (status, result) => { + callback(status, result ? mapMemberships(result) : result); + }); + return this.getMemberships(mappedParameters).then(mapMemberships); + } + + /** + * Add members to specific Space or memberships specific User. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous add members to specific Space or memberships specific User response or + * `void` in case if `callback` provided. + * + * @deprecated Use {@link PubNubObjects#setChannelMembers} or {@link PubNubObjects#setMemberships} methods instead. + */ + async addMemberships< + Custom extends AppContext.CustomData = AppContext.CustomData, + MetadataCustom extends AppContext.CustomData = AppContext.CustomData, + >( + parameters: AppContext.SetMembershipsParameters | AppContext.SetChannelMembersParameters, + callback?: ResultCallback< + AppContext.SetMembershipsResponse | AppContext.SetMembersResponse + >, + ): Promise< + | AppContext.SetMembershipsResponse + | AppContext.SetMembersResponse + | void + > { + if ('spaceId' in parameters) { + const spaceParameters = parameters as AppContext.SetChannelMembersParameters; + const mappedParameters = { + channel: spaceParameters.spaceId ?? spaceParameters.channel, + uuids: + spaceParameters.users?.map((user) => { + if (typeof user === 'string') return user; + user.userId; + return { id: user.userId, custom: user.custom }; + }) ?? spaceParameters.uuids, + limit: 0, + }; + + if (callback) return this.setChannelMembers(mappedParameters, callback); + return this.setChannelMembers(mappedParameters); + } + + const userParameters = parameters as AppContext.SetMembershipsParameters; + const mappedParameters = { + uuid: userParameters.userId ?? userParameters.uuid, + channels: + userParameters.spaces?.map((space) => { + if (typeof space === 'string') return space; + return { + id: space.spaceId, + custom: space.custom, + }; + }) ?? userParameters.channels, + limit: 0, + }; + + if (callback) return this.setMemberships(mappedParameters, callback); + return this.setMemberships(mappedParameters); + } + // endregion +} diff --git a/src/core/pubnub-push.ts b/src/core/pubnub-push.ts new file mode 100644 index 000000000..cc8e37b06 --- /dev/null +++ b/src/core/pubnub-push.ts @@ -0,0 +1,157 @@ +/** + * PubNub Push Notifications API module. + */ + +import { RemoveDevicePushNotificationChannelsRequest } from './endpoints/push/remove_push_channels'; +import { ListDevicePushNotificationChannelsRequest } from './endpoints/push/list_push_channels'; +import { AddDevicePushNotificationChannelsRequest } from './endpoints/push/add_push_channels'; +import { KeySet, ResultCallback, SendRequestFunction, StatusCallback } from './types/api'; +import { RemoveDevicePushNotificationRequest } from './endpoints/push/remove_device'; +import * as PushNotifications from './types/api/push-notifications'; +import * as Push from './types/api/push'; + +export default class PubNubPushNotifications { + constructor( + private readonly keySet: KeySet, + /* eslint-disable @typescript-eslint/no-explicit-any */ + private readonly sendRequest: SendRequestFunction, + ) {} + + // -------------------------------------------------------- + // ---------------------- Audit API ----------------------- + // -------------------------------------------------------- + // region Audit API + + /** + * Fetch device's push notification enabled channels. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public listChannels( + parameters: Push.ListDeviceChannelsParameters, + callback: ResultCallback, + ): void; + + /** + * Fetch device's push notification enabled channels. + * + * @param parameters - Request configuration parameters. + * + * @returns Asynchronous get device channels response. + */ + public async listChannels(parameters: Push.ListDeviceChannelsParameters): Promise; + + /** + * Fetch device's push notification enabled channels. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + * + * @returns Asynchronous get device channels response or `void` in case if `callback` provided. + */ + public async listChannels( + parameters: Push.ListDeviceChannelsParameters, + callback?: ResultCallback, + ): Promise { + const request = new ListDevicePushNotificationChannelsRequest({ ...parameters, keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + // endregion + + // -------------------------------------------------------- + // ---------------------- Manage API ---------------------- + // -------------------------------------------------------- + // region Manage API + + /** + * Enable push notifications on channels for device. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public addChannels(parameters: Push.ManageDeviceChannelsParameters, callback: StatusCallback): void; + + /** + * Enable push notifications on channels for device. + * + * @param parameters - Request configuration parameters. + */ + public async addChannels(parameters: Push.ManageDeviceChannelsParameters): Promise; + + /** + * Enable push notifications on channels for device. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + */ + public async addChannels(parameters: Push.ManageDeviceChannelsParameters, callback?: StatusCallback): Promise { + const request = new AddDevicePushNotificationChannelsRequest({ ...parameters, keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + + /** + * Disable push notifications on channels for device. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public removeChannels(parameters: Push.ManageDeviceChannelsParameters, callback: StatusCallback): void; + + /** + * Disable push notifications on channels for device. + * + * @param parameters - Request configuration parameters. + */ + public async removeChannels(parameters: Push.ManageDeviceChannelsParameters): Promise; + + /** + * Disable push notifications on channels for device. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + */ + public async removeChannels( + parameters: Push.ManageDeviceChannelsParameters, + callback?: StatusCallback, + ): Promise { + const request = new RemoveDevicePushNotificationChannelsRequest({ ...parameters, keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + + /** + * Disable push notifications for device. + * + * @param parameters - Request configuration parameters. + * @param callback - Request completion handler callback. + */ + public deleteDevice(parameters: Push.RemoveDeviceParameters, callback: StatusCallback): void; + + /** + * Disable push notifications for device. + * + * @param parameters - Request configuration parameters. + */ + public async deleteDevice(parameters: Push.RemoveDeviceParameters): Promise; + + /** + * Disable push notifications for device. + * + * @param parameters - Request configuration parameters. + * @param [callback] - Request completion handler callback. + */ + public async deleteDevice(parameters: Push.RemoveDeviceParameters, callback?: StatusCallback): Promise { + const request = new RemoveDevicePushNotificationRequest({ ...parameters, keySet: this.keySet }); + + if (callback) return this.sendRequest(request, callback); + return this.sendRequest(request); + } + + // endregion +} diff --git a/src/core/types/api/access-panager.ts b/src/core/types/api/access-panager.ts new file mode 100644 index 000000000..068d1afe2 --- /dev/null +++ b/src/core/types/api/access-panager.ts @@ -0,0 +1,564 @@ +// region Grant token +/** + * Metadata which will be associated with access token. + */ +export type Metadata = Record; + +/** + * Channel-specific token permissions. + */ +export type ChannelTokenPermissions = { + /** + * Whether `read` operations are permitted for corresponding level or not. + */ + read?: boolean; + + /** + * Whether `write` operations are permitted for corresponding level or not. + */ + write?: boolean; + + /** + * Whether `get` operations are permitted for corresponding level or not. + */ + get?: boolean; + + /** + * Whether `manage` operations are permitted for corresponding level or not. + */ + manage?: boolean; + + /** + * Whether `update` operations are permitted for corresponding level or not. + */ + update?: boolean; + + /** + * Whether `join` operations are permitted for corresponding level or not. + */ + join?: boolean; + + /** + * Whether `delete` operations are permitted for corresponding level or not. + */ + delete?: boolean; +}; + +/** + * Space-specific token permissions. + */ +type SpaceTokenPermissions = ChannelTokenPermissions; + +/** + * Channel group-specific token permissions. + */ +export type ChannelGroupTokenPermissions = { + /** + * Whether `read` operations are permitted for corresponding level or not. + */ + read?: boolean; + + /** + * Whether `manage` operations are permitted for corresponding level or not. + */ + manage?: boolean; +}; + +/** + * Uuid-specific token permissions. + */ +export type UuidTokenPermissions = { + /** + * Whether `get` operations are permitted for corresponding level or not. + */ + get?: boolean; + + /** + * Whether `update` operations are permitted for corresponding level or not. + */ + update?: boolean; + + /** + * Whether `delete` operations are permitted for corresponding level or not. + */ + delete?: boolean; +}; + +/** + * User-specific token permissions. + */ +type UserTokenPermissions = UuidTokenPermissions; + +/** + * Generate access token with permissions. + * + * Generate time-limited access token with required permissions for App Context objects. + */ +export type ObjectsGrantTokenParameters = { + /** + * Total number of minutes for which the token is valid. + * + * The minimum allowed value is `1`. + * The maximum is `43,200` minutes (`30` days). + */ + ttl: number; + + /** + * Object containing resource permissions. + */ + resources?: { + /** + * Object containing `spaces` metadata permissions. + */ + spaces?: Record; + + /** + * Object containing `users` permissions. + */ + users?: Record; + }; + + /** + * Object containing permissions to multiple resources specified by a RegEx pattern. + */ + patterns?: { + /** + * Object containing `spaces` metadata permissions. + */ + spaces?: Record; + + /** + * Object containing `users` permissions. + */ + users?: Record; + }; + + /** + * Extra metadata to be published with the request. + * + * **Important:** Values must be scalar only; `arrays` or `objects` aren't supported. + */ + meta?: Metadata; + + /** + * Single `userId` which is authorized to use the token to make API requests to PubNub. + */ + authorizedUserId?: string; +}; + +/** + * Generate token with permissions. + * + * Generate time-limited access token with required permissions for resources. + */ +export type GrantTokenParameters = { + /** + * Total number of minutes for which the token is valid. + * + * The minimum allowed value is `1`. + * The maximum is `43,200` minutes (`30` days). + */ + ttl: number; + + /** + * Object containing resource permissions. + */ + resources?: { + /** + * Object containing `uuid` metadata permissions. + */ + uuids?: Record; + + /** + * Object containing `channel` permissions. + */ + channels?: Record; + + /** + * Object containing `channel group` permissions. + */ + groups?: Record; + }; + + /** + * Object containing permissions to multiple resources specified by a RegEx pattern. + */ + patterns?: { + /** + * Object containing `uuid` metadata permissions to apply to all `uuids` matching the RegEx + * pattern. + */ + uuids?: Record; + + /** + * Object containing `channel` permissions to apply to all `channels` matching the RegEx + * pattern. + */ + channels?: Record; + + /** + * Object containing `channel group` permissions to apply to all `channel groups` matching the + * RegEx pattern. + */ + groups?: Record; + }; + + /** + * Extra metadata to be published with the request. + * + * **Important:** Values must be scalar only; `arrays` or `objects` aren't supported. + */ + meta?: Metadata; + + /** + * Single `uuid` which is authorized to use the token to make API requests to PubNub. + */ + authorized_uuid?: string; +}; + +/** + * Response with generated access token. + */ +export type GrantTokenResponse = string; +// endregion + +// region Revoke +export type RevokeParameters = { + /** + * Access token for which permissions should be revoked. + */ + token: string; +}; + +/** + * Response with revoked access token. + */ +export type RevokeTokenResponse = Record; +// endregion + +// -------------------------------------------------------- +// --------------------- Deprecated ----------------------- +// -------------------------------------------------------- +// region Deprecated + +/** + * Channel-specific permissions. + * + * Permissions include objects to the App Context Channel object as well. + */ +type ChannelPermissions = { + /** + * Whether `read` operations are permitted for corresponding level or not. + */ + r?: 0 | 1; + + /** + * Whether `write` operations are permitted for corresponding level or not. + */ + w?: 0 | 1; + + /** + * Whether `delete` operations are permitted for corresponding level or not. + */ + d?: 0 | 1; + + /** + * Whether `get` operations are permitted for corresponding level or not. + */ + g?: 0 | 1; + + /** + * Whether `update` operations are permitted for corresponding level or not. + */ + u?: 0 | 1; + + /** + * Whether `manage` operations are permitted for corresponding level or not. + */ + m?: 0 | 1; + + /** + * Whether `join` operations are permitted for corresponding level or not. + */ + j?: 0 | 1; + + /** + * Duration for which permissions has been granted. + */ + ttl?: number; +}; + +/** + * Channel group-specific permissions. + */ +type ChannelGroupPermissions = { + /** + * Whether `read` operations are permitted for corresponding level or not. + */ + r?: 0 | 1; + + /** + * Whether `manage` operations are permitted for corresponding level or not. + */ + m?: 0 | 1; + + /** + * Duration for which permissions has been granted. + */ + ttl?: number; +}; + +/** + * App Context User-specific permissions. + */ +type UserPermissions = { + /** + * Whether `get` operations are permitted for corresponding level or not. + */ + g?: 0 | 1; + + /** + * Whether `update` operations are permitted for corresponding level or not. + */ + u?: 0 | 1; + + /** + * Whether `delete` operations are permitted for corresponding level or not. + */ + d?: 0 | 1; + + /** + * Duration for which permissions has been granted. + */ + ttl?: number; +}; + +/** + * Common permissions audit response content. + */ +type BaseAuditResponse< + Level extends 'channel' | 'channel+auth' | 'channel-group' | 'channel-group+auth' | 'user' | 'subkey', +> = { + /** + * Permissions level. + */ + level: Level; + + /** + * Subscription key at which permissions has been granted. + */ + subscribe_key: string; + + /** + * Duration for which permissions has been granted. + */ + ttl?: number; +}; + +/** + * Auth keys permissions for specified `level`. + */ +type AuthKeysPermissions = { + /** + * Auth keys-based permissions for specified `level` permission. + */ + auths: Record; +}; + +/** + * Single channel permissions audit result. + */ +type ChannelPermissionsResponse = BaseAuditResponse<'channel+auth'> & { + /** + * Name of channel for which permissions audited. + */ + channel: string; +} & AuthKeysPermissions; + +/** + * Multiple channels permissions audit result. + */ +type ChannelsPermissionsResponse = BaseAuditResponse<'channel'> & { + /** + * Per-channel permissions. + */ + channels: Record>; +}; + +/** + * Single channel group permissions result. + */ +type ChannelGroupPermissionsResponse = BaseAuditResponse<'channel-group+auth'> & { + /** + * Name of channel group for which permissions audited. + */ + 'channel-group': string; +} & AuthKeysPermissions; + +/** + * Multiple channel groups permissions audit result. + */ +type ChannelGroupsPermissionsResponse = BaseAuditResponse<'channel'> & { + /** + * Per-channel group permissions. + */ + 'channel-groups': Record>; +}; + +/** + * App Context User permissions audit result. + */ +type UserPermissionsResponse = BaseAuditResponse<'user'> & { + /** + * Name of channel for which `user` permissions audited. + */ + channel: string; +} & AuthKeysPermissions; + +/** + * Global sub-key level permissions audit result. + */ +type SubKeyPermissionsResponse = BaseAuditResponse<'subkey'> & { + /** + * Per-channel permissions. + */ + channels: Record>; + + /** + * Per-channel group permissions. + */ + 'channel-groups': Record>; + + /** + * Per-object permissions. + */ + objects: Record>; +}; + +/** + * Response with permission information. + */ +export type PermissionsResponse = + | ChannelPermissionsResponse + | ChannelsPermissionsResponse + | ChannelGroupPermissionsResponse + | ChannelGroupsPermissionsResponse + | UserPermissionsResponse + | SubKeyPermissionsResponse; + +// region Audit +/** + * Audit permissions for provided auth keys / global permissions. + * + * Audit permissions on specific channel and / or channel group for the set of auth keys. + */ +export type AuditParameters = { + /** + * Name of channel for which channel-based permissions should be checked for {@link authKeys}. + */ + channel?: string; + + /** + * Name of channel group for which channel group-based permissions should be checked for {@link authKeys}. + */ + channelGroup?: string; + + /** + * List of auth keys for which permissions should be checked. + * + * Leave this empty to check channel / group -based permissions or global permissions. + * + * @default `[]` + */ + authKeys?: string[]; +}; +// endregion + +// region Grant +/** + * Grant permissions for provided auth keys / global permissions. + * + * Grant permissions on specific channel and / or channel group for the set of auth keys. + */ +export type GrantParameters = { + /** + * List of channels for which permissions should be granted. + */ + channels?: string[]; + + /** + * List of channel groups for which permissions should be granted. + */ + channelGroups?: string[]; + + /** + * List of App Context UUID for which permissions should be granted. + */ + uuids?: string[]; + + /** + * List of auth keys for which permissions should be granted on specified objects. + * + * Leave this empty to grant channel / group -based permissions or global permissions. + */ + authKeys?: string[]; + + /** + * Whether `read` operations are permitted for corresponding level or not. + * + * @default `false` + */ + read?: boolean; + + /** + * Whether `write` operations are permitted for corresponding level or not. + * + * @default `false` + */ + write?: boolean; + + /** + * Whether `delete` operations are permitted for corresponding level or not. + * + * @default `false` + */ + delete?: boolean; + + /** + * Whether `get` operations are permitted for corresponding level or not. + * + * @default `false` + */ + get?: boolean; + + /** + * Whether `update` operations are permitted for corresponding level or not. + * + * @default `false` + */ + update?: boolean; + + /** + * Whether `manage` operations are permitted for corresponding level or not. + * + * @default `false` + */ + manage?: boolean; + + /** + * Whether `join` operations are permitted for corresponding level or not. + * + * @default `false` + */ + join?: boolean; + + /** + * For how long permissions should be effective (in minutes). + * + * @default `1440` + */ + ttl?: number; +}; +// endregion + +// endregion diff --git a/src/core/types/api/app-context.ts b/src/core/types/api/app-context.ts new file mode 100644 index 000000000..041c0f764 --- /dev/null +++ b/src/core/types/api/app-context.ts @@ -0,0 +1,1088 @@ +/** + * Partial nullability helper type. + */ +type PartialNullable = { + [P in keyof T]?: T[P] | null; +}; + +/** + * Custom data which should be associated with metadata objects or their relation. + */ +export type CustomData = { + [key: string]: string | number | boolean | null; +}; + +/** + * Type provides shape of App Context parameters which is common to the all objects types to + * be updated. + */ +type ObjectParameters = { + custom?: Custom; +}; + +/** + * Type provides shape of App Context object which is common to the all objects types received + * from the PubNub service. + */ +export type ObjectData = { + /** + * Unique App Context object identifier. + * + * **Important:** For channel it is different from the channel metadata object name. + */ + id: string; + + /** + * Last date and time when App Context object has been updated. + * + * String built from date using ISO 8601. + */ + updated: string; + + /** + * App Context version hash. + */ + eTag: string; + + /** + * Additional data associated with App Context object. + * + * **Important:** Values must be scalars; only arrays or objects are supported. + * {@link /docs/sdks/javascript/api-reference/objects#app-context-filtering-language-definition|App Context + * filtering language} doesn’t support filtering by custom properties. + */ + custom?: Custom | null; +}; + +/** + * Type provides shape of object which let establish relation between metadata objects. + */ +type ObjectsRelation = { + /** + * App Context object unique identifier. + */ + id: string; + + /** + * App Context objects relation status. + */ + status?: string; + + /** + * Additional data associated with App Context object relation (membership or members). + * + * **Important:** Values must be scalars; only arrays or objects are supported. + * {@link /docs/sdks/javascript/api-reference/objects#app-context-filtering-language-definition|App Context + * filtering language} doesn’t support filtering by custom properties. + */ + custom?: Custom; +}; + +/** + * Response page cursor. + */ +type Page = { + /** + * Random string returned from the server, indicating a specific position in a data set. + * + * Used for forward pagination, it fetches the next page, allowing you to continue from where + * you left off. + */ + next?: string; + + /** + * Random string returned from the server, indicating a specific position in a data set. + * + * Used for backward pagination, it fetches the previous page, enabling access to earlier + * data. + * + * **Important:** Ignored if the `next` parameter is supplied. + */ + prev?: string; +}; + +/** + * Metadata objects include options. + * + * Allows to configure what additional information should be included into service response. + */ +type IncludeOptions = { + /** + * Whether to include total number of App Context objects in the response. + * + * @default `false` + */ + totalCount?: boolean; + + /** + * Whether to include App Context object `custom` field in the response. + * + * @default `false` + */ + customFields?: boolean; +}; + +/** + * Membership objects include options. + * + * Allows to configure what additional information should be included into service response. + */ +type MembershipsIncludeOptions = IncludeOptions & { + /** + * Whether to include all {@link ChannelMetadata} fields in the response. + * + * @default `false` + */ + channelFields?: boolean; + + /** + * Whether to include {@link ChannelMetadata} `custom` field in the response. + * + * @default `false` + */ + customChannelFields?: boolean; + + /** + * Whether to include the membership's status field in the response. + * + * @default `false` + */ + statusField?: boolean; + + /** + * Whether to include the channel's status field in the response. + * + * @default `false` + */ + channelStatusField?: boolean; + + /** + * Whether to include channel's type fields in the response. + * + * @default `false` + */ + channelTypeField?: boolean; +}; + +/** + * Members objects include options. + * + * Allows to configure what additional information should be included into service response. + */ +type MembersIncludeOptions = IncludeOptions & { + /** + * Whether to include all {@link UUIMetadata} fields in the response. + * + * @default `false` + */ + UUIDFields?: boolean; + + /** + * Whether to include {@link UUIMetadata} `custom` field in the response. + * + * @default `false` + */ + customUUIDFields?: boolean; + + /** + * Whether to include the members's status field in the response. + * + * @default `false` + */ + statusField?: boolean; + + /** + * Whether to include the user's status field in the response. + * + * @default `false` + */ + UUIDStatusField?: boolean; + + /** + * Whether to include user's type fields in the response. + * + * @default `false` + */ + UUIDTypeField?: boolean; +}; + +/** + * Type provides shape of App Context parameters which is common to the all objects types to + * fetch them by pages. + */ +type PagedRequestParameters = { + /** + * Fields which can be additionally included into response. + */ + include?: Include; + + /** + * Expression used to filter the results. + * + * Only objects whose properties satisfy the given expression are returned. The filter language is + * {@link /docs/sdks/javascript/api-reference/objects#app-context-filtering-language-definition|defined here}. + */ + filter?: string; + + /** + * Fetched App Context objects sorting options. + */ + sort?: Sort; + + /** + * Number of objects to return in response. + * + * **Important:** Maximum for this API is `100` objects per-response. + * + * @default `100` + */ + limit?: number; + + /** + * Response pagination configuration. + */ + page?: Page; +}; + +/** + * Type provides shape of App Context object fetch response which is common to the all objects + * types received from the PubNub service. + */ +type ObjectResponse = { + /** + * App Context objects list fetch result status code. + */ + status: number; + + /** + * Received App Context object information. + */ + data: ObjectType; +}; + +/** + * Type provides shape of App Context objects fetch response which is common to the all + * objects types received from the PubNub service. + */ +type PagedResponse = ObjectResponse & { + /** + * Total number of App Context objects in the response. + */ + totalCount?: number; + + /** + * Random string returned from the server, indicating a specific position in a data set. + * + * Used for forward pagination, it fetches the next page, allowing you to continue from where + * you left off. + */ + next?: string; + + /** + * Random string returned from the server, indicating a specific position in a data set. + * + * Used for backward pagination, it fetches the previous page, enabling access to earlier + * data. + * + * **Important:** Ignored if the `next` parameter is supplied. + */ + prev?: string; +}; + +/** + * Key-value pair of a property to sort by, and a sort direction. + */ +type MetadataSortingOptions = + | 'id' + | 'name' + | 'updated' + | { + /** + * Sort results by `id` in ascending (`asc`) or descending (`desc`) order. + * + * Specify `null` for default sorting direction (ascending). + */ + id?: 'asc' | 'desc' | null; + + /** + * Sort results by `name` in ascending (`asc`) or descending (`desc`) order. + * + * Specify `null` for default sorting direction (ascending). + */ + name?: 'asc' | 'desc' | null; + + /** + * Sort results by `updated` in ascending (`asc`) or descending (`desc`) order. + * + * Specify `null` for default sorting direction (ascending). + */ + updated?: 'asc' | 'desc' | null; + }; + +/** + * Key-value pair of a property to sort by, and a sort direction. + */ +type MembershipsSortingOptions = + | 'channel.id' + | 'channel.name' + | 'channel.updated' + | 'space.id' + | 'space.name' + | 'space.updated' + | 'updated' + | { + /** + * Sort results by channel's `id` in ascending (`asc`) or descending (`desc`) order. + * + * Specify `null` for default sorting direction (ascending). + */ + 'channel.id'?: 'asc' | 'desc' | null; + + /** + * Sort results by channel's `name` in ascending (`asc`) or descending (`desc`) order. + * + * Specify `null` for default sorting direction (ascending). + */ + 'channel.name'?: 'asc' | 'desc' | null; + + /** + * Sort results by channel's `update` in ascending (`asc`) or descending (`desc`) order. + * + * Specify `null` for default sorting direction (ascending). + */ + 'channel.updated'?: 'asc' | 'desc' | null; + + /** + * Sort results by channel's `id` in ascending (`asc`) or descending (`desc`) order. + * + * Specify `null` for default sorting direction (ascending). + * + * @deprecated Use `channel.id` instead. + */ + 'space.id'?: 'asc' | 'desc' | null; + + /** + * Sort results by channel's `name` in ascending (`asc`) or descending (`desc`) order. + * + * Specify `null` for default sorting direction (ascending). + * + * @deprecated Use `channel.name` instead. + */ + 'space.name'?: 'asc' | 'desc' | null; + + /** + * Sort results by channel's `update` in ascending (`asc`) or descending (`desc`) order. + * + * Specify `null` for default sorting direction (ascending). + * + * @deprecated Use `channel.updated` instead. + */ + 'space.updated'?: 'asc' | 'desc' | null; + + /** + * Sort results by `updated` in ascending (`asc`) or descending (`desc`) order. + * + * Specify `null` for default sorting direction (ascending). + */ + updated?: 'asc' | 'desc' | null; + }; + +/** + * Key-value pair of a property to sort by, and a sort direction. + */ +type MembersSortingOptions = + | 'uuid.id' + | 'uuid.name' + | 'uuid.updated' + | 'user.id' + | 'user.name' + | 'user.updated' + | 'updated' + | { + /** + * Sort results by user's `id` in ascending (`asc`) or descending (`desc`) order. + * + * Specify `null` for default sorting direction (ascending). + */ + 'uuid.id'?: 'asc' | 'desc' | null; + + /** + * Sort results by user's `name` in ascending (`asc`) or descending (`desc`) order. + * + * Specify `null` for default sorting direction (ascending). + */ + 'uuid.name'?: 'asc' | 'desc' | null; + + /** + * Sort results by user's `update` in ascending (`asc`) or descending (`desc`) order. + * + * Specify `null` for default sorting direction (ascending). + */ + 'uuid.updated'?: 'asc' | 'desc' | null; + + /** + * Sort results by user's `id` in ascending (`asc`) or descending (`desc`) order. + * + * Specify `null` for default sorting direction (ascending). + * + * @deprecated Use `uuid.id` instead. + */ + 'user.id'?: 'asc' | 'desc' | null; + + /** + * Sort results by user's `name` in ascending (`asc`) or descending (`desc`) order. + * + * Specify `null` for default sorting direction (ascending). + * + * @deprecated Use `uuid.name` instead. + */ + 'user.name'?: 'asc' | 'desc' | null; + + /** + * Sort results by user's `update` in ascending (`asc`) or descending (`desc`) order. + * + * Specify `null` for default sorting direction (ascending). + * + * @deprecated Use `uuid.updated` instead. + */ + 'user.updated'?: 'asc' | 'desc' | null; + + /** + * Sort results by `updated` in ascending (`asc`) or descending (`desc`) order. + * + * Specify `null` for default sorting direction (ascending). + */ + updated?: 'asc' | 'desc' | null; + }; + +// -------------------------------------------------------- +// --------------------- Common API ----------------------- +// -------------------------------------------------------- + +/** + * Fetch All UUID or Channel Metadata request parameters. + */ +export type GetAllMetadataParameters = PagedRequestParameters; + +// -------------------------------------------------------- +// ---------------------- UUID API ------------------------ +// -------------------------------------------------------- + +/** + * Type which describes own UUID metadata object fields. + */ +type UUIDMetadataFields = { + /** + * Display name for the user. + */ + name?: string; + + /** + * The user's email address. + */ + email?: string; + + /** + * User's identifier in an external system. + */ + externalId?: string; + + /** + * The URL of the user's profile picture. + */ + profileUrl?: string; + + /** + * User's object type information. + */ + type?: string; + + /** + * User's object status. + */ + status?: string; +}; + +/** + * Updated UUID metadata object. + * + * Type represents updated UUID metadata object which will be pushed to the PubNub service. + */ +type UUIDMetadata = ObjectParameters & Partial; + +/** + * Received UUID metadata object. + * + * Type represents UUID metadata retrieved from the PubNub service. + */ +export type UUIDMetadataObject = ObjectData & PartialNullable; + +/** + * Response with fetched page of UUID metadata objects. + */ +export type GetAllUUIDMetadataResponse = PagedResponse>; + +/** + * Fetch UUID Metadata request parameters. + */ +export type GetUUIDMetadataParameters = { + /** + * Unique user identifier. + * + * **Important:** If not supplied then current user's uuid is used. + * + * @default Current `uuid`. + */ + uuid?: string; + + /** + * Unique user identifier. + * + * **Important:** If not supplied then current user's uuid is used. + * + * @default Current `userId`. + * + * @deprecated Use `getUUIDMetadata()` method instead. + */ + userId?: string; + + /** + * Fields which can be additionally included into response. + */ + include?: Omit; +}; + +/** + * Response with requested UUID metadata object. + */ +export type GetUUIDMetadataResponse = ObjectResponse>; + +/** + * Update UUID Metadata request parameters. + */ +export type SetUUIDMetadataParameters = { + /** + * Unique user identifier. + * + * **Important:** If not supplied then current user's uuid is used. + * + * @default Current `uuid`. + */ + uuid?: string; + + /** + * Unique user identifier. + * + * **Important:** If not supplied then current user's uuid is used. + * + * @default Current `userId`. + * + * @deprecated Use `setUUIDMetadata()` method instead. + */ + userId?: string; + + /** + * Metadata, which should be associated with UUID. + */ + data: UUIDMetadata; + + /** + * Fields which can be additionally included into response. + */ + include?: Omit; +}; + +/** + * Response with result of the UUID metadata object update. + */ +export type SetUUIDMetadataResponse = ObjectResponse>; + +/** + * Remove UUID Metadata request parameters. + */ +export type RemoveUUIDMetadataParameters = { + /** + * Unique user identifier. + * + * **Important:** If not supplied then current user's uuid is used. + * + * @default Current `uuid`. + */ + uuid?: string; + + /** + * Unique user identifier. + * + * **Important:** If not supplied then current user's uuid is used. + * + * @default Current `userId`. + * + * @deprecated Use `removeUUIDMetadata()` method instead. + */ + userId?: string; +}; + +/** + * Response with result of the UUID metadata removal. + */ +export type RemoveUUIDMetadataResponse = ObjectResponse>; + +// -------------------------------------------------------- +// --------------------- Channel API ---------------------- +// -------------------------------------------------------- + +/** + * Type which describes own Channel metadata object fields. + */ +type ChannelMetadataFields = { + /** + * Name of a channel. + */ + name?: string; + + /** + * Description of a channel. + */ + description?: string; + + /** + * Channel's object type information. + */ + type?: string; + + /** + * Channel's object status. + */ + status?: string; +}; + +/** + * Updated channel metadata object. + * + * Type represents updated channel metadata object which will be pushed to the PubNub service. + */ +type ChannelMetadata = ObjectParameters & Partial; + +/** + * Received channel metadata object. + * + * Type represents chanel metadata retrieved from the PubNub service. + */ +export type ChannelMetadataObject = ObjectData & + PartialNullable; + +/** + * Response with fetched page of channel metadata objects. + */ +export type GetAllChannelMetadataResponse = PagedResponse>; + +/** + * Fetch Channel Metadata request parameters. + */ +export type GetChannelMetadataParameters = { + /** + * Channel name. + */ + channel: string; + + /** + * Space identifier. + * + * @deprecated Use `getChannelMetadata()` method instead. + */ + spaceId?: string; + + /** + * Fields which can be additionally included into response. + */ + include?: Omit; +}; + +/** + * Response with requested channel metadata object. + */ +export type GetChannelMetadataResponse = ObjectResponse>; + +/** + * Update Channel Metadata request parameters. + */ +export type SetChannelMetadataParameters = { + /** + * Channel name. + */ + channel: string; + + /** + * Space identifier. + * + * @deprecated Use `setChannelMetadata()` method instead. + */ + spaceId?: string; + + /** + * Metadata, which should be associated with UUID. + */ + data: ChannelMetadata; + + /** + * Fields which can be additionally included into response. + */ + include?: Omit; +}; + +/** + * Response with result of the channel metadata object update. + */ +export type SetChannelMetadataResponse = ObjectResponse>; + +/** + * Remove Channel Metadata request parameters. + */ +export type RemoveChannelMetadataParameters = { + /** + * Channel name. + */ + channel: string; + + /** + * Space identifier. + * + * @deprecated Use `removeChannelMetadata()` method instead. + */ + spaceId?: string; +}; + +/** + * Response with result of the channel metadata removal. + */ +export type RemoveChannelMetadataResponse = ObjectResponse>; + +// -------------------------------------------------------- +// ------------------ Memberships API --------------------- +// -------------------------------------------------------- + +/** + * Related channel metadata object. + * + * Type represents chanel metadata which has been used to create membership relation with UUID. + */ +type MembershipsObject = Omit< + ObjectData, + 'id' +> & { + channel: ChannelMetadataObject | { id: string }; +}; + +/** + * Response with fetched page of UUID membership objects. + */ +type MembershipsResponse = PagedResponse< + MembershipsObject +>; + +/** + * Fetch Memberships request parameters. + */ +export type GetMembershipsParameters = PagedRequestParameters & { + /** + * Unique user identifier. + * + * **Important:** If not supplied then current user's uuid is used. + * + * @default Current `uuid`. + */ + uuid?: string; + + /** + * Unique user identifier. + * + * **Important:** If not supplied then current user's uuid is used. + * + * @default Current `uuidId`. + * + * @deprecated Use `uuid` field instead. + */ + userId?: string; +}; + +/** + * Response with requested channel memberships information. + */ +export type GetMembershipsResponse< + MembershipCustom extends CustomData, + ChannelCustom extends CustomData, +> = MembershipsResponse; + +/** + * Update Memberships request parameters. + */ +export type SetMembershipsParameters = PagedRequestParameters< + Omit, + MembershipsSortingOptions +> & { + /** + * Unique user identifier. + * + * **Important:** If not supplied then current user's uuid is used. + * + * @default Current `uuid`. + */ + uuid?: string; + + /** + * Unique user identifier. + * + * **Important:** If not supplied then current user's uuid is used. + * + * @default Current `userId`. + * + * @deprecated Use `uuid` field instead. + */ + userId?: string; + + /** + * List of channels with which UUID membership should be established. + */ + channels: Array>; + + /** + * List of channels with which UUID membership should be established. + * + * @deprecated Use `channels` field instead. + */ + spaces?: Array< + | string + | (Omit, 'id'> & { + /** + * Unique Space object identifier. + */ + spaceId: string; + }) + >; +}; + +/** + * Response with requested channel memberships information change. + */ +export type SetMembershipsResponse< + MembershipCustom extends CustomData, + ChannelCustom extends CustomData, +> = MembershipsResponse; + +/** + * Remove Memberships request parameters. + */ +export type RemoveMembershipsParameters = PagedRequestParameters< + MembershipsIncludeOptions, + MembershipsSortingOptions +> & { + /** + * Unique user identifier. + * + * **Important:** If not supplied then current user's uuid is used. + * + * @default Current `uuid`. + */ + uuid?: string; + + /** + * Unique user identifier. + * + * **Important:** If not supplied then current user's uuid is used. + * + * @default Current `userId`. + * + * @deprecated Use {@link uuid} field instead. + */ + userId?: string; + + /** + * List of channels for which membership which UUID should be removed. + */ + channels: string[]; + + /** + * List of space names for which membership which UUID should be removed. + * + * @deprecated Use {@link channels} field instead. + */ + spaceIds?: string[]; +}; + +/** + * Response with remaining memberships. + */ +export type RemoveMembershipsResponse< + MembershipCustom extends CustomData, + ChannelCustom extends CustomData, +> = MembershipsResponse; + +// -------------------------------------------------------- +// -------------------- Members API ----------------------- +// -------------------------------------------------------- + +/** + * Related UUID metadata object. + * + * Type represents UUID metadata which has been used to when added members to the channel. + */ +type MembersObject = Omit< + ObjectData, + 'id' +> & { + uuid: UUIDMetadataObject | { id: string }; +}; + +/** + * Response with fetched page of channel member objects. + */ +type MembersResponse = PagedResponse< + MembersObject +>; + +/** + * Fetch Members request parameters. + */ +export type GetMembersParameters = PagedRequestParameters & { + /** + * Channel name. + */ + channel: string; + + /** + * Space identifier. + * + * @deprecated Use `channel` field instead. + */ + spaceId?: string; +}; + +/** + * Response with requested channel memberships information. + */ +export type GetMembersResponse = MembersResponse< + MembersCustom, + UUIDCustom +>; + +/** + * Update Members request parameters. + */ +export type SetChannelMembersParameters = PagedRequestParameters< + Omit, + MembersSortingOptions +> & { + /** + * Channel name. + */ + channel: string; + + /** + * Space identifier. + * + * @deprecated Use `channel` field instead. + */ + spaceId?: string; + + /** + * List of UUIDs which should be added as `channel` members. + */ + uuids: Array>; + + /** + * List of UUIDs which should be added as `channel` members. + * + * @deprecated Use `uuids` field instead. + */ + users?: Array< + | string + | (Omit, 'id'> & { + /** + * Unique User object identifier. + */ + userId: string; + }) + >; +}; + +/** + * Response with requested channel members information change. + */ +export type SetMembersResponse = MembersResponse< + MemberCustom, + UUIDCustom +>; +/** + * Remove Members request parameters. + */ +export type RemoveMembersParameters = PagedRequestParameters & { + /** + * Channel name. + */ + channel: string; + + /** + * Space identifier. + * + * @deprecated Use {@link channel} field instead. + */ + spaceId?: string; + + /** + * List of UUIDs which should be removed from the `channel` members list. + * removed. + */ + uuids: string[]; + + /** + * List of user identifiers which should be removed from the `channel` members list. + * removed. + * + * @deprecated Use {@link uuids} field instead. + */ + userIds?: string[]; +}; + +/** + * Response with remaining members. + */ +export type RemoveMembersResponse = MembersResponse< + MemberCustom, + UUIDCustom +>; + +// region Deprecated +/** + * Related User metadata object. + * + * Type represents User metadata which has been used to when added members to the Space. + */ +type UserMembersObject = Omit< + ObjectData, + 'id' +> & { + user: UUIDMetadataObject | { id: string }; +}; + +/** + * Response with fetched page of Space member objects. + */ +export type UserMembersResponse = PagedResponse< + UserMembersObject +>; + +type SpaceMembershipObject = Omit< + ObjectData, + 'id' +> & { + space: ChannelMetadataObject | { id: string }; +}; + +/** + * Response with fetched page of User membership objects. + */ +export type SpaceMembershipsResponse< + MembershipCustom extends CustomData, + ChannelCustom extends CustomData, +> = PagedResponse>; +// endregion diff --git a/src/core/types/api/channel-groups.ts b/src/core/types/api/channel-groups.ts new file mode 100644 index 000000000..79ea23091 --- /dev/null +++ b/src/core/types/api/channel-groups.ts @@ -0,0 +1,64 @@ +/** + * Add or remove Channels to the channel group request parameters. + */ +export type ManageChannelGroupChannelsParameters = { + /** + * Name of the channel group for which channels list should be changed. + */ + channelGroup: string; + + /** + * List of channels to be added or removed. + */ + channels: string[]; +}; + +/** + * Channel group channels list manage response. + */ +export type ManageChannelGroupChannelsResponse = Record; + +/** + * Response with result of the all channel groups list. + */ +export type ListAllChannelGroupsResponse = { + /** + * All channel groups with channels. + */ + groups: string[]; +}; + +/** + * List Channel Group Channels request parameters. + */ +export type ListChannelGroupChannelsParameters = { + /** + * Name of the channel group for which list of channels should be retrieved. + */ + channelGroup: string; +}; + +/** + * Response with result of the list channel group channels. + */ +export type ListChannelGroupChannelsResponse = { + /** + * List of the channels registered withing specified channel group. + */ + channels: string[]; +}; + +/** + * Delete Channel Group request parameters. + */ +export type DeleteChannelGroupParameters = { + /** + * Name of the channel group which should be removed. + */ + channelGroup: string; +}; + +/** + * Delete channel group response. + */ +export type DeleteChannelGroupResponse = Record; diff --git a/src/core/types/api/file-sharing.ts b/src/core/types/api/file-sharing.ts new file mode 100644 index 000000000..90200f69a --- /dev/null +++ b/src/core/types/api/file-sharing.ts @@ -0,0 +1,454 @@ +/** + * File Sharing REST API module. + */ + +import { PubNubFileInterface } from '../file'; +import { Payload } from './index'; + +// -------------------------------------------------------- +// ----------------------- Common ------------------------- +// -------------------------------------------------------- +// region Common + +/** + * Shared file object. + */ +export type SharedFile = { + /** + * Name with which file has been stored. + */ + name: string; + + /** + * Unique service-assigned file identifier. + */ + id: string; + + /** + * Shared file size. + */ + size: number; + + /** + * ISO 8601 time string when file has been shared. + */ + created: string; +}; +// endregion + +// -------------------------------------------------------- +// --------------------- List Files ----------------------- +// -------------------------------------------------------- +// region List Files + +/** + * List Files request parameters. + */ +export type ListFilesParameters = { + /** + * Name of channel for which list of files should be requested. + */ + channel: string; + + /** + * How many entries return with single response. + */ + limit?: number; + + /** + * Next files list page token. + */ + next?: string; +}; + +/** + * List Files request response. + */ +export type ListFilesResponse = { + /** + * Files list fetch result status code. + */ + status: number; + + /** + * List of fetched file objects. + */ + data: SharedFile[]; + + /** + * Next files list page token. + */ + next: string; + + /** + * Number of retrieved files. + */ + count: number; +}; +// endregion + +// -------------------------------------------------------- +// --------------------- Send File ------------------------ +// -------------------------------------------------------- +// region Send File + +/** + * Send File request parameters. + */ +export type SendFileParameters = Omit & { + /** + * Channel to send the file to. + */ + channel: string; + + /** + * File to send. + */ + file: FileParameters; +}; + +/** + * Send File request response. + */ +export type SendFileResponse = PublishFileMessageResponse & { + /** + * Send file request processing status code. + */ + status: number; + + /** + * Actual file name under which file has been stored. + * + * File name and unique {@link id} can be used to download file from the channel later. + * + * **Important:** Actual file name may be different from the one which has been used during file + * upload. + */ + name: string; + + /** + * Unique file identifier. + * + * Unique file identifier and it's {@link name} can be used to download file from the channel + * later. + */ + id: string; +}; + +/** + * Upload File request parameters. + */ +export type UploadFileParameters = { + /** + * Unique file identifier. + * + * Unique file identifier, and it's {@link fileName} can be used to download file from the channel + * later. + */ + fileId: string; + + /** + * Actual file name under which file has been stored. + * + * File name and unique {@link fileId} can be used to download file from the channel later. + * + * **Note:** Actual file name may be different from the one which has been used during file + * upload. + */ + fileName: string; + + /** + * File which should be uploaded. + */ + file: PubNubFileInterface; + + /** + * Pre-signed file upload Url. + */ + uploadUrl: string; + + /** + * An array of form fields to be used in the pre-signed POST request. + * + * **Important:** Form data fields should be passed in exact same order as received from + * the PubNub service. + */ + formFields: { + /** + * Form data field name. + */ + name: string; + + /** + * Form data field value. + */ + value: string; + }[]; +}; + +/** + * Upload File request response. + */ +export type UploadFileResponse = { + /** + * Upload File request processing status code. + */ + status: number; + + /** + * Service processing result response. + */ + message: Payload; +}; +// endregion + +// -------------------------------------------------------- +// -------------- Generate File Upload Url ---------------- +// -------------------------------------------------------- +// region Generate File Upload Url + +/** + * Generate File Upload URL request parameters. + */ +export type GenerateFileUploadUrlParameters = { + /** + * Name of channel to which file should be uploaded. + */ + channel: string; + + /** + * Actual name of the file which should be uploaded. + */ + name: string; +}; + +/** + * Generation File Upload URL request response. + */ +export type GenerateFileUploadUrlResponse = { + /** + * Unique file identifier. + * + * Unique file identifier, and it's {@link name} can be used to download file from the channel + * later. + */ + id: string; + + /** + * Actual file name under which file has been stored. + * + * File name and unique {@link id} can be used to download file from the channel later. + * + * **Note:** Actual file name may be different from the one which has been used during file + * upload. + */ + name: string; + + /** + * Pre-signed URL for file upload. + */ + url: string; + + /** + * An array of form fields to be used in the pre-signed POST request. + * + * **Important:** Form data fields should be passed in exact same order as received from + * the PubNub service. + */ + formFields: { + /** + * Form data field name. + */ + name: string; + + /** + * Form data field value. + */ + value: string; + }[]; +}; +// endregion + +// -------------------------------------------------------- +// ---------------- Publish File Message ------------------ +// -------------------------------------------------------- +// region Publish File Message + +/** + * Publish File Message request parameters. + */ +export type PublishFileMessageParameters = { + /** + * Name of channel to which file has been sent. + */ + channel: string; + + /** + * File annotation message. + */ + message?: Payload; + + /** + * Custom file and message encryption key. + * + * @deprecated Use {@link Configuration#cryptoModule|cryptoModule} configured for PubNub client + * instance or encrypt file prior {@link PubNub#sendFile|sendFile} method call. + */ + cipherKey?: string; + + /** + * Unique file identifier. + * + * Unique file identifier, and it's {@link fileName} can be used to download file from the channel + * later. + */ + fileId: string; + + /** + * Actual file name under which file has been stored. + * + * File name and unique {@link fileId} can be used to download file from the channel later. + * + * **Note:** Actual file name may be different from the one which has been used during file + * upload. + */ + fileName: string; + + /** + * Whether published file messages should be stored in the channel's history. + * + * **Note:** If `storeInHistory` not specified, then the history configuration on the key is + * used. + * + * @default `true` + */ + storeInHistory?: boolean; + + /** + * How long the message should be stored in the channel's history. + * + * **Note:** If not specified, defaults to the key set's retention value. + * + * @default `0` + */ + ttl?: number; + + /** + * Metadata, which should be associated with published file. + * + * Associated metadata can be utilized by message filtering feature. + */ + meta?: Payload; +}; + +/** + * Publish File Message request response. + */ +export type PublishFileMessageResponse = { + /** + * High-precision time when published file message has been received by the PubNub service. + */ + timetoken: string; +}; +// endregion + +// -------------------------------------------------------- +// -------------------- Download File --------------------- +// -------------------------------------------------------- +// region Download File +/** + * Download File request parameters. + */ +export type DownloadFileParameters = FileUrlParameters & { + /** + * Custom file and message encryption key. + * + * @deprecated Use {@link Configuration#cryptoModule|cryptoModule} configured for PubNub client + * instance or encrypt file prior {@link PubNub#sendFile|sendFile} method call. + */ + cipherKey?: string; +}; +// endregion + +// -------------------------------------------------------- +// ------------- Generate File Download Url --------------- +// -------------------------------------------------------- +// region Generate File Download Url + +/** + * Generate File download Url request parameters. + */ +export type FileUrlParameters = { + /** + * Name of channel where file has been sent. + */ + channel: string; + + /** + * Unique file identifier. + * + * Unique file identifier and it's {@link name} can be used to download file from the channel + * later. + */ + id: string; + + /** + * Actual file name under which file has been stored. + * + * File name and unique {@link id} can be used to download file from the channel later. + * + * **Important:** Actual file name may be different from the one which has been used during file + * upload. + */ + name: string; +}; + +/** + * Generate File Download Url response. + */ +export type FileUrlResponse = string; +// endregion + +// -------------------------------------------------------- +// --------------------- Delete File ---------------------- +// -------------------------------------------------------- +// region Delete File + +/** + * Delete File request parameters. + */ +export type DeleteFileParameters = { + /** + * Name of channel where file has been sent. + */ + channel: string; + + /** + * Unique file identifier. + * + * Unique file identifier and it's {@link name} can be used to download file from the channel + * later. + */ + id: string; + + /** + * Actual file name under which file has been stored. + * + * File name and unique {@link id} can be used to download file from the channel later. + * + * **Important:** Actual file name may be different from the one which has been used during file + * upload. + */ + name: string; +}; + +/** + * Delete File request response. + */ +export type DeleteFileResponse = { + /** + * Delete File request processing status code. + */ + status: number; +}; +// endregion diff --git a/src/core/types/api/history.ts b/src/core/types/api/history.ts new file mode 100644 index 000000000..6bea6b7eb --- /dev/null +++ b/src/core/types/api/history.ts @@ -0,0 +1,475 @@ +import { Payload } from './index'; + +// -------------------------------------------------------- +// --------------------- Get History ---------------------- +// -------------------------------------------------------- +// region Get History + +/** + * Get history request parameters. + */ +export type GetHistoryParameters = { + /** + * Channel to return history messages from. + */ + channel: string; + + /** + * Specifies the number of historical messages to return. + * + * **Note:** Maximum `100` messages can be returned in single response. + * + * @default `100` + */ + count?: number; + + /** + * Whether message `meta` information should be fetched or not. + * + * @default `false` + */ + includeMeta?: boolean; + + /** + * Timetoken delimiting the `start` of `time` slice (exclusive) to pull messages from. + */ + start?: string; + + /** + * Timetoken delimiting the `end` of `time` slice (inclusive) to pull messages from. + */ + end?: string; + + /** + * Whether timeline should traverse in reverse starting with the oldest message first or not. + * + * If both `start` and `end` arguments are provided, `reverse` is ignored and messages are + * returned starting with the newest message. + */ + reverse?: boolean; + + /** + * Whether message timetokens should be stringified or not. + * + * @default `false` + */ + stringifiedTimeToken?: boolean; +}; + +/** + * Get history response. + */ +export type GetHistoryResponse = { + /** + * List of previously published messages. + */ + messages: { + /** + * Message payload (decrypted). + */ + entry: Payload; + + /** + * When message has been received by PubNub service. + */ + timetoken: string | number; + + /** + * Additional data which has been published along with message to be used with real-time + * events filter expression. + */ + meta?: Payload; + + /** + * Message decryption error (if attempt has been done). + */ + error?: string; + }[]; + + /** + * Received messages timeline start. + */ + startTimeToken: string | number; + + /** + * Received messages timeline end. + */ + endTimeToken: string | number; +}; +// endregion + +// -------------------------------------------------------- +// -------------------- Fetch Messages -------------------- +// -------------------------------------------------------- +// region Fetch Messages + +/** + * PubNub-defined message type. + * + * Types of messages which can be retrieved with fetch messages REST API. + */ +export enum PubNubMessageType { + /** + * Regular message. + */ + Message = -1, + + /** + * File message. + */ + Files = 4, +} + +/** + * Per-message actions information. + */ +export type Actions = { + /** + * Message action type. + */ + [t: string]: { + /** + * Message action value. + */ + [v: string]: { + /** + * Unique identifier of the user which reacted on message. + */ + uuid: string; + + /** + * High-precision PubNub timetoken with time when {@link uuid} reacted on message. + */ + actionTimetoken: string; + }; + }; +}; + +/** + * Additional message actions fetch information. + */ +export type MoreActions = { + /** + * Prepared fetch messages with actions REST API URL. + */ + url: string; + + /** + * Next page time offset. + */ + start: string; + + /** + * Number of messages to retrieve with next page. + */ + max: number; +}; + +/** + * Common content of the fetched message. + */ +type BaseFetchedMessage = { + /** + * Name of channel for which message has been retrieved. + */ + channel: string; + + /** + * When message has been received by PubNub service. + */ + timetoken: string | number; + + /** + * Message publisher unique identifier. + */ + uuid?: string; + + /** + * Additional data which has been published along with message to be used with real-time + * events filter expression. + */ + meta?: Payload; + + /** + * Message decryption error (if attempt has been done). + */ + error?: string; +}; + +/** + * Regular message published to the channel. + */ +export type RegularMessage = BaseFetchedMessage & { + /** + * Message payload (decrypted). + */ + message: Payload; + + /** + * PubNub-defined message type. + */ + messageType?: PubNubMessageType.Message; +}; + +/** + * File message published to the channel. + */ +export type FileMessage = BaseFetchedMessage & { + /** + * Message payload (decrypted). + */ + message: { + /** + * File annotation message. + */ + message?: Payload; + + /** + * File information. + */ + file: { + /** + * Unique file identifier. + */ + id: string; + + /** + * Name with which file has been stored. + */ + name: string; + + /** + * File's content mime-type. + */ + 'mime-type': string; + + /** + * Stored file size. + */ + size: number; + + /** + * Pre-computed file download Url. + */ + url: string; + }; + }; + + /** + * PubNub-defined message type. + */ + messageType?: PubNubMessageType.Files; +}; + +/** + * Fetched message entry in channel messages list. + */ +export type FetchedMessage = RegularMessage | FileMessage; + +/** + * Fetched with actions message entry in channel messages list. + */ +export type FetchedMessageWithActions = FetchedMessage & { + /** + * List of message reactions. + */ + actions?: Actions; + /** + * List of message reactions. + * + * @deprecated Use {@link actions} field instead. + */ + data?: Actions; +}; + +/** + * Fetch messages request parameters. + */ +export type FetchMessagesParameters = { + /** + * Specifies channels to return history messages from. + * + * **Note:** Maximum of `500` channels are allowed. + */ + channels: string[]; + + /** + * Specifies the number of historical messages to return per channel. + * + * **Note:** Default is `100` per single channel and `25` per multiple channels or per + * single channel if {@link includeMessageActions} is used. + * + * @default `100` or `25` + */ + count?: number; + + /** + * Whether message type should be returned with each history message or not. + * + * @default `true` + */ + includeMessageType?: boolean; + + /** + * Whether publisher `uuid` should be returned with each history message or not. + * + * @default `true` + */ + includeUUID?: boolean; + + /** + * Whether publisher `uuid` should be returned with each history message or not. + * + * @deprecated Use {@link includeUUID} property instead. + */ + includeUuid?: boolean; + + /** + * Whether message `meta` information should be fetched or not. + * + * @default `false` + */ + includeMeta?: boolean; + + /** + * Whether message-added message actions should be fetched or not. + * + * If used, the limit of messages retrieved will be `25` per single channel. + * + * Each message can have a maximum of `25000` actions attached to it. Consider the example of + * querying for 10 messages. The first five messages have 5000 actions attached to each of + * them. The API will return the first 5 messages and all their 25000 actions. The response + * will also include a `more` link to get the remaining 5 messages. + * + * **Important:** Truncation will happen if the number of actions on the messages returned + * is > 25000. + * + * @default `false` + * + * @throws Exception if API is called with more than one channel. + */ + includeMessageActions?: boolean; + + /** + * Timetoken delimiting the `start` of `time` slice (exclusive) to pull messages from. + */ + start?: string; + + /** + * Timetoken delimiting the `end` of `time` slice (inclusive) to pull messages from. + */ + end?: string; + + /** + * Whether message timetokens should be stringified or not. + * + * @default `false` + */ + stringifiedTimeToken?: boolean; +}; + +/** + * Fetch messages response. + */ +export type FetchMessagesForChannelsResponse = { + /** + * List of previously published messages per requested channel. + */ + channels: { + [p: string]: FetchedMessage[]; + }; +}; + +/** + * Fetch messages with reactions response. + */ +export type FetchMessagesWithActionsResponse = { + channels: { + [p: string]: FetchedMessageWithActions[]; + }; + + /** + * Additional message actions fetch information. + */ + more: MoreActions; +}; + +/** + * Fetch messages response. + */ +export type FetchMessagesResponse = FetchMessagesForChannelsResponse | FetchMessagesWithActionsResponse; +// endregion + +// -------------------------------------------------------- +// ------------------- Messages Count --------------------- +// -------------------------------------------------------- +// region Messages Count + +/** + * Message count request parameters. + */ +export type MessageCountParameters = { + /** + * The channels to fetch the message count. + */ + channels: string[]; + + /** + * List of timetokens, in order of the {@link channels} list. + * + * Specify a single timetoken to apply it to all channels. Otherwise, the list of timetokens + * must be the same length as the list of {@link channels}, or the function returns an error + * flag. + */ + channelTimetokens?: string[]; + + /** + * High-precision PubNub timetoken starting from which number of messages should be counted. + * + * Same timetoken will be used to count messages for each passed {@link channels}. + * + * @deprecated Use {@link channelTimetokens} field instead. + */ + timetoken?: string; +}; +/** + * Message count response. + */ +export type MessageCountResponse = { + /** + * Map of channel names to the number of counted messages. + */ + channels: Record; +}; +// endregion + +// -------------------------------------------------------- +// ------------------- Delete Messages -------------------- +// -------------------------------------------------------- +// region Delete Messages + +/** + * Delete messages from channel parameters. + */ +export type DeleteMessagesParameters = { + /** + * Specifies channel messages to be deleted from history. + */ + channel: string; + + /** + * Timetoken delimiting the start of time slice (exclusive) to delete messages from. + */ + start?: string; + + /** + * Timetoken delimiting the end of time slice (inclusive) to delete messages from. + */ + end?: string; +}; + +/** + * Delete messages from channel response. + */ +export type DeleteMessagesResponse = Record; +// endregion diff --git a/src/core/types/api/index.ts b/src/core/types/api/index.ts new file mode 100644 index 000000000..75c2d1c93 --- /dev/null +++ b/src/core/types/api/index.ts @@ -0,0 +1,295 @@ +// PubNub client API common types. + +import { AbstractRequest } from '../../components/request'; +import RequestOperation from '../../constants/operations'; +import { TransportResponse } from '../transport-response'; +import StatusCategory from '../../constants/categories'; + +/** + * PubNub REST API call error. + */ +export class PubNubAPIError extends Error { + /** + * Construct API from known error object or {@link PubNub} service error response. + * + * @param errorOrResponse - `Error` or service error response object from which error information + * should be extracted. + * @param data - Preprocessed service error response. + * + * @returns `PubNubAPIError` object with known error category and additional information (if + * available). + */ + static create(errorOrResponse: Error | TransportResponse, data?: ArrayBuffer): PubNubAPIError { + if (errorOrResponse instanceof Error) return PubNubAPIError.createFromError(errorOrResponse); + else return PubNubAPIError.createFromServiceResponse(errorOrResponse, data); + } + + /** + * Create API error instance from other error object. + * + * @param error - `Error` object provided by network provider (mostly) or other {@link PubNub} client components. + * + * @returns `PubNubAPIError` object with known error category and additional information (if + * available). + */ + private static createFromError(error: unknown): PubNubAPIError { + let category: StatusCategory = StatusCategory.PNUnknownCategory; + let message = 'Unknown error'; + let errorName = 'Error'; + + if (!error) return new PubNubAPIError(message, category, 0); + + if (error instanceof Error) { + message = error.message; + errorName = error.name; + } + + if (errorName === 'AbortError') { + category = StatusCategory.PNCancelledCategory; + message = 'Request cancelled'; + } else if (errorName === 'FetchError') { + const errorCode = (error as Record).code; + + if (errorCode in ['ECONNREFUSED', 'ENOTFOUND', 'ECONNRESET', 'EAI_AGAIN']) + category = StatusCategory.PNNetworkIssuesCategory; + if (errorCode === 'ECONNREFUSED') message = 'Connection refused'; + else if (errorCode === 'ENOTFOUND') message = 'Server not found'; + else if (errorCode === 'ECONNRESET') message = 'Connection reset by peer'; + else if (errorCode === 'EAI_AGAIN') message = 'Name resolution error'; + else if (errorCode === 'ETIMEDOUT') { + category = StatusCategory.PNTimeoutCategory; + message = 'Request timeout'; + } else message = `Unknown system error: ${error}`; + } else if (message === 'Request timeout') category = StatusCategory.PNTimeoutCategory; + + return new PubNubAPIError(message, category, 0, error as Error); + } + + /** + * Construct API from known {@link PubNub} service error response. + * + * @param response - Service error response object from which error information should be + * extracted. + * @param data - Preprocessed service error response. + * + * @returns `PubNubAPIError` object with known error category and additional information (if + * available). + */ + private static createFromServiceResponse(response: TransportResponse, data?: ArrayBuffer): PubNubAPIError { + let category: StatusCategory = StatusCategory.PNUnknownCategory; + let errorData: Error | Payload | undefined; + let message = 'Unknown error'; + let { status } = response; + + if (status === 402) message = 'Not available for used key set. Contact support@pubnub.com'; + else if (status === 400) { + category = StatusCategory.PNBadRequestCategory; + message = 'Bad request'; + } else if (status === 403) { + category = StatusCategory.PNAccessDeniedCategory; + message = 'Access denied'; + } + + // Try get more information about error from service response. + if (data && data.byteLength > 0) { + const decoded = new TextDecoder().decode(data); + + if (response.headers['content-type']!.includes('application/json')) { + try { + const errorResponse: Payload = JSON.parse(decoded); + + if (typeof errorResponse === 'object' && !Array.isArray(errorResponse)) { + if ( + 'error' in errorResponse && + errorResponse.error === 1 && + 'status' in errorResponse && + typeof errorResponse.status === 'number' && + 'message' in errorResponse && + 'service' in errorResponse + ) { + errorData = errorResponse; + status = errorResponse.status; + } + + if ( + 'error' in errorResponse && + typeof errorResponse.error === 'object' && + !Array.isArray(errorResponse.error!) && + 'message' in errorResponse.error! + ) { + errorData = errorResponse.error; + } + } + } catch (_) { + errorData = decoded; + } + } else errorData = decoded; + } + + return new PubNubAPIError(message, category, status, errorData); + } + + /** + * Construct PubNub endpoint error. + * + * @param message - Short API call error description. + * @param category - Error category. + * @param statusCode - Response HTTP status code. + * @param errorData - Error information. + */ + constructor( + message: string, + public readonly category: StatusCategory, + public readonly statusCode: number, + public readonly errorData?: Error | Payload, + ) { + super(message); + this.name = this.constructor.name; + } + + /** + * Convert API error object to API callback status object. + * + * @param operation - Request operation during which error happened. + * + * @returns Pre-formatted API callback status object. + */ + public toStatus(operation: RequestOperation): Status { + return { + error: true, + category: this.category, + operation, + statusCode: this.statusCode, + errorData: this.errorData, + }; + } +} + +/** + * PubNub account keyset. + */ +export type KeySet = { + /** + * Specifies the `subscribeKey` to be used for subscribing to a channel and message publishing. + */ + subscribeKey: string; + + /** + * Specifies the `publishKey` to be used for publishing messages to a channel. + */ + publishKey?: string; + + /** + * Specifies the `secretKey` to be used for request signatures computation. + */ + secretKey?: string; +}; + +/** + * REST API request processing function. + */ +export type SendRequestFunction = ( + request: AbstractRequest, + callback?: ResultCallback, +) => Promise; + +export type ResultCallback = (status: Status, response: ResponseType | null) => void; +export type StatusCallback = (status: Status) => void; + +/** + * REST API endpoint processing status. + */ +export type Status = { + /** + * Whether status represent error or not. + */ + error: boolean; + /** + * API call status category. + */ + category?: StatusCategory; + + /** + * Type of REST API endpoint which reported status. + */ + operation?: RequestOperation; + + /** + * REST API response status code. + */ + statusCode?: number; + + /** + * Error data provided by REST API. + */ + errorData?: Error | Payload; + + /** + * Additional status information. + */ + [p: string]: Payload | Error | undefined; +}; + +/** + * Real-time PubNub client status change event. + */ +export type StatusEvent = { + /** + * API call status category. + */ + category: StatusCategory; + + /** + * Type of REST API endpoint which reported status. + */ + operation?: RequestOperation; + + /** + * List of channels for which status update announced. + */ + affectedChannels?: string[]; + + /** + * List of currently subscribed channels. + * + * List of channels from which PubNub client receives real-time updates. + */ + subscribedChannels?: string[]; + + /** + * List of channel groups for which status update announced. + */ + affectedChannelGroups?: string[]; + + /** + * High-precision timetoken which has been used with previous subscription loop. + */ + lastTimetoken?: number | string; + + /** + * High-precision timetoken which is used for current subscription loop. + */ + currentTimetoken?: number | string; +}; + +/** + * {@link TransportRequest} query parameter type. + */ +export type Query = Record; + +/** + * General payload type. + * + * Type should be used for: + * * generic messages and signals content, + * * published message metadata. + */ +export type Payload = string | number | boolean | { [key: string]: Payload | null } | Payload[]; + +/** + * Scalar payload type. + * + * Type used for REST API which doesn't allow nested types: + * * App Context + */ +export type PayloadWithScalars = { [key: string]: string | number | boolean | null }; diff --git a/src/core/types/api/message-action.ts b/src/core/types/api/message-action.ts new file mode 100644 index 000000000..125d3a3e0 --- /dev/null +++ b/src/core/types/api/message-action.ts @@ -0,0 +1,175 @@ +/** + * Message reaction object type. + */ +export type MessageAction = { + /** + * What feature this message action represents. + */ + type: string; + + /** + * Value which should be stored along with message action. + */ + value: string; + + /** + * Unique identifier of the user which added message action. + */ + uuid: string; + + /** + * Timetoken of when message reaction has been added. + * + * **Note:** This token required when it will be required to remove raction. + */ + actionTimetoken: string; + + /** + * Timetoken of message to which `action` has been added. + */ + messageTimetoken: string; +}; + +/** + * More message actions fetch information. + */ +export type MoreMessageActions = { + /** + * Prepared REST API url to fetch next page with message actions. + */ + url: string; + + /** + * Message action timetoken denoting the start of the range requested with next page. + * + * **Note:** Return values will be less than {@link start}. + */ + start: string; + + /** + * Message action timetoken denoting the end of the range requested with next page. + * + * **Note:** Return values will be greater than or equal to {@link end}. + */ + end: string; + /** + * Number of message actions to return in next response. + */ + limit: number; +}; + +/** + * Add Message Action request parameters. + */ +export type AddMessageActionParameters = { + /** + * Name of channel which stores the message for which {@link action} should be added. + */ + channel: string; + + /** + * Timetoken of message for which {@link action} should be added. + */ + messageTimetoken: string; + + /** + * Message `action` information. + */ + action: { + /** + * What feature this message action represents. + */ + type: string; + + /** + * Value which should be stored along with message action. + */ + value: string; + }; +}; + +/** + * Response with added message action object. + */ +export type AddMessageActionResponse = { data: MessageAction }; + +/** + * Get Message Actions request parameters. + */ +export type GetMessageActionsParameters = { + /** + * Name of channel from which list of messages `actions` should be retrieved. + */ + channel: string; + + /** + * Message action timetoken denoting the start of the range requested. + * + * **Note:** Return values will be less than {@link start}. + */ + start?: string; + + /** + * Message action timetoken denoting the end of the range requested. + * + * **Note:** Return values will be greater than or equal to {@link end}. + */ + end?: string; + + /** + * Number of message actions to return in response. + */ + limit?: number; +}; + +/** + * Response with message actions in specific `channel`. + */ +export type GetMessageActionsResponse = { + /** + * Retrieved list of message actions. + */ + data: MessageAction[]; + + /** + * Received message actions time frame start. + */ + start: string | null; + + /** + * Received message actions time frame end. + */ + end: string | null; + + /** + * More message actions fetch information. + */ + more?: MoreMessageActions; +}; + +/** + * Remove Message Action request parameters. + */ +export type RemoveMessageActionParameters = { + /** + * Name of channel which store message for which `action` should be removed. + */ + channel: string; + + /** + * Timetoken of message for which `action` should be removed. + */ + messageTimetoken: string; + + /** + * Action addition timetoken. + */ + actionTimetoken: string; +}; + +/** + * Response with message remove result. + */ +export type RemoveMessageActionResponse = { + data: Record; +}; diff --git a/src/core/types/api/presence.ts b/src/core/types/api/presence.ts new file mode 100644 index 000000000..16d9e2f33 --- /dev/null +++ b/src/core/types/api/presence.ts @@ -0,0 +1,250 @@ +import { Payload } from './index'; + +// region Get Presence State +/** + * Associated presence state fetch parameters. + */ +export type GetPresenceStateParameters = { + /** + * The subscriber uuid to get the current state. + * + * @default `current uuid` + */ + uuid?: string; + + /** + * List of channels for which state associated with {@link uuid} should be retrieved. + * + * **Important:** Either {@link channels} or {@link channelGroups} should be provided; + */ + channels?: string[]; + + /** + * List of channel groups for which state associated with {@link uuid} should be retrieved. + * + * **Important:** Either {@link channels} or {@link channelGroups} should be provided; + */ + channelGroups?: string[]; +}; + +/** + * Associated presence state fetch response. + */ +export type GetPresenceStateResponse = { + /** + * Channels map to state which `uuid` has associated with them. + */ + channels: Record; +}; +// endregion + +// region Set Presence State +/** + * Associate presence state parameters. + */ +export type SetPresenceStateParameters = { + /** + * List of channels for which state should be associated with {@link uuid}. + */ + channels?: string[]; + + /** + * List of channel groups for which state should be associated with {@link uuid}. + */ + channelGroups?: string[]; + + /** + * State which should be associated with `uuid` on provided list of {@link channels} and {@link channelGroups}. + */ + state: Payload; +}; + +/** + * Associate presence state parameters using heartbeat. + */ +export type SetPresenceStateWithHeartbeatParameters = { + /** + * List of channels for which state should be associated with {@link uuid}. + */ + channels?: string[]; + + /** + * State which should be associated with `uuid` on provided list of {@link channels}. + */ + state: Payload; + + /** + * Whether `presence/heartbeat` REST API should be used to manage state or not. + * + * @default `false` + */ + withHeartbeat: boolean; +}; + +/** + * Associate presence state response. + */ +export type SetPresenceStateResponse = { + /** + * State which has been associated with `uuid` on provided list of channels and groups. + */ + state: Payload; +}; +// endregion + +// region Heartbeat announce +/** + * Announce heartbeat parameters. + */ +export type PresenceHeartbeatParameters = { + /** + * How long the server will consider the client alive for presence.The value is in seconds. + */ + heartbeat: number; + + /** + * List of channels for which heartbeat should be announced for {@link uuid}. + */ + channels?: string[]; + + /** + * List of channel groups for which heartbeat should be announced for {@link uuid}. + */ + channelGroups?: string[]; + + /** + * State which should be associated with `uuid` on provided list of {@link channels} and {@link channelGroups}. + */ + state?: Payload; +}; + +/** + * Announce heartbeat response. + */ +export type PresenceHeartbeatResponse = Record; +// endregion + +// region Get Presence State +/** + * Presence leave parameters. + */ +export type PresenceLeaveParameters = { + /** + * List of channels for which `uuid` should be marked as `offline`. + */ + channels?: string[]; + + /** + /** + * List of channel groups for which `uuid` should be marked as `offline`. + */ + channelGroups?: string[]; +}; + +/** + * Presence leave response. + */ +export type PresenceLeaveResponse = Record; +// endregion + +// region Here now +/** + * Channel / channel group presence fetch parameters.. + */ +export type HereNowParameters = { + /** + * List of channels for which presence should be retrieved. + */ + channels?: string[]; + + /** + * List of channel groups for which presence should be retrieved. + */ + channelGroups?: string[]; + + /** + * Whether `uuid` information should be included in response or not. + * + * **Note:** Only occupancy information will be returned if both {@link includeUUIDs} and {@link includeState} is + * set to `false`. + * + * @default `true` + */ + includeUUIDs?: boolean; + + /** + * Whether state associated with `uuid` should be included in response or not. + * + * @default `false`. + */ + includeState?: boolean; + + /** + * Additional query parameters. + */ + queryParameters?: Record; +}; + +/** + * `uuid` where now response. + */ +export type HereNowResponse = { + /** + * Total number of channels for which presence information received. + */ + totalChannels: number; + + /** + * Total occupancy for all retrieved channels. + */ + totalOccupancy: number; + + /** + * List of channels to which `uuid` currently subscribed. + */ + channels: { + [p: string]: { + /** + * List of received channel subscribers. + * + * **Note:** Field is missing if `uuid` and `state` not included. + */ + occupants: { uuid: string; state?: Payload | null }[]; + + /** + * Name of channel for which presence information retrieved. + */ + name: string; + + /** + * Total number of active subscribers in single channel. + */ + occupancy: number; + }; + }; +}; +// endregion + +// region Where now +/** + * `uuid` where now parameters. + */ +export type WhereNowParameters = { + /** + * The subscriber uuid to get the current state. + * + * @default `current uuid` + */ + uuid?: string; +}; + +/** + * `uuid` where now response. + */ +export type WhereNowResponse = { + /** + * Channels map to state which `uuid` has associated with them. + */ + channels: string[]; +}; +// endregion diff --git a/src/core/types/api/push-notifications.ts b/src/core/types/api/push-notifications.ts new file mode 100644 index 000000000..8dd0dadcf --- /dev/null +++ b/src/core/types/api/push-notifications.ts @@ -0,0 +1,53 @@ +/** + * Type of Push Notifications gateway which should be used with Push Notifications REST API. + */ +type PushGateway = 'apns2' | 'gcm'; + +/** + * Basic information required by Push Notifications REST API about device. + */ +type DevicePush = { + /** + * Device ID for which list of registered channel push notifications will be changed. + */ + device: string; + + /** + * Push Notifications gateway to use. + * + * **Important:** Depends from the source of `device` token and can be `apns2` (for token + * provided during device registration using Apple's framework) or `gcm` (when used Firebase + * or similar framework to receive token). + */ + pushGateway: PushGateway; +}; + +/** + * Register and unregister push notifications for device request parameters. + */ +export type ManageDeviceChannelsParameters = { + /** + * List of channels to be added or removed. + */ + channels: string[]; +} & DevicePush; + +/** + * List Device Channels request parameters. + */ +export type ListDeviceChannelsParameters = DevicePush; + +/** + * Response with result of the list device channels. + */ +export type ListDeviceChannelsResponse = { + /** + * List of the channels for which `device` will receive push notifications. + */ + channels: string[]; +}; + +/** + * Delete Push Notification for device request parameters. + */ +export type DeleteDeviceParameters = DevicePush; diff --git a/src/core/types/api/push.ts b/src/core/types/api/push.ts new file mode 100644 index 000000000..6463bfabc --- /dev/null +++ b/src/core/types/api/push.ts @@ -0,0 +1,121 @@ +/** + * Common managed channels push notification parameters. + */ +type ManagedDeviceChannels = { + /** + * Channels to register or unregister with mobile push notifications. + */ + channels: string[]; + + /** + * The device ID to associate with mobile push notifications. + */ + device: string; + + /** + * Starting channel for pagination. + * + * **Note:** Use the last channel from the previous page request. + */ + start?: string; + + /** + * Number of channels to return for pagination. + * + * **Note:** maximum of 1000 tokens at a time. + * + * @default `500` + */ + count?: number; +}; + +// region List channels +/** + * List all FCM device push notification enabled channels parameters. + */ +type ListFCMDeviceChannelsParameters = Omit; + +/** + * List all APNS2 device push notification enabled channels parameters. + */ +type ListAPNS2DeviceChannelsParameters = Omit; + +/** + * List all device push notification enabled channels parameters. + */ +export type ListDeviceChannelsParameters = ListFCMDeviceChannelsParameters | ListAPNS2DeviceChannelsParameters; + +/** + * List all device push notification enabled channels response. + */ +export type ListDeviceChannelsResponse = { + /** + * List of channels registered for device push notifications. + */ + channels: string[]; +}; +// endregion + +// region Add / Remove channels +/** + * Manage FCM device push notification enabled channels parameters. + */ +type ManageFCMDeviceChannelsParameters = ManagedDeviceChannels & { + /** + * Push Notifications gateway type. + */ + pushGateway: 'gcm'; +}; + +/** + * Manage APNS2 device push notification enabled channels parameters. + */ +type ManageAPNS2DeviceChannelsParameters = ManagedDeviceChannels & { + /** + * Push Notifications gateway type. + */ + pushGateway: 'apns2'; + + /** + * Environment within which device should manage list of channels with enabled notifications. + */ + environment?: 'development' | 'production'; + + /** + * Notifications topic name (usually it is bundle identifier of application for Apple platform). + */ + topic: string; +}; + +/** + * Manage device push notification enabled channels parameters. + */ +export type ManageDeviceChannelsParameters = ManageFCMDeviceChannelsParameters | ManageAPNS2DeviceChannelsParameters; + +/** + * Manage device push notification enabled channels response. + */ +export type ManageDeviceChannelsResponse = Record; +// endregion + +// region Remove device +/** + * Remove all FCM device push notification enabled channels parameters. + */ +type RemoveFCMDeviceParameters = Omit; + +/** + * Manage APNS2 device push notification enabled channels parameters. + */ +type RemoveAPNS2DeviceParameters = Omit; + +/** + * Remove all device push notification enabled channels parameters. + */ +export type RemoveDeviceParameters = RemoveFCMDeviceParameters | RemoveAPNS2DeviceParameters; + +/** + * Remove all device push notification enabled channels response. + */ +export type RemoveDeviceResponse = Record; +// endregion diff --git a/src/core/types/api/subscription.ts b/src/core/types/api/subscription.ts new file mode 100644 index 000000000..5cdab91fe --- /dev/null +++ b/src/core/types/api/subscription.ts @@ -0,0 +1,371 @@ +import { + RequestParameters as SubscribeRequestParameters, + VSPMembershipObjectData, + AppContextObjectData, + MessageActionData, + PubNubEventType, + SpaceObjectData, + UserObjectData, + PresenceData, + FileData, +} from '../../endpoints/subscribe'; +import { AbortSignal } from '../../components/abort_signal'; +import { Payload } from './index'; + +// -------------------------------------------------------- +// --------------------- Event types ---------------------- +// -------------------------------------------------------- +// region Even types + +/** + * Time cursor. + * + * Cursor used by subscription loop to identify point in time after which updates will be + * delivered. + */ +export type SubscriptionCursor = { + /** + * PubNub high-precision timestamp. + * + * Aside of specifying exact time of receiving data / event this token used to catchup / + * follow on real-time updates. + */ + timetoken: string | number; + + /** + * Data center region for which `timetoken` has been generated. + */ + region?: number; +}; + +/** + * Common real-time event. + */ +type Event = { + /** + * Channel to which real-time event has been sent. + */ + channel: string; + + /** + * Actual subscription at which real-time event has been received. + * + * PubNub client provide various ways to subscribe to the real-time stream: channel groups, + * wildcard subscription, and spaces. + * + * **Note:** Value will be `null` if it is the same as {@link channel}. + */ + subscription: string | null; + + /** + * High-precision PubNub timetoken with time when event has been received by PubNub services. + */ + timetoken: string; +}; + +/** + * Common legacy real-time event for backward compatibility. + */ +type LegacyEvent = Event & { + /** + * Channel to which real-time event has been sent. + * + * @deprecated Use {@link channel} field instead. + */ + actualChannel?: string | null; + + /** + * Actual subscription at which real-time event has been received. + * + * @deprecated Use {@link subscription} field instead. + */ + subscribedChannel?: string; +}; + +// region Presence event +/** + * Presence change real-time event. + */ +export type Presence = LegacyEvent & PresenceData; + +/** + * Extended presence real-time event. + * + * Type extended for listener manager support. + */ +type PresenceEvent = { + type: PubNubEventType.Presence; + data: Presence; +}; +// endregion + +// region Data publish event +/** + * Common published data information. + */ +type PublishedData = { + /** + * Unique identifier of the user which sent data. + */ + publisher?: string; + + /** + * Additional user-provided metadata which can be used with real-time filtering expression. + */ + userMetadata?: { [p: string]: Payload }; + + /** + * Sent data. + */ + message: Payload; +}; + +/** + * Real-time message event. + */ +export type Message = LegacyEvent & + PublishedData & { + /** + * Decryption error message in case of failure. + */ + error?: string; + }; + +/** + * Extended real-time message event. + * + * Type extended for listener manager support. + */ +type MessageEvent = { + type: PubNubEventType.Message; + data: Message; +}; + +/** + * Real-time signal event. + */ +export type Signal = Event & PublishedData; + +/** + * Extended real-time signal event. + * + * Type extended for listener manager support. + */ +type SignalEvent = { + type: PubNubEventType.Signal; + data: Signal; +}; +// endregion + +// region Message action event + +/** + * Message action real-time event. + */ +export type MessageAction = Event & + Omit & { + /** + * Unique identifier of the user which added message reaction. + * + * @deprecated Use `data.uuid` field instead. + */ + publisher?: string; + + data: MessageActionData['data'] & { + /** + * Unique identifier of the user which added message reaction. + */ + uuid: string; + }; + }; + +/** + * Extended message action real-time event. + * + * Type extended for listener manager support. + */ +type MessageActionEvent = { + type: PubNubEventType.MessageAction; + data: MessageAction; +}; +// endregion + +// region App Context event +/** + * App Context Object change real-time event. + */ +export type AppContextObject = Event & { + /** + * Information about App Context object for which event received. + */ + message: AppContextObjectData; +}; + +/** + * `User` App Context Object change real-time event. + */ +export type UserAppContextObject = Omit & { + /** + * Space to which real-time event has been sent. + */ + spaceId: string; + + /** + * Information about User Object for which event received. + */ + message: UserObjectData; +}; + +/** + * `Space` App Context Object change real-time event. + */ +export type SpaceAppContextObject = Omit & { + /** + * Space to which real-time event has been sent. + */ + spaceId: string; + + /** + * Information about `Space` Object for which event received. + */ + message: SpaceObjectData; +}; + +/** + * VSP `Membership` App Context Object change real-time event. + */ +export type VSPMembershipAppContextObject = Omit & { + /** + * Space to which real-time event has been sent. + */ + spaceId: string; + + /** + * Information about `Membership` Object for which event received. + */ + message: VSPMembershipObjectData; +}; + +/** + * Extended App Context Object change real-time event. + * + * Type extended for listener manager support. + */ +type AppContextEvent = { + type: PubNubEventType.AppContext; + data: AppContextObject; +}; +// endregion + +// region File event +/** + * File real-time event. + */ +export type File = Event & + Omit & + Omit & { + /** + * Message which has been associated with uploaded file. + */ + message?: Payload; + + /** + * Information about uploaded file. + */ + file?: FileData['file'] & { + /** + * File download url. + */ + url: string; + }; + + /** + * Decryption error message in case of failure. + */ + error?: string; + }; + +/** + * Extended File real-time event. + * + * Type extended for listener manager support. + */ +type FileEvent = { + type: PubNubEventType.Files; + data: File; +}; +// endregion + +// -------------------------------------------------------- +// -------------------- Request types --------------------- +// -------------------------------------------------------- + +/** + * Cancelable subscribe request parameters. + */ +export type CancelableSubscribeParameters = Omit< + SubscribeRequestParameters, + 'crypto' | 'timeout' | 'keySet' | 'getFileUrl' +> & { + /** + * Long-poll request termination signal. + */ + abortSignal: AbortSignal; +}; + +/** + * Subscribe request parameters. + */ +export type SubscribeParameters = { + /** + * List of channels from which real-time events should be delivered. + * + * @default `,` if {@link channelGroups} is set. + */ + channels?: string[]; + + /** + * List of channel groups from which real-time events should be retrieved. + */ + channelGroups?: string[]; + + /** + * Next subscription loop timetoken. + */ + timetoken?: string | number; + + /** + * Whether should subscribe to channels / groups presence announcements or not. + * + * @default `false` + */ + withPresence?: boolean; + + // region Deprecated + /** + * Presence information which should be associated with `userId`. + * + * `state` information will be associated with `userId` on channels mentioned as keys in + * this object. + * + * @deprecated Use set state methods to specify associated user's data instead of passing to + * subscribe. + */ + state?: Record; + + /** + * Whether should subscribe to channels / groups presence announcements or not. + * + * @default `false` + */ + withHeartbeats?: boolean; + // endregion +}; + +/** + * Service success response. + */ +export type SubscriptionResponse = { + cursor: SubscriptionCursor; + messages: (PresenceEvent | MessageEvent | SignalEvent | MessageActionEvent | AppContextEvent | FileEvent)[]; +}; diff --git a/src/core/types/file.ts b/src/core/types/file.ts new file mode 100644 index 000000000..02c80c35a --- /dev/null +++ b/src/core/types/file.ts @@ -0,0 +1,107 @@ +/** + * {@link PubNub} File object interface module. + */ + +/** + * Base file constructor parameters. + * + * Minimum set of parameters which can be p + */ +export type PubNubBasicFileParameters = { + data: string | ArrayBuffer; + name: string; + mimeType?: string; +}; + +/** + * Platform-agnostic {@link PubNub} File object. + * + * Interface describes share of {@link PubNub} File which is required by {@link PubNub} core to + * perform required actions. + */ +export interface PubNubFileInterface { + /** + * Actual file name. + */ + name: string; + + /** + * File mime-type. + */ + mimeType?: string; + + /** + * File content length. + */ + contentLength?: number; + + /** + * Convert {@link PubNub} file object content to {@link ArrayBuffer}. + * + * @returns Asynchronous results of conversion to the {@link ArrayBuffer}. + */ + toArrayBuffer(): Promise; +} + +/** + * {@link PubNub} File object class interface. + */ +export interface PubNubFileConstructor { + /** + * Whether {@link Blob} data supported by platform or not. + */ + supportsBlob: boolean; + + /** + * Whether {@link File} data supported by platform or not. + */ + supportsFile: boolean; + + /** + * Whether {@link Buffer} data supported by platform or not. + */ + supportsBuffer: boolean; + + /** + * Whether {@link Stream} data supported by platform or not. + */ + supportsStream: boolean; + + /** + * Whether {@link String} data supported by platform or not. + */ + supportsString: boolean; + + /** + * Whether {@link ArrayBuffer} supported by platform or not. + */ + supportsArrayBuffer: boolean; + + /** + * Whether {@link PubNub} File object encryption supported or not. + */ + supportsEncryptFile: boolean; + + /** + * Whether `File Uri` data supported by platform or not. + */ + supportsFileUri: boolean; + + /** + * {@link PubNub} File object constructor. + * + * @param file - File instantiation parameters (can be raw data or structured object). + * + * @returns Constructed platform-specific {@link PubNub} File object. + */ + create(file: ConstructorParameters): File; + + /** + * {@link PubNub} File object constructor. + * + * @param file - File instantiation parameters (can be raw data or structured object). + * + * @returns Constructed platform-specific {@link PubNub} File object. + */ + new (file: ConstructorParameters): File; +} diff --git a/src/core/types/transport-request.ts b/src/core/types/transport-request.ts index 9d725b60f..58917c7cb 100644 --- a/src/core/types/transport-request.ts +++ b/src/core/types/transport-request.ts @@ -1,3 +1,6 @@ +import { PubNubFileInterface } from './file'; +import { Query } from './api'; + /** * Enum representing possible transport methods for HTTP requests. * @@ -20,24 +23,39 @@ export enum TransportMethod { * Request will be sent using `DELETE` method. */ DELETE = 'DELETE', + + /** + * Local request. + * + * Request won't be sent to the service and probably used to compute URL. + */ + LOCAL = 'LOCAL', } +/** + * Request cancellation controller. + */ +export type CancellationController = { + /** + * Request cancellation / abort function. + */ + abort: () => void; +}; + /** * This object represents a request to be sent to the PubNub API. * - * This struct represents a request to be sent to the PubNub API. It is used by the the - * transport provider which implements {@link Transport} interface. + * This struct represents a request to be sent to the PubNub API. It is used by the transport + * provider which implements {@link Transport} interface. * * All fields are representing certain parts of the request that can be used to prepare one. - * - * @typedef {Object} TransportRequest - * @property path - Path to the resource. - * @property [queryParameters] - Query parameters to be sent with the request. - * @property method - Transport request HTTP method. - * @property [body] - Body to be sent with the request. - * @property timeout - For how long request should wait response from the server. */ export type TransportRequest = { + /** + * Remote host name. + */ + origin?: string; + /** * Remote resource path. */ @@ -46,7 +64,7 @@ export type TransportRequest = { /** * Query parameters to be sent with the request. */ - queryParameters?: Record; + queryParameters?: Query; /** * Transport request HTTP method. @@ -59,14 +77,34 @@ export type TransportRequest = { headers?: Record; /** - * Body to be sent with the request. - * + * Multipart form data fields. * + * **Important:** `Content-Types` header should be sent the {@link body} data type when + * `multipart/form-data` should request should be sent. */ - body?: ArrayBuffer | string; + formData?: Record; + + /** + * Body to be sent with the request. + */ + body?: ArrayBuffer | PubNubFileInterface | string; /** * For how long request should wait response from the server. + * + * @default `10` seconds. */ timeout: number; + + /** + * Whether request can be cancelled or not. + * + * @default `false`. + */ + cancellable: boolean; + + /** + * Unique request identifier. + */ + identifier: string; }; diff --git a/src/core/types/transport-response.ts b/src/core/types/transport-response.ts index 6d1612555..22dc20ef4 100644 --- a/src/core/types/transport-response.ts +++ b/src/core/types/transport-response.ts @@ -1,12 +1,12 @@ /** * Represents a transport response from a service. - * - * @typedef {Object} TransportResponse - * @property status - The response status code. - * @property headers - The response headers. - * @property body - The response body. */ export type TransportResponse = { + /** + * Full remote resource URL used to retrieve response. + */ + url: string; + /** * Service response status code. */ @@ -14,6 +14,8 @@ export type TransportResponse = { /** * Service response headers. + * + * **Important:** Header names are in lowercase. */ headers: Record; diff --git a/src/core/utils.js b/src/core/utils.js deleted file mode 100644 index 668845dd6..000000000 --- a/src/core/utils.js +++ /dev/null @@ -1,71 +0,0 @@ -function objectToList(o) { - const l = []; - Object.keys(o).forEach((key) => l.push(key)); - return l; -} - -function encodeString(input) { - return encodeURIComponent(input).replace(/[!~*'()]/g, (x) => `%${x.charCodeAt(0).toString(16).toUpperCase()}`); -} - -function objectToListSorted(o) { - return objectToList(o).sort(); -} - -function signPamFromParams(params) { - const l = objectToListSorted(params); - return l.map((paramKey) => `${paramKey}=${encodeString(params[paramKey])}`).join('&'); -} - -function endsWith(searchString, suffix) { - return searchString.indexOf(suffix, this.length - suffix.length) !== -1; -} - -function createPromise() { - let successResolve; - let failureResolve; - const promise = new Promise((fulfill, reject) => { - successResolve = fulfill; - failureResolve = reject; - }); - - return { promise, reject: failureResolve, fulfill: successResolve }; -} - -function stringToArrayBuffer(str) { - var buf = new ArrayBuffer(str.length * 2); - var bufView = new Uint16Array(buf); - for (var i = 0, strLen = str.length; i < strLen; i++) { - bufView[i] = str.charCodeAt(i); - } - return buf; -} - -function removeSingleOccurance(source, elementsToRemove) { - let removed = Object.fromEntries(elementsToRemove.map((prop) => [prop, false])); - - return source.filter((e) => { - if (elementsToRemove.includes(e) && !removed[e]) { - removed[e] = true; - return false; - } - return true; - }); -} - -function findUniqueCommonElements(a, b) { - return [...a].filter( - (value) => - b.includes(value) && a.indexOf(value) === a.lastIndexOf(value) && b.indexOf(value) === b.lastIndexOf(value), - ); -} - -module.exports = { - signPamFromParams, - endsWith, - createPromise, - encodeString, - stringToArrayBuffer, - removeSingleOccurance, - findUniqueCommonElements, -}; diff --git a/src/core/utils.ts b/src/core/utils.ts new file mode 100644 index 000000000..d98320c69 --- /dev/null +++ b/src/core/utils.ts @@ -0,0 +1,51 @@ +import { Query } from './types/api'; + +/** + * Percent-encode input string. + * + * **Note:** Encode content in accordance of the `PubNub` service requirements. + * + * @param input - Source string or number for encoding. + * + * @returns Percent-encoded string. + */ +export const encodeString = (input: string | number) => { + return encodeURIComponent(input).replace(/[!~*'()]/g, (x) => `%${x.charCodeAt(0).toString(16).toUpperCase()}`); +}; + +export const removeSingleOccurance = (source: string[], elementsToRemove: string[]) => { + const removed = Object.fromEntries(elementsToRemove.map((prop) => [prop, false])); + + return source.filter((e) => { + if (elementsToRemove.includes(e) && !removed[e]) { + removed[e] = true; + return false; + } + return true; + }); +}; + +export const findUniqueCommonElements = (a: string[], b: string[]) => { + return [...a].filter( + (value) => + b.includes(value) && a.indexOf(value) === a.lastIndexOf(value) && b.indexOf(value) === b.lastIndexOf(value), + ); +}; + +/** + * Transform query key / value pairs to the string. + * + * @param query - Key / value pairs of the request query parameters. + * + * @returns Stringified query key / value pairs. + */ +export const queryStringFromObject = (query: Query) => { + return Object.keys(query) + .map((key) => { + const queryValue = query[key]; + if (!Array.isArray(queryValue)) return `${key}=${encodeString(queryValue)}`; + + return queryValue.map((value) => `${key}=${encodeString(value)}`).join('&'); + }) + .join('&'); +}; diff --git a/src/crypto/modules/NodeCryptoModule/ICryptor.ts b/src/crypto/modules/NodeCryptoModule/ICryptor.ts index 5e73cee31..63860b300 100644 --- a/src/crypto/modules/NodeCryptoModule/ICryptor.ts +++ b/src/crypto/modules/NodeCryptoModule/ICryptor.ts @@ -1,19 +1,106 @@ +/** + * Cryptor module. + */ + +/** + * Data encrypted by {@link CryptoModule}. + */ export type EncryptedDataType = { + /** + * Encrypted data. + */ data: Buffer | string; + + /** + * Used cryptor's metadata. + */ metadata: Buffer | null; }; +/** + * {@link Readable} stream encrypted by {@link CryptoModule}. + */ export type EncryptedStream = { + /** + * Stream with encrypted content. + */ stream: NodeJS.ReadableStream; + + /** + * Length of encrypted data in {@link Readable} stream. + */ metadataLength: number; + + /** + * Used cryptor's metadata. + */ metadata?: Buffer | undefined; }; +/** + * Cryptor algorithm interface. + */ export interface ICryptor { + /** + * Cryptor unique identifier. + * + * @returns Cryptor identifier. + */ get identifier(): string; + + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + + // region Encryption + /** + * Encrypt provided source data. + * + * @param data - Source data for encryption. + * + * @returns Encrypted data object. + * + * @throws Error if unknown data type has been passed. + */ encrypt(data: BufferSource | string): EncryptedDataType; - decrypt(data: EncryptedDataType): ArrayBuffer; + /** + * Encrypt provided source {@link Readable} stream. + * + * @param stream - Stream for encryption. + * + * @returns Encrypted stream object. + * + * @throws Error if unknown data type has been passed. + */ encryptStream(stream: NodeJS.ReadableStream): Promise; - decryptStream(encryptedStream: EncryptedStream): Promise; + // endregion + + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + + // region Decryption + /** + * Decrypt provided encrypted data object. + * + * @param data - Encrypted data object for decryption. + * + * @returns Decrypted data. + * + * @throws Error if unknown data type has been passed. + */ + decrypt(data: EncryptedDataType): ArrayBuffer; + + /** + * Decrypt provided encrypted stream object. + * + * @param stream - Encrypted stream object for decryption. + * + * @returns Decrypted data as {@link Readable} stream. + * + * @throws Error if unknown data type has been passed. + */ + decryptStream(stream: EncryptedStream): Promise; + // endregion } diff --git a/src/crypto/modules/NodeCryptoModule/ILegacyCryptor.ts b/src/crypto/modules/NodeCryptoModule/ILegacyCryptor.ts index 9a63aa455..8fd6ae953 100644 --- a/src/crypto/modules/NodeCryptoModule/ILegacyCryptor.ts +++ b/src/crypto/modules/NodeCryptoModule/ILegacyCryptor.ts @@ -1,26 +1,84 @@ +/** + * Legacy cryptor module. + */ + +import PubNubFile, { PubNubFileParameters } from '../../../file/modules/node'; +import { PubNubFileConstructor } from '../../../core/types/file'; +import { Payload } from '../../../core/types/api'; import { EncryptedDataType } from './ICryptor'; -export type PubNubFileType = { - stream: NodeJS.ReadStream; - data: NodeJS.ReadStream | Buffer; - name: string; - mimeType: string; - contentLength: number; +/** + * Legacy cryptor algorithm interface. + */ +export interface ILegacyCryptor { + /** + * Cryptor unique identifier. + */ + get identifier(): string; + + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- - create(config: any): PubNubFileType; + // region Encryption + /** + * Encrypt provided source data. + * + * @param data - Source data for encryption. + * + * @returns Encrypted data object. + * + * @throws Error if unknown data type has been passed. + */ + encrypt(data: string): EncryptedDataType; - toBuffer(): Buffer; - toArrayBuffer(): ArrayBuffer; - toString(): string; - toStream(): NodeJS.ReadStream; -}; + /** + * Encrypt provided source {@link PubNub} File object. + * + * @param file - Source {@link PubNub} File object for encryption. + * @param File - Class constructor for {@link PubNub} File object. + * + * @returns Encrypted data as {@link PubNub} File object. + * + * @throws Error if file is empty or contains unsupported data type. + * @throws Error if cipher key not set. + */ + encryptFile( + file: PubNubFile, + File: PubNubFileConstructor, + ): Promise; + // endregion -export interface ILegacyCryptor { - get identifier(): string; + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- - encrypt(data: string | ArrayBuffer): EncryptedDataType; - decrypt(data: EncryptedDataType): BufferSource | string; + // region Decryption + /** + * Decrypt provided encrypted data object. + * + * @param data - Encrypted data object for decryption. + * + * @returns Decrypted data. + * + * @throws Error if unknown data type has been passed. + */ + decrypt(data: EncryptedDataType): Payload | null; - encryptFile(file: T, File: T): Promise; - decryptFile(file: T, File: T): Promise; + /** + * Decrypt provided encrypted {@link PubNub} File object. + * + * @param file - Encrypted {@link PubNub} File object for decryption. + * @param File - Class constructor for {@link PubNub} File object. + * + * @returns Decrypted data as {@link PubNub} File object. + * + * @throws Error if file is empty or contains unsupported data type. + * @throws Error if cipher key not set. + */ + decryptFile( + file: PubNubFile, + File: PubNubFileConstructor, + ): Promise; + // endregion } diff --git a/src/crypto/modules/NodeCryptoModule/aesCbcCryptor.ts b/src/crypto/modules/NodeCryptoModule/aesCbcCryptor.ts index 68cfb89a6..69f7679f8 100644 --- a/src/crypto/modules/NodeCryptoModule/aesCbcCryptor.ts +++ b/src/crypto/modules/NodeCryptoModule/aesCbcCryptor.ts @@ -1,39 +1,50 @@ -import { PassThrough } from 'stream'; +/** + * AES-CBC cryptor module. + */ + import { createCipheriv, createDecipheriv, createHash, randomBytes } from 'crypto'; +import { PassThrough } from 'stream'; + import { ICryptor, EncryptedDataType, EncryptedStream } from './ICryptor'; +/** + * AES-CBC cryptor. + * + * AES-CBC cryptor with enhanced cipher strength. + */ export default class AesCbcCryptor implements ICryptor { + /** + * Cryptor block size. + */ static BLOCK_SIZE = 16; - cipherKey: string; - constructor(configuration: { cipherKey: string }) { - this.cipherKey = configuration.cipherKey; - } + /** + * {@link string|String} to {@link ArrayBuffer} response decoder. + */ + static encoder = new TextEncoder(); - get algo() { - return 'aes-256-cbc'; - } - - get identifier() { - return 'ACRH'; - } + /** + * Data encryption / decryption cipher key. + */ + cipherKey: string; - getIv() { - return randomBytes(AesCbcCryptor.BLOCK_SIZE); + constructor({ cipherKey }: { cipherKey: string }) { + this.cipherKey = cipherKey; } - getKey() { - const sha = createHash('sha256'); - sha.update(Buffer.from(this.cipherKey, 'utf8')); - return Buffer.from(sha.digest()); - } + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + // region Encryption - encrypt(data: ArrayBuffer | string) { + encrypt(data: ArrayBuffer | string): EncryptedDataType { const iv = this.getIv(); const key = this.getKey(); - const plainData = typeof data === 'string' ? new TextEncoder().encode(data) : data; + const plainData = typeof data === 'string' ? AesCbcCryptor.encoder.encode(data) : data; const bPlain = Buffer.from(plainData); - if (bPlain.byteLength === 0) throw new Error('encryption error. empty content'); + + if (bPlain.byteLength === 0) throw new Error('Encryption error: empty content'); + const aes = createCipheriv(this.algo, key, iv); return { @@ -42,37 +53,48 @@ export default class AesCbcCryptor implements ICryptor { }; } - decrypt(encryptedData: EncryptedDataType) { - const data = - typeof encryptedData.data === 'string' ? new TextEncoder().encode(encryptedData.data) : encryptedData.data; - if (data.byteLength <= 0) throw new Error('decryption error: empty content'); - const aes = createDecipheriv(this.algo, this.getKey(), encryptedData.metadata); - return Uint8Array.from(Buffer.concat([aes.update(data), aes.final()])).buffer; - } - async encryptStream(stream: NodeJS.ReadableStream) { + if (!stream.readable) throw new Error('Encryption error: empty stream'); + const output = new PassThrough(); const bIv = this.getIv(); - if (stream.readable === false) throw new Error('encryption error. empty stream'); const aes = createCipheriv(this.algo, this.getKey(), bIv); stream.pipe(aes).pipe(output); + return { stream: output, metadata: bIv, metadataLength: AesCbcCryptor.BLOCK_SIZE, }; } + // endregion + + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + // region Decryption - async decryptStream(encryptedStream: EncryptedStream) { + decrypt(input: EncryptedDataType) { + const data = typeof input.data === 'string' ? new TextEncoder().encode(input.data) : input.data; + + if (data.byteLength <= 0) throw new Error('Decryption error: empty content'); + const aes = createDecipheriv(this.algo, this.getKey(), input.metadata!); + return Uint8Array.from(Buffer.concat([aes.update(data), aes.final()])).buffer; + } + + async decryptStream(stream: EncryptedStream) { const decryptedStream = new PassThrough(); let bIv = Buffer.alloc(0); - let aes: any = null; + let aes: ReturnType | null = null; + const onReadable = () => { - let data = encryptedStream.stream.read(); + let data = stream.stream.read(); + while (data !== null) { if (data) { const bChunk = Buffer.from(data); - const sliceLen = encryptedStream.metadataLength - bIv.byteLength; + const sliceLen = stream.metadataLength - bIv.byteLength; + if (bChunk.byteLength < sliceLen) { bIv = Buffer.concat([bIv, bChunk]); } else { @@ -82,16 +104,55 @@ export default class AesCbcCryptor implements ICryptor { aes.write(bChunk.slice(sliceLen)); } } - data = encryptedStream.stream.read(); + data = stream.stream.read(); } }; - encryptedStream.stream.on('readable', onReadable); - encryptedStream.stream.on('end', () => { - if (aes) { - aes.end(); - } + stream.stream.on('readable', onReadable); + stream.stream.on('end', () => { + if (aes) aes.end(); decryptedStream.end(); }); + return decryptedStream; } + // endregion + + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + // region Helpers + + get identifier() { + return 'ACRH'; + } + + /** + * Cryptor algorithm. + * + * @returns Cryptor module algorithm. + */ + private get algo() { + return 'aes-256-cbc'; + } + + /** + * Generate random initialization vector. + * + * @returns Random initialization vector. + */ + private getIv() { + return randomBytes(AesCbcCryptor.BLOCK_SIZE); + } + + /** + * Convert cipher key to the {@link Buffer}. + * + * @returns SHA256 encoded cipher key {@link Buffer}. + */ + private getKey() { + const sha = createHash('sha256'); + sha.update(Buffer.from(this.cipherKey, 'utf8')); + return Buffer.from(sha.digest()); + } + // endregion } diff --git a/src/crypto/modules/NodeCryptoModule/legacyCryptor.ts b/src/crypto/modules/NodeCryptoModule/legacyCryptor.ts index c8a28fc6b..131acc9ac 100644 --- a/src/crypto/modules/NodeCryptoModule/legacyCryptor.ts +++ b/src/crypto/modules/NodeCryptoModule/legacyCryptor.ts @@ -1,41 +1,88 @@ +/** + * Legacy cryptor module. + */ + +import PubNubFile, { PubNubFileParameters } from '../../../file/modules/node'; +import { CryptorConfiguration } from '../../../core/interfaces/crypto-module'; import Crypto from '../../../core/components/cryptography/index'; +import { PubNubFileConstructor } from '../../../core/types/file'; import { encode } from '../../../core/components/base64_codec'; -import FileCryptor from '../node'; +import { PubNubError } from '../../../models/PubNubError'; +import { ILegacyCryptor } from './ILegacyCryptor'; import { EncryptedDataType } from './ICryptor'; -import { ILegacyCryptor, PubNubFileType } from './ILegacyCryptor'; +import FileCryptor from '../node'; -export default class LegacyCryptor implements ILegacyCryptor { +/** + * Legacy cryptor. + */ +export default class LegacyCryptor implements ILegacyCryptor { + /** + * Legacy cryptor configuration. + */ config; - cryptor; + /** + * Configured file cryptor. + */ fileCryptor; - constructor(config: any) { + /** + * Configured legacy cryptor. + */ + cryptor; + + constructor(config: CryptorConfiguration) { this.config = config; - this.cryptor = new Crypto({ config }); + this.cryptor = new Crypto({ ...config }); this.fileCryptor = new FileCryptor(); } - get identifier() { - return ''; - } - encrypt(data: string) { - if (data.length === 0) throw new Error('encryption error. empty content'); + + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + // region Encryption + + encrypt(data: string): EncryptedDataType { + if (data.length === 0) throw new Error('Encryption error: empty content'); + return { data: this.cryptor.encrypt(data), metadata: null, }; } + async encryptFile(file: PubNubFile, File: PubNubFileConstructor) { + if (!this.config.cipherKey) throw new PubNubError('File encryption error: cipher key not set.'); + + return this.fileCryptor.encryptFile(this.config.cipherKey, file, File); + } + // endregion + + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + // region Decryption + decrypt(encryptedData: EncryptedDataType) { const data = typeof encryptedData.data === 'string' ? encryptedData.data : encode(encryptedData.data); + return this.cryptor.decrypt(data); } - async encryptFile(file: PubNubFileType, File: PubNubFileType) { - return this.fileCryptor.encryptFile(this.config.cipherKey, file, File); - } + async decryptFile(file: PubNubFile, File: PubNubFileConstructor) { + if (!this.config.cipherKey) throw new PubNubError('File decryption error: cipher key not set.'); - async decryptFile(file: PubNubFileType, File: PubNubFileType) { return this.fileCryptor.decryptFile(this.config.cipherKey, file, File); } + // endregion + + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + // region Helpers + + get identifier() { + return ''; + } + // endregion } diff --git a/src/crypto/modules/NodeCryptoModule/nodeCryptoModule.ts b/src/crypto/modules/NodeCryptoModule/nodeCryptoModule.ts index a1d218946..10df101f6 100644 --- a/src/crypto/modules/NodeCryptoModule/nodeCryptoModule.ts +++ b/src/crypto/modules/NodeCryptoModule/nodeCryptoModule.ts @@ -1,123 +1,144 @@ +/** + * Node.js crypto module. + */ + import { Readable, PassThrough } from 'stream'; +import { Buffer } from 'buffer'; + +import { AbstractCryptoModule, CryptorConfiguration } from '../../../core/interfaces/crypto-module'; +import PubNubFile, { PubNubFileParameters } from '../../../file/modules/node'; +import { PubNubFileConstructor } from '../../../core/types/file'; import { decode } from '../../../core/components/base64_codec'; -import LegacyCryptor from './legacyCryptor'; +import { PubNubError } from '../../../models/PubNubError'; +import { EncryptedDataType, ICryptor } from './ICryptor'; +import { ILegacyCryptor } from './ILegacyCryptor'; import AesCbcCryptor from './aesCbcCryptor'; -import { ICryptor } from './ICryptor'; -import { ILegacyCryptor, PubNubFileType } from './ILegacyCryptor'; +import LegacyCryptor from './legacyCryptor'; +/** + * Re-export bundled cryptors. + */ export { LegacyCryptor, AesCbcCryptor }; -type CryptorType = ICryptor | ILegacyCryptor; - -type CryptoModuleConfiguration = { - default: CryptorType; - cryptors?: Array; -}; - -export class CryptoModule { +/** + * Crypto module cryptors interface. + */ +type CryptorType = ICryptor | ILegacyCryptor; + +/** + * CryptoModule for Node.js platform. + */ +export class CryptoModule extends AbstractCryptoModule { + /** + * {@link LegacyCryptor|Legacy} cryptor identifier. + */ static LEGACY_IDENTIFIER = ''; - defaultCryptor: CryptorType; - cryptors: Array; + // -------------------------------------------------------- + // --------------- Convenience functions ------------------ + // ------------------------------------------------------- + // region Convenience functions - constructor(cryptoModuleConfiguration: CryptoModuleConfiguration) { - this.defaultCryptor = cryptoModuleConfiguration.default; - this.cryptors = cryptoModuleConfiguration.cryptors ?? []; - } + static legacyCryptoModule(config: CryptorConfiguration) { + if (!config.cipherKey) throw new PubNubError('Crypto module error: cipher key not set.'); - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore: type detection issue with old Config type assignment - static legacyCryptoModule(config) { return new this({ default: new LegacyCryptor({ - cipherKey: config.cipherKey, + ...config, useRandomIVs: config.useRandomIVs ?? true, }), cryptors: [new AesCbcCryptor({ cipherKey: config.cipherKey })], }); } - static aesCbcCryptoModule(config: any) { + static aesCbcCryptoModule(config: CryptorConfiguration) { + if (!config.cipherKey) throw new PubNubError('Crypto module error: cipher key not set.'); + return new this({ default: new AesCbcCryptor({ cipherKey: config.cipherKey }), cryptors: [ new LegacyCryptor({ - cipherKey: config.cipherKey, + ...config, useRandomIVs: config.useRandomIVs ?? true, }), ], }); } + + /** + * Construct crypto module with `cryptor` as default for data encryption and decryption. + * + * @param defaultCryptor - Default cryptor for data encryption and decryption. + * + * @returns Crypto module with pre-configured default cryptor. + */ static withDefaultCryptor(defaultCryptor: CryptorType) { return new this({ default: defaultCryptor }); } + // endregion - private getAllCryptors() { - return [this.defaultCryptor, ...this.cryptors]; - } - - private getLegacyCryptor() { - return this.getAllCryptors().find((c) => c.identifier === ''); - } + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + // region Encryption encrypt(data: ArrayBuffer | string) { - const encrypted = this.defaultCryptor.encrypt(data); + // Encrypt data. + const encrypted = + data instanceof ArrayBuffer && this.defaultCryptor.identifier === CryptoModule.LEGACY_IDENTIFIER + ? (this.defaultCryptor as ILegacyCryptor).encrypt(CryptoModule.decoder.decode(data)) + : (this.defaultCryptor as ICryptor).encrypt(data); + if (!encrypted.metadata) return encrypted.data; - const header = CryptorHeader.from(this.defaultCryptor.identifier, encrypted.metadata); + const headerData = this.getHeaderData(encrypted)!; + // Write encrypted data payload content. + const encryptedData = + typeof encrypted.data === 'string' ? CryptoModule.encoder.encode(encrypted.data) : encrypted.data.buffer; - const headerData = new Uint8Array(header!.length); - let pos = 0; - headerData.set(header!.data, pos); - pos = header!.length - encrypted.metadata.length; - headerData.set(encrypted.metadata, pos); - return Buffer.concat([headerData, Buffer.from(encrypted.data)]); - } - - decrypt(data: ArrayBuffer | string) { - const encryptedData = Buffer.from(typeof data === 'string' ? decode(data) : data); - const header = CryptorHeader.tryParse(encryptedData); - const cryptor = this.getCryptor(header); - const metadata = - header.length > 0 - ? encryptedData.slice(header.length - (header as CryptorHeaderV1).metadataLength, header.length) - : null; - if (encryptedData.slice(header.length).byteLength <= 0) throw new Error('decryption error. empty content'); - return cryptor!.decrypt({ - data: encryptedData.slice(header.length), - metadata: metadata, - }); + return this.concatArrayBuffer(headerData, encryptedData); } - async encryptFile(file: PubNubFileType, File: PubNubFileType) { + async encryptFile(file: PubNubFile, File: PubNubFileConstructor) { /** * Files handled differently in case of Legacy cryptor. - * (as long as we support legacy need to check on intsance type) + * (as long as we support legacy need to check on instance type) */ if (this.defaultCryptor.identifier === CryptorHeader.LEGACY_IDENTIFIER) - return (this.defaultCryptor as ILegacyCryptor).encryptFile(file, File); + return (this.defaultCryptor as ILegacyCryptor).encryptFile(file, File); + if (file.data instanceof Buffer) { + const encryptedData = this.encrypt(file.data); + return File.create({ name: file.name, mimeType: 'application/octet-stream', - data: Buffer.from(this.encrypt(file.data!) as Buffer), + data: Buffer.from( + typeof encryptedData === 'string' ? CryptoModule.encoder.encode(encryptedData) : encryptedData, + ), }); } + if (file.data instanceof Readable) { - if (file.contentLength === 0) throw new Error('encryption error. empty content'); + if (file.contentLength === 0) throw new Error('Encryption error: empty content'); + const encryptedStream = await (this.defaultCryptor as ICryptor).encryptStream(file.data); const header = CryptorHeader.from(this.defaultCryptor.identifier, encryptedStream.metadata!); const payload = new Uint8Array(header!.length); let pos = 0; payload.set(header!.data, pos); pos += header!.length; + if (encryptedStream.metadata) { - pos -= encryptedStream.metadata.length; - payload.set(encryptedStream.metadata, pos); + const metadata = new Uint8Array(encryptedStream.metadata); + pos -= encryptedStream.metadata.byteLength; + payload.set(metadata, pos); } + const output = new PassThrough(); output.write(payload); encryptedStream.stream.pipe(output); + return File.create({ name: file.name, mimeType: 'application/octet-stream', @@ -125,172 +146,302 @@ export class CryptoModule { }); } } + // endregion + + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + // region Decryption - async decryptFile(file: PubNubFileType, File: PubNubFileType) { - if (file?.data instanceof Buffer) { + decrypt(data: ArrayBuffer | string) { + const encryptedData = Buffer.from(typeof data === 'string' ? decode(data) : data); + const header = CryptorHeader.tryParse(encryptedData); + const cryptor = this.getCryptor(header); + const metadata = + header.length > 0 + ? encryptedData.slice(header.length - (header as CryptorHeaderV1).metadataLength, header.length) + : null; + + if (encryptedData.slice(header.length).byteLength <= 0) throw new Error('Decryption error: empty content'); + + return cryptor!.decrypt({ + data: encryptedData.slice(header.length), + metadata: metadata, + }); + } + + async decryptFile( + file: PubNubFile, + File: PubNubFileConstructor, + ): Promise { + if (file.data && file.data instanceof Buffer) { const header = CryptorHeader.tryParse(file.data); const cryptor = this.getCryptor(header); /** - * If It's legacyone then redirect it. + * If It's legacy one then redirect it. * (as long as we support legacy need to check on instance type) */ if (cryptor?.identifier === CryptoModule.LEGACY_IDENTIFIER) - return (cryptor as ILegacyCryptor).decryptFile(file, File); + return (cryptor as ILegacyCryptor).decryptFile(file, File); + return File.create({ name: file.name, - data: Buffer.from(this.decrypt(file?.data) as ArrayBuffer), + data: Buffer.from(this.decrypt(file.data) as ArrayBuffer), }); } - if (file.data instanceof Readable) { + if (file.data && file.data instanceof Readable) { const stream = file.data; return new Promise((resolve) => { stream.on('readable', () => resolve(this.onStreamReadable(stream, file, File))); }); } } + // endregion + + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + // region Helpers + + /** + * Retrieve registered legacy cryptor. + * + * @returns Previously registered {@link ILegacyCryptor|legacy} cryptor. + * + * @throws Error if legacy cryptor not registered. + */ + private getLegacyCryptor(): ILegacyCryptor | undefined { + return this.getCryptorFromId(CryptoModule.LEGACY_IDENTIFIER) as ILegacyCryptor; + } + + /** + * Retrieve registered cryptor by its identifier. + * + * @param id - Unique cryptor identifier. + * + * @returns Registered cryptor with specified identifier. + * + * @throws Error if cryptor with specified {@link id} can't be found. + */ + private getCryptorFromId(id: string) { + const cryptor = this.getAllCryptors().find((cryptor) => id === cryptor.identifier); + if (cryptor) return cryptor; + + throw new Error('Unknown cryptor error'); + } + + /** + * Retrieve cryptor by its identifier. + * + * @param header - Header with cryptor-defined data or raw cryptor identifier. + * + * @returns Cryptor which correspond to provided {@link header}. + */ + private getCryptor(header: CryptorHeader | string) { + if (typeof header === 'string') { + const cryptor = this.getAllCryptors().find((c) => c.identifier === header); + if (cryptor) return cryptor; + + throw new Error('Unknown cryptor error'); + } else if (header instanceof CryptorHeaderV1) { + return this.getCryptorFromId(header.identifier); + } + } - private async onStreamReadable(stream: NodeJS.ReadableStream, file: PubNubFileType, File: PubNubFileType) { + /** + * Create cryptor header data. + * + * @param encrypted - Encryption data object as source for header data. + * + * @returns Binary representation of the cryptor header data. + */ + private getHeaderData(encrypted: EncryptedDataType) { + if (!encrypted.metadata) return; + const header = CryptorHeader.from(this.defaultCryptor.identifier, encrypted.metadata); + const headerData = new Uint8Array(header!.length); + let pos = 0; + headerData.set(header!.data, pos); + pos += header!.length - encrypted.metadata.byteLength; + headerData.set(new Uint8Array(encrypted.metadata), pos); + return headerData.buffer; + } + + /** + * Merge two {@link ArrayBuffer} instances. + * + * @param ab1 - First {@link ArrayBuffer}. + * @param ab2 - Second {@link ArrayBuffer}. + * + * @returns Merged data as {@link ArrayBuffer}. + */ + private concatArrayBuffer(ab1: ArrayBuffer, ab2: ArrayBuffer): ArrayBuffer { + const tmp = new Uint8Array(ab1.byteLength + ab2.byteLength); + + tmp.set(new Uint8Array(ab1), 0); + tmp.set(new Uint8Array(ab2), ab1.byteLength); + + return tmp.buffer; + } + + /** + * {@link Readable} stream event handler. + * + * @param stream - Stream which can be used to read data for decryption. + * @param file - File object which has been created with {@link stream}. + * @param File - Class constructor for {@link PubNub} File object. + * + * @returns Decrypted data as {@link PubNub} File object. + * + * @throws Error if file is empty or contains unsupported data type. + */ + private async onStreamReadable( + stream: NodeJS.ReadableStream, + file: PubNubFile, + File: PubNubFileConstructor, + ) { stream.removeAllListeners('readable'); const magicBytes = stream.read(4); + if (!CryptorHeader.isSentinel(magicBytes as Buffer)) { - if (magicBytes === null) throw new Error('decryption error. empty content'); + if (magicBytes === null) throw new Error('Decryption error: empty content'); stream.unshift(magicBytes); + return this.decryptLegacyFileStream(stream, file, File); } + const versionByte = stream.read(1); CryptorHeader.validateVersion(versionByte[0] as number); const identifier = stream.read(4); const cryptor = this.getCryptorFromId(CryptorHeader.tryGetIdentifier(identifier as Buffer)); const headerSize = CryptorHeader.tryGetMetadataSizeFromStream(stream); - if (file.contentLength <= CryptorHeader.MIN_HEADER_LEGTH + headerSize) - throw new Error('decryption error. empty content'); + + if (!file.contentLength || file.contentLength <= CryptorHeader.MIN_HEADER_LENGTH + headerSize) + throw new Error('Decryption error: empty content'); + return File.create({ name: file.name, mimeType: 'application/octet-stream', - stream: await (cryptor as ICryptor).decryptStream({ stream: stream, metadataLength: headerSize as number }), + stream: (await (cryptor as ICryptor).decryptStream({ + stream: stream, + metadataLength: headerSize as number, + })) as Readable, }); } - private async decryptLegacyFileStream(stream: NodeJS.ReadableStream, file: PubNubFileType, File: PubNubFileType) { - if (file.contentLength <= 16) throw new Error('decryption error: empty content'); + /** + * Decrypt {@link Readable} stream using legacy cryptor. + * + * @param stream - Stream which can be used to read data for decryption. + * @param file - File object which has been created with {@link stream}. + * @param File - Class constructor for {@link PubNub} File object. + * + * @returns Decrypted data as {@link PubNub} File object. + * + * @throws Error if file is empty or contains unsupported data type. + */ + private async decryptLegacyFileStream( + stream: NodeJS.ReadableStream, + file: PubNubFile, + File: PubNubFileConstructor, + ) { + if (!file.contentLength || file.contentLength <= 16) throw new Error('Decryption error: empty content'); + const cryptor = this.getLegacyCryptor(); + if (cryptor) { - return (cryptor as ILegacyCryptor).decryptFile( + return cryptor.decryptFile( File.create({ name: file.name, - stream: stream, + stream: stream as Readable, }), File, ); - } else { - throw new Error('unknown cryptor error'); - } - } - - private getCryptor(header: CryptorHeader) { - if (header === '') { - const cryptor = this.getAllCryptors().find((c) => c.identifier === ''); - if (cryptor) return cryptor; - throw new Error('unknown cryptor error'); - } else if (header instanceof CryptorHeaderV1) { - return this.getCryptorFromId(header.identifier); - } - } - - private getCryptorFromId(id: string) { - const cryptor = this.getAllCryptors().find((c) => id === c.identifier); - if (cryptor) { - return cryptor; - } - throw new Error('unknown cryptor error'); + } else throw new Error('unknown cryptor error'); } + // endregion } -// CryptorHeader Utility +/** + * CryptorHeader Utility + */ class CryptorHeader { + static decoder = new TextDecoder(); static SENTINEL = 'PNED'; static LEGACY_IDENTIFIER = ''; static IDENTIFIER_LENGTH = 4; static VERSION = 1; static MAX_VERSION = 1; - static MIN_HEADER_LEGTH = 10; + static MIN_HEADER_LENGTH = 10; - static from(id: string, metadata: Buffer) { + static from(id: string, metadata: ArrayBuffer) { if (id === CryptorHeader.LEGACY_IDENTIFIER) return; - return new CryptorHeaderV1(id, metadata.length); + return new CryptorHeaderV1(id, metadata.byteLength); } - static isSentinel(bytes: Buffer) { - if (bytes && bytes.byteLength >= 4) { - if (bytes.toString('utf8') == CryptorHeader.SENTINEL) return true; - } + static isSentinel(bytes: ArrayBuffer) { + return bytes && bytes.byteLength >= 4 && CryptorHeader.decoder.decode(bytes) == CryptorHeader.SENTINEL; } static validateVersion(data: number) { - if (data && data > CryptorHeader.MAX_VERSION) throw new Error('decryption error. invalid header version'); + if (data && data > CryptorHeader.MAX_VERSION) throw new Error('Decryption error: invalid header version'); return data; } - static tryGetIdentifier(data: Buffer) { - if (data.byteLength < 4) { - throw new Error('unknown cryptor error. decryption failed'); - } else { - return data.toString('utf8'); - } + static tryGetIdentifier(data: ArrayBuffer) { + if (data.byteLength < 4) throw new Error('Decryption error: unknown cryptor error'); + else return CryptorHeader.decoder.decode(data); } static tryGetMetadataSizeFromStream(stream: NodeJS.ReadableStream) { const sizeBuf = stream.read(1); - if (sizeBuf && (sizeBuf[0] as number) < 255) { - return sizeBuf[0] as number; - } + + if (sizeBuf && (sizeBuf[0] as number) < 255) return sizeBuf[0] as number; if ((sizeBuf[0] as number) === 255) { const nextBuf = stream.read(2); + if (nextBuf.length >= 2) { return new Uint16Array([nextBuf[0] as number, nextBuf[1] as number]).reduce((acc, val) => (acc << 8) + val, 0); } } - throw new Error('decryption error. Invalid metadata size'); + + throw new Error('Decryption error: invalid metadata size'); } - static tryParse(encryptedData: Buffer) { - let sentinel: any = ''; + + static tryParse(encryptedData: ArrayBuffer) { + const encryptedDataView = new DataView(encryptedData); + let sentinel: ArrayBuffer; let version = null; - if (encryptedData.length >= 4) { + if (encryptedData.byteLength >= 4) { sentinel = encryptedData.slice(0, 4); - if (sentinel.toString('utf8') !== CryptorHeader.SENTINEL) return ''; + if (!this.isSentinel(sentinel)) return CryptoModule.LEGACY_IDENTIFIER; } - if (encryptedData.length >= 5) { - version = encryptedData[4]; - } else { - throw new Error('decryption error. invalid header version'); - } + if (encryptedData.byteLength >= 5) version = encryptedDataView.getInt8(4); + else throw new Error('Decryption error: invalid header version'); if (version > CryptorHeader.MAX_VERSION) throw new Error('unknown cryptor error'); - let identifier: Buffer; + let identifier: ArrayBuffer; let pos = 5 + CryptorHeader.IDENTIFIER_LENGTH; - if (encryptedData.length >= pos) { - identifier = encryptedData.slice(5, pos); - } else { - throw new Error('decryption error. invalid crypto identifier'); - } + if (encryptedData.byteLength >= pos) identifier = encryptedData.slice(5, pos); + else throw new Error('Decryption error: invalid crypto identifier'); + let metadataLength = null; - if (encryptedData.length >= pos + 1) { - metadataLength = encryptedData[pos]; - } else { - throw new Error('decryption error. invalid metadata length'); - } + if (encryptedData.byteLength >= pos + 1) metadataLength = encryptedDataView.getInt8(pos); + else throw new Error('Decryption error: invalid metadata length'); + pos += 1; - if (metadataLength === 255 && encryptedData.length >= pos + 2) { + if (metadataLength === 255 && encryptedData.byteLength >= pos + 2) { metadataLength = new Uint16Array(encryptedData.slice(pos, pos + 2)).reduce((acc, val) => (acc << 8) + val, 0); - pos += 2; } - return new CryptorHeaderV1(identifier.toString('utf8'), metadataLength); + + return new CryptorHeaderV1(CryptorHeader.decoder.decode(identifier), metadataLength); } } -// v1 CryptorHeader +/** + * Cryptor header (v1). + */ class CryptorHeaderV1 { _identifier; _metadataLength; @@ -337,14 +488,15 @@ class CryptorHeaderV1 { pos += CryptorHeader.SENTINEL.length; header[pos] = this.version; pos++; + if (this.identifier) header.set(Buffer.from(this.identifier), pos); - pos += CryptorHeader.IDENTIFIER_LENGTH; + const metadataLength = this.metadataLength; - if (metadataLength < 255) { - header[pos] = metadataLength; - } else { - header.set([255, metadataLength >> 8, metadataLength & 0xff], pos); - } + pos += CryptorHeader.IDENTIFIER_LENGTH; + + if (metadataLength < 255) header[pos] = metadataLength; + else header.set([255, metadataLength >> 8, metadataLength & 0xff], pos); + return header; } } diff --git a/src/crypto/modules/WebCryptoModule/ICryptor.ts b/src/crypto/modules/WebCryptoModule/ICryptor.ts index b15709c75..5245a3641 100644 --- a/src/crypto/modules/WebCryptoModule/ICryptor.ts +++ b/src/crypto/modules/WebCryptoModule/ICryptor.ts @@ -1,13 +1,86 @@ +/** + * Cryptor module. + */ + +/** + * Data encrypted by {@link CryptoModule}. + */ export type EncryptedDataType = { + /** + * Encrypted data. + */ data: ArrayBuffer; + + /** + * Used cryptor's metadata. + */ metadata: ArrayBuffer | null; }; +/** + * Cryptor algorithm interface. + */ export interface ICryptor { + /** + * Cryptor unique identifier. + * + * @returns Cryptor identifier. + */ get identifier(): string; + + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + + // region Encryption + /** + * Encrypt provided source data. + * + * @param data - Source data for encryption. + * + * @returns Encrypted data object. + * + * @throws Error if unknown data type has been passed. + */ encrypt(data: ArrayBuffer | string): EncryptedDataType; - decrypt(data: EncryptedDataType): ArrayBuffer; + /** + * Encrypt provided source {@link ArrayBuffer}. + * + * @param data - Source {@link ArrayBuffer} for encryption. + * + * @returns Encrypted data object. + * + * @throws Error if unknown data type has been passed. + */ encryptFileData(data: ArrayBuffer): Promise; - decryptFileData(data: EncryptedDataType): Promise; + // endregion + + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + + // region Decryption + /** + * Decrypt provided encrypted data object. + * + * @param data - Encrypted data object for decryption. + * + * @returns Decrypted data. + * + * @throws Error if unknown data type has been passed. + */ + decrypt(data: EncryptedDataType): ArrayBuffer; + + /** + * Decrypt provided encrypted {@link ArrayBuffer} File object. + * + * @param file - Encrypted {@link ArrayBuffer} for decryption. + * + * @returns Decrypted data as {@link ArrayBuffer}. + * + * @throws Error if unknown data type has been passed. + */ + decryptFileData(file: EncryptedDataType): Promise; + // endregion } diff --git a/src/crypto/modules/WebCryptoModule/ILegacyCryptor.ts b/src/crypto/modules/WebCryptoModule/ILegacyCryptor.ts index c9ae022c0..a0afa95e5 100644 --- a/src/crypto/modules/WebCryptoModule/ILegacyCryptor.ts +++ b/src/crypto/modules/WebCryptoModule/ILegacyCryptor.ts @@ -1,24 +1,86 @@ +/** + * Legacy cryptor module. + */ + +import { PubNubFile, PubNubFileParameters } from '../../../file/modules/web'; +import { PubNubFileConstructor } from '../../../core/types/file'; +import { Payload } from '../../../core/types/api'; import { EncryptedDataType } from './ICryptor'; -export type PubNubFileType = { - data: File | Blob; - name: string; - mimeType: string; +/** + * Legacy cryptor algorithm interface. + */ +export interface ILegacyCryptor { + /** + * Cryptor unique identifier. + * + * @returns Cryptor identifier. + */ + get identifier(): string; + + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- - create(config: any): PubNubFileType; + // region Encryption + /** + * Encrypt provided source data. + * + * @param data - Source data for encryption. + * + * @returns Encrypted data object. + * + * @throws Error if unknown data type has been passed. + */ + encrypt(data: ArrayBuffer | string): EncryptedDataType; - toArrayBuffer(): ArrayBuffer; - toBlob(): Blob; - toString(): string; - toFile(): File; -}; + /** + * Encrypt provided source {@link PubNub} File object. + * + * @param file - Source {@link PubNub} File object for encryption. + * @param File - Class constructor for {@link PubNub} File object. + * + * @returns Encrypted data as {@link PubNub} File object. + * + * @throws Error if file is empty or contains unsupported data type. + * @throws Error if cipher key not set. + */ + encryptFile( + file: PubNubFile, + File: PubNubFileConstructor, + ): Promise; + // endregion -export interface ILegacyCryptor { - get identifier(): string; + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- - encrypt(data: ArrayBuffer | string): EncryptedDataType; - decrypt(data: EncryptedDataType): ArrayBuffer | string; + // region Decryption + /** + * Decrypt provided encrypted data object. + * + * @param data - Encrypted data object for decryption. + * + * @returns Decrypted data. + * + * @throws Error if unknown data type has been passed. + */ + decrypt(data: EncryptedDataType): Payload | null; - encryptFile(file: T, File: T): Promise; - decryptFile(file: T, File: T): Promise; + /** + * Decrypt provided encrypted {@link PubNub} File object. + * + * @param file - Encrypted {@link PubNub} File object for decryption. + * @param File - Class constructor for {@link PubNub} File object. + * + * @returns Decrypted data as {@link PubNub} File object. + * + * @throws Error if file is empty or contains unsupported data type. + * @throws Error if cipher key not set. + */ + decryptFile( + file: PubNubFile, + File: PubNubFileConstructor, + ): Promise; + // endregion } diff --git a/src/crypto/modules/WebCryptoModule/aesCbcCryptor.ts b/src/crypto/modules/WebCryptoModule/aesCbcCryptor.ts index 78bda2175..6d5300bf0 100644 --- a/src/crypto/modules/WebCryptoModule/aesCbcCryptor.ts +++ b/src/crypto/modules/WebCryptoModule/aesCbcCryptor.ts @@ -1,44 +1,58 @@ -import { ICryptor, EncryptedDataType } from './ICryptor'; +/** + * AES-CBC cryptor module. + */ + import cryptoJS from '../../../core/components/cryptography/hmac-sha256'; import { decode } from '../../../core/components/base64_codec'; +import { ICryptor, EncryptedDataType } from './ICryptor'; +/** + * AES-CBC cryptor. + * + * AES-CBC cryptor with enhanced cipher strength. + */ export default class AesCbcCryptor implements ICryptor { + /** + * Cryptor block size. + */ static BLOCK_SIZE = 16; + + /** + * {@link string|String} to {@link ArrayBuffer} response decoder. + */ static encoder = new TextEncoder(); + + /** + * {@link ArrayBuffer} to {@link string} decoder. + */ static decoder = new TextDecoder(); + /** + * Data encryption / decryption cipher key. + */ cipherKey: string; + + /* eslint-disable @typescript-eslint/no-explicit-any */ encryptedKey: any; + /* eslint-disable @typescript-eslint/no-explicit-any */ CryptoJS: any; - constructor(configuration: { cipherKey: string }) { - this.cipherKey = configuration.cipherKey; + constructor({ cipherKey }: { cipherKey: string }) { + this.cipherKey = cipherKey; this.CryptoJS = cryptoJS; - this.encryptedKey = this.CryptoJS.SHA256(this.cipherKey); - } - - get algo() { - return 'AES-CBC'; - } - - get identifier() { - return 'ACRH'; - } - - private getIv() { - return crypto.getRandomValues(new Uint8Array(AesCbcCryptor.BLOCK_SIZE)); + this.encryptedKey = this.CryptoJS.SHA256(cipherKey); } - private async getKey() { - const bKey = AesCbcCryptor.encoder.encode(this.cipherKey); - const abHash = await crypto.subtle.digest('SHA-256', bKey.buffer); - return crypto.subtle.importKey('raw', abHash, this.algo, true, ['encrypt', 'decrypt']); - } + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + // region Encryption - encrypt(data: ArrayBuffer | string) { + encrypt(data: ArrayBuffer | string): EncryptedDataType { const stringData = typeof data === 'string' ? data : AesCbcCryptor.decoder.decode(data); if (stringData.length === 0) throw new Error('encryption error. empty content'); const abIv = this.getIv(); + return { metadata: abIv, data: decode( @@ -50,9 +64,25 @@ export default class AesCbcCryptor implements ICryptor { }; } + async encryptFileData(data: ArrayBuffer): Promise { + const key = await this.getKey(); + const iv = this.getIv(); + return { + data: await crypto.subtle.encrypt({ name: this.algo, iv: iv }, key, data), + metadata: iv, + }; + } + // endregion + + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + // region Decryption + decrypt(encryptedData: EncryptedDataType) { const iv = this.bufferToWordArray(new Uint8ClampedArray(encryptedData.metadata!)); const data = this.bufferToWordArray(new Uint8ClampedArray(encryptedData.data)); + return AesCbcCryptor.encoder.encode( this.CryptoJS.AES.decrypt({ ciphertext: data }, this.encryptedKey, { iv, @@ -61,26 +91,66 @@ export default class AesCbcCryptor implements ICryptor { ).buffer; } - async encryptFileData(data: ArrayBuffer): Promise { - const key = await this.getKey(); - const iv = this.getIv(); - return { - data: await crypto.subtle.encrypt({ name: this.algo, iv: iv }, key, data), - metadata: iv, - }; - } - async decryptFileData(encryptedData: EncryptedDataType): Promise { const key = await this.getKey(); return crypto.subtle.decrypt({ name: this.algo, iv: encryptedData.metadata! }, key, encryptedData.data); } + // endregion + + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + // region Helpers + + get identifier() { + return 'ACRH'; + } - private bufferToWordArray(b: any) { - const wa: any[] = []; + /** + * Cryptor algorithm. + * + * @returns Cryptor module algorithm. + */ + private get algo() { + return 'AES-CBC'; + } + + /** + * Generate random initialization vector. + * + * @returns Random initialization vector. + */ + + private getIv() { + return crypto.getRandomValues(new Uint8Array(AesCbcCryptor.BLOCK_SIZE)); + } + + /** + * Convert cipher key to the {@link Buffer}. + * + * @returns SHA256 encoded cipher key {@link Buffer}. + */ + private async getKey() { + const bKey = AesCbcCryptor.encoder.encode(this.cipherKey); + const abHash = await crypto.subtle.digest('SHA-256', bKey.buffer); + return crypto.subtle.importKey('raw', abHash, this.algo, true, ['encrypt', 'decrypt']); + } + + /** + * Convert bytes array to words array. + * + * @param b - Bytes array (buffer) which should be converted. + * + * @returns Word sized array. + */ + private bufferToWordArray(b: string | any[] | Uint8Array | Uint8ClampedArray) { + const wa: number[] = []; let i; + for (i = 0; i < b.length; i += 1) { wa[(i / 4) | 0] |= b[i] << (24 - 8 * i); } + return this.CryptoJS.lib.WordArray.create(wa, b.length); } } diff --git a/src/crypto/modules/WebCryptoModule/legacyCryptor.ts b/src/crypto/modules/WebCryptoModule/legacyCryptor.ts index db4b96bed..613640f35 100644 --- a/src/crypto/modules/WebCryptoModule/legacyCryptor.ts +++ b/src/crypto/modules/WebCryptoModule/legacyCryptor.ts @@ -1,46 +1,98 @@ +/** + * Legacy cryptor module. + */ + +import { CryptorConfiguration } from '../../../core/interfaces/crypto-module'; +import { PubNubFile, PubNubFileParameters } from '../../../file/modules/web'; import Crypto from '../../../core/components/cryptography/index'; -import FileCryptor from '../web'; -import { EncryptedDataType } from './ICryptor'; -import { ILegacyCryptor, PubNubFileType } from './ILegacyCryptor'; +import { PubNubFileConstructor } from '../../../core/types/file'; import { encode } from '../../../core/components/base64_codec'; +import { PubNubError } from '../../../models/PubNubError'; +import { ILegacyCryptor } from './ILegacyCryptor'; +import { EncryptedDataType } from './ICryptor'; +import FileCryptor from '../web'; + +/** + * Legacy cryptor. + */ +export default class LegacyCryptor implements ILegacyCryptor { + /** + * `string` to {@link ArrayBuffer} response decoder. + */ + static encoder = new TextEncoder(); + + /** + * {@link ArrayBuffer} to {@link string} decoder. + */ + static decoder = new TextDecoder(); -export default class LegacyCryptor implements ILegacyCryptor { + /** + * Legacy cryptor configuration. + */ config; - cryptor; + /** + * Configured file cryptor. + */ fileCryptor; - constructor(config: any) { + /** + * Configured legacy cryptor. + */ + cryptor; + + constructor(config: CryptorConfiguration) { this.config = config; - this.cryptor = new Crypto({ config }); + this.cryptor = new Crypto({ ...config }); this.fileCryptor = new FileCryptor(); } - get identifier() { - return ''; - } + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + // region Encryption + encrypt(data: ArrayBuffer | string) { - const stringData = typeof data === 'string' ? data : new TextDecoder().decode(data); + const stringData = typeof data === 'string' ? data : LegacyCryptor.decoder.decode(data); + return { - data: this.cryptor.encrypt(stringData), + data: LegacyCryptor.encoder.encode(this.cryptor.encrypt(stringData)), metadata: null, }; } + async encryptFile(file: PubNubFile, File: PubNubFileConstructor) { + if (!this.config.cipherKey) throw new PubNubError('File encryption error: cipher key not set.'); + + return this.fileCryptor.encryptFile(this.config?.cipherKey, file, File); + } + // endregion + + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + // region Decryption + decrypt(encryptedData: EncryptedDataType) { const data = typeof encryptedData.data === 'string' ? encryptedData.data : encode(encryptedData.data); + return this.cryptor.decrypt(data); } - async encryptFile(file: PubNubFileType, File: PubNubFileType) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - //@ts-ignore: can not detect cipherKey from old Config - return this.fileCryptor.encryptFile(this.config?.cipherKey, file, File); - } + async decryptFile(file: PubNubFile, File: PubNubFileConstructor) { + if (!this.config.cipherKey) throw new PubNubError('File encryption error: cipher key not set.'); - async decryptFile(file: PubNubFileType, File: PubNubFileType) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - //@ts-ignore: can not detect cipherKey from old Config return this.fileCryptor.decryptFile(this.config.cipherKey, file, File); } + // endregion + + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + // region Helpers + + get identifier() { + return ''; + } + // endregion } diff --git a/src/crypto/modules/WebCryptoModule/webCryptoModule.ts b/src/crypto/modules/WebCryptoModule/webCryptoModule.ts index daff33552..b38bd3c11 100644 --- a/src/crypto/modules/WebCryptoModule/webCryptoModule.ts +++ b/src/crypto/modules/WebCryptoModule/webCryptoModule.ts @@ -1,25 +1,47 @@ -import LegacyCryptor from './legacyCryptor'; -import AesCbcCryptor from './aesCbcCryptor'; -import { EncryptedDataType, ICryptor } from './ICryptor'; -import { ILegacyCryptor, PubNubFileType } from './ILegacyCryptor'; +/** + * Browser crypto module. + */ + +import { AbstractCryptoModule, CryptorConfiguration } from '../../../core/interfaces/crypto-module'; +import { PubNubFile, PubNubFileParameters } from '../../../file/modules/web'; +import { PubNubFileConstructor } from '../../../core/types/file'; import { decode } from '../../../core/components/base64_codec'; -import { CryptoModule, CryptorConfiguration } from '../../../core/interfaces/crypto-module'; +import { PubNubError } from '../../../models/PubNubError'; +import { EncryptedDataType, ICryptor } from './ICryptor'; +import { ILegacyCryptor } from './ILegacyCryptor'; +import AesCbcCryptor from './aesCbcCryptor'; +import LegacyCryptor from './legacyCryptor'; +/** + * Re-export bundled cryptors. + */ export { LegacyCryptor, AesCbcCryptor }; -type CryptorType = ICryptor | ILegacyCryptor; - -export class WebCryptoModule extends CryptoModule { +/** + * Crypto module cryptors interface. + */ +type CryptorType = ICryptor | ILegacyCryptor; + +/** + * CryptoModule for browser platform. + */ +export class WebCryptoModule extends AbstractCryptoModule { + /** + * {@link LegacyCryptor|Legacy} cryptor identifier. + */ static LEGACY_IDENTIFIER = ''; - static encoder = new TextEncoder(); - static decoder = new TextDecoder(); - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - //@ts-ignore: type detection issue with old Config type assignment + // -------------------------------------------------------- + // --------------- Convenience functions ------------------ + // ------------------------------------------------------- + // region Convenience functions + static legacyCryptoModule(config: CryptorConfiguration) { + if (!config.cipherKey) throw new PubNubError('Crypto module error: cipher key not set.'); + return new WebCryptoModule({ default: new LegacyCryptor({ - cipherKey: config.cipherKey, + ...config, useRandomIVs: config.useRandomIVs ?? true, }), cryptors: [new AesCbcCryptor({ cipherKey: config.cipherKey })], @@ -27,32 +49,74 @@ export class WebCryptoModule extends CryptoModule { } static aesCbcCryptoModule(config: CryptorConfiguration) { + if (!config.cipherKey) throw new PubNubError('Crypto module error: cipher key not set.'); + return new WebCryptoModule({ default: new AesCbcCryptor({ cipherKey: config.cipherKey }), cryptors: [ new LegacyCryptor({ - cipherKey: config.cipherKey, + ...config, useRandomIVs: config.useRandomIVs ?? true, }), ], }); } + /** + * Construct crypto module with `cryptor` as default for data encryption and decryption. + * + * @param defaultCryptor - Default cryptor for data encryption and decryption. + * + * @returns Crypto module with pre-configured default cryptor. + */ static withDefaultCryptor(defaultCryptor: CryptorType) { return new this({ default: defaultCryptor }); } + // endregion - private getAllCryptors() { - return [this.defaultCryptor, ...this.cryptors]; - } + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + // region Encryption encrypt(data: ArrayBuffer | string) { - const encrypted = (this.defaultCryptor as ICryptor).encrypt(data); + // Encrypt data. + const encrypted = + data instanceof ArrayBuffer && this.defaultCryptor.identifier === WebCryptoModule.LEGACY_IDENTIFIER + ? (this.defaultCryptor as ILegacyCryptor).encrypt(WebCryptoModule.decoder.decode(data)) + : (this.defaultCryptor as ICryptor).encrypt(data); + if (!encrypted.metadata) return encrypted.data; + const headerData = this.getHeaderData(encrypted); + return this.concatArrayBuffer(headerData!, encrypted.data); } + async encryptFile(file: PubNubFile, File: PubNubFileConstructor) { + /** + * Files handled differently in case of Legacy cryptor. + * (as long as we support legacy need to check on instance type) + */ + if (this.defaultCryptor.identifier === CryptorHeader.LEGACY_IDENTIFIER) + return (this.defaultCryptor as ILegacyCryptor).encryptFile(file, File); + + const fileData = await this.getFileData(file); + const encrypted = await (this.defaultCryptor as ICryptor).encryptFileData(fileData); + + return File.create({ + name: file.name, + mimeType: 'application/octet-stream', + data: this.concatArrayBuffer(this.getHeaderData(encrypted)!, encrypted.data), + }); + } + // endregion + + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + // region Decryption + decrypt(data: ArrayBuffer | string) { const encryptedData = typeof data === 'string' ? decode(data) : data; const header = CryptorHeader.tryParse(encryptedData); @@ -61,34 +125,29 @@ export class WebCryptoModule extends CryptoModule { header.length > 0 ? encryptedData.slice(header.length - (header as CryptorHeaderV1).metadataLength, header.length) : null; - if (encryptedData.slice(header.length).byteLength <= 0) throw new Error('decryption error. empty content'); + + if (encryptedData.slice(header.length).byteLength <= 0) throw new Error('Decryption error: empty content'); + return cryptor!.decrypt({ data: encryptedData.slice(header.length), metadata: metadata, }); } - async encryptFile(file: PubNubFileType, File: PubNubFileType) { - if (this.defaultCryptor.identifier === CryptorHeader.LEGACY_IDENTIFIER) - return (this.defaultCryptor as ILegacyCryptor).encryptFile(file, File); - const fileData = await this.getFileData(file.data); - const encrypted = await (this.defaultCryptor as ICryptor).encryptFileData(fileData); - return File.create({ - name: file.name, - mimeType: 'application/octet-stream', - data: this.concatArrayBuffer(this.getHeaderData(encrypted)!, encrypted.data), - }); - } - - async decryptFile(file: PubNubFileType, File: PubNubFileType) { + async decryptFile(file: PubNubFile, File: PubNubFileConstructor) { const data = await file.data.arrayBuffer(); const header = CryptorHeader.tryParse(data); const cryptor = this.getCryptor(header); - if (cryptor?.identifier === CryptoModule.LEGACY_IDENTIFIER) { - return (cryptor as ILegacyCryptor).decryptFile(file, File); - } + /** + * Files handled differently in case of Legacy cryptor. + * (as long as we support legacy need to check on instance type) + */ + if (cryptor?.identifier === CryptorHeader.LEGACY_IDENTIFIER) + return (cryptor as ILegacyCryptor).decryptFile(file, File); + const fileData = await this.getFileData(data); const metadata = fileData.slice(header.length - (header as CryptorHeaderV1).metadataLength, header.length); + return File.create({ name: file.name, data: await (this.defaultCryptor as ICryptor).decryptFileData({ @@ -97,34 +156,54 @@ export class WebCryptoModule extends CryptoModule { }), }); } + // endregion + + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + // region Helpers + + /** + * Retrieve registered cryptor by its identifier. + * + * @param id - Unique cryptor identifier. + * + * @returns Registered cryptor with specified identifier. + * + * @throws Error if cryptor with specified {@link id} can't be found. + */ + private getCryptorFromId(id: string) { + const cryptor = this.getAllCryptors().find((cryptor) => id === cryptor.identifier); + if (cryptor) return cryptor; + + throw Error('Unknown cryptor error'); + } - private getCryptor(header: string | CryptorHeaderV1) { - if (header === '') { - const cryptor = this.getAllCryptors().find((c) => c.identifier === ''); + /** + * Retrieve cryptor by its identifier. + * + * @param header - Header with cryptor-defined data or raw cryptor identifier. + * + * @returns Cryptor which correspond to provided {@link header}. + */ + private getCryptor(header: CryptorHeader | string) { + if (typeof header === 'string') { + const cryptor = this.getAllCryptors().find((cryptor) => cryptor.identifier === header); if (cryptor) return cryptor; - throw new Error('unknown cryptor error'); + + throw new Error('Unknown cryptor error'); } else if (header instanceof CryptorHeaderV1) { return this.getCryptorFromId(header.identifier); } } - private getCryptorFromId(id: string) { - const cryptor = this.getAllCryptors().find((c) => id === c.identifier); - if (cryptor) { - return cryptor; - } - throw Error('unknown cryptor error'); - } - - private concatArrayBuffer(ab1: ArrayBuffer, ab2: ArrayBuffer) { - const tmp = new Uint8Array(ab1.byteLength + ab2.byteLength); - - tmp.set(new Uint8Array(ab1), 0); - tmp.set(new Uint8Array(ab2), ab1.byteLength); - - return tmp.buffer; - } - + /** + * Create cryptor header data. + * + * @param encrypted - Encryption data object as source for header data. + * + * @returns Binary representation of the cryptor header data. + */ private getHeaderData(encrypted: EncryptedDataType) { if (!encrypted.metadata) return; const header = CryptorHeader.from(this.defaultCryptor.identifier, encrypted.metadata); @@ -136,24 +215,43 @@ export class WebCryptoModule extends CryptoModule { return headerData.buffer; } - private async getFileData(input: any) { - if (input instanceof Blob) { - const fileData = await input.arrayBuffer(); - return fileData; - } - if (input instanceof ArrayBuffer) { - return input; - } - if (typeof input === 'string') { - return CryptoModule.encoder.encode(input); - } + /** + * Merge two {@link ArrayBuffer} instances. + * + * @param ab1 - First {@link ArrayBuffer}. + * @param ab2 - Second {@link ArrayBuffer}. + * + * @returns Merged data as {@link ArrayBuffer}. + */ + private concatArrayBuffer(ab1: ArrayBuffer, ab2: ArrayBuffer): ArrayBuffer { + const tmp = new Uint8Array(ab1.byteLength + ab2.byteLength); + + tmp.set(new Uint8Array(ab1), 0); + tmp.set(new Uint8Array(ab2), ab1.byteLength); + + return tmp.buffer; + } + + /** + * Retrieve file content. + * + * @param file - Content of the {@link PubNub} File object. + * + * @returns Normalized file {@link data} as {@link ArrayBuffer}; + */ + private async getFileData(file: PubNubFile | ArrayBuffer) { + if (file instanceof ArrayBuffer) return file; + else if (file instanceof PubNubFile) return file.toArrayBuffer(); + throw new Error( 'Cannot decrypt/encrypt file. In browsers file encrypt/decrypt supported for string, ArrayBuffer or Blob', ); } } -// CryptorHeader Utility +/** + * CryptorHeader Utility + */ class CryptorHeader { static SENTINEL = 'PNED'; static LEGACY_IDENTIFIER = ''; @@ -169,37 +267,33 @@ class CryptorHeader { static tryParse(data: ArrayBuffer) { const encryptedData = new Uint8Array(data); - let sentinel: any = ''; + let sentinel: Uint8Array; let version = null; + if (encryptedData.byteLength >= 4) { sentinel = encryptedData.slice(0, 4); - if (this.decoder.decode(sentinel) !== CryptorHeader.SENTINEL) return ''; + if (this.decoder.decode(sentinel) !== CryptorHeader.SENTINEL) return WebCryptoModule.LEGACY_IDENTIFIER; } - if (encryptedData.byteLength >= 5) { - version = (encryptedData as Uint8Array)[4] as number; - } else { - throw new Error('decryption error. invalid header version'); - } - if (version > CryptorHeader.MAX_VERSION) throw new Error('unknown cryptor error'); - let identifier: any = ''; + if (encryptedData.byteLength >= 5) version = (encryptedData as Uint8Array)[4] as number; + else throw new Error('Decryption error: invalid header version'); + + if (version > CryptorHeader.MAX_VERSION) throw new Error('Decryption error: Unknown cryptor error'); + + let identifier: Uint8Array; let pos = 5 + CryptorHeader.IDENTIFIER_LENGTH; - if (encryptedData.byteLength >= pos) { - identifier = encryptedData.slice(5, pos); - } else { - throw new Error('decryption error. invalid crypto identifier'); - } + if (encryptedData.byteLength >= pos) identifier = encryptedData.slice(5, pos); + else throw new Error('Decryption error: invalid crypto identifier'); + let metadataLength = null; - if (encryptedData.byteLength >= pos + 1) { - metadataLength = (encryptedData as Uint8Array)[pos]; - } else { - throw new Error('decryption error. invalid metadata length'); - } + if (encryptedData.byteLength >= pos + 1) metadataLength = (encryptedData as Uint8Array)[pos]; + else throw new Error('Decryption error: invalid metadata length'); + pos += 1; if (metadataLength === 255 && encryptedData.byteLength >= pos + 2) { metadataLength = new Uint16Array(encryptedData.slice(pos, pos + 2)).reduce((acc, val) => (acc << 8) + val, 0); - pos += 2; } + return new CryptorHeaderV1(this.decoder.decode(identifier), metadataLength); } } @@ -255,14 +349,15 @@ class CryptorHeaderV1 { pos += CryptorHeader.SENTINEL.length; header[pos] = this.version; pos++; + if (this.identifier) header.set(encoder.encode(this.identifier), pos); - pos += CryptorHeader.IDENTIFIER_LENGTH; + const metadataLength = this.metadataLength; - if (metadataLength < 255) { - header[pos] = metadataLength; - } else { - header.set([255, metadataLength >> 8, metadataLength & 0xff], pos); - } + pos += CryptorHeader.IDENTIFIER_LENGTH; + + if (metadataLength < 255) header[pos] = metadataLength; + else header.set([255, metadataLength >> 8, metadataLength & 0xff], pos); + return header; } } diff --git a/src/crypto/modules/node.js b/src/crypto/modules/node.js deleted file mode 100644 index 11055962c..000000000 --- a/src/crypto/modules/node.js +++ /dev/null @@ -1,191 +0,0 @@ -/** */ -import { Readable, PassThrough, Transform } from 'stream'; -import { createCipheriv, createDecipheriv, createHash, randomBytes } from 'crypto'; - -export default class NodeCryptography { - static IV_LENGTH = 16; - - get algo() { - return 'aes-256-cbc'; - } - - async encrypt(key, input) { - const bKey = this.getKey(key); - if (input instanceof Buffer) { - return this.encryptBuffer(bKey, input); - } - if (input instanceof Readable) { - return this.encryptStream(bKey, input); - } - if (typeof input === 'string') { - return this.encryptString(bKey, input); - } - throw new Error('Unsupported input format'); - } - - async decrypt(key, input) { - const bKey = this.getKey(key); - if (input instanceof Buffer) { - return this.decryptBuffer(bKey, input); - } - if (input instanceof Readable) { - return this.decryptStream(bKey, input); - } - if (typeof input === 'string') { - return this.decryptString(bKey, input); - } - throw new Error('Unsupported input format'); - } - - async encryptFile(key, file, File) { - const bKey = this.getKey(key); - - if (file.data instanceof Buffer) { - if (file.data.byteLength <= 0) throw new Error('encryption error. empty content'); - return File.create({ - name: file.name, - mimeType: 'application/octet-stream', - data: await this.encryptBuffer(bKey, file.data), - }); - } - if (file.data instanceof Readable) { - if (file.contentLength === 0) throw new Error('encryption error. empty content'); - return File.create({ - name: file.name, - mimeType: 'application/octet-stream', - stream: await this.encryptStream(bKey, file.data), - }); - } - throw new Error('Cannot encrypt this file. In Node.js file encryption supports only string, Buffer or Stream.'); - } - - async decryptFile(key, file, File) { - const bKey = this.getKey(key); - - if (file.data instanceof Buffer) { - return File.create({ - name: file.name, - data: await this.decryptBuffer(bKey, file.data), - }); - } - if (file.data instanceof Readable) { - return File.create({ - name: file.name, - stream: await this.decryptStream(bKey, file.data), - }); - } - throw new Error('Cannot decrypt this file. In Node.js file decryption supports only string, Buffer or Stream.'); - } - - getKey(key) { - const sha = createHash('sha256'); - - sha.update(Buffer.from(key, 'utf8')); - - return Buffer.from(sha.digest('hex').slice(0, 32), 'utf8'); - } - - getIv() { - return randomBytes(NodeCryptography.IV_LENGTH); - } - - encryptString(key, plaintext) { - const bIv = this.getIv(); - - const bPlaintext = Buffer.from(plaintext); - - const aes = createCipheriv(this.algo, key, bIv); - - return Buffer.concat([bIv, aes.update(bPlaintext), aes.final()]).toString('utf8'); - } - - decryptString(key, sCiphertext) { - const ciphertext = Buffer.from(sCiphertext); - const bIv = ciphertext.slice(0, NodeCryptography.IV_LENGTH); - const bCiphertext = ciphertext.slice(NodeCryptography.IV_LENGTH); - - const aes = createDecipheriv(this.algo, key, bIv); - - return Buffer.concat([aes.update(bCiphertext), aes.final()]).toString('utf8'); - } - - encryptBuffer(key, plaintext) { - const bIv = this.getIv(); - - const aes = createCipheriv(this.algo, key, bIv); - - return Buffer.concat([bIv, aes.update(plaintext), aes.final()]); - } - - decryptBuffer(key, ciphertext) { - const bIv = ciphertext.slice(0, NodeCryptography.IV_LENGTH); - const bCiphertext = ciphertext.slice(NodeCryptography.IV_LENGTH); - if (bCiphertext.byteLength <= 0) throw new Error('decryption error: empty content'); - const aes = createDecipheriv(this.algo, key, bIv); - - return Buffer.concat([aes.update(bCiphertext), aes.final()]); - } - - async encryptStream(key, stream) { - const bIv = this.getIv(); - const aes = createCipheriv('aes-256-cbc', key, bIv).setAutoPadding(true); - let inited = false; - return stream.pipe(aes).pipe( - new Transform({ - transform(chunk, _, cb) { - if (!inited) { - inited = true; - this.push(Buffer.concat([bIv, chunk])); - } else { - this.push(chunk); - } - cb(); - }, - }), - ); - } - - decryptStream(key, stream) { - const output = new PassThrough(); - - let bIv = Buffer.alloc(0); - let aes = null; - - const getIv = () => { - let data = stream.read(); - - while (data !== null) { - if (data) { - const bChunk = Buffer.from(data); - const sliceLen = NodeCryptography.IV_LENGTH - bIv.byteLength; - - if (bChunk.byteLength < sliceLen) { - bIv = Buffer.concat([bIv, bChunk]); - } else { - bIv = Buffer.concat([bIv, bChunk.slice(0, sliceLen)]); - - aes = createDecipheriv(this.algo, key, bIv); - - aes.pipe(output); - - aes.write(bChunk.slice(sliceLen)); - } - } - - data = stream.read(); - } - }; - - stream.on('readable', getIv); - - stream.on('end', () => { - if (aes) { - aes.end(); - } - - output.end(); - }); - - return output; - } -} diff --git a/src/crypto/modules/node.ts b/src/crypto/modules/node.ts new file mode 100644 index 000000000..d59d20fec --- /dev/null +++ b/src/crypto/modules/node.ts @@ -0,0 +1,293 @@ +/** + * Legacy Node.js cryptography module. + */ + +import { createCipheriv, createDecipheriv, createHash, randomBytes } from 'crypto'; +import { Readable, PassThrough, Transform } from 'stream'; +import { Buffer } from 'buffer'; + +import PubNubFile, { PubNubFileParameters } from '../../file/modules/node'; +import { Cryptography } from '../../core/interfaces/cryptography'; +import { PubNubFileConstructor } from '../../core/types/file'; + +/** + * Legacy cryptography implementation for Node.js-based {@link PubNub} client. + */ +export default class NodeCryptography implements Cryptography { + /** + * Random initialization vector size. + */ + static IV_LENGTH = 16; + + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + // region Encryption + + public async encrypt( + key: string, + input: string | ArrayBuffer | Buffer | Readable, + ): Promise { + const bKey = this.getKey(key); + + if (input instanceof Buffer) return this.encryptBuffer(bKey, input); + if (input instanceof Readable) return this.encryptStream(bKey, input); + if (typeof input === 'string') return this.encryptString(bKey, input); + + throw new Error('Encryption error: unsupported input format'); + } + + /** + * Encrypt provided source {@link Buffer} using specific encryption {@link key}. + * + * @param key - Data encryption key.
**Note:** Same key should be used to `decrypt` {@link Buffer}. + * @param buffer - Source {@link Buffer} for encryption. + * + * @returns Encrypted data as {@link Buffer} object. + */ + private encryptBuffer(key: Buffer, buffer: Buffer) { + const bIv = this.getIv(); + const aes = createCipheriv(this.algo, key, bIv); + + return Buffer.concat([bIv, aes.update(buffer), aes.final()]); + } + + /** + * Encrypt provided source {@link Readable} stream using specific encryption {@link key}. + * + * @param key - Data encryption key.
**Note:** Same key should be used to `decrypt` {@link Readable} stream. + * @param stream - Source {@link Readable} stream for encryption. + * + * @returns Encrypted data as {@link Transform} object. + */ + private async encryptStream(key: Buffer, stream: Readable) { + const bIv = this.getIv(); + const aes = createCipheriv(this.algo, key, bIv).setAutoPadding(true); + let initiated = false; + + return stream.pipe(aes).pipe( + new Transform({ + transform(chunk, _, cb) { + if (!initiated) { + initiated = true; + this.push(Buffer.concat([bIv, chunk])); + } else this.push(chunk); + + cb(); + }, + }), + ); + } + + /** + * Encrypt provided source {@link string} using specific encryption {@link key}. + * + * @param key - Data encryption key.
**Note:** Same key should be used to `decrypt` {@link string}. + * @param text - Source {@link string} for encryption. + * + * @returns Encrypted data as byte {@link string}. + */ + private encryptString(key: Buffer, text: string) { + const bIv = this.getIv(); + const bPlaintext = Buffer.from(text); + const aes = createCipheriv(this.algo, key, bIv); + + return Buffer.concat([bIv, aes.update(bPlaintext), aes.final()]).toString('utf8'); + } + + public async encryptFile( + key: string, + file: PubNubFile, + File: PubNubFileConstructor, + ) { + const bKey = this.getKey(key); + + /** + * Buffer type check also covers `string` which converted to the `Buffer` during file object creation. + */ + if (file.data instanceof Buffer) { + if (file.data.byteLength <= 0) throw new Error('Encryption error: empty content.'); + + return File.create({ + name: file.name, + mimeType: file.mimeType, + data: this.encryptBuffer(bKey, file.data), + }); + } + + if (file.data instanceof Readable) { + if (file.contentLength === 0) throw new Error('Encryption error: empty content.'); + + return File.create({ + name: file.name, + mimeType: file.mimeType, + stream: await this.encryptStream(bKey, file.data), + }); + } + + throw new Error('Cannot encrypt this file. In Node.js file encryption supports only string, Buffer or Stream.'); + } + // endregion + + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + // region Decryption + + public async decrypt(key: string, input: string | Buffer | Readable) { + const bKey = this.getKey(key); + + if (input instanceof Buffer) return this.decryptBuffer(bKey, input); + if (input instanceof Readable) return this.decryptStream(bKey, input); + if (typeof input === 'string') return this.decryptString(bKey, input); + + throw new Error('Decryption error: unsupported input format'); + } + + /** + * Decrypt provided encrypted {@link Buffer} using specific decryption {@link key}. + * + * @param key - Data decryption key.
**Note:** Should be the same as used to `encrypt` {@link Buffer}. + * @param buffer - Encrypted {@link Buffer} for decryption. + * + * @returns Decrypted data as {@link Buffer} object. + */ + private decryptBuffer(key: Buffer, buffer: Buffer) { + const bIv = buffer.slice(0, NodeCryptography.IV_LENGTH); + const bCiphertext = buffer.slice(NodeCryptography.IV_LENGTH); + + if (bCiphertext.byteLength <= 0) throw new Error('Decryption error: empty content'); + + const aes = createDecipheriv(this.algo, key, bIv); + + return Buffer.concat([aes.update(bCiphertext), aes.final()]); + } + + /** + * Decrypt provided encrypted {@link Readable} stream using specific decryption {@link key}. + * + * @param key - Data decryption key.
**Note:** Should be the same as used to `encrypt` {@link Readable} stream. + * @param stream - Encrypted {@link Readable} stream for decryption. + * + * @returns Decrypted data as {@link Readable} object. + */ + private decryptStream(key: Buffer, stream: Readable) { + let aes: ReturnType | null = null; + const output = new PassThrough(); + let bIv = Buffer.alloc(0); + + const getIv = () => { + let data = stream.read(); + + while (data !== null) { + if (data) { + const bChunk = Buffer.from(data); + const sliceLen = NodeCryptography.IV_LENGTH - bIv.byteLength; + + if (bChunk.byteLength < sliceLen) bIv = Buffer.concat([bIv, bChunk]); + else { + bIv = Buffer.concat([bIv, bChunk.slice(0, sliceLen)]); + aes = createDecipheriv(this.algo, key, bIv); + aes.pipe(output); + aes.write(bChunk.slice(sliceLen)); + } + } + + data = stream.read(); + } + }; + + stream.on('readable', getIv); + stream.on('end', () => { + if (aes) aes.end(); + output.end(); + }); + + return output; + } + + /** + * Decrypt provided encrypted {@link string} using specific decryption {@link key}. + * + * @param key - Data decryption key.
**Note:** Should be the same as used to `encrypt` {@link string}. + * @param text - Encrypted {@link string} for decryption. + * + * @returns Decrypted data as byte {@link string}. + */ + private decryptString(key: Buffer, text: string) { + const ciphertext = Buffer.from(text); + const bIv = ciphertext.slice(0, NodeCryptography.IV_LENGTH); + const bCiphertext = ciphertext.slice(NodeCryptography.IV_LENGTH); + const aes = createDecipheriv(this.algo, key, bIv); + + return Buffer.concat([aes.update(bCiphertext), aes.final()]).toString('utf8'); + } + + public async decryptFile( + key: string, + file: PubNubFile, + File: PubNubFileConstructor, + ) { + const bKey = this.getKey(key); + + /** + * Buffer type check also covers `string` which converted to the `Buffer` during file object creation. + */ + if (file.data instanceof Buffer) { + return File.create({ + name: file.name, + mimeType: file.mimeType, + data: this.decryptBuffer(bKey, file.data), + }); + } + + if (file.data instanceof Readable) { + return File.create({ + name: file.name, + mimeType: file.mimeType, + stream: this.decryptStream(bKey, file.data), + }); + } + + throw new Error('Cannot decrypt this file. In Node.js file decryption supports only string, Buffer or Stream.'); + } + // endregion + + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + + // region Helpers + /** + * Cryptography algorithm. + * + * @returns Cryptography module algorithm. + */ + private get algo() { + return 'aes-256-cbc'; + } + + /** + * Convert cipher key to the {@link Buffer}. + * + * @param key - String cipher key. + * + * @returns SHA256 HEX encoded cipher key {@link Buffer}. + */ + private getKey(key: string) { + const sha = createHash('sha256'); + sha.update(Buffer.from(key, 'utf8')); + + return Buffer.from(sha.digest('hex').slice(0, 32), 'utf8'); + } + + /** + * Generate random initialization vector. + * + * @returns Random initialization vector. + */ + private getIv() { + return randomBytes(NodeCryptography.IV_LENGTH); + } + // endregion +} diff --git a/src/crypto/modules/web.js b/src/crypto/modules/web.js deleted file mode 100644 index 20e1a274b..000000000 --- a/src/crypto/modules/web.js +++ /dev/null @@ -1,117 +0,0 @@ -/* global crypto */ - -function concatArrayBuffer(ab1, ab2) { - const tmp = new Uint8Array(ab1.byteLength + ab2.byteLength); - - tmp.set(new Uint8Array(ab1), 0); - tmp.set(new Uint8Array(ab2), ab1.byteLength); - - return tmp.buffer; -} - -export default class WebCryptography { - static IV_LENGTH = 16; - static encoder = new TextEncoder(); - static decoder = new TextDecoder(); - - get algo() { - return 'aes-256-cbc'; - } - - async encrypt(key, input) { - const cKey = await this.getKey(key); - - if (input instanceof ArrayBuffer) { - return this.encryptArrayBuffer(cKey, input); - } - if (typeof input === 'string') { - return this.encryptString(cKey, input); - } - throw new Error('Cannot encrypt this file. In browsers file encryption supports only string or ArrayBuffer'); - } - - async decrypt(key, input) { - const cKey = await this.getKey(key); - if (input instanceof ArrayBuffer) { - return this.decryptArrayBuffer(cKey, input); - } - if (typeof input === 'string') { - return this.decryptString(cKey, input); - } - throw new Error('Cannot decrypt this file. In browsers file decryption supports only string or ArrayBuffer'); - } - - async encryptFile(key, file, File) { - if (file.data.byteLength <= 0) throw new Error('encryption error. empty content'); - const bKey = await this.getKey(key); - - const abPlaindata = await file.data.arrayBuffer(); - - const abCipherdata = await this.encryptArrayBuffer(bKey, abPlaindata); - - return File.create({ - name: file.name, - mimeType: 'application/octet-stream', - data: abCipherdata, - }); - } - - async decryptFile(key, file, File) { - const bKey = await this.getKey(key); - - const abCipherdata = await file.data.arrayBuffer(); - const abPlaindata = await this.decryptArrayBuffer(bKey, abCipherdata); - - return File.create({ - name: file.name, - data: abPlaindata, - }); - } - - async getKey(key) { - const digest = await crypto.subtle.digest('SHA-256', WebCryptography.encoder.encode(key)); - const hashHex = Array.from(new Uint8Array(digest)) - .map((b) => b.toString(16).padStart(2, '0')) - .join(''); - const abKey = WebCryptography.encoder.encode(hashHex.slice(0, 32)).buffer; - return crypto.subtle.importKey('raw', abKey, 'AES-CBC', true, ['encrypt', 'decrypt']); - } - - async encryptArrayBuffer(key, plaintext) { - const abIv = crypto.getRandomValues(new Uint8Array(16)); - - return concatArrayBuffer(abIv.buffer, await crypto.subtle.encrypt({ name: 'AES-CBC', iv: abIv }, key, plaintext)); - } - - async decryptArrayBuffer(key, ciphertext) { - const abIv = ciphertext.slice(0, 16); - if (ciphertext.slice(WebCryptography.IV_LENGTH).byteLength <= 0) throw new Error('decryption error: empty content'); - const data = await crypto.subtle.decrypt( - { name: 'AES-CBC', iv: abIv }, - key, - ciphertext.slice(WebCryptography.IV_LENGTH), - ); - return data; - } - - async encryptString(key, plaintext) { - const abIv = crypto.getRandomValues(new Uint8Array(16)); - - const abPlaintext = WebCryptography.encoder.encode(plaintext).buffer; - const abPayload = await crypto.subtle.encrypt({ name: 'AES-CBC', iv: abIv }, key, abPlaintext); - - const ciphertext = concatArrayBuffer(abIv.buffer, abPayload); - - return WebCryptography.decoder.decode(ciphertext); - } - - async decryptString(key, ciphertext) { - const abCiphertext = WebCryptography.encoder.encode(ciphertext).buffer; - const abIv = abCiphertext.slice(0, 16); - const abPayload = abCiphertext.slice(16); - - const abPlaintext = await crypto.subtle.decrypt({ name: 'AES-CBC', iv: abIv }, key, abPayload); - - return WebCryptography.decoder.decode(abPlaintext); - } -} diff --git a/src/crypto/modules/web.ts b/src/crypto/modules/web.ts new file mode 100644 index 000000000..014f90940 --- /dev/null +++ b/src/crypto/modules/web.ts @@ -0,0 +1,233 @@ +/* global crypto */ +/** + * Legacy browser cryptography module. + */ + +import { PubNubFile, PubNubFileParameters } from '../../file/modules/web'; +import { Cryptography } from '../../core/interfaces/cryptography'; +import { PubNubFileConstructor } from '../../core/types/file'; + +function concatArrayBuffer(ab1: ArrayBuffer, ab2: ArrayBuffer) { + const tmp = new Uint8Array(ab1.byteLength + ab2.byteLength); + + tmp.set(new Uint8Array(ab1), 0); + tmp.set(new Uint8Array(ab2), ab1.byteLength); + + return tmp.buffer; +} + +/** + * Legacy cryptography implementation for browser-based {@link PubNub} client. + */ +export default class WebCryptography implements Cryptography { + /** + * Random initialization vector size. + */ + static IV_LENGTH = 16; + + /** + * {@link string|String} to {@link ArrayBuffer} response decoder. + */ + static encoder = new TextEncoder(); + + /** + * {@link ArrayBuffer} to {@link string} decoder. + */ + static decoder = new TextDecoder(); + + // -------------------------------------------------------- + // --------------------- Encryption ----------------------- + // -------------------------------------------------------- + + // region Encryption + /** + * Encrypt provided source data using specific encryption {@link key}. + * + * @param key - Data encryption key.
**Note:** Same key should be used to `decrypt` data. + * @param input - Source data for encryption. + * + * @returns Encrypted data as object or stream (depending on from source data type). + * + * @throws Error if unknown data type has been passed. + */ + public async encrypt(key: string, input: ArrayBuffer | string) { + if (!(input instanceof ArrayBuffer) && typeof input !== 'string') + throw new Error('Cannot encrypt this file. In browsers file encryption supports only string or ArrayBuffer'); + + const cKey = await this.getKey(key); + + return input instanceof ArrayBuffer ? this.encryptArrayBuffer(cKey, input) : this.encryptString(cKey, input); + } + + /** + * Encrypt provided source {@link Buffer} using specific encryption {@link ArrayBuffer}. + * + * @param key - Data encryption key.
**Note:** Same key should be used to `decrypt` {@link ArrayBuffer}. + * @param buffer - Source {@link ArrayBuffer} for encryption. + * + * @returns Encrypted data as {@link ArrayBuffer} object. + */ + private async encryptArrayBuffer(key: CryptoKey, buffer: ArrayBuffer) { + const abIv = crypto.getRandomValues(new Uint8Array(16)); + + return concatArrayBuffer(abIv.buffer, await crypto.subtle.encrypt({ name: 'AES-CBC', iv: abIv }, key, buffer)); + } + + /** + * Encrypt provided source {@link string} using specific encryption {@link key}. + * + * @param key - Data encryption key.
**Note:** Same key should be used to `decrypt` {@link string}. + * @param text - Source {@link string} for encryption. + * + * @returns Encrypted data as byte {@link string}. + */ + private async encryptString(key: CryptoKey, text: string) { + const abIv = crypto.getRandomValues(new Uint8Array(16)); + + const abPlaintext = WebCryptography.encoder.encode(text).buffer; + const abPayload = await crypto.subtle.encrypt({ name: 'AES-CBC', iv: abIv }, key, abPlaintext); + + const ciphertext = concatArrayBuffer(abIv.buffer, abPayload); + + return WebCryptography.decoder.decode(ciphertext); + } + + /** + * Encrypt provided {@link PubNub} File object using specific encryption {@link key}. + * + * @param key - Key for {@link PubNub} File object encryption.
**Note:** Same key should be + * used to `decrypt` data. + * @param file - Source {@link PubNub} File object for encryption. + * @param File - Class constructor for {@link PubNub} File object. + * + * @returns Encrypted data as {@link PubNub} File object. + * + * @throws Error if file is empty or contains unsupported data type. + */ + public async encryptFile( + key: string, + file: PubNubFile, + File: PubNubFileConstructor, + ) { + if (file.contentLength ?? 0 <= 0) throw new Error('encryption error. empty content'); + const bKey = await this.getKey(key); + const abPlaindata = await file.toArrayBuffer(); + const abCipherdata = await this.encryptArrayBuffer(bKey, abPlaindata); + + return File.create({ + name: file.name, + mimeType: file.mimeType ?? 'application/octet-stream', + data: abCipherdata, + }); + } + // endregion + + // -------------------------------------------------------- + // --------------------- Decryption ----------------------- + // -------------------------------------------------------- + + // region Decryption + /** + * Decrypt provided encrypted data using specific decryption {@link key}. + * + * @param key - Data decryption key.
**Note:** Should be the same as used to `encrypt` data. + * @param input - Encrypted data for decryption. + * + * @returns Decrypted data as object or stream (depending on from encrypted data type). + * + * @throws Error if unknown data type has been passed. + */ + public async decrypt(key: string, input: ArrayBuffer | string) { + if (!(input instanceof ArrayBuffer) && typeof input !== 'string') + throw new Error('Cannot decrypt this file. In browsers file decryption supports only string or ArrayBuffer'); + + const cKey = await this.getKey(key); + + return input instanceof ArrayBuffer ? this.decryptArrayBuffer(cKey, input) : this.decryptString(cKey, input); + } + + /** + * Decrypt provided encrypted {@link ArrayBuffer} using specific decryption {@link key}. + * + * @param key - Data decryption key.
**Note:** Should be the same as used to `encrypt` {@link ArrayBuffer}. + * @param buffer - Encrypted {@link ArrayBuffer} for decryption. + * + * @returns Decrypted data as {@link ArrayBuffer} object. + */ + private async decryptArrayBuffer(key: CryptoKey, buffer: ArrayBuffer) { + const abIv = buffer.slice(0, 16); + if (buffer.slice(WebCryptography.IV_LENGTH).byteLength <= 0) throw new Error('decryption error: empty content'); + + return await crypto.subtle.decrypt({ name: 'AES-CBC', iv: abIv }, key, buffer.slice(WebCryptography.IV_LENGTH)); + } + + /** + * Decrypt provided encrypted {@link string} using specific decryption {@link key}. + * + * @param key - Data decryption key.
**Note:** Should be the same as used to `encrypt` {@link string}. + * @param text - Encrypted {@link string} for decryption. + * + * @returns Decrypted data as byte {@link string}. + */ + private async decryptString(key: CryptoKey, text: string) { + const abCiphertext = WebCryptography.encoder.encode(text).buffer; + const abIv = abCiphertext.slice(0, 16); + const abPayload = abCiphertext.slice(16); + const abPlaintext = await crypto.subtle.decrypt({ name: 'AES-CBC', iv: abIv }, key, abPayload); + + return WebCryptography.decoder.decode(abPlaintext); + } + + /** + * Decrypt provided {@link PubNub} File object using specific decryption {@link key}. + * + * @param key - Key for {@link PubNub} File object decryption.
**Note:** Should be the same + * as used to `encrypt` data. + * @param file - Encrypted {@link PubNub} File object for decryption. + * @param File - Class constructor for {@link PubNub} File object. + * + * @returns Decrypted data as {@link PubNub} File object. + * + * @throws Error if file is empty or contains unsupported data type. + */ + public async decryptFile( + key: string, + file: PubNubFile, + File: PubNubFileConstructor, + ) { + const bKey = await this.getKey(key); + + const abCipherdata = await file.toArrayBuffer(); + const abPlaindata = await this.decryptArrayBuffer(bKey, abCipherdata); + + return File.create({ + name: file.name, + mimeType: file.mimeType, + data: abPlaindata, + }); + } + // endregion + + // -------------------------------------------------------- + // ----------------------- Helpers ------------------------ + // -------------------------------------------------------- + + // region Helpers + /** + * Convert cipher key to the {@link Buffer}. + * + * @param key - String cipher key. + * + * @returns SHA256 HEX encoded cipher key {@link CryptoKey}. + */ + private async getKey(key: string) { + const digest = await crypto.subtle.digest('SHA-256', WebCryptography.encoder.encode(key)); + const hashHex = Array.from(new Uint8Array(digest)) + .map((b) => b.toString(16).padStart(2, '0')) + .join(''); + const abKey = WebCryptography.encoder.encode(hashHex.slice(0, 32)).buffer; + + return crypto.subtle.importKey('raw', abKey, 'AES-CBC', true, ['encrypt', 'decrypt']); + } + // endregion +} diff --git a/src/entities/Channel.ts b/src/entities/Channel.ts index e3ad72904..5e09713a0 100644 --- a/src/entities/Channel.ts +++ b/src/entities/Channel.ts @@ -1,17 +1,19 @@ +import type { PubNubCore as PubNub } from '../core/pubnub-common'; +import EventEmitter from '../core/components/eventEmitter'; +import { SubscriptionOptions } from './commonTypes'; import { Subscription } from './Subscription'; -import { SubscriptionOptions, EventEmitter } from './commonTypes'; -import type PubNub from '../core/pubnub-common'; export class Channel { - private name: string; - private eventEmitter: EventEmitter; - private pubnub: PubNub; + private readonly name: string; - constructor(channelName: string, eventEmitter: EventEmitter, pubnub: PubNub) { + constructor( + channelName: string, + private readonly eventEmitter: EventEmitter, + private readonly pubnub: PubNub, + ) { this.name = channelName; - this.eventEmitter = eventEmitter; - this.pubnub = pubnub; } + subscription(subscriptionOptions?: SubscriptionOptions) { return new Subscription({ channels: subscriptionOptions?.receivePresenceEvents ? [this.name, `${this.name}-pnpres`] : [this.name], diff --git a/src/entities/ChannelGroup.ts b/src/entities/ChannelGroup.ts index f668e79c9..ff6671ba8 100644 --- a/src/entities/ChannelGroup.ts +++ b/src/entities/ChannelGroup.ts @@ -1,17 +1,19 @@ +import type { PubNubCore as PubNub } from '../core/pubnub-common'; +import EventEmitter from '../core/components/eventEmitter'; +import { SubscriptionOptions } from './commonTypes'; import { Subscription } from './Subscription'; -import { SubscriptionOptions, EventEmitter } from './commonTypes'; -import type PubNub from '../core/pubnub-common'; export class ChannelGroup { - private name: string; - private eventEmitter: EventEmitter; - private pubnub: PubNub; + private readonly name: string; - constructor(channelGroup: string, eventEmitter: EventEmitter, pubnub: PubNub) { + constructor( + channelGroup: string, + private readonly eventEmitter: EventEmitter, + private readonly pubnub: PubNub, + ) { this.name = channelGroup; - this.eventEmitter = eventEmitter; - this.pubnub = pubnub; } + subscription(subscriptionOptions?: SubscriptionOptions) { return new Subscription({ channels: [], diff --git a/src/entities/ChannelMetadata.ts b/src/entities/ChannelMetadata.ts index 78020d988..a06bfffa1 100644 --- a/src/entities/ChannelMetadata.ts +++ b/src/entities/ChannelMetadata.ts @@ -1,17 +1,15 @@ +import type { PubNubCore as PubNub } from '../core/pubnub-common'; +import EventEmitter from '../core/components/eventEmitter'; +import { SubscriptionOptions } from './commonTypes'; import { Subscription } from './Subscription'; -import { SubscriptionOptions, EventEmitter } from './commonTypes'; -import type PubNub from '../core/pubnub-common'; export class ChannelMetadata { - private id: string; - private eventEmitter: EventEmitter; - private pubnub: PubNub; + constructor( + private readonly id: string, + private readonly eventEmitter: EventEmitter, + private readonly pubnub: PubNub, + ) {} - constructor(id: string, eventEmitter: EventEmitter, pubnub: PubNub) { - this.id = id; - this.eventEmitter = eventEmitter; - this.pubnub = pubnub; - } subscription(subscriptionOptions?: SubscriptionOptions) { return new Subscription({ channels: [this.id], diff --git a/src/entities/SubscribeCapable.ts b/src/entities/SubscribeCapable.ts index 93d2e7ebf..b6cdcc84d 100644 --- a/src/entities/SubscribeCapable.ts +++ b/src/entities/SubscribeCapable.ts @@ -1,13 +1,15 @@ -import { EventEmitter, Listener, SubscriptionOptions } from './commonTypes'; -import PubNubType from 'pubnub'; -import type PubNub from '../core/pubnub-common'; +import type { PubNubCore as PubNub } from '../core/pubnub-common'; +import { Listener } from '../core/components/listener_manager'; +import * as Subscription from '../core/types/api/subscription'; +import EventEmitter from '../core/components/eventEmitter'; +import { SubscriptionOptions } from './commonTypes'; export abstract class SubscribeCapable { protected abstract channelNames: string[]; protected abstract groupNames: string[]; protected abstract listener: Listener; protected abstract eventEmitter: EventEmitter; - protected abstract pubnub: PubNub; + protected abstract pubnub: PubNub; protected abstract options?: SubscriptionOptions; subscribe() { @@ -24,27 +26,27 @@ export abstract class SubscribeCapable { }); } - set onMessage(onMessagelistener: (messageEvent: PubNubType.MessageEvent) => void) { - this.listener.message = onMessagelistener; + set onMessage(onMessageListener: (messageEvent: Subscription.Message) => void) { + this.listener.message = onMessageListener; } - set onPresence(onPresencelistener: (presenceEvent: PubNubType.PresenceEvent) => void) { - this.listener.presence = onPresencelistener; + set onPresence(onPresenceListener: (presenceEvent: Subscription.Presence) => void) { + this.listener.presence = onPresenceListener; } - set onSignal(onSignalListener: (signalEvent: PubNubType.SignalEvent) => void) { + set onSignal(onSignalListener: (signalEvent: Subscription.Signal) => void) { this.listener.signal = onSignalListener; } - set onObjects(onObjectsListener: (objectsEvent: PubNubType.ObjectsEvent) => void) { + set onObjects(onObjectsListener: (objectsEvent: Subscription.AppContextObject) => void) { this.listener.objects = onObjectsListener; } - set onMessageAction(messageActionEventListener: (messageActionEvent: PubNubType.MessageActionEvent) => void) { + set onMessageAction(messageActionEventListener: (messageActionEvent: Subscription.MessageAction) => void) { this.listener.messageAction = messageActionEventListener; } - set onFile(fileEventListener: (fileEvent: PubNubType.FileEvent) => void) { + set onFile(fileEventListener: (fileEvent: Subscription.File) => void) { this.listener.file = fileEventListener; } diff --git a/src/entities/Subscription.ts b/src/entities/Subscription.ts index 6e2a17aa3..2002313e5 100644 --- a/src/entities/Subscription.ts +++ b/src/entities/Subscription.ts @@ -1,13 +1,15 @@ -import { SubscriptionSet } from './SubscriptionSet'; -import { SubscriptionOptions, EventEmitter, Listener } from './commonTypes'; -import type PubNub from '../core/pubnub-common'; +import type { PubNubCore as PubNub } from '../core/pubnub-common'; +import { Listener } from '../core/components/listener_manager'; +import EventEmitter from '../core/components/eventEmitter'; import { SubscribeCapable } from './SubscribeCapable'; +import { SubscriptionOptions } from './commonTypes'; +import { SubscriptionSet } from './SubscriptionSet'; export class Subscription extends SubscribeCapable { protected channelNames: string[] = []; protected groupNames: string[] = []; protected options?: SubscriptionOptions; - protected pubnub: PubNub; + protected pubnub: PubNub; protected eventEmitter: EventEmitter; protected listener: Listener; @@ -22,7 +24,7 @@ export class Subscription extends SubscribeCapable { channelGroups: string[]; subscriptionOptions?: SubscriptionOptions; eventEmitter: EventEmitter; - pubnub: PubNub; + pubnub: PubNub; }) { super(); this.channelNames = channels; diff --git a/src/entities/SubscriptionSet.ts b/src/entities/SubscriptionSet.ts index 83eedff14..6691fd60f 100644 --- a/src/entities/SubscriptionSet.ts +++ b/src/entities/SubscriptionSet.ts @@ -1,13 +1,15 @@ -import { Subscription } from './Subscription'; -import { SubscriptionOptions, EventEmitter, Listener } from './commonTypes'; -import type PubNub from '../core/pubnub-common'; +import type { PubNubCore as PubNub } from '../core/pubnub-common'; +import { Listener } from '../core/components/listener_manager'; +import EventEmitter from '../core/components/eventEmitter'; import { SubscribeCapable } from './SubscribeCapable'; +import { SubscriptionOptions } from './commonTypes'; +import { Subscription } from './Subscription'; export class SubscriptionSet extends SubscribeCapable { protected channelNames: string[] = []; protected groupNames: string[] = []; protected options: SubscriptionOptions; - protected pubnub: PubNub; + protected pubnub: PubNub; protected eventEmitter: EventEmitter; protected subscriptionList: Subscription[] = []; protected listener: Listener; @@ -23,7 +25,7 @@ export class SubscriptionSet extends SubscribeCapable { channelGroups: string[]; subscriptionOptions: SubscriptionOptions; eventEmitter: EventEmitter; - pubnub: PubNub; + pubnub: PubNub; }) { super(); this.options = subscriptionOptions; diff --git a/src/entities/UserMetadata.ts b/src/entities/UserMetadata.ts index 3364374f0..abc11abac 100644 --- a/src/entities/UserMetadata.ts +++ b/src/entities/UserMetadata.ts @@ -1,17 +1,15 @@ +import type { PubNubCore as PubNub } from '../core/pubnub-common'; +import EventEmitter from '../core/components/eventEmitter'; +import { SubscriptionOptions } from './commonTypes'; import { Subscription } from './Subscription'; -import { SubscriptionOptions, EventEmitter } from './commonTypes'; -import type PubNub from '../core/pubnub-common'; export class UserMetadata { - private id: string; - private eventEmitter: EventEmitter; - private pubnub: PubNub; + constructor( + private readonly id: string, + private readonly eventEmitter: EventEmitter, + private readonly pubnub: PubNub, + ) {} - constructor(id: string, eventEmitter: EventEmitter, pubnub: PubNub) { - this.id = id; - this.eventEmitter = eventEmitter; - this.pubnub = pubnub; - } subscription(subscriptionOptions?: SubscriptionOptions) { return new Subscription({ channels: [this.id], diff --git a/src/entities/commonTypes.ts b/src/entities/commonTypes.ts index 496d5047d..cd30c0c61 100644 --- a/src/entities/commonTypes.ts +++ b/src/entities/commonTypes.ts @@ -1,31 +1,4 @@ -import PubNub from 'pubnub'; - export type SubscriptionOptions = { cursor?: { timetoken?: string; region?: number }; receivePresenceEvents?: boolean; }; - -export type EventEmitter = { - emitEvent(e: Event): void; - addListener(l: Listener, channels?: string[], groups?: string[]): void; - removeListener(listener: Listener, channels?: string[], groups?: string[]): void; - removeAllListeners(): void; -}; - -export type Listener = { - message?(m: PubNub.MessageEvent): void; - presence?(p: PubNub.PresenceEvent): void; - signal?(s: PubNub.SignalEvent): void; - objects?(o: PubNub.ObjectsEvent): void; - messageAction?(ma: PubNub.MessageActionEvent): void; - file?(f: PubNub.FileEvent): void; - status?(s: PubNub.StatusEvent): void; -}; - -type Event = - | PubNub.MessageEvent - | PubNub.PresenceEvent - | PubNub.SignalEvent - | PubNub.ObjectsEvent - | PubNub.MessageActionEvent - | PubNub.FileEvent; diff --git a/src/event-engine/core/handler.ts b/src/event-engine/core/handler.ts index 041eba17b..338a922f9 100644 --- a/src/event-engine/core/handler.ts +++ b/src/event-engine/core/handler.ts @@ -1,7 +1,10 @@ import { AbortSignal } from '../../core/components/abort_signal'; export abstract class Handler { - constructor(protected payload: Payload, protected readonly dependencies: Dependencies) {} + constructor( + protected payload: Payload, + protected readonly dependencies: Dependencies, + ) {} abstract start(): void; abstract cancel(): void; diff --git a/src/event-engine/core/retryPolicy.ts b/src/event-engine/core/retryPolicy.ts index a1692ca75..bfd0b657b 100644 --- a/src/event-engine/core/retryPolicy.ts +++ b/src/event-engine/core/retryPolicy.ts @@ -1,18 +1,26 @@ +import { PubNubError } from '../../models/PubNubError'; + export class RetryPolicy { - static LinearRetryPolicy(configuration: LinearRetryPolicyConfiguration) { + static LinearRetryPolicy( + configuration: LinearRetryPolicyConfiguration, + ): RequestRetryPolicy & LinearRetryPolicyConfiguration { return { delay: configuration.delay, maximumRetry: configuration.maximumRetry, + // TODO: Find out actual `error` type. + /* eslint-disable @typescript-eslint/no-explicit-any */ shouldRetry(error: any, attempt: number) { if (error?.status?.statusCode === 403) { return false; } return this.maximumRetry > attempt; }, - getDelay(_: number, reason: any) { + getDelay(_, reason) { const delay = reason.retryAfter ?? this.delay; return (delay + Math.random()) * 1000; }, + // TODO: Find out actual `error` type. + /* eslint-disable @typescript-eslint/no-explicit-any */ getGiveupReason(error: any, attempt: number) { if (this.maximumRetry <= attempt) { return 'retry attempts exhaused.'; @@ -22,40 +30,94 @@ export class RetryPolicy { } return 'unknown error'; }, + validate() { + if (this.maximumRetry > 10) throw new Error('Maximum retry for linear retry policy can not be more than 10'); + }, }; } - static ExponentialRetryPolicy(configuration: ExponentialRetryPolicyConfiguration) { + static ExponentialRetryPolicy( + configuration: ExponentialRetryPolicyConfiguration, + ): RequestRetryPolicy & ExponentialRetryPolicyConfiguration { return { minimumDelay: configuration.minimumDelay, maximumDelay: configuration.maximumDelay, maximumRetry: configuration.maximumRetry, - shouldRetry(error: any, attempt: number) { - if (error?.status?.statusCode === 403) { + shouldRetry(reason, attempt) { + if (reason?.status?.statusCode === 403) { return false; } return this.maximumRetry > attempt; }, - getDelay(attempt: number, reason: any) { + getDelay(attempt, reason) { const delay = reason.retryAfter ?? Math.min(Math.pow(2, attempt), this.maximumDelay); return (delay + Math.random()) * 1000; }, - getGiveupReason(error: any, attempt: number) { + getGiveupReason(reason, attempt) { if (this.maximumRetry <= attempt) { - return 'retry attempts exhaused.'; + return 'retry attempts exhausted.'; } - if (error?.status?.statusCode === 403) { + if (reason?.status?.statusCode === 403) { return 'forbidden operation.'; } return 'unknown error'; }, + + validate() { + if (this.minimumDelay < 2) throw new Error('Minimum delay can not be set less than 2 seconds for retry'); + else if (this.maximumDelay) throw new Error('Maximum delay can not be set more than 150 seconds for retry'); + else if (this.maximumRetry > 6) + throw new Error('Maximum retry for exponential retry policy can not be more than 6'); + }, }; } } +export type RequestRetryPolicy = { + /** + * Check whether failed request can be retried. + * + * @param reason - Request processing failure reason. + * @param attempt - Number of consequent failure. + * + * @returns `true` if another request retry attempt can be done. + */ + shouldRetry(reason: PubNubError & { retryAfter?: number }, attempt: number): boolean; + + /** + * Computed delay for next request retry attempt. + * + * @param attempt - Number of consequent failure. + * @param reason - Request processing failure reason. + * + * @returns Delay before next request retry attempt in milliseconds. + */ + getDelay(attempt: number, reason: PubNubError & { retryAfter?: number }): number; + + /** + * Identify reason why another retry attempt can't be made. + * + * @param reason - Request processing failure reason. + * @param attempt - Number of consequent failure. + * + * @returns Give up reason. + */ + getGiveupReason(reason: PubNubError & { retryAfter?: number }, attempt: number): string; + + /** + * Validate retry policy parameters. + * + * @throws Error if `minimum` delay is smaller than 2 seconds for `exponential` retry policy. + * @throws Error if `maximum` delay is larger than 150 seconds for `exponential` retry policy. + * @throws Error if `maximumRetry` attempts is larger than 6 for `exponential` retry policy. + * @throws Error if `maximumRetry` attempts is larger than 10 for `linear` retry policy. + */ + validate(): void; +}; + export type LinearRetryPolicyConfiguration = { delay: number; maximumRetry: number; diff --git a/src/event-engine/core/types.ts b/src/event-engine/core/types.ts index e5c6f7f2b..a10f31336 100644 --- a/src/event-engine/core/types.ts +++ b/src/event-engine/core/types.ts @@ -1,7 +1,5 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { State } from './state'; - export type Event = { type: T; payload: P }; export type Invocation = { type: T; payload: P; managed: boolean }; diff --git a/src/event-engine/dispatcher.ts b/src/event-engine/dispatcher.ts index 3054d5ee2..00a587c53 100644 --- a/src/event-engine/dispatcher.ts +++ b/src/event-engine/dispatcher.ts @@ -1,21 +1,26 @@ -import { PubNubError } from '../core/components/endpoint'; +import { PrivateClientConfiguration } from '../core/interfaces/configuration'; +import * as Subscription from '../core/types/api/subscription'; +import { PubNubError } from '../models/PubNubError'; import { asyncHandler, Dispatcher, Engine } from './core'; import * as effects from './effects'; import * as events from './events'; +import { Payload, StatusEvent } from '../core/types/api'; export type Dependencies = { - handshake: any; - receiveMessages: any; - join: any; - leave: any; - leaveAll: any; - presenceState: any; - config: any; + handshake: (parameters: Subscription.CancelableSubscribeParameters) => Promise; + receiveMessages: ( + parameters: Subscription.CancelableSubscribeParameters, + ) => Promise; + join?: (parameters: { channels?: string[]; groups?: string[] }) => void; + leave?: (parameters: { channels?: string[]; groups?: string[] }) => void; + leaveAll?: () => void; + presenceState: Record; + config: PrivateClientConfiguration; delay: (milliseconds: number) => Promise; - emitMessages: (events: any[]) => void; - emitStatus: (status: any) => void; + emitMessages: (events: Subscription.SubscriptionResponse['messages']) => void; + emitStatus: (status: StatusEvent) => void; }; export class EventEngineDispatcher extends Dispatcher { @@ -62,7 +67,7 @@ export class EventEngineDispatcher extends Dispatcher ({ channels, @@ -10,11 +10,16 @@ export const handshake = createManagedEffect('HANDSHAKE', (channels: string[], g export const receiveMessages = createManagedEffect( 'RECEIVE_MESSAGES', - (channels: string[], groups: string[], cursor: Cursor) => ({ channels, groups, cursor }), + (channels: string[], groups: string[], cursor: Subscription.SubscriptionCursor) => ({ channels, groups, cursor }), ); -export const emitMessages = createEffect('EMIT_MESSAGES', (events: any[]) => events); +export const emitMessages = createEffect( + 'EMIT_MESSAGES', + (events: Subscription.SubscriptionResponse['messages']) => events, +); +// TODO: Find out actual `status` type. +/* eslint-disable @typescript-eslint/no-explicit-any */ export const emitStatus = createEffect('EMIT_STATUS', (status: any) => status); export const receiveReconnect = createManagedEffect( diff --git a/src/event-engine/events.ts b/src/event-engine/events.ts index c0341d8f0..16e0616c2 100644 --- a/src/event-engine/events.ts +++ b/src/event-engine/events.ts @@ -1,5 +1,5 @@ -import { PubNubError } from '../core/components/endpoint'; -import { Cursor } from '../models/Cursor'; +import * as Subscription from '../core/types/api/subscription'; +import { PubNubError } from '../models/PubNubError'; import { createEvent, MapOf } from './core'; export const subscriptionChange = createEvent('SUBSCRIPTION_CHANGED', (channels: string[], groups: string[]) => ({ @@ -9,7 +9,7 @@ export const subscriptionChange = createEvent('SUBSCRIPTION_CHANGED', (channels: export const restore = createEvent( 'SUBSCRIPTION_RESTORED', - (channels: string[], groups: string[], timetoken: string, region?: number) => ({ + (channels: string[], groups: string[], timetoken: string | number, region?: number) => ({ channels, groups, cursor: { @@ -19,25 +19,34 @@ export const restore = createEvent( }), ); -export const handshakeSuccess = createEvent('HANDSHAKE_SUCCESS', (cursor: Cursor) => cursor); +export const handshakeSuccess = createEvent('HANDSHAKE_SUCCESS', (cursor: Subscription.SubscriptionCursor) => cursor); export const handshakeFailure = createEvent('HANDSHAKE_FAILURE', (error: PubNubError) => error); -export const handshakeReconnectSuccess = createEvent('HANDSHAKE_RECONNECT_SUCCESS', (cursor: Cursor) => ({ - cursor, -})); +export const handshakeReconnectSuccess = createEvent( + 'HANDSHAKE_RECONNECT_SUCCESS', + (cursor: Subscription.SubscriptionCursor) => ({ + cursor, + }), +); export const handshakeReconnectFailure = createEvent('HANDSHAKE_RECONNECT_FAILURE', (error: PubNubError) => error); export const handshakeReconnectGiveup = createEvent('HANDSHAKE_RECONNECT_GIVEUP', (error: PubNubError) => error); -export const receiveSuccess = createEvent('RECEIVE_SUCCESS', (cursor: Cursor, events: any[]) => ({ - cursor, - events, -})); +export const receiveSuccess = createEvent( + 'RECEIVE_SUCCESS', + (cursor: Subscription.SubscriptionCursor, events: Subscription.SubscriptionResponse['messages']) => ({ + cursor, + events, + }), +); export const receiveFailure = createEvent('RECEIVE_FAILURE', (error: PubNubError) => error); -export const receiveReconnectSuccess = createEvent('RECEIVE_RECONNECT_SUCCESS', (cursor: Cursor, events: any[]) => ({ - cursor, - events, -})); +export const receiveReconnectSuccess = createEvent( + 'RECEIVE_RECONNECT_SUCCESS', + (cursor: Subscription.SubscriptionCursor, events: Subscription.SubscriptionResponse['messages']) => ({ + cursor, + events, + }), +); export const receiveReconnectFailure = createEvent('RECEIVE_RECONNECT_FAILURE', (error: PubNubError) => error); export const receiveReconnectGiveup = createEvent('RECEIVING_RECONNECT_GIVEUP', (error: PubNubError) => error); export const disconnect = createEvent('DISCONNECT', () => ({})); diff --git a/src/event-engine/index.ts b/src/event-engine/index.ts index c4fb5a0a1..1a189fc4d 100644 --- a/src/event-engine/index.ts +++ b/src/event-engine/index.ts @@ -15,7 +15,7 @@ export class EventEngine { return this.engine; } - private _unsubscribeEngine!: () => void; + private readonly _unsubscribeEngine!: () => void; constructor(dependencies: Dependencies) { this.dependencies = dependencies; @@ -41,7 +41,7 @@ export class EventEngine { }: { channels?: string[]; channelGroups?: string[]; - timetoken?: string; + timetoken?: string | number; withPresence?: boolean; }): void { this.channels = [...this.channels, ...(channels ?? [])]; @@ -136,11 +136,11 @@ export class EventEngine { } getSubscribedChannels(): string[] { - return this.channels.slice(0); + return Array.from(new Set(this.channels.slice(0))); } getSubscribedChannelGroups(): string[] { - return this.groups.slice(0); + return Array.from(new Set(this.groups.slice(0))); } dispose(): void { diff --git a/src/event-engine/presence/dispatcher.ts b/src/event-engine/presence/dispatcher.ts index 39c455362..51651f741 100644 --- a/src/event-engine/presence/dispatcher.ts +++ b/src/event-engine/presence/dispatcher.ts @@ -1,18 +1,25 @@ -import { PubNubError } from '../../core/components/endpoint'; +import { PrivateClientConfiguration } from '../../core/interfaces/configuration'; import { asyncHandler, Dispatcher, Engine } from '../core'; import PNOperations from '../../core/constants/operations'; +import * as Presence from '../../core/types/api/presence'; +import { PubNubError } from '../../models/PubNubError'; +import { Payload } from '../../core/types/api'; import * as effects from './effects'; import * as events from './events'; export type Dependencies = { - heartbeat: any; - leave: any; + heartbeat: ( + parameters: Presence.PresenceHeartbeatParameters, + ) => Promise; + leave: (parameters: Presence.PresenceLeaveParameters) => void; heartbeatDelay: () => Promise; retryDelay: (milliseconds: number) => Promise; - config: any; - presenceState: any; + config: PrivateClientConfiguration; + presenceState: Record; + // TODO: Find out actual `status` type. + /* eslint-disable @typescript-eslint/no-explicit-any */ emitStatus: (status: any) => void; }; @@ -28,6 +35,7 @@ export class PresenceEventEngineDispatcher extends Dispatcher { if (!config.suppressLeaveEvents) { try { - const result = await leave({ + leave({ channels: payload.channels, channelGroups: payload.groups, }); @@ -70,13 +78,16 @@ export class PresenceEventEngineDispatcher extends Dispatcher { if (config.retryConfiguration && config.retryConfiguration.shouldRetry(payload.reason, payload.attempts)) { abortSignal.throwIfAborted(); + await retryDelay(config.retryConfiguration.getDelay(payload.attempts, payload.reason)); + abortSignal.throwIfAborted(); try { const result = await heartbeat({ channels: payload.channels, channelGroups: payload.groups, ...(config.maintainPresenceState && { state: presenceState }), + heartbeat: config.presenceTimeout!, }); return engine.transition(events.heartbeatSuccess(200)); } catch (e) { diff --git a/src/event-engine/presence/effects.ts b/src/event-engine/presence/effects.ts index e60579f5f..3f7f21b1e 100644 --- a/src/event-engine/presence/effects.ts +++ b/src/event-engine/presence/effects.ts @@ -1,5 +1,6 @@ import { createEffect, createManagedEffect, MapOf } from '../core'; import { HeartbeatReconnectingStateContext } from './states/heartbeat_reconnecting'; +import { Status } from '../../core/types/api'; export const heartbeat = createEffect('HEARTBEAT', (channels: string[], groups: string[]) => ({ channels, @@ -11,6 +12,8 @@ export const leave = createEffect('LEAVE', (channels: string[], groups: string[] groups, })); +// TODO: Find out actual `status` type. +/* eslint-disable @typescript-eslint/no-explicit-any */ export const emitStatus = createEffect('EMIT_STATUS', (status: any) => status); export const wait = createManagedEffect('WAIT', () => ({})); diff --git a/src/event-engine/presence/events.ts b/src/event-engine/presence/events.ts index d25642967..07097e395 100644 --- a/src/event-engine/presence/events.ts +++ b/src/event-engine/presence/events.ts @@ -1,4 +1,4 @@ -import { PubNubError } from '../../core/components/endpoint'; +import { PubNubError } from '../../models/PubNubError'; import { createEvent, MapOf } from '../core'; export const reconnect = createEvent('RECONNECT', () => ({})); diff --git a/src/event-engine/presence/presence.ts b/src/event-engine/presence/presence.ts index 05cb03500..768fbed1e 100644 --- a/src/event-engine/presence/presence.ts +++ b/src/event-engine/presence/presence.ts @@ -8,7 +8,6 @@ import { HeartbeatInactiveState } from './states/heartbeat_inactive'; export class PresenceEventEngine { private engine: Engine = new Engine(); private dispatcher: Dispatcher; - private dependencies: any; get _engine() { return this.engine; @@ -16,9 +15,8 @@ export class PresenceEventEngine { private _unsubscribeEngine!: () => void; - constructor(dependencies: Dependencies) { + constructor(private dependencies: Dependencies) { this.dispatcher = new PresenceEventEngineDispatcher(this.engine, dependencies); - this.dependencies = dependencies; this._unsubscribeEngine = this.engine.subscribe((change) => { if (change.type === 'invocationDispatched') { diff --git a/src/event-engine/presence/states/heartbeat_reconnecting.ts b/src/event-engine/presence/states/heartbeat_reconnecting.ts index 099a05e4d..4351ea60b 100644 --- a/src/event-engine/presence/states/heartbeat_reconnecting.ts +++ b/src/event-engine/presence/states/heartbeat_reconnecting.ts @@ -1,5 +1,5 @@ +import { PubNubError } from '../../../models/PubNubError'; import { State } from '../../core/state'; -import { PubNubError } from '../../../core/components/endpoint'; import { Events, disconnect, diff --git a/src/event-engine/states/handshake_failed.ts b/src/event-engine/states/handshake_failed.ts index dd86cd552..618f4c090 100644 --- a/src/event-engine/states/handshake_failed.ts +++ b/src/event-engine/states/handshake_failed.ts @@ -1,15 +1,15 @@ import { State } from '../core/state'; import { Effects } from '../effects'; import { Events, reconnect, restore, subscriptionChange, unsubscribeAll } from '../events'; -import { PubNubError } from '../../core/components/endpoint'; +import { PubNubError } from '../../models/PubNubError'; import { HandshakingState } from './handshaking'; import { UnsubscribedState } from './unsubscribed'; -import { Cursor } from '../../models/Cursor'; +import * as Subscription from '../../core/types/api/subscription'; export type HandshakeFailedStateContext = { channels: string[]; groups: string[]; - cursor?: Cursor; + cursor?: Subscription.SubscriptionCursor; reason: PubNubError; }; diff --git a/src/event-engine/states/handshake_reconnecting.ts b/src/event-engine/states/handshake_reconnecting.ts index 75a2fe6d3..8500479fc 100644 --- a/src/event-engine/states/handshake_reconnecting.ts +++ b/src/event-engine/states/handshake_reconnecting.ts @@ -1,4 +1,4 @@ -import { PubNubError } from '../../core/components/endpoint'; +import { PubNubError } from '../../models/PubNubError'; import { State } from '../core/state'; import { Effects, emitStatus, handshakeReconnect } from '../effects'; import { @@ -17,12 +17,12 @@ import { HandshakingState } from './handshaking'; import { ReceivingState } from './receiving'; import { UnsubscribedState } from './unsubscribed'; import categoryConstants from '../../core/constants/categories'; -import { Cursor } from '../../models/Cursor'; +import * as Subscription from '../../core/types/api/subscription'; export type HandshakeReconnectingStateContext = { channels: string[]; groups: string[]; - cursor?: Cursor; + cursor?: Subscription.SubscriptionCursor; attempts: number; reason: PubNubError; diff --git a/src/event-engine/states/handshake_stopped.ts b/src/event-engine/states/handshake_stopped.ts index 133451f93..e7040c417 100644 --- a/src/event-engine/states/handshake_stopped.ts +++ b/src/event-engine/states/handshake_stopped.ts @@ -1,14 +1,14 @@ -import { Cursor } from '../../models/Cursor'; import { State } from '../core/state'; import { Effects } from '../effects'; import { Events, reconnect, restore, subscriptionChange, unsubscribeAll } from '../events'; import { HandshakingState } from './handshaking'; import { UnsubscribedState } from './unsubscribed'; +import * as Subscription from '../../core/types/api/subscription'; type HandshakeStoppedStateContext = { channels: string[]; groups: string[]; - cursor?: Cursor; + cursor?: Subscription.SubscriptionCursor; }; export const HandshakeStoppedState = new State('HANDSHAKE_STOPPED'); diff --git a/src/event-engine/states/handshaking.ts b/src/event-engine/states/handshaking.ts index 14ea66adc..c2dcdb7b5 100644 --- a/src/event-engine/states/handshaking.ts +++ b/src/event-engine/states/handshaking.ts @@ -14,12 +14,12 @@ import { HandshakeStoppedState } from './handshake_stopped'; import { ReceivingState } from './receiving'; import { UnsubscribedState } from './unsubscribed'; import categoryConstants from '../../core/constants/categories'; -import { Cursor } from '../../models/Cursor'; +import * as Subscription from '../../core/types/api/subscription'; export type HandshakingStateContext = { channels: string[]; groups: string[]; - cursor?: Cursor; + cursor?: Subscription.SubscriptionCursor; }; export const HandshakingState = new State('HANDSHAKING'); diff --git a/src/event-engine/states/receive_failed.ts b/src/event-engine/states/receive_failed.ts index 91de8e787..5fb6fb3c7 100644 --- a/src/event-engine/states/receive_failed.ts +++ b/src/event-engine/states/receive_failed.ts @@ -1,15 +1,15 @@ import { State } from '../core/state'; -import { Cursor } from '../../models/Cursor'; import { Effects } from '../effects'; import { Events, reconnect, restore, subscriptionChange, unsubscribeAll } from '../events'; -import { PubNubError } from '../../core/components/endpoint'; +import { PubNubError } from '../../models/PubNubError'; import { HandshakingState } from './handshaking'; import { UnsubscribedState } from './unsubscribed'; +import * as Subscription from '../../core/types/api/subscription'; export type ReceiveFailedStateContext = { channels: string[]; groups: string[]; - cursor: Cursor; + cursor: Subscription.SubscriptionCursor; reason: PubNubError; }; diff --git a/src/event-engine/states/receive_reconnecting.ts b/src/event-engine/states/receive_reconnecting.ts index 69b550558..d87cd5cd1 100644 --- a/src/event-engine/states/receive_reconnecting.ts +++ b/src/event-engine/states/receive_reconnecting.ts @@ -1,5 +1,4 @@ -import { PubNubError } from '../../core/components/endpoint'; -import { Cursor } from '../../models/Cursor'; +import { PubNubError } from '../../models/PubNubError'; import { State } from '../core/state'; import { Effects, emitMessages, receiveReconnect, emitStatus } from '../effects'; import { @@ -17,11 +16,12 @@ import { ReceiveFailedState } from './receive_failed'; import { ReceiveStoppedState } from './receive_stopped'; import { UnsubscribedState } from './unsubscribed'; import categoryConstants from '../../core/constants/categories'; +import * as Subscription from '../../core/types/api/subscription'; export type ReceiveReconnectingStateContext = { channels: string[]; groups: string[]; - cursor: Cursor; + cursor: Subscription.SubscriptionCursor; attempts: number; reason: PubNubError; diff --git a/src/event-engine/states/receive_stopped.ts b/src/event-engine/states/receive_stopped.ts index 20993b80f..49027d275 100644 --- a/src/event-engine/states/receive_stopped.ts +++ b/src/event-engine/states/receive_stopped.ts @@ -1,14 +1,14 @@ -import { Cursor } from '../../models/Cursor'; import { State } from '../core/state'; import { Effects } from '../effects'; import { Events, reconnect, restore, subscriptionChange, unsubscribeAll } from '../events'; import { HandshakingState } from './handshaking'; import { UnsubscribedState } from './unsubscribed'; +import * as Subscription from '../../core/types/api/subscription'; type ReceiveStoppedStateContext = { channels: string[]; groups: string[]; - cursor: Cursor; + cursor: Subscription.SubscriptionCursor; }; export const ReceiveStoppedState = new State('RECEIVE_STOPPED'); diff --git a/src/event-engine/states/receiving.ts b/src/event-engine/states/receiving.ts index e7789debc..7219f0bf3 100644 --- a/src/event-engine/states/receiving.ts +++ b/src/event-engine/states/receiving.ts @@ -1,5 +1,4 @@ import { State } from '../core/state'; -import { Cursor } from '../../models/Cursor'; import { Effects, emitMessages, emitStatus, receiveMessages } from '../effects'; import { disconnect, @@ -14,11 +13,12 @@ import { UnsubscribedState } from './unsubscribed'; import { ReceiveReconnectingState } from './receive_reconnecting'; import { ReceiveStoppedState } from './receive_stopped'; import categoryConstants from '../../core/constants/categories'; +import * as Subscription from '../../core/types/api/subscription'; export type ReceivingStateContext = { channels: string[]; groups: string[]; - cursor: Cursor; + cursor: Subscription.SubscriptionCursor; }; export const ReceivingState = new State('RECEIVING'); diff --git a/src/file/index.js b/src/file/index.js deleted file mode 100644 index 0975b9062..000000000 --- a/src/file/index.js +++ /dev/null @@ -1 +0,0 @@ -/** */ diff --git a/src/file/modules/node.ts b/src/file/modules/node.ts index dd991d826..bb6c8e4fb 100644 --- a/src/file/modules/node.ts +++ b/src/file/modules/node.ts @@ -1,158 +1,257 @@ +/** + * Node.js {@link PubNub} File object module. + */ + import { Readable, PassThrough } from 'stream'; +import { Buffer } from 'buffer'; import { basename } from 'path'; import fs from 'fs'; -import { FileInterface, FileObject } from '../../core/interfaces/file'; - -const PubNubFile = class PubNubFile implements FileInterface { - contentLength; - mimeType; - - data; - - name; - - supportsFile() { - return false; - } - - supportsBlob() { - return false; - } - - static supportsArrayBuffer() { - return false; - } - - supportsBuffer() { - return typeof Buffer !== 'undefined'; - } - - supportsStream() { - return true; - } - - supportsString() { - return true; - } - - supportsEncryptFile() { - return true; +import { PubNubFileInterface } from '../../core/types/file'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- + +// region Types +/** + * PubNub File instance creation parameters. + */ +export type PubNubFileParameters = { + /** + * Readable stream represents file object content. + */ + stream?: Readable; + + /** + * Buffer or string represents file object content. + */ + data?: Buffer | ArrayBuffer | string; + + /** + * String {@link PubNubFileParameters#data|data} encoding. + * + * @default `utf8` + */ + encoding?: StringEncoding; + + /** + * File object name. + */ + name: string; + + /** + * File object content type. + */ + mimeType?: string; +}; +// endregion + +/** + * Node.js implementation for {@link PubNub} File object. + * + * **Important:** Class should implement constructor and class fields from {@link PubNubFileConstructor}. + */ +export default class PubNubFile implements PubNubFileInterface { + // region Class properties + /** + * Whether {@link Blob} data supported by platform or not. + */ + static supportsBlob = false; + + /** + * Whether {@link File} data supported by platform or not. + */ + static supportsFile = false; + + /** + * Whether {@link Buffer} data supported by platform or not. + */ + static supportsBuffer = true; + + /** + * Whether {@link Stream} data supported by platform or not. + */ + static supportsStream = true; + + /** + * Whether {@link String} data supported by platform or not. + */ + static supportsString = true; + + /** + * Whether {@link ArrayBuffer} supported by platform or not. + */ + static supportsArrayBuffer = true; + + /** + * Whether {@link PubNub} File object encryption supported or not. + */ + static supportsEncryptFile = true; + + /** + * Whether `File Uri` data supported by platform or not. + */ + static supportsFileUri = false; + // endregion + + // region Instance properties + /** + * File object content source. + */ + readonly data: Readable | Buffer; + + /** + * File object content length. + */ + contentLength?: number; + + /** + * File object content type. + */ + mimeType: string; + + /** + * File object name. + */ + name: string; + // endregion + + static create(file: PubNubFileParameters) { + return new PubNubFile(file); } - supportsFileUri() { - return false; - } + constructor(file: PubNubFileParameters) { + const { stream, data, encoding, name, mimeType } = file; + let fileData: Readable | Buffer | undefined; + let contentLength: number | undefined; + let fileMimeType: string | undefined; + let fileName: string | undefined; - constructor({ stream, data, encoding, name, mimeType }, ed: FileObject) { - if ('encoding' in ed) { - const { stream, data, encoding, name, mimeType } = ed; - if (stream instanceof Readable) { - } else if (data instanceof Buffer) { - } else if (typeof data === 'string') { - } - } - if (stream instanceof Readable) { - this.data = stream; + if (stream && stream instanceof Readable) { + fileData = stream; if (stream instanceof fs.ReadStream) { - // $FlowFixMe: incomplete flow node definitions - this.name = basename(stream.path); - this.contentLength = fs.statSync(stream.path).size; + const streamFilePath = stream.path instanceof Buffer ? new TextDecoder().decode(stream.path) : stream.path; + fileName = basename(streamFilePath); + contentLength = fs.statSync(streamFilePath).size; } - } else if ('encoding' in data) { - let d = data; } else if (data instanceof Buffer) { - this.data = Buffer.from(data); + contentLength = data.length; + // Copy content of the source Buffer. + fileData = Buffer.alloc(contentLength!); + data.copy(fileData); + } else if (data instanceof ArrayBuffer) { + contentLength = data.byteLength; + fileData = Buffer.from(data); } else if (typeof data === 'string') { - // $FlowFixMe: incomplete flow node definitions - this.data = Buffer.from(data, encoding ?? 'utf8'); + fileData = Buffer.from(data, encoding ?? 'utf8'); + contentLength = fileData.length; } - if (name) { - this.name = basename(name); - } - - if (mimeType) { - this.mimeType = mimeType; - } + if (contentLength) this.contentLength = contentLength; + if (mimeType) fileMimeType = mimeType; + else fileMimeType = 'application/octet-stream'; + if (name) fileName = basename(name); - if (this.data === undefined) { - throw new Error("Couldn't construct a file out of supplied options."); - } + if (fileData === undefined) throw new Error("Couldn't construct a file out of supplied options."); + if (fileName === undefined) throw new Error("Couldn't guess filename out of the options. Please provide one."); - if (this.name === undefined) { - throw new Error("Couldn't guess filename out of the options. Please provide one."); - } + this.mimeType = fileMimeType; + this.data = fileData; + this.name = fileName; } - toBuffer() { - if (this.data instanceof Buffer) { - return Promise.resolve(Buffer.from(this.data)); - } + /** + * Convert {@link PubNub} File object content to {@link Buffer}. + * + * @returns Asynchronous results of conversion to the {@link Buffer}. + */ + async toBuffer(): Promise { + if (this.data instanceof Buffer) return this.data; - if (this.data instanceof Readable) { - const stream = this.data; - return new Promise((resolve, reject) => { - const chunks = []; - - stream.on('data', (chunk) => chunks.push(chunk)); - stream.once('error', reject); - stream.once('end', () => { - resolve(Buffer.concat(chunks)); - }); - }); - } + const stream = this.data; + return new Promise((resolve, reject) => { + const chunks: Uint8Array[] = []; - if (typeof this.data === 'string') { - return Promise.resolve(Buffer.from(this.data)); - } + stream.on('data', (chunk) => { + chunks.push(chunk); + }); + stream.on('end', () => { + resolve(Buffer.concat(chunks)); + }); - throw new Error("Can't cast to 'buffer'."); + // Handle any errors during streaming + stream.on('error', (error) => reject(error)); + }); } - async toArrayBuffer() { - throw new Error('This feature is only supported in browser environments.'); + /** + * Convert {@link PubNub} File object content to {@link ArrayBuffer}. + * + * @returns Asynchronous results of conversion to the {@link ArrayBuffer}. + */ + async toArrayBuffer(): Promise { + return this.toBuffer().then((buffer) => buffer.buffer); } - async toString(encoding = 'utf8') { - const buffer = await this.toBuffer(); - - return buffer.toString(encoding); + /** + * Convert {@link PubNub} File object content to {@link string}. + * + * @returns Asynchronous results of conversion to the {@link string}. + */ + async toString(encoding: BufferEncoding = 'utf8') { + return this.toBuffer().then((buffer) => buffer.toString(encoding)); } + /** + * Convert {@link PubNub} File object content to {@link Readable} stream. + * + * @returns Asynchronous results of conversion to the {@link Readable} stream. + */ async toStream() { - if (!(this.data instanceof Readable)) { - const input = this.data; - - return new Readable({ - read() { - this.push(Buffer.from(input)); - this.push(null); - }, - }); - } - - const stream = new PassThrough(); - if (this.data instanceof Readable) { + const stream = new PassThrough(); this.data.pipe(stream); + + return stream; } - return stream; + return this.toBuffer().then( + (buffer) => + new Readable({ + read() { + this.push(buffer); + this.push(null); + }, + }), + ); } + /** + * Convert {@link PubNub} File object content to {@link File}. + * + * @throws Error because {@link File} not available in Node.js environment. + */ async toFile() { throw new Error('This feature is only supported in browser environments.'); } + /** + * Convert {@link PubNub} File object content to file `Uri`. + * + * @throws Error because file `Uri` not available in Node.js environment. + */ async toFileUri() { - throw new Error('This feature is only supported in react native environments.'); + throw new Error('This feature is only supported in React Native environments.'); } + /** + * Convert {@link PubNub} File object content to {@link Blob}. + * + * @throws Error because {@link Blob} not available in Node.js environment. + */ async toBlob() { throw new Error('This feature is only supported in browser environments.'); } -}; - -export default PubNubFile; +} diff --git a/src/file/modules/react-native.js b/src/file/modules/react-native.js deleted file mode 100644 index 4d9921862..000000000 --- a/src/file/modules/react-native.js +++ /dev/null @@ -1,167 +0,0 @@ -/* global File, FileReader */ - -import { IFile, FileClass } from '..'; - -const PubNubFile = class PubNubFile { - static supportsFile = typeof File !== 'undefined'; - - static supportsBlob = typeof Blob !== 'undefined'; - - static supportsArrayBuffer = typeof ArrayBuffer !== 'undefined'; - - static supportsBuffer = false; - - static supportsStream = false; - - static supportsString = true; - - static supportsEncryptFile = false; - - static supportsFileUri = true; - - static create(config) { - return new this(config); - } - - data; - - name; - - mimeType; - - constructor(config) { - if (config instanceof File) { - this.data = config; - - this.name = this.data.name; - this.mimeType = this.data.type; - } else if (config.uri) { - // uri upload for react native - this.data = { - uri: config.uri, - name: config.name, - type: config.mimeType, - }; - - this.name = config.name; - - if (config.mimeType) { - this.mimeType = config.mimeType; - } - } else if (config.data) { - this.data = config.data; - this.name = config.name; - - if (config.mimeType) { - this.mimeType = config.mimeType; - } - } else { - throw new Error("Couldn't construct a file out of supplied options. URI or file data required."); - } - - if (this.data === undefined) { - throw new Error("Couldn't construct a file out of supplied options."); - } - - if (this.name === undefined) { - throw new Error("Couldn't guess filename out of the options. Please provide one."); - } - } - - async toBuffer() { - throw new Error('This feature is only supported in Node.js environments.'); - } - - async toStream() { - throw new Error('This feature is only supported in Node.js environments.'); - } - - async toBlob() { - if (this.data && this.data.uri) { - throw new Error('This file contains a file URI and does not contain the file contents.'); - } else if (this.data instanceof File) { - return this.data; - } else { - // data must be a fetch response - return this.data.blob(); - } - } - - async toArrayBuffer() { - if (this.data && this.data.uri) { - throw new Error('This file contains a file URI and does not contain the file contents.'); - } else if (this.data instanceof File) { - return new Promise((resolve, reject) => { - const reader = new FileReader(); - - reader.addEventListener('load', () => { - if (reader.result instanceof ArrayBuffer) { - return resolve(reader.result); - } - }); - - reader.addEventListener('error', () => { - reject(reader.error); - }); - - reader.readAsArrayBuffer(this.data); - }); - } else { - // data must be a fetch response - let result; - - try { - result = await this.data.arrayBuffer(); - } catch (e) { - throw new Error(`Unable to support toArrayBuffer in ReactNative environment: ${e}`); - } - - return result; - } - } - - async toString() { - if (this.data && this.data.uri) { - return JSON.stringify(this.data); - } - if (this.data instanceof File) { - return new Promise((resolve, reject) => { - const reader = new FileReader(); - - reader.addEventListener('load', () => { - if (typeof reader.result === 'string') { - return resolve(reader.result); - } - }); - - reader.addEventListener('error', () => { - reject(reader.error); - }); - - reader.readAsBinaryString(this.data); - }); - } - // data must be a fetch response - return this.data.text(); - } - - async toFile() { - if (this.data.uri) { - throw new Error('This file contains a file URI and does not contain the file contents.'); - } else if (this.data instanceof File) { - return this.data; - } else { - // data must be a fetch response - return this.data.blob(); - } - } - - async toFileUri() { - if (this.data && this.data.uri) { - return this.data; - } - throw new Error('This file does not contain a file URI'); - } -}; - -export default PubNubFile; diff --git a/src/file/modules/react-native.ts b/src/file/modules/react-native.ts new file mode 100644 index 000000000..2a75ef9d9 --- /dev/null +++ b/src/file/modules/react-native.ts @@ -0,0 +1,261 @@ +/* global File, FileReader */ +/** + * React Native {@link PubNub} File object module. + */ + +import { PubNubFileInterface } from '../../core/types/file'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- + +// region Types +/** + * File path-based file. + */ +type FileUri = { uri: string; name: string; mimeType?: string }; + +/** + * Asynchronously fetched file content. + */ +type ReadableFile = { arrayBuffer: () => Promise; blob: () => Promise; text: () => Promise }; + +/** + * PubNub File instance creation parameters. + */ +export type PubNubFileParameters = + | File + | FileUri + | ReadableFile + | { data: string | Blob | ArrayBuffer | ArrayBufferView; name: string; mimeType?: string }; +// endregion + +export class PubNubFile implements PubNubFileInterface { + // region Class properties + /** + * Whether {@link Blob} data supported by platform or not. + */ + static supportsBlob = typeof Blob !== 'undefined'; + + /** + * Whether {@link File} data supported by platform or not. + */ + static supportsFile = typeof File !== 'undefined'; + + /** + * Whether {@link Buffer} data supported by platform or not. + */ + static supportsBuffer = false; + + /** + * Whether {@link Stream} data supported by platform or not. + */ + static supportsStream = false; + + /** + * Whether {@link String} data supported by platform or not. + */ + static supportsString = true; + + /** + * Whether {@link ArrayBuffer} supported by platform or not. + */ + static supportsArrayBuffer = true; + + /** + * Whether {@link PubNub} File object encryption supported or not. + */ + static supportsEncryptFile = false; + + /** + * Whether `File Uri` data supported by platform or not. + */ + static supportsFileUri = true; + // endregion + + // region Instance properties + /** + * File object content source. + */ + readonly data: File | FileUri | ReadableFile; + + /** + * File object content length. + */ + contentLength?: number; + + /** + * File object content type. + */ + mimeType: string; + + /** + * File object name. + */ + name: string; + // endregion + + static create(file: PubNubFileParameters) { + return new PubNubFile(file); + } + + constructor(file: PubNubFileParameters) { + let fileMimeType: string | undefined; + let fileName: string | undefined; + let fileData: PubNubFile['data'] | undefined; + + if (file instanceof File) { + fileData = file; + + fileName = file.name; + fileMimeType = file.type; + } else if ('data' in file) { + const contents = file.data; + + fileMimeType = file.mimeType; + fileName = file.name; + fileData = new File([contents], fileName, { type: fileMimeType }); + } else if ('uri' in file) { + fileMimeType = file.mimeType; + fileName = file.name; + fileData = { + uri: file.uri, + name: file.name, + type: file.mimeType!, + }; + } else throw new Error("Couldn't construct a file out of supplied options. URI or file data required."); + + if (fileData === undefined) throw new Error("Couldn't construct a file out of supplied options."); + if (fileName === undefined) throw new Error("Couldn't guess filename out of the options. Please provide one."); + + this.mimeType = fileMimeType!; + this.data = fileData; + this.name = fileName; + } + + /** + * Convert {@link PubNub} File object content to {@link Buffer}. + * + * @throws Error because {@link Buffer} not available in React Native environment. + */ + async toBuffer() { + throw new Error('This feature is only supported in Node.js environments.'); + } + + /** + * Convert {@link PubNub} File object content to {@link ArrayBuffer}. + * + * @returns Asynchronous results of conversion to the {@link ArrayBuffer}. + * + * @throws Error if provided {@link PubNub} File object content is not supported for this + * operation. + */ + async toArrayBuffer(): Promise { + if (this.data && this.data instanceof File) { + const data = this.data; + + return new Promise((resolve, reject) => { + const reader = new FileReader(); + + reader.addEventListener('load', () => { + if (reader.result instanceof ArrayBuffer) return resolve(reader.result); + }); + reader.addEventListener('error', () => reject(reader.error)); + reader.readAsArrayBuffer(data); + }); + } else if (this.data && 'uri' in this.data) { + throw new Error('This file contains a file URI and does not contain the file contents.'); + } else if (this.data) { + let result: ArrayBuffer | undefined; + + try { + result = await this.data.arrayBuffer(); + } catch (error) { + throw new Error(`Unable to support toArrayBuffer in ReactNative environment: ${error}`); + } + + return result; + } + + throw new Error('Unable convert provided file content type to ArrayBuffer'); + } + + /** + * Convert {@link PubNub} File object content to {@link string}. + * + * @returns Asynchronous results of conversion to the {@link string}. + */ + async toString(): Promise { + if (this.data && 'uri' in this.data) return JSON.stringify(this.data); + else if (this.data && this.data instanceof File) { + const data = this.data; + + return new Promise((resolve, reject) => { + const reader = new FileReader(); + + reader.addEventListener('load', () => { + if (typeof reader.result === 'string') return resolve(reader.result); + }); + reader.addEventListener('error', () => reject(reader.error)); + reader.readAsBinaryString(data); + }); + } + + return this.data.text(); + } + + /** + * Convert {@link PubNub} File object content to {@link Readable} stream. + * + * @throws Error because {@link Readable} stream not available in React Native environment. + */ + async toStream() { + throw new Error('This feature is only supported in Node.js environments.'); + } + + /** + * Convert {@link PubNub} File object content to {@link File}. + * + * @returns Asynchronous results of conversion to the {@link File}. + * + * @throws Error if provided {@link PubNub} File object content is not supported for this + * operation. + */ + async toFile() { + if (this.data instanceof File) return this.data; + else if ('uri' in this.data) + throw new Error('This file contains a file URI and does not contain the file contents.'); + else return this.data.blob(); + } + + /** + * Convert {@link PubNub} File object content to file `Uri`. + * + * @returns Asynchronous results of conversion to file `Uri`. + * + * @throws Error if provided {@link PubNub} File object content is not supported for this + * operation. + */ + async toFileUri() { + if (this.data && 'uri' in this.data) return this.data; + + throw new Error('This file does not contain a file URI'); + } + + /** + * Convert {@link PubNub} File object content to {@link Blob}. + * + * @returns Asynchronous results of conversion to the {@link Blob}. + * + * @throws Error if provided {@link PubNub} File object content is not supported for this + * operation. + */ + async toBlob() { + if (this.data instanceof File) return this.data; + else if (this.data && 'uri' in this.data) + throw new Error('This file contains a file URI and does not contain the file contents.'); + else return this.data.blob(); + } +} + +export default PubNubFile; diff --git a/src/file/modules/web.ts b/src/file/modules/web.ts index 6590ded3b..e4fd3c38b 100644 --- a/src/file/modules/web.ts +++ b/src/file/modules/web.ts @@ -1,110 +1,156 @@ /* global File, FileReader */ - -import { FileInterface, FileObject } from '../../core/interfaces/file'; - -const PubNubFile = class PubNubFile implements FileInterface { - mimeType; - name; - data; - - supportsFile() { - return typeof File !== 'undefined'; - } - - supportsBlob() { - return typeof Blob !== 'undefined'; - } - - supportsArrayBuffer() { - return typeof ArrayBuffer !== 'undefined'; - } - - supportsBuffer() { - return false; - } - - supportsStream() { - return false; - } - - supportsString() { - return true; - } - - supportsEncryptFile() { - return true; - } - - supportsFileUri() { - return false; - } - - constructor(config: FileObject) { - let data, name, mimeType; - if (config instanceof File) { - data = config; - - name = data.name; - mimeType = data.type; - } else if (config.data) { - const contents = config.data; - - data = new File(contents, config.name, { type: config.mimeType }); - - name = config.name; - - if (config.mimeType) { - mimeType = config.mimeType; - } - } - - if (data === undefined) { - throw new Error("Couldn't construct a file out of supplied options."); +/** + * Browser {@link PubNub} File object module. + */ + +import { PubNubFileInterface } from '../../core/types/file'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- + +// region Types +/** + * PubNub File instance creation parameters. + */ +export type PubNubFileParameters = + | File + | { data: string | Blob | ArrayBuffer | ArrayBufferView; name: string; mimeType?: string }; +// endregion + +/** + * Web implementation for {@link PubNub} File object. + * + * **Important:** Class should implement constructor and class fields from {@link PubNubFileConstructor}. + */ +export class PubNubFile implements PubNubFileInterface { + // region Class properties + /** + * Whether {@link Blob} data supported by platform or not. + */ + static supportsBlob = typeof Blob !== 'undefined'; + + /** + * Whether {@link File} data supported by platform or not. + */ + static supportsFile = typeof File !== 'undefined'; + + /** + * Whether {@link Buffer} data supported by platform or not. + */ + static supportsBuffer = false; + + /** + * Whether {@link Stream} data supported by platform or not. + */ + static supportsStream = false; + + /** + * Whether {@link String} data supported by platform or not. + */ + static supportsString = true; + + /** + * Whether {@link ArrayBuffer} supported by platform or not. + */ + static supportsArrayBuffer = true; + + /** + * Whether {@link PubNub} File object encryption supported or not. + */ + static supportsEncryptFile = true; + + /** + * Whether `File Uri` data supported by platform or not. + */ + static supportsFileUri = false; + // endregion + + // region Instance properties + /** + * File object content source. + */ + readonly data: File; + + /** + * File object content length. + */ + contentLength?: number; + + /** + * File object content type. + */ + mimeType: string; + + /** + * File object name. + */ + name: string; + // endregion + + static create(file: PubNubFileParameters) { + return new PubNubFile(file); + } + + constructor(file: PubNubFileParameters) { + let fileMimeType: string | undefined; + let fileName: string | undefined; + let fileData: File | undefined; + + if (file instanceof File) { + fileData = file; + + fileName = file.name; + fileMimeType = file.type; + } else if ('data' in file) { + const contents = file.data; + + fileMimeType = file.mimeType; + fileName = file.name; + fileData = new File([contents], fileName, { type: fileMimeType }); } - if (name === undefined) { - throw new Error("Couldn't guess filename out of the options. Please provide one."); - } + if (fileData === undefined) throw new Error("Couldn't construct a file out of supplied options."); + if (fileName === undefined) throw new Error("Couldn't guess filename out of the options. Please provide one."); - this.data = data; - this.name = name; - this.mimeType = mimeType; + this.mimeType = fileMimeType!; + this.data = fileData; + this.name = fileName; } + /** + * Convert {@link PubNub} File object content to {@link Buffer}. + * + * @throws Error because {@link Buffer} not available in browser environment. + */ async toBuffer() { throw new Error('This feature is only supported in Node.js environments.'); } - async toStream() { - throw new Error('This feature is only supported in Node.js environments.'); - } - - async toFileUri() { - throw new Error('This feature is only supported in react native environments.'); - } - - async toBlob() { - return this.data as File; - } - - async toArrayBuffer() { - return new Promise((resolve, reject) => { + /** + * Convert {@link PubNub} File object content to {@link ArrayBuffer}. + * + * @returns Asynchronous results of conversion to the {@link ArrayBuffer}. + */ + async toArrayBuffer(): Promise { + return new Promise((resolve, reject) => { const reader = new FileReader(); - reader.onload = () => { - if (reader.result instanceof ArrayBuffer) { - resolve(reader.result as ArrayBuffer); - } - }; - - reader.onerror = () => reject(reader.error); - + reader.addEventListener('load', () => { + if (reader.result instanceof ArrayBuffer) return resolve(reader.result); + }); + reader.addEventListener('error', () => reject(reader.error)); reader.readAsArrayBuffer(this.data); }); } + /** + * Convert {@link PubNub} File object content to {@link string}. + * + * @returns Asynchronous results of conversion to the {@link string}. + */ async toString() { - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { const reader = new FileReader(); reader.addEventListener('load', () => { @@ -121,9 +167,39 @@ const PubNubFile = class PubNubFile implements FileInterface { }); } - async toFile() { - return this.data as File; + /** + * Convert {@link PubNub} File object content to {@link Readable} stream. + * + * @throws Error because {@link Readable} stream not available in browser environment. + */ + async toStream() { + throw new Error('This feature is only supported in Node.js environments.'); + } + + /** + * Convert {@link PubNub} File object content to {@link File}. + * + * @returns Asynchronous results of conversion to the {@link File}. + */ + async toFile() { + return this.data; + } + + /** + * Convert {@link PubNub} File object content to file `Uri`. + * + * @throws Error because file `Uri` not available in browser environment. + */ + async toFileUri() { + throw new Error('This feature is only supported in React Native environments.'); } -}; -export default PubNubFile; + /** + * Convert {@link PubNub} File object content to {@link Blob}. + * + * @returns Asynchronous results of conversion to the {@link Blob}. + */ + async toBlob() { + return this.data; + } +} diff --git a/src/models/PubNubError.ts b/src/models/PubNubError.ts new file mode 100644 index 000000000..670bd3c27 --- /dev/null +++ b/src/models/PubNubError.ts @@ -0,0 +1,32 @@ +import { Status } from '../core/types/api'; + +export class PubNubError extends Error { + constructor( + message: string, + public status?: Status, + ) { + super(message); + this.name = this.constructor.name; + this.message = message; + + Object.setPrototypeOf(this, new.target.prototype); + } +} + +function createError( + errorPayload: { message: string; statusCode?: number }, + type: string, +): { message: string; type: string; error: boolean; statusCode: number } { + errorPayload.statusCode ??= 0; + + return { + ...errorPayload, + statusCode: errorPayload.statusCode!, + error: true, + type, + }; +} + +export function createValidationError(message: string, statusCode?: number) { + return createError({ message, ...(statusCode !== undefined ? { statusCode } : {}) }, 'validationError'); +} diff --git a/src/networking/index.js b/src/networking/index.js deleted file mode 100644 index 74d666294..000000000 --- a/src/networking/index.js +++ /dev/null @@ -1,135 +0,0 @@ -/* */ - -import Config from '../core/components/config'; -import categoryConstants from '../core/constants/categories'; - -export default class { - _modules; - - _config; - - _currentSubDomain; - - _standardOrigin; - - _subscribeOrigin; - - _requestTimeout; - - _coreParams; /* items that must be passed with each request. */ - - constructor(modules) { - this._modules = {}; - - Object.keys(modules).forEach((key) => { - this._modules[key] = modules[key].bind(this); - }); - } - - init(config) { - this._config = config; - - if (Array.isArray(this._config.origin)) { - this._currentSubDomain = Math.floor(Math.random() * this._config.origin.length); - } else { - this._currentSubDomain = 0; - } - - this._coreParams = {}; - - // create initial origins - this.shiftStandardOrigin(); - } - - nextOrigin() { - const protocol = this._config.secure ? 'https://' : 'http://'; - - if (typeof this._config.origin === 'string') { - return `${protocol}${this._config.origin}`; - } - - this._currentSubDomain += 1; - - if (this._currentSubDomain >= this._config.origin.length) { - this._currentSubDomain = 0; - } - - const origin = this._config.origin[this._currentSubDomain]; - - return `${protocol}${origin}`; - } - - hasModule(name) { - return name in this._modules; - } - - // origin operations - shiftStandardOrigin() { - this._standardOrigin = this.nextOrigin(); - - return this._standardOrigin; - } - - getStandardOrigin() { - return this._standardOrigin; - } - - POSTFILE(url, fields, file) { - return this._modules.postfile(url, fields, file); - } - - GETFILE(params, endpoint, callback) { - return this._modules.getfile(params, endpoint, callback); - } - - POST(params, body, endpoint, callback) { - return this._modules.post(params, body, endpoint, callback); - } - - PATCH(params, body, endpoint, callback) { - return this._modules.patch(params, body, endpoint, callback); - } - - GET(params, endpoint, callback) { - return this._modules.get(params, endpoint, callback); - } - - DELETE(params, endpoint, callback) { - return this._modules.del(params, endpoint, callback); - } - - _detectErrorCategory(err) { - if (err.code === 'ENOTFOUND') { - return categoryConstants.PNNetworkIssuesCategory; - } - if (err.code === 'ECONNREFUSED') { - return categoryConstants.PNNetworkIssuesCategory; - } - if (err.code === 'ECONNRESET') { - return categoryConstants.PNNetworkIssuesCategory; - } - if (err.code === 'EAI_AGAIN') { - return categoryConstants.PNNetworkIssuesCategory; - } - - if (err.status === 0 || (err.hasOwnProperty('status') && typeof err.status === 'undefined')) { - return categoryConstants.PNNetworkIssuesCategory; - } - if (err.timeout) return categoryConstants.PNTimeoutCategory; - - if (err.code === 'ETIMEDOUT') { - return categoryConstants.PNNetworkIssuesCategory; - } - - if (err.response) { - if (err.response.badRequest) { - return categoryConstants.PNBadRequestCategory; - } - if (err.response.forbidden) { - return categoryConstants.PNAccessDeniedCategory; - } - } - - return categoryConstants.PNUnknownCategory; - } -} diff --git a/src/networking/modules/web-node.js b/src/networking/modules/web-node.js index ce80930a1..358fe7128 100644 --- a/src/networking/modules/web-node.js +++ b/src/networking/modules/web-node.js @@ -5,28 +5,21 @@ import superagent from 'superagent'; import categories from '../../core/constants/categories'; function log(req) { - const _pickLogger = () => { - if (console && console.log) return console; // eslint-disable-line no-console - if (window && window.console && window.console.log) return window.console; - return console; - }; - const start = new Date().getTime(); const timestamp = new Date().toISOString(); - const logger = _pickLogger(); - logger.log('<<<<<'); - logger.log(`[${timestamp}]`, '\n', req.url, '\n', req.qs); - logger.log('-----'); + console.log('<<<<<'); + console.log(`[${timestamp}]`, '\n', req.url, '\n', req.qs); + console.log('-----'); req.on('response', (res) => { const now = new Date().getTime(); const elapsed = now - start; const timestampDone = new Date().toISOString(); - logger.log('>>>>>>'); + console.log('>>>>>>'); - logger.log(`[${timestampDone} / ${elapsed}]`, '\n', req.url, '\n', req.qs, '\n', res.text); - logger.log('-----'); + console.log(`[${timestampDone} / ${elapsed}]`, '\n', req.url, '\n', req.qs, '\n', res.text); + console.log('-----'); }); } diff --git a/src/networking/utils.js b/src/networking/utils.js index 0d1733599..1c00cdf73 100644 --- a/src/networking/utils.js +++ b/src/networking/utils.js @@ -1,5 +1,8 @@ /* */ +import { Query } from '../core/types/api'; +import { encodeString } from '../core/utils'; + export function encodedKeyValuePair(pairs, key, value) { if (value != null) { if (Array.isArray(value)) { diff --git a/src/node/configuration.ts b/src/node/configuration.ts index e25651e34..4f8d0c747 100644 --- a/src/node/configuration.ts +++ b/src/node/configuration.ts @@ -1,24 +1,30 @@ -import { BaseConfiguration, PrivateConfigurationOptions } from '../core/interfaces/configuration'; -import { TransportKeepAlive } from '../core/interfaces/transport'; +/** + * Node.js specific {@link PubNub} client configuration module. + */ + +import { + UserConfiguration, + ExtendedConfiguration, + setDefaults as setBaseDefaults, +} from '../core/interfaces/configuration'; import { CryptoModule } from '../crypto/modules/NodeCryptoModule/nodeCryptoModule'; -import { FileConstructor } from '../core/interfaces/file'; +import { TransportKeepAlive } from '../core/interfaces/transport'; -export type PrivateNodeConfigurationOptions = PrivateConfigurationOptions; +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults /** - * NodeJS platform PubNub client configuration. + * Whether PubNub client should try utilize existing TCP connection for new requests or not. */ -export interface NodeConfiguration extends BaseConfiguration { - platform: 'node'; - - /** - * If set to `true`, SDK will use the same TCP connection for each HTTP request, instead of - * opening a new one for each new request. - * - * @default `false` - */ - keepAlive?: boolean; +const KEEP_ALIVE = false; +// endregion +/** + * NodeJS platform PubNub client configuration. + */ +export type PubNubConfiguration = UserConfiguration & { /** * Set a custom parameters for setting your connection `keepAlive` if this is set to `true`. */ @@ -26,18 +32,20 @@ export interface NodeConfiguration extends BaseConfiguration { /** * The cryptography module used for encryption and decryption of messages and files. Takes the - * `cipherKey` and `useRandomIVs` parameters as arguments. + * {@link cipherKey} and {@link useRandomIVs} parameters as arguments. * - * For more information, refer to the {@link /docs/sdks/javascript/api-reference/configuration#cryptomodule|cryptoModule} section. + * For more information, refer to the + * {@link /docs/sdks/javascript/api-reference/configuration#cryptomodule|cryptoModule} section. * * @default `not set` */ cryptoModule?: CryptoModule; + // region Deprecated parameters /** * If passed, will encrypt the payloads. * - * @deprecated Pass it to `cryptoModule` instead. + * @deprecated Pass it to {@link cryptoModule} instead. */ cipherKey?: string; @@ -47,7 +55,39 @@ export interface NodeConfiguration extends BaseConfiguration { * When `false` the IV is hard-coded for all requests except for file upload. * * @default `true` - * @deprecated Pass it to `cryptoModule` instead. + * + * @deprecated Pass it to {@link cryptoModule} instead. */ useRandomIVs?: boolean; -} + + /** + * Custom data encryption method. + * + * @deprecated Instead use {@link cryptoModule} for data encryption. + */ + customEncrypt?: (data: string) => string; + + /** + * Custom data decryption method. + * + * @deprecated Instead use {@link cryptoModule} for data decryption. + */ + customDecrypt?: (data: string) => string; + // endregion +}; + +/** + * Apply configuration default values. + * + * @param configuration - User-provided configuration. + * + * @returns Extended {@link PubNub} client configuration object pre-filled with default values. + */ +export const setDefaults = (configuration: PubNubConfiguration): PubNubConfiguration & ExtendedConfiguration => { + return { + // Set base configuration defaults. + ...setBaseDefaults(configuration), + // Set platform-specific options. + keepAlive: configuration.keepAlive ?? KEEP_ALIVE, + }; +}; diff --git a/src/node/index.ts b/src/node/index.ts index c9b3375b9..425ef147d 100755 --- a/src/node/index.ts +++ b/src/node/index.ts @@ -1,55 +1,103 @@ +import { ProxyAgentOptions } from 'proxy-agent'; import CborReader from 'cbor-sync'; -import PubNubCore from '../core/pubnub-common'; -import Networking from '../networking'; -import Cbor from '../cbor/common'; -import { decode } from '../core/components/base64_codec'; -import { del, get, patch, post, getfile, postfile } from '../networking/modules/web-node'; -import { keepAlive, proxy } from '../networking/modules/node'; +import { Readable } from 'stream'; +import { Buffer } from 'buffer'; -import NodeCryptography from '../crypto/modules/node'; -import PubNubFile from '../file/modules/node'; import { CryptoModule, LegacyCryptor, AesCbcCryptor } from '../crypto/modules/NodeCryptoModule/nodeCryptoModule'; +import PubNubFile, { PubNubFileParameters } from '../file/modules/node'; +import { CryptorConfiguration } from '../core/interfaces/crypto-module'; +import { makeConfiguration } from '../core/components/configuration'; +import { PubNubConfiguration, setDefaults } from './configuration'; +import TokenManager from '../core/components/token_manager'; import { NodeTransport } from '../transport/node-transport'; -import { NodeConfiguration, PrivateNodeConfigurationOptions } from './configuration'; +import { PubNubMiddleware } from '../transport/middleware'; +import { decode } from '../core/components/base64_codec'; +import NodeCryptography from '../crypto/modules/node'; +import Crypto from '../core/components/cryptography'; +import { PubNubError } from '../models/PubNubError'; +import { PubNubCore } from '../core/pubnub-common'; +import Cbor from '../cbor/common'; -export = class extends PubNubCore { +/** + * PubNub client for Node.js platform. + */ +export default class PubNub extends PubNubCore< + string | ArrayBuffer | Buffer | Readable, + PubNubFileParameters, + PubNubFile +> { + /** + * Data encryption / decryption module constructor. + */ static CryptoModule = CryptoModule; - constructor(setup: Exclude) { - setup.cbor = new Cbor((buffer: ArrayBuffer) => CborReader.decode(Buffer.from(buffer)), decode); - setup.networking = new Networking({ - keepAlive, - del, - get, - post, - patch, - proxy, - getfile, - postfile, - }); - setup.sdkFamily = 'Nodejs'; - - setup.PubNubFile = PubNubFile; - setup.cryptography = new NodeCryptography(); - - setup.initCryptoModule = (cryptoConfiguration: any) => { - return new CryptoModule({ - default: new LegacyCryptor({ - cipherKey: cryptoConfiguration.cipherKey, - useRandomIVs: cryptoConfiguration.useRandomIVs, - }), - cryptors: [new AesCbcCryptor({ cipherKey: cryptoConfiguration.cipherKey })], - }); - }; - - if (!('ssl' in setup)) { - setup.ssl = true; - } - { - const { keepAlive, keepAliveSettings } = setup; - const network = new NodeTransport(keepAlive, keepAliveSettings); + /** + * Actual underlying transport provider. + */ + private nodeTransport: NodeTransport; + + constructor(configuration: PubNubConfiguration) { + const configurationCopy = setDefaults(configuration); + const platformConfiguration = { ...configurationCopy, sdkFamily: 'Nodejs', PubNubFile }; + + // Prepare full client configuration. + const clientConfiguration = makeConfiguration( + platformConfiguration, + (cryptoConfiguration: CryptorConfiguration) => { + if (!cryptoConfiguration.cipherKey) return undefined; + + return new CryptoModule({ + default: new LegacyCryptor({ ...cryptoConfiguration }), + cryptors: [new AesCbcCryptor({ cipherKey: cryptoConfiguration.cipherKey })], + }); + }, + ); + + // Prepare Token manager. + const tokenManager = new TokenManager( + new Cbor((buffer: ArrayBuffer) => CborReader.decode(Buffer.from(buffer)), decode), + ); + + // Legacy crypto (legacy data encryption / decryption and request signature support). + let crypto: Crypto | undefined; + if (clientConfiguration.cipherKey || clientConfiguration.secretKey) { + const { secretKey, cipherKey, useRandomIVs, customEncrypt, customDecrypt } = clientConfiguration; + crypto = new Crypto({ secretKey, cipherKey, useRandomIVs, customEncrypt, customDecrypt }); } - super(setup); + // Setup transport provider. + const transport = new NodeTransport(configuration.keepAlive, configuration.keepAliveSettings); + const transportMiddleware = new PubNubMiddleware({ + clientConfiguration, + tokenManager, + transport, + shaHMAC: crypto?.HMACSHA256, + }); + + super({ + configuration: clientConfiguration, + transport: transportMiddleware, + cryptography: new NodeCryptography(), + tokenManager, + crypto, + }); + + this.nodeTransport = transport; + } + + /** + * Update request proxy configuration. + * + * @param configuration - Updated request proxy configuration. + * + * @throws An error if {@link PubNub} client already configured to use `keepAlive`. + * `keepAlive` and `proxy` can't be used simultaneously. + */ + public setProxy(configuration?: ProxyAgentOptions) { + if (configuration && (this._configuration.keepAlive ?? false)) + throw new PubNubError("Can't set 'proxy' because already configured for 'keepAlive'"); + + this.nodeTransport.setProxy(configuration); + this.reconnect(); } -}; +} diff --git a/src/react_native/configuration.ts b/src/react_native/configuration.ts new file mode 100644 index 000000000..02c310ee0 --- /dev/null +++ b/src/react_native/configuration.ts @@ -0,0 +1,19 @@ +import { + UserConfiguration, + ExtendedConfiguration, + setDefaults as setBaseDefaults, +} from '../core/interfaces/configuration'; + +/** + * React Native platform PubNub client configuration. + */ +export type PubNubConfiguration = UserConfiguration; + +/** + * Apply configuration default values. + * + * @param configuration - User-provided configuration. + */ +export const setDefaults = (configuration: PubNubConfiguration): PubNubConfiguration & ExtendedConfiguration => { + return setBaseDefaults(configuration); +}; diff --git a/src/react_native/index.js b/src/react_native/index.js deleted file mode 100644 index 921477ec3..000000000 --- a/src/react_native/index.js +++ /dev/null @@ -1,35 +0,0 @@ -import CborReader from 'cbor-js'; -import { Buffer } from 'buffer'; -import PubNubCore from '../core/pubnub-common'; -import Networking from '../networking'; -import { decode } from '../core/components/base64_codec'; -import { stringifyBufferKeys } from '../core/components/stringify_buffer_keys'; -import Cbor from '../cbor/common'; -import { del, get, post, patch } from '../networking/modules/web-node'; -import { getfile, postfile } from '../networking/modules/react_native'; - -import PubNubFile from '../file/modules/react-native'; -import { stringifyBufferKeys } from '../web'; - -global.Buffer = global.Buffer || Buffer; - -export default class extends PubNubCore { - constructor(setup) { - setup.cbor = new Cbor((arrayBuffer) => stringifyBufferKeys(CborReader.decode(arrayBuffer)), decode); - - setup.PubNubFile = PubNubFile; - - setup.networking = new Networking({ - del, - get, - post, - patch, - getfile, - postfile, - }); - setup.sdkFamily = 'ReactNative'; - setup.ssl = true; - - super(setup); - } -} diff --git a/src/react_native/index.ts b/src/react_native/index.ts new file mode 100644 index 000000000..edb74d29a --- /dev/null +++ b/src/react_native/index.ts @@ -0,0 +1,57 @@ +import CborReader from 'cbor-js'; +import { Buffer } from 'buffer'; + +import { stringifyBufferKeys } from '../core/components/stringify_buffer_keys'; +import { ReactNativeTransport } from '../transport/react-native-transport'; +import { makeConfiguration } from '../core/components/configuration'; +import { PubNubFileParameters } from '../file/modules/react-native'; +import TokenManager from '../core/components/token_manager'; +import { PubNubMiddleware } from '../transport/middleware'; +import { decode } from '../core/components/base64_codec'; +import Crypto from '../core/components/cryptography'; +import PubNubFile from '../file/modules/react-native'; +import { PubNubConfiguration } from './configuration'; +import { PubNubCore } from '../core/pubnub-common'; +import { setDefaults } from '../web/configuration'; +import Cbor from '../cbor/common'; + +global.Buffer = global.Buffer || Buffer; + +/** + * PubNub client for React Native platform. + */ +export default class PubNub extends PubNubCore { + constructor(configuration: PubNubConfiguration) { + const configurationCopy = setDefaults(configuration); + const platformConfiguration = { ...configurationCopy, sdkFamily: 'ReactNative', PubNubFile }; + + // Prepare full client configuration. + const clientConfiguration = makeConfiguration(platformConfiguration); + + // Prepare Token manager. + const tokenManager = new TokenManager( + new Cbor((arrayBuffer: ArrayBuffer) => stringifyBufferKeys(CborReader.decode(arrayBuffer)), decode), + ); + + // Legacy crypto (legacy data encryption / decryption and request signature support). + let crypto: Crypto | undefined; + if (clientConfiguration.cipherKey || clientConfiguration.secretKey) { + const { secretKey, cipherKey, useRandomIVs, customEncrypt, customDecrypt } = clientConfiguration; + crypto = new Crypto({ secretKey, cipherKey, useRandomIVs, customEncrypt, customDecrypt }); + } + + // Setup transport layer. + const transportMiddleware = new PubNubMiddleware({ + clientConfiguration, + tokenManager, + transport: new ReactNativeTransport(clientConfiguration.keepAlive, clientConfiguration.logVerbosity!), + }); + + super({ + configuration: clientConfiguration, + transport: transportMiddleware, + tokenManager, + crypto, + }); + } +} diff --git a/src/transport/middleware.ts b/src/transport/middleware.ts index c6ba51e96..e4fbca2f8 100644 --- a/src/transport/middleware.ts +++ b/src/transport/middleware.ts @@ -1,52 +1,33 @@ -import { Transport } from '../core/interfaces/transport'; import { TransportMethod, TransportRequest } from '../core/types/transport-request'; -import { TransportResponse } from '../core/types/transport-response'; -import uuidGenerator from '../core/components/uuid'; +import { PrivateClientConfiguration } from '../core/interfaces/configuration'; +import TokenManager from '../core/components/token_manager'; +import { Transport } from '../core/interfaces/transport'; import { encodeString } from '../core/utils'; +import { Query } from '../core/types/api'; -// Current SDK version. -const PUBNUB_SDK_VERSION = '7.5.0'; - +/** + * Transport middleware configuration options. + */ type PubNubMiddlewareConfiguration = { - userId: string; - authKey?: string; - accessToken?: string; - /** - * Whether or not to include the PubNub object instance ID in outgoing requests. + * Private client configuration. */ - useInstanceId: boolean; + clientConfiguration: PrivateClientConfiguration; /** - * Unique PubNub client instance identifier. + * REST API endpoints access tokens manager. */ - instanceId: string; + tokenManager: TokenManager; /** - * PubNub service origin which should be for REST API calls. + * HMAC-SHA256 hash generator from provided `data`. */ - origin: string; + shaHMAC?: (data: string) => string; /** * Platform-specific transport for requests processing. */ transport: Transport; - - /** - * Track of the SDK family for identifier generator. - */ - sdkFamily: string; - - /** - * If the SDK is running as part of another SDK built atop of it, allow a custom pnsdk with - * name and version. - */ - sdkName: string; - - /** - * If the SDK is operated by a partner, allow a custom pnsdk item for them. - */ - partnerId?: string; }; export class RequestSignature { @@ -66,14 +47,14 @@ export class RequestSignature { public signature(req: TransportRequest): string { const method = req.path.startsWith('/publish') ? TransportMethod.GET : req.method; - let signatureInput = `${method}\n${this.publishKey}\n${req.path}\n${this.queryParameters(req.queryParameters)}\n`; + let signatureInput = `${method}\n${this.publishKey}\n${req.path}\n${this.queryParameters(req.queryParameters!)}\n`; if (method === TransportMethod.POST || method === TransportMethod.PATCH) { const body = req.body; let payload: string | undefined; if (body && body instanceof ArrayBuffer) { payload = RequestSignature.textDecoder.decode(body); - } else if (body) { + } else if (body && typeof body !== 'object') { payload = body; } @@ -92,25 +73,52 @@ export class RequestSignature { * @param query - Key / value pair of the request query parameters. * @private */ - private queryParameters(query: Record = {}) { + private queryParameters(query: Query) { return Object.keys(query) .sort() - .map((key) => `${key}=${encodeString(query[key])}`) + .map((key) => { + const queryValue = query[key]; + if (!Array.isArray(queryValue)) return `${key}=${encodeString(queryValue)}`; + + return queryValue + .sort() + .map((value) => `${key}=${encodeString(value)}`) + .join('&'); + }) .join('&'); } } export class PubNubMiddleware implements Transport { - constructor(private configuration: PubNubMiddlewareConfiguration) {} + /** + * Request signature generator. + */ + signatureGenerator?: RequestSignature; - async send(req: TransportRequest): Promise { + constructor(private configuration: PubNubMiddlewareConfiguration) { + const { + clientConfiguration: { keySet }, + shaHMAC, + } = configuration; + + if (keySet.secretKey && shaHMAC) + this.signatureGenerator = new RequestSignature(keySet.publishKey!, keySet.secretKey, shaHMAC); + } + + makeSendable(req: TransportRequest) { + return this.configuration.transport.makeSendable(this.request(req)); + } + + request(req: TransportRequest): TransportRequest { + const { clientConfiguration } = this.configuration; if (!req.queryParameters) req.queryParameters = {}; // Modify request with required information. - req.queryParameters['uuid'] = this.configuration.userId; - req.queryParameters['requestid'] = uuidGenerator.createUUID(); - if (this.configuration.useInstanceId) req.queryParameters['instanceid'] = this.configuration.instanceId; + if (clientConfiguration.useInstanceId) req.queryParameters['instanceid'] = clientConfiguration.instanceId!; + if (!req.queryParameters['uuid']) req.queryParameters['uuid'] = clientConfiguration.userId; + req.queryParameters['requestid'] = req.identifier; req.queryParameters['pnsdk'] = this.generatePNSDK(); + req.origin ??= clientConfiguration.origin as string; // Authenticate request if required. this.authenticateRequest(req); @@ -118,33 +126,47 @@ export class PubNubMiddleware implements Transport { // Sign request if it is required. this.signRequest(req); - return this.configuration.transport.send(req); + return req; } private authenticateRequest(req: TransportRequest) { - if (!req.path.startsWith('/v2/auth/') && !req.path.startsWith('/v3/pam/')) return; - if (!req.queryParameters) req.queryParameters = {}; + // Access management endpoints doesn't need authentication (signature required instead). + if (req.path.startsWith('/v2/auth/') || req.path.startsWith('/v3/pam/') || req.path.startsWith('/time')) return; - const accessKey = this.configuration.accessToken ?? this.configuration.authKey; - if (accessKey) req.queryParameters['auth'] = accessKey; + const { clientConfiguration, tokenManager } = this.configuration; + const accessKey = tokenManager.getToken() ?? clientConfiguration.authKey; + if (accessKey) req.queryParameters!['auth'] = accessKey; } + /** + * Compute and append request signature. + * + * @param req - Transport request with information which should be used to generate signature. + */ private signRequest(req: TransportRequest) { - if (!req.queryParameters) req.queryParameters = {}; + if (!this.signatureGenerator || req.path.startsWith('/time')) return; - req.queryParameters['timestamp'] = String(Math.floor(new Date().getTime() / 1000)); - // TODO: ADD CALL TO THE SIGNATURE - req.queryParameters['signature'] = 'dfff'; + req.queryParameters!['timestamp'] = String(Math.floor(new Date().getTime() / 1000)); + req.queryParameters!['signature'] = this.signatureGenerator.signature(req); } + /** + * Compose `pnsdk` query parameter. + * + * SDK provides ability to set custom name or append vendor information to the `pnsdk` query + * parameter. + * + * @returns Finalized `pnsdk` query parameter value. + */ private generatePNSDK() { - if (this.configuration.sdkName) return this.configuration.sdkName; + const { clientConfiguration } = this.configuration; + if (clientConfiguration.sdkName) return clientConfiguration.sdkName; - let base = `PubNub-JS-${this.configuration.sdkFamily}`; - if (this.configuration.partnerId) base += `-${this.configuration.partnerId}`; - base += `/${PUBNUB_SDK_VERSION}`; + let base = `PubNub-JS-${clientConfiguration.sdkFamily}`; + if (clientConfiguration.partnerId) base += `-${clientConfiguration.partnerId}`; + base += `/${clientConfiguration.version}`; - const pnsdkSuffix = config._getPnsdkSuffix(' '); + const pnsdkSuffix = clientConfiguration._getPnsdkSuffix(' '); if (pnsdkSuffix.length > 0) base += pnsdkSuffix; return base; diff --git a/src/transport/node-transport.ts b/src/transport/node-transport.ts index 5673a2b66..8f73e0cb6 100644 --- a/src/transport/node-transport.ts +++ b/src/transport/node-transport.ts @@ -1,16 +1,31 @@ +import fetch, { Request, Response, RequestInit } from 'node-fetch'; +import { ProxyAgent, ProxyAgentOptions } from 'proxy-agent'; import { Agent as HttpsAgent } from 'https'; import { Agent as HttpAgent } from 'http'; -import fetch, { Headers, Request, Response } from 'node-fetch'; +import FormData from 'form-data'; +import { Buffer } from 'buffer'; +import { CancellationController, TransportRequest } from '../core/types/transport-request'; import { Transport, TransportKeepAlive } from '../core/interfaces/transport'; -import { TransportRequest } from '../core/types/transport-request'; import { TransportResponse } from '../core/types/transport-response'; -import { BaseTransport } from './transport'; +import { queryStringFromObject } from '../core/utils'; +import { PubNubAPIError } from '../core/types/api'; /** - * Class representing a fetch-based Node.JS transport provider. + * Class representing a fetch-based Node.js transport provider. */ -export class NodeTransport extends BaseTransport implements Transport { +export class NodeTransport implements Transport { + /** + * Service {@link ArrayBuffer} response decoder. + */ + protected static decoder = new TextDecoder(); + + /** + * Request proxy configuration. + */ + private proxyConfiguration?: ProxyAgentOptions; + + private proxyAgent?: ProxyAgent; private httpsAgent?: HttpsAgent; private httpAgent?: HttpAgent; @@ -19,42 +34,129 @@ export class NodeTransport extends BaseTransport implements Transport { * * @param keepAlive - Indicates whether keep-alive should be enabled. * @param [keepAliveSettings] - Optional settings for keep-alive. + * @param [logVerbosity] - Whether verbose logging enabled or not. * * @returns Transport for performing network requests. */ - constructor(private keepAlive: boolean = false, private keepAliveSettings: TransportKeepAlive = { timeout: 30000 }) { - super(); + constructor( + private keepAlive: boolean = false, + private keepAliveSettings: TransportKeepAlive = { timeout: 30000 }, + private readonly logVerbosity: boolean = false, + ) {} + + /** + * Update request proxy configuration. + * + * @param configuration - New proxy configuration. + */ + public setProxy(configuration?: ProxyAgentOptions) { + this.proxyConfiguration = configuration; } - async send(req: TransportRequest): Promise { - const request = this.requestFromTransportRequest(req); - return this.transportResponseFromResponse(await fetch(request)); + makeSendable(req: TransportRequest): [Promise, CancellationController | undefined] { + let controller: CancellationController | undefined = undefined; + let abortController: AbortController | undefined; + + if (req.cancellable) { + abortController = new AbortController(); + controller = { + // Storing controller inside to prolong object lifetime. + abortController, + abort: () => abortController?.abort(), + } as CancellationController; + } + + return [ + this.requestFromTransportRequest(req).then((request) => { + const start = new Date().getTime(); + + this.logRequestProcessProgress(request); + + return fetch(request, { + signal: abortController?.signal, + timeout: req.timeout * 1000, + } as RequestInit) + .then((response): Promise<[Response, ArrayBuffer]> | [Response, ArrayBuffer | undefined] => { + if (parseInt(response.headers.get('Content-Length')!, 10) > 0) { + return response.arrayBuffer().then((arrayBuffer) => [response, arrayBuffer]); + } + + return [response, undefined]; + }) + .then((response) => { + const { status, headers: requestHeaders } = response[0]; + const headers: Record = {}; + + // Copy Headers object content into plain Record. + requestHeaders.forEach((value, key) => (headers[key] = value.toLowerCase())); + + const transportResponse: TransportResponse = { + status, + url: request.url, + headers, + body: response[1], + }; + + if (status >= 400) throw PubNubAPIError.create(transportResponse); + + this.logRequestProcessProgress(request, new Date().getTime() - start, response[1]); + + return transportResponse; + }) + .catch((error) => { + throw PubNubAPIError.create(error); + }); + }), + controller, + ]; + } + + request(req: TransportRequest): TransportRequest { + return req; } /** - * Creates a Request object from a given TransportRequest object. + * Creates a Request object from a given {@link TransportRequest} object. + * + * @param req - The {@link TransportRequest} object containing request information. * - * @param req - The TransportRequest object containing request information. - * @returns {Request} - The Request object generated from the TransportRequest object. - * @private + * @returns Request object generated from the {@link TransportRequest} object. */ - private requestFromTransportRequest(req: TransportRequest): Request { + private async requestFromTransportRequest(req: TransportRequest): Promise { let headers: Record | undefined = undefined; + let body: string | ArrayBuffer | FormData | undefined; + let path = req.path; if (req.headers) { headers = {}; - for (const [key, value] of Object.entries(req.headers)) { - headers[key] = value; - } + for (const [key, value] of Object.entries(req.headers)) headers[key] = value; } - return new Request(req.url, { + if (req.queryParameters && Object.keys(req.queryParameters).length !== 0) + path = `${path}?${queryStringFromObject(req.queryParameters)}`; + + if (req.body && typeof req.body === 'object') { + if (req.body instanceof ArrayBuffer) body = req.body; + else { + // Create multipart request body. + const fileData = await req.body.toArrayBuffer(); + const formData = new FormData(); + for (const [key, value] of Object.entries(req.formData ?? {})) formData.append(key, value); + + formData.append('file', Buffer.from(fileData), { contentType: req.body.mimeType, filename: req.body.name }); + body = formData; + + headers = formData.getHeaders(headers); + } + } else body = req.body; + + return new Request(`${req.origin!}${path}`, { agent: this.agentForTransportRequest(req), method: req.method, headers, redirect: 'follow', - body: req.body, - }); + body, + } as RequestInit); } /** @@ -63,15 +165,20 @@ export class NodeTransport extends BaseTransport implements Transport { * If keep alive is not requested, returns undefined. * * @param req - The transport request object. + * * @returns {HttpAgent | HttpsAgent | undefined} - The appropriate agent for the request, or - * undefined if keep alive is not requested. - * @private + * undefined if keep alive or proxy not requested. */ private agentForTransportRequest(req: TransportRequest): HttpAgent | HttpsAgent | undefined { // Don't configure any agents if keep alive not requested. - if (!this.keepAlive) return undefined; + if (!this.keepAlive && !this.proxyConfiguration) return undefined; - const useSecureAgent = req.url.startsWith('https:'); + // Create proxy agent (if possible). + if (this.proxyConfiguration) + return this.proxyAgent ? this.proxyAgent : (this.proxyAgent = new ProxyAgent(this.proxyConfiguration)); + + // Create keep alive agent. + const useSecureAgent = req.origin!.startsWith('https:'); if (useSecureAgent && this.httpsAgent === undefined) this.httpsAgent = new HttpsAgent({ keepAlive: true, ...this.keepAliveSettings }); @@ -81,4 +188,35 @@ export class NodeTransport extends BaseTransport implements Transport { return useSecureAgent ? this.httpsAgent : this.httpAgent; } + + /** + * Log out request processing progress and result. + * + * @param request - Platform-specific + * @param [elapsed] - How many time passed since request processing started. + * @param [body] - Service response (if available). + */ + protected logRequestProcessProgress(request: Request, elapsed?: number, body?: ArrayBuffer) { + if (!this.logVerbosity) return; + + const { protocol, host, pathname, search } = new URL(request.url); + const timestamp = new Date().toISOString(); + + if (!elapsed) { + console.log('<<<<<'); + console.log(`[${timestamp}]`, `\n${protocol}//${host}${pathname}`, `\n${search}`); + console.log('-----'); + } else { + const stringifiedBody = body ? NodeTransport.decoder.decode(body) : undefined; + + console.log('>>>>>>'); + console.log( + `[${timestamp} / ${elapsed}]`, + `\n${protocol}//${host}${pathname}`, + `\n${search}`, + `\n${stringifiedBody}`, + ); + console.log('-----'); + } + } } diff --git a/src/transport/react-native-transport.ts b/src/transport/react-native-transport.ts new file mode 100644 index 000000000..b6cde6f50 --- /dev/null +++ b/src/transport/react-native-transport.ts @@ -0,0 +1,176 @@ +/** + * React Native Transport provider module. + */ + +import { CancellationController, TransportRequest } from '../core/types/transport-request'; +import { TransportResponse } from '../core/types/transport-response'; +import { Transport } from '../core/interfaces/transport'; +import { queryStringFromObject } from '../core/utils'; +import { PubNubAPIError } from '../core/types/api'; + +/** + * Class representing a fetch-based React Native transport provider. + */ +export class ReactNativeTransport implements Transport { + /** + * Service {@link ArrayBuffer} response decoder. + */ + protected static decoder = new TextDecoder(); + + constructor( + private keepAlive: boolean = false, + private readonly logVerbosity: boolean, + ) {} + + makeSendable(req: TransportRequest): [Promise, CancellationController | undefined] { + let controller: CancellationController | undefined; + let abortController: AbortController | undefined; + + if (req.cancellable) { + abortController = new AbortController(); + controller = { + // Storing controller inside to prolong object lifetime. + abortController, + abort: () => abortController?.abort(), + } as CancellationController; + } + + return [ + this.requestFromTransportRequest(req).then((request) => { + const start = new Date().getTime(); + + this.logRequestProcessProgress(request); + + /** + * Setup request timeout promise. + * + * **Note:** Native Fetch API doesn't support `timeout` out-of-box. + */ + const requestTimeout = new Promise((_, reject) => { + const timeoutId = setTimeout(() => { + // Clean up. + clearTimeout(timeoutId); + + reject(new Error('Request timeout')); + }, req.timeout * 1000); + }); + + return Promise.race([ + fetch(request, { + signal: abortController?.signal, + timeout: req.timeout * 1000, + keepalive: this.keepAlive, + } as RequestInit), + requestTimeout, + ]) + .then((response): Promise<[Response, ArrayBuffer]> | [Response, ArrayBuffer | undefined] => { + if (parseInt(response.headers.get('Content-Length')!, 10) > 0) { + return response.arrayBuffer().then((arrayBuffer) => [response, arrayBuffer]); + } + + return [response, undefined]; + }) + .then((response) => { + const { status, headers: requestHeaders } = response[0]; + const headers: Record = {}; + + // Copy Headers object content into plain Record. + requestHeaders.forEach((value, key) => (headers[key] = value.toLowerCase())); + + const transportResponse: TransportResponse = { + status, + url: request.url, + headers, + body: response[1], + }; + + if (status >= 400) throw PubNubAPIError.create(transportResponse); + + this.logRequestProcessProgress(request, new Date().getTime() - start, response[1]); + + return transportResponse; + }) + .catch((error) => { + throw PubNubAPIError.create(error); + }); + }), + controller, + ]; + } + + request(req: TransportRequest): TransportRequest { + return req; + } + + /** + * Creates a Request object from a given {@link TransportRequest} object. + * + * @param req - The {@link TransportRequest} object containing request information. + * + * @returns Request object generated from the {@link TransportRequest} object. + */ + private async requestFromTransportRequest(req: TransportRequest): Promise { + let headers: Record | undefined = undefined; + let body: string | ArrayBuffer | FormData | undefined; + let path = req.path; + + if (req.headers) { + headers = {}; + for (const [key, value] of Object.entries(req.headers)) headers[key] = value; + } + + if (req.queryParameters && Object.keys(req.queryParameters).length !== 0) + path = `${path}?${queryStringFromObject(req.queryParameters)}`; + + if (req.body && typeof req.body === 'object') { + if (req.body instanceof ArrayBuffer) body = req.body; + else { + // Create multipart request body. + const fileData = await req.body.toArrayBuffer(); + const formData = new FormData(); + for (const [key, value] of Object.entries(req.formData ?? {})) formData.append(key, value); + + formData.append('file', new Blob([fileData], { type: req.body.mimeType }), req.body.name); + body = formData; + } + } else body = req.body; + + return new Request(`${req.origin!}${path}`, { + method: req.method, + headers, + redirect: 'follow', + body, + }); + } + + /** + * Log out request processing progress and result. + * + * @param request - Platform-specific + * @param [elapsed] - How many time passed since request processing started. + * @param [body] - Service response (if available). + */ + protected logRequestProcessProgress(request: Request, elapsed?: number, body?: ArrayBuffer) { + if (!this.logVerbosity) return; + + const { protocol, host, pathname, search } = new URL(request.url); + const timestamp = new Date().toISOString(); + + if (!elapsed) { + console.log('<<<<<'); + console.log(`[${timestamp}]`, `\n${protocol}//${host}${pathname}`, `\n${search}`); + console.log('-----'); + } else { + const stringifiedBody = body ? ReactNativeTransport.decoder.decode(body) : undefined; + + console.log('>>>>>>'); + console.log( + `[${timestamp} / ${elapsed}]`, + `\n${protocol}//${host}${pathname}`, + `\n${search}`, + `\n${stringifiedBody}`, + ); + console.log('-----'); + } + } +} diff --git a/src/transport/titanium-transport.ts b/src/transport/titanium-transport.ts deleted file mode 100644 index cb189d085..000000000 --- a/src/transport/titanium-transport.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Transport } from '../core/interfaces/transport'; -import { TransportRequest } from '../core/types/transport-request'; -import { TransportResponse } from '../core/types/transport-response'; - -export class TitaniumTransport implements Transport { - async send(req: TransportRequest): Promise { - return Promise.resolve(undefined); - } -} diff --git a/src/transport/transport.ts b/src/transport/transport.ts deleted file mode 100644 index 3a0dab4c5..000000000 --- a/src/transport/transport.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { Transport } from '../core/interfaces/transport'; -import { TransportRequest } from '../core/types/transport-request'; -import { TransportResponse } from '../core/types/transport-response'; - -type BaseResponse = { - status: number; - headers: { get(name: string): string | null; forEach(callback: (value: string, key: string) => void): void }; - arrayBuffer(): Promise; -}; - -/** - * Represents a base transport class for interpreting service responses into a platform-agnostic - * data type. - */ -export class BaseTransport { - /** - * Interpret service response into platform-agnostic data type. - * - * @param {BaseResponse} response - The BaseResponse object to transport. - * @returns {Promise} - A Promise that resolves to the TransportResponse - * object. - * @protected - */ - protected async transportResponseFromResponse(response: BaseResponse): Promise { - const contentLength = response.headers.get('Content-Length'); - const headers: Record = {}; - let body: ArrayBuffer | undefined; - - // Copy Headers object content into plain Record. - response.headers.forEach((value, key) => { - headers[key] = value; - }); - - if (contentLength ? parseInt(contentLength, 10) : 0 !== 0) { - body = await response.arrayBuffer(); - } - - return { - status: response.status, - headers, - body, - }; - } -} diff --git a/src/transport/web-transport.ts b/src/transport/web-transport.ts index f8cf57216..959f59ed9 100644 --- a/src/transport/web-transport.ts +++ b/src/transport/web-transport.ts @@ -1,32 +1,164 @@ -import { Transport } from '../core/interfaces/transport'; -import { TransportRequest } from '../core/types/transport-request'; +/* global window */ +/** + * Web Transport provider module. + */ + +import { CancellationController, TransportRequest } from '../core/types/transport-request'; import { TransportResponse } from '../core/types/transport-response'; -import { BaseTransport } from './transport'; +import { PubNubAPIError, Query } from '../core/types/api'; +import StatusCategory from '../core/constants/categories'; +import { Transport } from '../core/interfaces/transport'; +import * as PubNubWebWorker from './web-worker'; /** - * Class representing a fetch-based web transport provider. + * RollUp placeholder. */ -export class WebTransport extends BaseTransport implements Transport { - async send(req: TransportRequest): Promise { - const request = this.requestFromTransportRequest(req); - return this.transportResponseFromResponse(await fetch(request)); +const WEB_WORKER_PLACEHOLDER: string = ''; + +/** + * Class representing a fetch-based Web Worker transport provider. + */ +export class WebTransport implements Transport { + /** + * Scheduled requests result handling callback. + */ + callbacks?: Map void; reject: (value: Error) => void }>; + + /** + * Spawned Web Worker. + */ + worker?: Worker; + + constructor( + private keepAlive: boolean = false, + private readonly logVerbosity: boolean, + ) { + this.setupWorker(); } - private requestFromTransportRequest(req: TransportRequest): Request { - let headers: Record | undefined = undefined; + makeSendable(req: TransportRequest): [Promise, CancellationController | undefined] { + let controller: CancellationController | undefined; + const sendRequestEvent: PubNubWebWorker.SendRequestEvent = { + type: 'send-request', + request: req, + }; - if (req.headers) { - headers = {}; - for (const [key, value] of Object.entries(req.headers)) { - headers[key] = value; - } + if (req.cancellable) { + controller = { + abort: () => { + const cancelRequest: PubNubWebWorker.CancelRequestEvent = { + type: 'cancel-request', + identifier: req.identifier, + }; + + // Cancel active request with specified identifier. + this.worker!.postMessage(cancelRequest); + }, + }; } - return new Request(req.url, { - method: req.method, - headers, - redirect: 'follow', - body: req.body, - }); + return [ + new Promise((resolve, reject) => { + // Associate Promise resolution / reject with request identifier for future usage in + // `onmessage` handler block to return results. + this.callbacks!.set(req.identifier, { resolve, reject }); + + // Trigger request processing by Web Worker. + this.worker!.postMessage(sendRequestEvent); + }), + controller, + ]; + } + + request(req: TransportRequest): TransportRequest { + return req; + } + + /** + * Complete PubNub Web Worker setup. + */ + private setupWorker() { + this.worker = new Worker( + URL.createObjectURL(new Blob([WEB_WORKER_PLACEHOLDER], { type: 'application/javascript' })), + { + name: '/pubnub', + type: 'module', + }, + ); + this.callbacks = new Map(); + + // Complete Web Worker initialization. + const setupEvent: PubNubWebWorker.SetupEvent = { + type: 'setup', + logVerbosity: this.logVerbosity, + keepAlive: this.keepAlive, + }; + this.worker.postMessage(setupEvent); + + this.worker.onmessage = (event: MessageEvent) => { + const { data } = event; + if (data.type === 'request-progress-start' || data.type === 'request-progress-end') { + this.logRequestProgress(data); + } else if (data.type === 'request-process-success' || data.type === 'request-process-error') { + const { resolve, reject } = this.callbacks!.get(data.identifier)!; + + if (data.type === 'request-process-success') { + resolve({ + status: data.response.status, + url: data.url, + headers: data.response.headers, + body: data.response.body, + }); + } else { + let category: StatusCategory = StatusCategory.PNUnknownCategory; + let message = 'Unknown error'; + + // Handle client-side issues (if any). + if (data.error) { + if (data.error.type === 'NETWORK_ISSUE') category = StatusCategory.PNNetworkIssuesCategory; + else if (data.error.type === 'TIMEOUT') category = StatusCategory.PNTimeoutCategory; + message = data.error.message; + } + // Handle service error response. + else if (data.response) { + return reject( + PubNubAPIError.create({ + url: data.url, + headers: data.response.headers, + body: data.response.body, + status: data.response.status, + }), + ); + } + + reject(new PubNubAPIError(message, category, 0)); + } + } + }; + } + + /** + * Print request progress information. + * + * @param information - Request progress information from Web Worker. + */ + private logRequestProgress(information: PubNubWebWorker.RequestSendingProgress) { + if (information.type === 'request-progress-start') { + console.log('<<<<<'); + console.log(`[${information.timestamp}]`, '\n', information.url, '\n', JSON.stringify(information.query ?? {})); + console.log('-----'); + } else { + console.log('>>>>>>'); + console.log( + `[${information.timestamp} / ${information.duration}]`, + '\n', + information.url, + '\n', + JSON.stringify(information.query ?? {}), + '\n', + information.response, + ); + console.log('-----'); + } } } diff --git a/src/transport/web-worker.ts b/src/transport/web-worker.ts new file mode 100644 index 000000000..41599e157 --- /dev/null +++ b/src/transport/web-worker.ts @@ -0,0 +1,543 @@ +/** + * Web Worker module. + */ + +import { TransportRequest } from '../core/types/transport-request'; +import { Query } from '../core/types/api'; + +// -------------------------------------------------------- +// ------------------------ Types ------------------------- +// -------------------------------------------------------- + +// region Types + +// region PubNub Core +export type SetupEvent = { + type: 'setup'; + + /** + * Whether verbose logging enabled or not. + */ + logVerbosity: boolean; + + /** + * If set to `true`, SDK will use the same TCP connection for each HTTP request, instead of + * opening a new one for each new request. + * + * @default `true` + */ + keepAlive: boolean; +}; + +/** + * Send HTTP request event. + * + * Request from Web Worker to schedule {@link Request} using provided {@link SendRequestSignal#request|request} data. + */ +export type SendRequestEvent = { + type: 'send-request'; + + /** + * Instruction to construct actual {@link Request}. + */ + request: TransportRequest; +}; + +/** + * Cancel HTTP request event. + */ +export type CancelRequestEvent = { + type: 'cancel-request'; + + /** + * Identifier of request which should be cancelled. + */ + identifier: string; +}; + +/** + * List of known events from the PubNub Core. + */ +export type PubNubEvent = SetupEvent | SendRequestEvent | CancelRequestEvent; +// endregion + +// region Web Worker +/** + * {@link Request} processing start event. + * + * This event will be sent if {@link logVerbosity} set to `true` when worker will receive + * {@link SendRequestEvent}. + */ +export type RequestSendingStart = { + type: 'request-progress-start'; + + /** + * Url of request which has been sent. + */ + url: string; + + /** + * Key / value pairs of request which has been sent. + */ + query?: Query; + + /** + * When request processing started. + */ + timestamp: string; +}; +/** + * {@link Request} processing completion event. + * + * This event will be sent if {@link logVerbosity} set to `true` when worker will receive + * response from service or error. + */ +export type RequestSendingEnd = { + type: 'request-progress-end'; + /** + * Url of request which has been sent. + */ + url: string; + + /** + * Key / value pairs of request which has been sent. + */ + query?: Query; + + /** + * Stringified service response (if `Content-Type` allows it). + */ + response: string | undefined; + + /** + * How long it took to perform request. + */ + duration: number; + + /** + * When request processing ended. + */ + timestamp: string; +}; + +/** + * Request processing progress. + */ +export type RequestSendingProgress = RequestSendingStart | RequestSendingEnd; + +/** + * Request processing error. + * + * Object may include either service error response or client-side processing error object. + */ +export type RequestSendingError = { + type: 'request-process-error'; + + /** + * Failed request identifier. + */ + identifier: string; + + /** + * Url which has been used to perform request. + */ + url: string; + + /** + * Service error response. + */ + response?: RequestSendingSuccess['response']; + + /** + * Client side request processing error. + */ + error?: { + /** + * Name of error object which has been received. + */ + name: string; + + /** + * Available client-side errors. + */ + type: 'NETWORK_ISSUE' | 'ABORTED' | 'TIMEOUT'; + + /** + * Triggered error message. + */ + message: string; + }; +}; + +/** + * Request processing success. + */ +export type RequestSendingSuccess = { + type: 'request-process-success'; + + /** + * Processed request identifier. + */ + identifier: string; + + /** + * Url which has been used to perform request. + */ + url: string; + + /** + * Service success response. + */ + response: { + /** + * Received {@link RequestSendingSuccess#response.body|body} content type. + */ + contentType: string; + + /** + * Received {@link RequestSendingSuccess#response.body|body} content length. + */ + contentLength: number; + + /** + * Response headers key / value pairs. + */ + headers: Record; + + /** + * Response status code. + */ + status: number; + + /** + * Service response. + */ + body?: ArrayBuffer; + }; +}; + +/** + * Request processing results. + */ +export type RequestSendingResult = RequestSendingError | RequestSendingSuccess; + +/** + * List of known events from the PubNub Web Worker. + */ +export type PubNubWebWorkerEvent = RequestSendingProgress | RequestSendingResult; +// endregion +// endregion + +/** + * Map of request identifiers to their abort controllers. + * + * **Note:** Because of message-based nature of interaction it will be impossible to pass actual {@link AbortController} + * to the transport provider code. + */ +const abortControllers: Map = new Map(); +/** + * Service `ArrayBuffer` response decoder. + */ +const decoder = new TextDecoder(); + +/** + * Whether verbose logging enabled or not. + */ +let logVerbosity = false; + +/** + * If set to `true`, SDK will use the same TCP connection for each HTTP request, instead of + * opening a new one for each new request. + * + * @default `true` + */ +let keepAlive = true; + +// -------------------------------------------------------- +// ------------------- Event Handlers --------------------- +// -------------------------------------------------------- +// region Event Handlers +/** + * Handle signals from the PubNub core. + * + * @param event - Event object from the PubNub Core with instructions for worker. + */ +self.onmessage = (event: MessageEvent) => { + const { data } = event; + + if (data.type === 'setup') { + logVerbosity = data.logVerbosity; + keepAlive = data.keepAlive; + } else if (data.type === 'send-request') { + sendRequestEventHandler(data.request); + } + + if (data.type === 'cancel-request') { + const controller = abortControllers.get(data.identifier); + + // Abort request if possible. + if (controller) { + abortControllers.delete(data.identifier); + controller.abort(); + } + } + event.data; +}; + +/** + * Handle request send event. + * + * @param req - Data for {@link Request} creation and scheduling. + */ +const sendRequestEventHandler = (req: TransportRequest) => { + (async () => { + const request = await requestFromTransportRequest(req); + // Request progress support. + const timestamp = new Date().toISOString(); + const start = new Date().getTime(); + + if (req.cancellable) abortControllers.set(req.identifier, new AbortController()); + + /** + * Setup request timeout promise. + * + * **Note:** Native Fetch API doesn't support `timeout` out-of-box. + */ + const requestTimeout = new Promise((_, reject) => { + const timeoutId = setTimeout(() => { + // Clean up. + abortControllers.delete(req.identifier); + clearTimeout(timeoutId); + + reject(new Error('Request timeout')); + }, req.timeout * 1000); + }); + if (logVerbosity) notifyRequestProcessing('start', request, timestamp, req.queryParameters); + + Promise.race([ + fetch(request, { signal: abortControllers.get(req.identifier)?.signal, keepalive: keepAlive }), + requestTimeout, + ]) + .then((response): Promise<[Response, ArrayBuffer]> | [Response, ArrayBuffer | undefined] => { + if (parseInt(response.headers.get('Content-Length')!, 10) > 0) { + return response.arrayBuffer().then((buffer) => [response, buffer]); + } + + return [response, undefined]; + }) + .then((response) => { + if (logVerbosity) { + const contentType = response[0].headers.get('Content-Type'); + const timestampDone = new Date().toISOString(); + const now = new Date().getTime(); + const elapsed = now - start; + let body: string | undefined; + + if ( + contentType && + (contentType.includes('application/json') || + contentType.includes('text/plain') || + contentType.includes('text/html')) + ) { + body = decoder.decode(response[1]); + } + + notifyRequestProcessing('end', request, timestampDone, req.queryParameters, body, elapsed); + } + + // Treat 4xx and 5xx status codes as errors. + if (response[0].status >= 400) + postMessage(requestProcessingError(req.identifier, request.url, undefined, response)); + else postMessage(requestProcessingSuccess(req.identifier, request.url, response)); + }) + .catch((error) => postMessage(requestProcessingError(error, request.url))); + })(); +}; +// endregion + +// -------------------------------------------------------- +// ----------------------- Helpers ------------------------ +// -------------------------------------------------------- + +// region Helpers +const notifyRequestProcessing = ( + type: 'start' | 'end', + request: Request, + timestamp: string, + query?: Query, + response?: string, + duration?: number, +) => { + let event: RequestSendingProgress; + const [url] = request.url.split('?'); + + if (type === 'start') { + event = { + type: 'request-progress-start', + url, + query, + timestamp, + }; + } else { + event = { + type: 'request-progress-end', + url, + query, + response, + timestamp, + duration: duration!, + }; + } + + postMessage(event); +}; + +/** + * Create processing success event from service response. + * + * @param identifier - Identifier of the processed request. + * @param url - Url which has been used to perform request. + * @param res - Service response for used REST API endpoint along with response body. + * + * @returns Request processing success event object. + */ +const requestProcessingSuccess = ( + identifier: string, + url: string, + res: [Response, ArrayBuffer | undefined], +): RequestSendingSuccess => { + const [response, body] = res; + const contentLength = parseInt(response.headers.get('Content-Length')!, 10); + const contentType = response.headers.get('Content-Type')!; + const headers: Record = {}; + + // Copy Headers object content into plain Record. + response.headers.forEach((value, key) => (headers[key] = value.toLowerCase())); + + return { + type: 'request-process-success', + identifier, + url, + response: { + contentLength, + contentType, + headers, + status: response.status, + body, + }, + }; +}; + +/** + * Create processing error event from service response. + * + * @param identifier - Identifier of the failed request. + * @param url - Url which has been used to perform request. + * @param [error] - Client-side request processing error (for example network issues). + * @param [res] - Service error response (for example permissions error or malformed + * payload) along with service body. + * + * @returns Request processing error event object. + */ +const requestProcessingError = ( + identifier: string, + url: string, + error?: unknown, + res?: [Response, ArrayBuffer | undefined], +): RequestSendingError => { + // User service response as error information source. + if (res) { + return { + ...requestProcessingSuccess(identifier, url, res), + type: 'request-process-error', + }; + } + + let type: NonNullable['type'] = 'NETWORK_ISSUE'; + let message = 'Unknown error'; + let name = 'Error'; + + if (error && error instanceof Error) { + message = error.message; + name = error.name; + } + + if (name === 'AbortError') { + message = 'Request aborted'; + type = 'ABORTED'; + } else if (message === 'Request timeout') type = 'TIMEOUT'; + + return { + type: 'request-process-error', + identifier, + url, + error: { name, type, message }, + }; +}; + +/** + * Creates a Request object from a given {@link TransportRequest} object. + * + * @param req - The {@link TransportRequest} object containing request information. + * + * @returns {@link Request} object generated from the {@link TransportRequest} object. + */ +const requestFromTransportRequest = async (req: TransportRequest): Promise => { + let headers: Record | undefined = undefined; + let body: string | ArrayBuffer | FormData | undefined; + let path = req.path; + + if (req.headers) { + headers = {}; + for (const [key, value] of Object.entries(req.headers)) headers[key] = value; + } + + if (req.queryParameters && Object.keys(req.queryParameters).length !== 0) + path = `${path}?${queryStringFromObject(req.queryParameters)}`; + + if (req.body && typeof req.body === 'object') { + if (req.body instanceof ArrayBuffer) body = req.body; + else { + // Create multipart request body. + const fileData = await req.body.toArrayBuffer(); + const formData = new FormData(); + for (const [key, value] of Object.entries(req.formData ?? {})) formData.append(key, value); + + formData.append('file', new Blob([fileData], { type: req.body.mimeType }), req.body.name); + body = formData; + } + } else body = req.body; + + return new Request(`${req.origin!}${path}`, { + method: req.method, + headers, + redirect: 'follow', + body, + }); +}; + +const queryStringFromObject = (query: Query) => { + return Object.keys(query) + .map((key) => { + const queryValue = query[key]; + if (!Array.isArray(queryValue)) return `${key}=${encodeString(queryValue)}`; + + return queryValue.map((value) => `${key}=${encodeString(value)}`).join('&'); + }) + .join('&'); +}; + +/** + * Percent-encode input string. + * + * **Note:** Encode content in accordance of the `PubNub` service requirements. + * + * @param input - Source string or number for encoding. + * + * @returns Percent-encoded string. + */ +const encodeString = (input: string | number) => { + return encodeURIComponent(input).replace(/[!~*'()]/g, (x) => `%${x.charCodeAt(0).toString(16).toUpperCase()}`); +}; + +// endregion diff --git a/src/web/configuration.ts b/src/web/configuration.ts index 15e8c465c..96c7b0887 100644 --- a/src/web/configuration.ts +++ b/src/web/configuration.ts @@ -1,16 +1,32 @@ -import { BaseConfiguration, PrivateConfigurationOptions } from '../core/interfaces/configuration'; -import { TransportKeepAlive } from '../core/interfaces/transport'; -import { CryptoModule } from '../crypto/modules/WebCryptoModule/webCryptoModule'; -import { FileConstructor } from '../core/interfaces/file'; +import { + UserConfiguration, + ExtendedConfiguration, + setDefaults as setBaseDefaults, +} from '../core/interfaces/configuration'; -export type PrivateWebConfigurationOptions = PrivateConfigurationOptions | 'PubNubFile'; +// -------------------------------------------------------- +// ----------------------- Defaults ----------------------- +// -------------------------------------------------------- +// region Defaults /** - * Browser platform PubNub client configuration. + * Whether PubNub client should update its state using browser's reachability events or not. + * + * If the browser fails to detect the network changes from Wi-Fi to LAN and vice versa, or you get + * reconnection issues, set the flag to `false`. This allows the SDK reconnection logic to take over. + */ +const LISTEN_TO_BROWSER_NETWORK_EVENTS = true; + +/** + * Whether PubNub client should try utilize existing TCP connection for new requests or not. */ -export interface WebConfiguration extends BaseConfiguration { - platform: 'browser'; +const KEEP_ALIVE = true; +// endregion +/** + * Browser platform PubNub client configuration. + */ +export type PubNubConfiguration = UserConfiguration & { /** * If the browser fails to detect the network changes from WiFi to LAN and vice versa or you * get reconnection issues, set the flag to `false`. This allows the SDK reconnection logic to @@ -24,41 +40,22 @@ export interface WebConfiguration extends BaseConfiguration { * If set to `true`, SDK will use the same TCP connection for each HTTP request, instead of * opening a new one for each new request. * - * @default `false` - */ - keepAlive?: boolean; - - /** - * Set a custom parameters for setting your connection `keepAlive` if this is set to `true`. - */ - keepAliveSettings?: TransportKeepAlive; - - /** - * The cryptography module used for encryption and decryption of messages and files. Takes the - * `cipherKey` and `useRandomIVs` parameters as arguments. - * - * For more information, refer to the {@link /docs/sdks/javascript/api-reference/configuration#cryptomodule|cryptoModule} section. - * - * @default `not set` - */ - cryptoModule?: CryptoModule; - - /** - * If passed, will encrypt the payloads. - * - * @deprecated Pass it to `cryptoModule` instead. - */ - cipherKey?: string; - - /** - * When `true` the initialization vector (IV) is random for all requests (not just for file - * upload). - * When `false` the IV is hard-coded for all requests except for file upload. - * * @default `true` - * @deprecated Pass it to `cryptoModule` instead. */ - useRandomIVs?: boolean; -} + keepAlive?: boolean; +}; -export type PubNubConfiguration = Exclude; +/** + * Apply configuration default values. + * + * @param configuration - User-provided configuration. + */ +export const setDefaults = (configuration: PubNubConfiguration): PubNubConfiguration & ExtendedConfiguration => { + return { + // Set base configuration defaults. + ...setBaseDefaults(configuration), + // Set platform-specific options. + listenToBrowserNetworkEvents: configuration.listenToBrowserNetworkEvents ?? LISTEN_TO_BROWSER_NETWORK_EVENTS, + keepAlive: configuration.keepAlive ?? KEEP_ALIVE, + }; +}; diff --git a/src/web/index.ts b/src/web/index.ts index b353e0f6c..17eb91312 100644 --- a/src/web/index.ts +++ b/src/web/index.ts @@ -2,68 +2,76 @@ /* global navigator, window */ import CborReader from 'cbor-js'; -import PubNubCore from '../core/pubnub-common'; -import Networking from '../networking'; -import { decode } from '../core/components/base64_codec'; + +import { WebCryptoModule, LegacyCryptor, AesCbcCryptor } from '../crypto/modules/WebCryptoModule/webCryptoModule'; import { stringifyBufferKeys } from '../core/components/stringify_buffer_keys'; +import { CryptorConfiguration } from '../core/interfaces/crypto-module'; +import { PubNubFileParameters, PubNubFile } from '../file/modules/web'; +import { makeConfiguration } from '../core/components/configuration'; +import { PubNubConfiguration, setDefaults } from './configuration'; +import TokenManager from '../core/components/token_manager'; +import { PubNubMiddleware } from '../transport/middleware'; +import { WebTransport } from '../transport/web-transport'; +import { decode } from '../core/components/base64_codec'; +import Crypto from '../core/components/cryptography'; +import WebCryptography from '../crypto/modules/web'; +import { PubNubCore } from '../core/pubnub-common'; import Cbor from '../cbor/common'; -import { del, get, post, patch, getfile, postfile } from '../networking/modules/web-node'; -import WebCryptography from '../crypto/modules/web'; -import PubNubFile from '../file/modules/web'; -import { CryptoModule, LegacyCryptor, AesCbcCryptor } from '../crypto/modules/WebCryptoModule/webCryptoModule'; -import { PrivateWebConfigurationOptions, WebConfiguration } from './configuration'; -import { WebTransport } from '../transport/web-transport'; -import { BaseConfiguration } from '../core/interfaces/configuration'; +/** + * PubNub client for browser platform. + */ +export default class PubNub extends PubNubCore { + /** + * Data encryption / decryption module constructor. + */ + static CryptoModule = WebCryptoModule; -function sendBeacon(url) { - if (navigator && navigator.sendBeacon) { - navigator.sendBeacon(url); - } else { - return false; - } -} + constructor(configuration: PubNubConfiguration) { + const configurationCopy = setDefaults(configuration); + const platformConfiguration = { ...configurationCopy, sdkFamily: 'Nodejs', PubNubFile }; -export default class extends PubNubCore { - static CryptoModule = CryptoModule; - constructor(setup: Exclude) { - // extract config. - const { listenToBrowserNetworkEvents = true } = setup; - setup.sdkFamily = 'Web'; - setup.networking = new Networking({ - del, - get, - post, - patch, - sendBeacon, - getfile, - postfile, - }); - setup.cbor = new Cbor((arrayBuffer) => stringifyBufferKeys(CborReader.decode(arrayBuffer)), decode); + // Prepare full client configuration. + const clientConfiguration = makeConfiguration( + platformConfiguration, + (cryptoConfiguration: CryptorConfiguration) => { + if (!cryptoConfiguration.cipherKey) return undefined; - setup.PubNubFile = PubNubFile; - setup.cryptography = new WebCryptography(); + return new WebCryptoModule({ + default: new LegacyCryptor({ ...cryptoConfiguration }), + cryptors: [new AesCbcCryptor({ cipherKey: cryptoConfiguration.cipherKey })], + }); + }, + ); - setup.initCryptoModule = (cryptoConfiguration) => { - return new CryptoModule({ - default: new LegacyCryptor({ - cipherKey: cryptoConfiguration.cipherKey, - useRandomIVs: cryptoConfiguration.useRandomIVs, - }), - cryptors: [new AesCbcCryptor({ cipherKey: cryptoConfiguration.cipherKey })], - }); - }; + // Prepare Token manager. + const tokenManager = new TokenManager( + new Cbor((arrayBuffer: ArrayBuffer) => stringifyBufferKeys(CborReader.decode(arrayBuffer)), decode), + ); - { - const network = new WebTransport(); + // Legacy crypto (legacy data encryption / decryption and request signature support). + let crypto: Crypto | undefined; + if (clientConfiguration.cipherKey || clientConfiguration.secretKey) { + const { secretKey, cipherKey, useRandomIVs, customEncrypt, customDecrypt } = clientConfiguration; + crypto = new Crypto({ secretKey, cipherKey, useRandomIVs, customEncrypt, customDecrypt }); } - super(setup); + // Setup transport provider. + const transportMiddleware = new PubNubMiddleware({ + clientConfiguration, + tokenManager, + transport: new WebTransport(clientConfiguration.keepAlive, clientConfiguration.logVerbosity!), + }); - this.some(setup); + super({ + configuration: clientConfiguration, + transport: transportMiddleware, + cryptography: new WebCryptography(), + tokenManager, + crypto, + }); - if (listenToBrowserNetworkEvents) { - // mount network events. + if (configuration.listenToBrowserNetworkEvents ?? true) { window.addEventListener('offline', () => { this.networkDownDetected(); }); @@ -73,4 +81,16 @@ export default class extends PubNubCore { }); } } + + private networkDownDetected() { + this.listenerManager.announceNetworkDown(); + + if (this._configuration.restore) this.disconnect(); + else this.destroy(true); + } + + private networkUpDetected() { + this.listenerManager.announceNetworkUp(); + this.reconnect(); + } } diff --git a/test/setup.js b/test/setup.cjs similarity index 100% rename from test/setup.js rename to test/setup.cjs