@crmcom/self-service-sdk 3.0.0-build.7 → 3.0.0-build.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,165 @@
1
+ # @crmcom/self-service-sdk
2
+
3
+ Official CRM.COM Self-Service JavaScript SDK for consumer-facing API integration.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @crmcom/self-service-sdk
9
+ ```
10
+
11
+ ### Peer Dependencies
12
+
13
+ ```bash
14
+ npm install jwt-decode js-sha256 xml2js
15
+ ```
16
+
17
+ ## Quick Start
18
+
19
+ ### 1. Initialize the SDK
20
+
21
+ You **must** call `init()` before using any other SDK method. This configures the HTTP layer with your API credentials and session management callbacks.
22
+
23
+ ```js
24
+ import { init } from '@crmcom/self-service-sdk';
25
+
26
+ await init({
27
+ apiKey: 'YOUR_API_KEY',
28
+ host: 'https://api.crm.com',
29
+ storeKVFn: (key, value) => localStorage.setItem(key, value),
30
+ getKVFn: (key) => localStorage.getItem(key),
31
+ sessionInvalidCallback: (shouldLogout) => {
32
+ if (shouldLogout) {
33
+ // redirect to login
34
+ }
35
+ },
36
+ });
37
+ ```
38
+
39
+ ### 2. Use SDK modules
40
+
41
+ Once initialized, import and use any module:
42
+
43
+ ```js
44
+ import { authentication, contacts, orders, wallet } from '@crmcom/self-service-sdk';
45
+
46
+ // Authenticate
47
+ const authResult = await authentication.authenticateEmail({
48
+ username: 'user@example.com',
49
+ password: 'password',
50
+ });
51
+
52
+ // Get contact profile
53
+ const profile = await contacts.getContact();
54
+
55
+ // Browse products
56
+ const products = await orders.getProducts({ page: 1, size: 20 });
57
+
58
+ // Check wallet balance
59
+ const myWallet = await wallet.getWallet();
60
+ ```
61
+
62
+ ### React Example
63
+
64
+ ```jsx
65
+ // App.jsx
66
+ import { useEffect, useState } from 'react';
67
+ import { init } from '@crmcom/self-service-sdk';
68
+
69
+ function App() {
70
+ const [ready, setReady] = useState(false);
71
+
72
+ useEffect(() => {
73
+ init({
74
+ apiKey: process.env.REACT_APP_CRM_API_KEY,
75
+ host: process.env.REACT_APP_CRM_HOST,
76
+ storeKVFn: (key, value) => localStorage.setItem(key, JSON.stringify(value)),
77
+ getKVFn: (key) => JSON.parse(localStorage.getItem(key)),
78
+ sessionInvalidCallback: () => {
79
+ window.location.href = '/login';
80
+ },
81
+ }).then(() => setReady(true));
82
+ }, []);
83
+
84
+ if (!ready) return <div>Loading...</div>;
85
+
86
+ return <YourApp />;
87
+ }
88
+ ```
89
+
90
+ ## Init Options
91
+
92
+ | Parameter | Type | Required | Description |
93
+ |-----------|------|----------|-------------|
94
+ | `apiKey` | `string` | Yes | Your CRM.COM API key |
95
+ | `host` | `string` | Yes | Base API URL (e.g. `https://api.crm.com`) |
96
+ | `storeKVFn` | `(key, value) => void \| Promise<void>` | Yes | Function to persist key-value pairs (tokens, session data) |
97
+ | `getKVFn` | `(key) => any \| Promise<any>` | Yes | Function to retrieve persisted values |
98
+ | `sessionInvalidCallback` | `(shouldLogout) => void` | Yes | Called when session is invalid and refresh fails |
99
+ | `fetchFn` | `typeof fetch` | No | Custom fetch implementation (defaults to global `fetch`) |
100
+ | `enableSslPinning` | `boolean` | No | Enable SSL pinning (mobile apps) |
101
+ | `sslPinningOptions` | `Record<string, any>` | No | SSL pinning configuration |
102
+ | `isBackend` | `boolean` | No | Set `true` for backend/server usage |
103
+ | `middlewareHost` | `string` | No | Middleware service host URL |
104
+ | `middlewareApiKey` | `string` | No | Middleware API key |
105
+ | `mwNodejsHost` | `string` | No | Node.js middleware host URL |
106
+ | `mwNodejsApiKey` | `string` | No | Node.js middleware API key |
107
+
108
+ ## Available Modules
109
+
110
+ | Module | Description |
111
+ |--------|-------------|
112
+ | `authentication` | Phone, email, Facebook, SSO/OIDC auth flows |
113
+ | `contacts` | Contact profile, addresses, preferences |
114
+ | `orders` | Catalogue, products, order estimation and placement |
115
+ | `wallet` | Balance, transactions, top-ups, transfers |
116
+ | `payment` | Payment methods, forms, top-ups |
117
+ | `subscriptions` | Services, devices, billing |
118
+ | `rewards` | Offers, promotions, schemes |
119
+ | `account` | Journals, balances, rewards |
120
+ | `communications` | Messages, notifications |
121
+ | `community` | Members, relations, groups |
122
+ | `config` | App config, languages, address lookup |
123
+ | `organisations` | Organisation search, locations |
124
+ | `servicerequest` | Support tickets |
125
+ | `connectx` | SIM management |
126
+ | `jcccards` | Card operations |
127
+ | `mobilepass` | Mobile wallet passes |
128
+ | `paymentgateway` | Payment gateway client tokens |
129
+ | `payouts` | Payout creation |
130
+
131
+ ## Error Handling
132
+
133
+ All SDK methods return an `SDKResult` object:
134
+
135
+ ```js
136
+ const result = await contacts.getContact();
137
+
138
+ if (result.code === 'OK') {
139
+ console.log(result.data);
140
+ } else {
141
+ console.error('Error:', result.code, result.error);
142
+ }
143
+ ```
144
+
145
+ If the SDK is used before calling `init()`, it throws:
146
+
147
+ ```
148
+ Error: CRM.COM SDK not initialized. Call init() before using any SDK methods.
149
+ ```
150
+
151
+ ## Migration from v2
152
+
153
+ If you were using `setupChannel`, it still works but is deprecated:
154
+
155
+ ```diff
156
+ - import { httpUtil } from '@crmcom/self-service-sdk';
157
+ - await httpUtil.setupChannel({ apiKey, host, ... });
158
+
159
+ + import { init } from '@crmcom/self-service-sdk';
160
+ + await init({ apiKey, host, ... });
161
+ ```
162
+
163
+ ## License
164
+
165
+ MIT
@@ -6,8 +6,13 @@
6
6
  import {jwtDecode} from 'jwt-decode';
7
7
  import { logger } from './logger';
8
8
 
9
+ let _initialized = false;
10
+
9
11
  export const httpBackOfficeUtil = {
10
- setupChannel,
12
+ init,
13
+ /** @deprecated Use init() instead */
14
+ setupChannel: init,
15
+ isInitialized: () => _initialized,
11
16
  put,
12
17
  post,
13
18
  get,
@@ -29,6 +34,15 @@ const initOptionHeader = () => {
29
34
 
30
35
  /** local variables */
31
36
 
37
+ function _assertInitialized() {
38
+ if (!_initialized) {
39
+ throw new Error(
40
+ 'CRM.COM Back-Office SDK not initialized. Call initBackOffice() before using any back-office SDK methods. ' +
41
+ 'Example: import { initBackOffice } from "@crmcom/self-service-sdk"; await initBackOffice({ apiKey, host, ... });'
42
+ );
43
+ }
44
+ }
45
+
32
46
  let _storeKVFn;
33
47
  let _getKVFn;
34
48
  let _sessionInvalidCallback;
@@ -48,7 +62,7 @@ let _backofficePath = 'backoffice/v1/';
48
62
  * when no connection refresh token will not be available -> should not kick user out.
49
63
  */
50
64
 
51
- async function setupChannel({
65
+ async function init({
52
66
  storeKVFn, //function to store key value
53
67
  getKVFn, //function to get value by key from the storage
54
68
  sessionInvalidCallback, //function to call when api_key or token key is invalid and refresh token if available was failed
@@ -80,7 +94,7 @@ async function setupChannel({
80
94
  _sessionData = undefined;
81
95
  }
82
96
  }
83
- //TODO add silent refresh token here
97
+ _initialized = true;
84
98
  }
85
99
 
86
100
  async function refreshToken() {
@@ -184,6 +198,7 @@ async function post({
184
198
  logOutIfSessionInvalid=true,
185
199
  refreshToken
186
200
  }) {
201
+ _assertInitialized();
187
202
  // let serverConfig = getServerConfig();
188
203
  // let uri = getURI(isBackend, resourcePath);
189
204
  let uri = _host + 'backoffice/v1/' + resourcePath;
@@ -247,6 +262,7 @@ async function get({
247
262
  logOutIfSessionInvalid = true,
248
263
  returnText=false
249
264
  }) {
265
+ _assertInitialized();
250
266
  let uri = getURI(isBackend, resourcePath);
251
267
  // let uri = _host + 'backoffice/v1/' + resourcePath;
252
268
  var options = {};
@@ -296,6 +312,7 @@ async function sendDelete({
296
312
  isBackend = false,
297
313
  logOutIfSessionInvalid = true
298
314
  }) {
315
+ _assertInitialized();
299
316
  // let uri = getURI(isBackend, resourcePath);
300
317
  let uri = _host + 'backoffice/v1/' + resourcePath;
301
318
  var options = {};
@@ -344,6 +361,7 @@ async function put({
344
361
  isBackend = false,
345
362
  logOutIfSessionInvalid = true
346
363
  }) {
364
+ _assertInitialized();
347
365
  // let uri = getURI(isBackend, resourcePath);
348
366
  let uri = _host + 'backoffice/v1/' + resourcePath;
349
367
  var options = {};
package/httpUtil.js CHANGED
@@ -17,8 +17,13 @@ const initOptionHeader = () => {
17
17
  }
18
18
 
19
19
  // import { showMessageError } from '../../utils/util';
20
+ let _initialized = false;
21
+
20
22
  export const httpUtil = {
21
- setupChannel,
23
+ init,
24
+ /** @deprecated Use init() instead */
25
+ setupChannel: init,
26
+ isInitialized: () => _initialized,
22
27
  put,
23
28
  post,
24
29
  get,
@@ -43,6 +48,15 @@ export const httpUtil = {
43
48
 
44
49
  /** local variables */
45
50
 
51
+ function _assertInitialized() {
52
+ if (!_initialized) {
53
+ throw new Error(
54
+ 'CRM.COM SDK not initialized. Call init() before using any SDK methods. ' +
55
+ 'Example: import { init } from "@crmcom/self-service-sdk"; await init({ apiKey, host, ... });'
56
+ );
57
+ }
58
+ }
59
+
46
60
  let _storeKVFn;
47
61
  let _getKVFn;
48
62
  let _sessionInvalidCallback;
@@ -65,7 +79,7 @@ let _mwNodejs_host;
65
79
  let _mwNodejs_apiKey;
66
80
 
67
81
 
68
- async function setupChannel({
82
+ async function init({
69
83
  storeKVFn, //function to store key value
70
84
  getKVFn, //function to get value by key from the storage
71
85
  sessionInvalidCallback, //function to call when api_key or token key is invalid and refresh token if available was failed
@@ -114,7 +128,7 @@ async function setupChannel({
114
128
  _sessionData = undefined;
115
129
  }
116
130
  }
117
- //TODO add silent refresh token here
131
+ _initialized = true;
118
132
  }
119
133
 
120
134
  async function setupApiKey(apikey){
@@ -282,6 +296,7 @@ async function post({
282
296
  isMwNodejs = false,
283
297
  plugin,
284
298
  }) {
299
+ _assertInitialized();
285
300
  try {
286
301
  //let logoutStatus = await getData('LOGOUT_STATUS');
287
302
  //if(logoutStatus == 'PROCESSING') return;
@@ -421,6 +436,7 @@ async function get({
421
436
  isMwNodejs = false,
422
437
  plugin,
423
438
  }) {
439
+ _assertInitialized();
424
440
  try {
425
441
  // let logoutStatus = await getData('LOGOUT_STATUS');
426
442
  //if(logoutStatus == 'PROCESSING') return;
@@ -481,16 +497,38 @@ async function get({
481
497
  return { code: response.status, bodyText: bodyText, error: json2Obj(bodyText) };
482
498
  }
483
499
  } catch (e) {
484
- logger.error("Request error:", e);
485
- let bodyText = await e.text();
486
- // if (e.status == '401') {
487
- // let uri = getURI(isBackend, resourcePath);
488
- // if (queryParams)
489
- // uri = uri + '?' + querystring.encode(cleanObj(queryParams));
490
- // var result = await processRefreshToken(uri,logOutIfSessionInvalid,returnText);
491
- // return result;
492
- // }
493
- return { code: e.status, bodyText: bodyText, error: json2Obj(bodyText) };
500
+ logger.error("Request error:", e);
501
+
502
+ // If fetch throws (CORS/network), e is usually a TypeError with message "Failed to fetch"
503
+ const message = e?.message || String(e);
504
+
505
+ // Some codebases throw a Response object; handle that too (rare, but possible)
506
+ const isResponseLike = e && typeof e.text === "function" && typeof e.status !== "undefined";
507
+
508
+ if (isResponseLike) {
509
+ let bodyText = "";
510
+ try {
511
+ bodyText = await e.text();
512
+ } catch (_) {}
513
+ return { code: String(e.status || "UNKNOWN"), bodyText, error: bodyText ? json2Obj(bodyText) : null };
514
+ }
515
+
516
+ // No response exists => network/CORS/etc.
517
+ return {
518
+ code: "NETWORK_ERROR",
519
+ bodyText: message,
520
+ error: { message }
521
+ };
522
+ // logger.error("Request error:", e);
523
+ // let bodyText = await e.text();
524
+ // // if (e.status == '401') {
525
+ // // let uri = getURI(isBackend, resourcePath);
526
+ // // if (queryParams)
527
+ // // uri = uri + '?' + querystring.encode(cleanObj(queryParams));
528
+ // // var result = await processRefreshToken(uri,logOutIfSessionInvalid,returnText);
529
+ // // return result;
530
+ // // }
531
+ // return { code: e.status, bodyText: bodyText, error: json2Obj(bodyText) };
494
532
  }
495
533
  }
496
534
 
@@ -503,6 +541,7 @@ async function sendDelete({
503
541
  isMiddleware = false,
504
542
  isMwNodejs = false,
505
543
  }) {
544
+ _assertInitialized();
506
545
  try {
507
546
  let uri = getURI(isBackend, resourcePath, isMiddleware, isMwNodejs);
508
547
  var options = {};
@@ -582,6 +621,7 @@ async function put({
582
621
  isMwNodejs = false,
583
622
  accessToken,
584
623
  }) {
624
+ _assertInitialized();
585
625
  try {
586
626
  let uri = getURI(isBackend, resourcePath, isMiddleware, isMwNodejs);
587
627
  var options = {};
@@ -714,6 +754,7 @@ async function uploadFile({
714
754
  keyParam = 'file',
715
755
  disalbedContentType = false,
716
756
  }) {
757
+ _assertInitialized();
717
758
  try {
718
759
  let uri = getURI(isBackend, resourcePath, isMiddleware);
719
760
  var options = {};
@@ -801,6 +842,7 @@ async function uploadFileNew({
801
842
  accessToken,
802
843
  isMiddleware = false
803
844
  }) {
845
+ _assertInitialized();
804
846
  try {
805
847
  let uri = getURI(isBackend, resourcePath, isMiddleware);
806
848
 
package/index.d.ts CHANGED
@@ -69,7 +69,7 @@ export declare const logger: {
69
69
  // HTTP Utilities
70
70
  // ============================================================================
71
71
 
72
- interface SetupChannelOptions {
72
+ export interface InitOptions {
73
73
  storeKVFn: (key: string, value: any) => void | Promise<void>;
74
74
  getKVFn: (key: string) => any | Promise<any>;
75
75
  sessionInvalidCallback: (shouldLogout: boolean) => void | Promise<void>;
@@ -129,7 +129,10 @@ interface UploadFileOptions {
129
129
  }
130
130
 
131
131
  export declare const httpUtil: {
132
- setupChannel(options: SetupChannelOptions): Promise<void>;
132
+ init(options: InitOptions): Promise<void>;
133
+ /** @deprecated Use init() instead */
134
+ setupChannel(options: InitOptions): Promise<void>;
135
+ isInitialized(): boolean;
133
136
  setupApiKey(apiKey: string): Promise<void>;
134
137
  post(options: HttpRequestOptions): Promise<SDKResult>;
135
138
  get(options: HttpRequestOptions): Promise<SDKResult>;
@@ -152,7 +155,10 @@ export declare const httpUtil: {
152
155
  };
153
156
 
154
157
  export declare const httpBackOfficeUtil: {
155
- setupChannel(options: Pick<SetupChannelOptions, 'storeKVFn' | 'getKVFn' | 'sessionInvalidCallback' | 'apiKey' | 'host' | 'fetchFn'>): Promise<void>;
158
+ init(options: Pick<InitOptions, 'storeKVFn' | 'getKVFn' | 'sessionInvalidCallback' | 'apiKey' | 'host' | 'fetchFn'>): Promise<void>;
159
+ /** @deprecated Use init() instead */
160
+ setupChannel(options: Pick<InitOptions, 'storeKVFn' | 'getKVFn' | 'sessionInvalidCallback' | 'apiKey' | 'host' | 'fetchFn'>): Promise<void>;
161
+ isInitialized(): boolean;
156
162
  post(options: HttpRequestOptions): Promise<SDKResult>;
157
163
  get(options: HttpRequestOptions): Promise<SDKResult>;
158
164
  put(options: HttpRequestOptions): Promise<SDKResult>;
@@ -519,9 +525,18 @@ export declare const eventListener: {
519
525
  };
520
526
 
521
527
  // ============================================================================
522
- // Data Utilities
528
+ // Top-level SDK Initialization
523
529
  // ============================================================================
524
530
 
525
- export declare const dataUtil: {
526
- [key: string]: (...args: any[]) => any;
527
- };
531
+ /**
532
+ * Initialize the Self-Service SDK. Must be called before using any other SDK module.
533
+ * Alias for httpUtil.init().
534
+ */
535
+ export declare function init(options: InitOptions): Promise<void>;
536
+
537
+ /**
538
+ * Initialize the Back-Office SDK. Must be called before using any back-office module.
539
+ * Alias for httpBackOfficeUtil.init().
540
+ */
541
+ export declare function initBackOffice(options: Pick<InitOptions, 'storeKVFn' | 'getKVFn' | 'sessionInvalidCallback' | 'apiKey' | 'host' | 'fetchFn'>): Promise<void>;
542
+
package/index.js CHANGED
@@ -1,5 +1,22 @@
1
1
  export { httpUtil } from './httpUtil.js';
2
2
  export { httpBackOfficeUtil } from './httpBackOfficeUtil.js';
3
+
4
+ // Top-level convenience aliases for SDK initialization
5
+ import { httpUtil as _httpUtil } from './httpUtil.js';
6
+ import { httpBackOfficeUtil as _httpBackOfficeUtil } from './httpBackOfficeUtil.js';
7
+
8
+ /**
9
+ * Initialize the Self-Service SDK. Must be called before using any other SDK module.
10
+ * @see httpUtil.init
11
+ */
12
+ export const init = _httpUtil.init;
13
+
14
+ /**
15
+ * Initialize the Back-Office SDK. Must be called before using any back-office module.
16
+ * @see httpBackOfficeUtil.init
17
+ */
18
+ export const initBackOffice = _httpBackOfficeUtil.init;
19
+
3
20
  export { authentication } from './authentication.js';
4
21
  export { contacts } from './contacts.js';
5
22
  export { orders } from './orders.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crmcom/self-service-sdk",
3
- "version": "3.0.0-build.7",
3
+ "version": "3.0.0-build.9",
4
4
  "description": "Official CRM.COM Self-Service JavaScript SDK for consumer-facing API integration",
5
5
  "type": "module",
6
6
  "main": "index.js",