@webority/mobile-core 0.96.0 → 0.99.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.isJWTExpired=exports.getJWTExpiry=exports.decodeJWT=void 0;var _index=require("../logger/index.js");const base64UrlToBase64=e=>(e+"=".repeat((4-e.length%4)%4)).replace(/-/g,"+").replace(/_/g,"/"),BASE64_ALPHABET="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",decodeBase64Fallback=e=>{let t="";for(let r=0;r<e.length;r+=4){const o=[0,1,2,3].map(t=>BASE64_ALPHABET.indexOf(e[r+t]??"=")),n=Math.max(o[0],0)<<18|Math.max(o[1],0)<<12|Math.max(o[2],0)<<6|Math.max(o[3],0);t+=String.fromCharCode(n>>16&255),-1!==o[2]&&(t+=String.fromCharCode(n>>8&255)),-1!==o[3]&&(t+=String.fromCharCode(255&n))}return t},decodeBase64=e=>"function"==typeof atob?atob(e):decodeBase64Fallback(e),utf8FromBinary=e=>{try{return decodeURIComponent(e.split("").map(e=>"%"+e.charCodeAt(0).toString(16).padStart(2,"0")).join(""))}catch{return e}},decodeJWT=e=>{if(!e||"string"!=typeof e)return null;const t=e.split(".");if(3!==t.length)return _index.Logger.warn("[jwt] decodeJWT: token is not a valid JWT (expected 3 segments)"),null;try{const e=t[1],r=utf8FromBinary(decodeBase64(base64UrlToBase64(e)));return JSON.parse(r)}catch(e){return _index.Logger.warn("[jwt] decodeJWT failed to parse payload",e),null}};exports.decodeJWT=decodeJWT;const isJWTExpired=(e,t=30)=>{const r=decodeJWT(e);if(!r||"number"!=typeof r.exp)return!0;const o=Math.floor(Date.now()/1e3);return r.exp<=o+t};exports.isJWTExpired=isJWTExpired;const getJWTExpiry=e=>{const t=decodeJWT(e);return t&&"number"==typeof t.exp?new Date(1e3*t.exp):null};exports.getJWTExpiry=getJWTExpiry;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.isJWTExpired=exports.getJWTExpiry=exports.decodeJWT=void 0;var _index=require("../logger/index.js");const base64UrlToBase64=e=>(e+"=".repeat((4-e.length%4)%4)).replace(/-/g,"+").replace(/_/g,"/"),BASE64_ALPHABET="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",decodeBase64Fallback=e=>{let t="";for(let r=0;r<e.length;r+=4){const o=[0,1,2,3].map(t=>BASE64_ALPHABET.indexOf(e[r+t]??"=")),n=Math.max(o[0],0)<<18|Math.max(o[1],0)<<12|Math.max(o[2],0)<<6|Math.max(o[3],0);t+=String.fromCharCode(n>>16&255),-1!==o[2]&&(t+=String.fromCharCode(n>>8&255)),-1!==o[3]&&(t+=String.fromCharCode(255&n))}return t},decodeBase64=e=>"function"==typeof atob?atob(e):decodeBase64Fallback(e),utf8FromBinary=e=>{try{return decodeURIComponent(e.split("").map(e=>`%${e.charCodeAt(0).toString(16).padStart(2,"0")}`).join(""))}catch{return e}},decodeJWT=e=>{if(!e||"string"!=typeof e)return null;const t=e.split(".");if(3!==t.length)return _index.Logger.warn("[jwt] decodeJWT: token is not a valid JWT (expected 3 segments)"),null;try{const e=t[1],r=utf8FromBinary(decodeBase64(base64UrlToBase64(e)));return JSON.parse(r)}catch(e){return _index.Logger.warn("[jwt] decodeJWT failed to parse payload",e),null}};exports.decodeJWT=decodeJWT;const isJWTExpired=(e,t=30)=>{const r=decodeJWT(e);if(!r||"number"!=typeof r.exp)return!0;const o=Math.floor(Date.now()/1e3);return r.exp<=o+t};exports.isJWTExpired=isJWTExpired;const getJWTExpiry=e=>{const t=decodeJWT(e);return t&&"number"==typeof t.exp?new Date(1e3*t.exp):null};exports.getJWTExpiry=getJWTExpiry;
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.withdrawBroadcastConsent=exports.initPushBroadcasts=exports.handleBroadcastOpen=exports.handleBroadcastAction=exports.grantBroadcastConsent=exports.getBroadcastConsent=exports.BROADCAST_OPT_OUT_ACTION=void 0;var _reactNative=require("react-native"),_publicClient=_interopRequireDefault(require("../api/publicClient.js")),_userClient=_interopRequireDefault(require("../api/userClient.js")),_index=require("../config/index.js"),_index2=require("../errors/index.js"),_index3=require("../logger/index.js"),_push=require("./push.js");function _interopRequireDefault(t){return t&&t.__esModule?t:{default:t}}const BROADCAST_OPT_OUT_ACTION=exports.BROADCAST_OPT_OUT_ACTION="broadcast-opt-out",WITHDRAW_FROM_PUSH_ROUTE="/consent/withdraw-from-push",OPENS_ROUTE="/opens";let broadcastsConfig=null;const reportedOpens=new Set,requireBroadcastsConfig=()=>{if(!broadcastsConfig)throw new Error("[@webority/mobile-core] call initPushBroadcasts before using push broadcasts.");return broadcastsConfig},clientName=()=>[_reactNative.Platform.OS,(0,_index.getConfigValue)("appId"),(0,_index.getConfigValue)("appVersion")].filter(Boolean).join(" "),toConsent=t=>({status:t.status,statusDateTimeUtc:t.statusDateTimeUtc??null}),initPushBroadcasts=t=>{if(!t.basePath.startsWith("/")||t.basePath.endsWith("/"))throw new Error("[@webority/mobile-core] PushBroadcastsConfig.basePath must start with / and not end with /.");broadcastsConfig=t,(0,_push.setCategories)([{id:t.categoryId,actions:[{id:BROADCAST_OPT_OUT_ACTION,title:t.optOutTitle,opensApp:!1}]}]).catch(t=>_index3.Logger.error("[push] registering the broadcast category failed",t))};exports.initPushBroadcasts=initPushBroadcasts;const getBroadcastConsent=async()=>{const{basePath:t}=requireBroadcastsConfig();try{const e=await _userClient.default.get(`${t}/consent`);return toConsent(e.data)}catch(t){throw(0,_index2.extractApiError)(t)}};exports.getBroadcastConsent=getBroadcastConsent;const grantBroadcastConsent=async()=>{const{basePath:t,consentTextVersion:e}=requireBroadcastsConfig();try{const a=await _userClient.default.post(`${t}/consent/grant`,{consentTextVersion:e,source:"MobileApp",client:clientName()});return toConsent(a.data)}catch(t){throw(0,_index2.extractApiError)(t)}};exports.grantBroadcastConsent=grantBroadcastConsent;const withdrawBroadcastConsent=async()=>{const{basePath:t}=requireBroadcastsConfig();try{const e=await _userClient.default.post(`${t}/consent/withdraw`,{source:"MobileApp",broadcastRecipientId:null,client:clientName()});return toConsent(e.data)}catch(t){throw(0,_index2.extractApiError)(t)}};exports.withdrawBroadcastConsent=withdrawBroadcastConsent;const handleBroadcastAction=async t=>{if(t.actionId!==BROADCAST_OPT_OUT_ACTION||"Broadcast"!==t.data.kind)return;if(!broadcastsConfig)return void _index3.Logger.error("[push] a broadcast opt-out arrived before initPushBroadcasts; call it at module scope in the entry file");const e=t.data.optOutToken;if(e)try{await _publicClient.default.post(`${broadcastsConfig.basePath}${WITHDRAW_FROM_PUSH_ROUTE}`,{token:e})}catch(t){_index3.Logger.warn(`[push] ${WITHDRAW_FROM_PUSH_ROUTE} failed with status ${(0,_index2.extractApiError)(t).status}`)}else _index3.Logger.error("[push] a broadcast opt-out carried no token")};exports.handleBroadcastAction=handleBroadcastAction;const handleBroadcastOpen=t=>{const e=t.broadcastRecipientId;"Broadcast"===t.kind&&e&&(broadcastsConfig?reportedOpens.has(e)||(reportedOpens.add(e),_userClient.default.post(`${broadcastsConfig.basePath}/opens`,{broadcastRecipientId:e}).catch(t=>_index3.Logger.warn(`[push] /opens failed with status ${(0,_index2.extractApiError)(t).status}`))):_index3.Logger.error("[push] a broadcast open arrived before initPushBroadcasts; call it at module scope in the entry file"))};exports.handleBroadcastOpen=handleBroadcastOpen;
@@ -1 +1 @@
1
- "use strict";import{Logger}from"../logger/index.js";const base64UrlToBase64=e=>(e+"=".repeat((4-e.length%4)%4)).replace(/-/g,"+").replace(/_/g,"/"),BASE64_ALPHABET="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",decodeBase64Fallback=e=>{let t="";for(let r=0;r<e.length;r+=4){const o=[0,1,2,3].map(t=>BASE64_ALPHABET.indexOf(e[r+t]??"=")),n=Math.max(o[0],0)<<18|Math.max(o[1],0)<<12|Math.max(o[2],0)<<6|Math.max(o[3],0);t+=String.fromCharCode(n>>16&255),-1!==o[2]&&(t+=String.fromCharCode(n>>8&255)),-1!==o[3]&&(t+=String.fromCharCode(255&n))}return t},decodeBase64=e=>"function"==typeof atob?atob(e):decodeBase64Fallback(e),utf8FromBinary=e=>{try{return decodeURIComponent(e.split("").map(e=>"%"+e.charCodeAt(0).toString(16).padStart(2,"0")).join(""))}catch{return e}};export const decodeJWT=e=>{if(!e||"string"!=typeof e)return null;const t=e.split(".");if(3!==t.length)return Logger.warn("[jwt] decodeJWT: token is not a valid JWT (expected 3 segments)"),null;try{const e=t[1],r=utf8FromBinary(decodeBase64(base64UrlToBase64(e)));return JSON.parse(r)}catch(e){return Logger.warn("[jwt] decodeJWT failed to parse payload",e),null}};export const isJWTExpired=(e,t=30)=>{const r=decodeJWT(e);if(!r||"number"!=typeof r.exp)return!0;const o=Math.floor(Date.now()/1e3);return r.exp<=o+t};export const getJWTExpiry=e=>{const t=decodeJWT(e);return t&&"number"==typeof t.exp?new Date(1e3*t.exp):null};
1
+ "use strict";import{Logger}from"../logger/index.js";const base64UrlToBase64=e=>(e+"=".repeat((4-e.length%4)%4)).replace(/-/g,"+").replace(/_/g,"/"),BASE64_ALPHABET="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",decodeBase64Fallback=e=>{let t="";for(let r=0;r<e.length;r+=4){const o=[0,1,2,3].map(t=>BASE64_ALPHABET.indexOf(e[r+t]??"=")),n=Math.max(o[0],0)<<18|Math.max(o[1],0)<<12|Math.max(o[2],0)<<6|Math.max(o[3],0);t+=String.fromCharCode(n>>16&255),-1!==o[2]&&(t+=String.fromCharCode(n>>8&255)),-1!==o[3]&&(t+=String.fromCharCode(255&n))}return t},decodeBase64=e=>"function"==typeof atob?atob(e):decodeBase64Fallback(e),utf8FromBinary=e=>{try{return decodeURIComponent(e.split("").map(e=>`%${e.charCodeAt(0).toString(16).padStart(2,"0")}`).join(""))}catch{return e}};export const decodeJWT=e=>{if(!e||"string"!=typeof e)return null;const t=e.split(".");if(3!==t.length)return Logger.warn("[jwt] decodeJWT: token is not a valid JWT (expected 3 segments)"),null;try{const e=t[1],r=utf8FromBinary(decodeBase64(base64UrlToBase64(e)));return JSON.parse(r)}catch(e){return Logger.warn("[jwt] decodeJWT failed to parse payload",e),null}};export const isJWTExpired=(e,t=30)=>{const r=decodeJWT(e);if(!r||"number"!=typeof r.exp)return!0;const o=Math.floor(Date.now()/1e3);return r.exp<=o+t};export const getJWTExpiry=e=>{const t=decodeJWT(e);return t&&"number"==typeof t.exp?new Date(1e3*t.exp):null};
@@ -0,0 +1 @@
1
+ "use strict";import{Platform}from"react-native";import publicClient from"../api/publicClient.js";import userClient from"../api/userClient.js";import{getConfigValue}from"../config/index.js";import{extractApiError}from"../errors/index.js";import{Logger}from"../logger/index.js";import{setCategories}from"./push.js";export const BROADCAST_OPT_OUT_ACTION="broadcast-opt-out";const WITHDRAW_FROM_PUSH_ROUTE="/consent/withdraw-from-push",OPENS_ROUTE="/opens";let broadcastsConfig=null;const reportedOpens=new Set,requireBroadcastsConfig=()=>{if(!broadcastsConfig)throw new Error("[@webority/mobile-core] call initPushBroadcasts before using push broadcasts.");return broadcastsConfig},clientName=()=>[Platform.OS,getConfigValue("appId"),getConfigValue("appVersion")].filter(Boolean).join(" "),toConsent=t=>({status:t.status,statusDateTimeUtc:t.statusDateTimeUtc??null});export const initPushBroadcasts=t=>{if(!t.basePath.startsWith("/")||t.basePath.endsWith("/"))throw new Error("[@webority/mobile-core] PushBroadcastsConfig.basePath must start with / and not end with /.");broadcastsConfig=t,setCategories([{id:t.categoryId,actions:[{id:"broadcast-opt-out",title:t.optOutTitle,opensApp:!1}]}]).catch(t=>Logger.error("[push] registering the broadcast category failed",t))};export const getBroadcastConsent=async()=>{const{basePath:t}=requireBroadcastsConfig();try{const o=await userClient.get(`${t}/consent`);return toConsent(o.data)}catch(t){throw extractApiError(t)}};export const grantBroadcastConsent=async()=>{const{basePath:t,consentTextVersion:o}=requireBroadcastsConfig();try{const r=await userClient.post(`${t}/consent/grant`,{consentTextVersion:o,source:"MobileApp",client:clientName()});return toConsent(r.data)}catch(t){throw extractApiError(t)}};export const withdrawBroadcastConsent=async()=>{const{basePath:t}=requireBroadcastsConfig();try{const o=await userClient.post(`${t}/consent/withdraw`,{source:"MobileApp",broadcastRecipientId:null,client:clientName()});return toConsent(o.data)}catch(t){throw extractApiError(t)}};export const handleBroadcastAction=async t=>{if("broadcast-opt-out"!==t.actionId||"Broadcast"!==t.data.kind)return;if(!broadcastsConfig)return void Logger.error("[push] a broadcast opt-out arrived before initPushBroadcasts; call it at module scope in the entry file");const o=t.data.optOutToken;if(o)try{await publicClient.post(`${broadcastsConfig.basePath}${WITHDRAW_FROM_PUSH_ROUTE}`,{token:o})}catch(t){Logger.warn(`[push] ${WITHDRAW_FROM_PUSH_ROUTE} failed with status ${extractApiError(t).status}`)}else Logger.error("[push] a broadcast opt-out carried no token")};export const handleBroadcastOpen=t=>{const o=t.broadcastRecipientId;"Broadcast"===t.kind&&o&&(broadcastsConfig?reportedOpens.has(o)||(reportedOpens.add(o),userClient.post(`${broadcastsConfig.basePath}/opens`,{broadcastRecipientId:o}).catch(t=>Logger.warn(`[push] /opens failed with status ${extractApiError(t).status}`))):Logger.error("[push] a broadcast open arrived before initPushBroadcasts; call it at module scope in the entry file"))};
@@ -0,0 +1,39 @@
1
+ import { type PushActionHandler } from "./push";
2
+ export type BroadcastConsentStatus = "None" | "Granted" | "Withdrawn";
3
+ export interface BroadcastConsent {
4
+ status: BroadcastConsentStatus;
5
+ /** When the status last changed, as UTC text; null when it never did. */
6
+ statusDateTimeUtc: string | null;
7
+ }
8
+ export interface PushBroadcastsConfig {
9
+ /** The route the server maps the broadcast endpoints on. Starts with `/`, does not end with `/`. */
10
+ basePath: string;
11
+ /** The notification category the opt-out button belongs to. */
12
+ categoryId: string;
13
+ /** The wording version the person is shown; the server refuses one it does not list. */
14
+ consentTextVersion: string;
15
+ /** The label of the opt-out button, in the app's own wording. */
16
+ optOutTitle: string;
17
+ }
18
+ export declare const BROADCAST_OPT_OUT_ACTION = "broadcast-opt-out";
19
+ /**
20
+ * Wires the broadcast opt-out for this app. Call it at module scope in the entry
21
+ * file, before definePushActionTask from `/push/task`: a tap on a killed Android
22
+ * app runs that background task without the UI, so the config must already exist.
23
+ */
24
+ export declare const initPushBroadcasts: (config: PushBroadcastsConfig) => void;
25
+ export declare const getBroadcastConsent: () => Promise<BroadcastConsent>;
26
+ export declare const grantBroadcastConsent: () => Promise<BroadcastConsent>;
27
+ export declare const withdrawBroadcastConsent: () => Promise<BroadcastConsent>;
28
+ /**
29
+ * Handles the opt-out button. Call it from the action handler of definePushActionTask,
30
+ * then run the app's own actions. Never throws: a background task has no screen to
31
+ * show a failure on. Logs never carry the token.
32
+ */
33
+ export declare const handleBroadcastAction: PushActionHandler;
34
+ /**
35
+ * Reports that a broadcast was opened. Call it from the onOpen of initPush. Each
36
+ * recipient is reported once per process; a failed report is not retried.
37
+ */
38
+ export declare const handleBroadcastOpen: (data: Record<string, string>) => void;
39
+ //# sourceMappingURL=broadcasts.d.ts.map
@@ -0,0 +1,39 @@
1
+ import { type PushActionHandler } from "./push.js";
2
+ export type BroadcastConsentStatus = "None" | "Granted" | "Withdrawn";
3
+ export interface BroadcastConsent {
4
+ status: BroadcastConsentStatus;
5
+ /** When the status last changed, as UTC text; null when it never did. */
6
+ statusDateTimeUtc: string | null;
7
+ }
8
+ export interface PushBroadcastsConfig {
9
+ /** The route the server maps the broadcast endpoints on. Starts with `/`, does not end with `/`. */
10
+ basePath: string;
11
+ /** The notification category the opt-out button belongs to. */
12
+ categoryId: string;
13
+ /** The wording version the person is shown; the server refuses one it does not list. */
14
+ consentTextVersion: string;
15
+ /** The label of the opt-out button, in the app's own wording. */
16
+ optOutTitle: string;
17
+ }
18
+ export declare const BROADCAST_OPT_OUT_ACTION = "broadcast-opt-out";
19
+ /**
20
+ * Wires the broadcast opt-out for this app. Call it at module scope in the entry
21
+ * file, before definePushActionTask from `/push/task`: a tap on a killed Android
22
+ * app runs that background task without the UI, so the config must already exist.
23
+ */
24
+ export declare const initPushBroadcasts: (config: PushBroadcastsConfig) => void;
25
+ export declare const getBroadcastConsent: () => Promise<BroadcastConsent>;
26
+ export declare const grantBroadcastConsent: () => Promise<BroadcastConsent>;
27
+ export declare const withdrawBroadcastConsent: () => Promise<BroadcastConsent>;
28
+ /**
29
+ * Handles the opt-out button. Call it from the action handler of definePushActionTask,
30
+ * then run the app's own actions. Never throws: a background task has no screen to
31
+ * show a failure on. Logs never carry the token.
32
+ */
33
+ export declare const handleBroadcastAction: PushActionHandler;
34
+ /**
35
+ * Reports that a broadcast was opened. Call it from the onOpen of initPush. Each
36
+ * recipient is reported once per process; a failed report is not retried.
37
+ */
38
+ export declare const handleBroadcastOpen: (data: Record<string, string>) => void;
39
+ //# sourceMappingURL=broadcasts.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webority/mobile-core",
3
- "version": "0.96.0",
3
+ "version": "0.99.0",
4
4
  "description": "Platform layer for Webority React Native apps: HTTP clients, auth/token storage, config, logging, formatters, validators, network status, permissions, storage, version checks and over-the-air updates. No UI.",
5
5
  "keywords": [
6
6
  "react-native",
@@ -202,6 +202,16 @@
202
202
  "default": "./lib/commonjs/push/task.js"
203
203
  }
204
204
  },
205
+ "./push/broadcasts": {
206
+ "import": {
207
+ "types": "./lib/typescript/module/push/broadcasts.d.ts",
208
+ "default": "./lib/module/push/broadcasts.js"
209
+ },
210
+ "require": {
211
+ "types": "./lib/typescript/commonjs/push/broadcasts.d.ts",
212
+ "default": "./lib/commonjs/push/broadcasts.js"
213
+ }
214
+ },
205
215
  "./smsRetriever": {
206
216
  "import": {
207
217
  "types": "./lib/typescript/module/smsRetriever/index.d.ts",