@nokinc-flur/sdk 0.1.6 → 1.0.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.
package/LICENSE CHANGED
@@ -1,21 +1,32 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 NokInc Flur
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ Copyright (c) 2026 NokInc / Flur. All rights reserved.
2
+
3
+ PROPRIETARY AND CONFIDENTIAL
4
+
5
+ This software (the "Software") is the confidential and proprietary information
6
+ of NokInc / Flur ("Licensor"). It is licensed, not sold, to authorized partners
7
+ and developers ("Licensee") for the sole purpose of integrating with Flur
8
+ services.
9
+
10
+ Licensee MAY:
11
+ * Install and use the Software in applications that consume Flur APIs under
12
+ a valid agreement with Licensor.
13
+ * Make local copies for backup and development purposes.
14
+
15
+ Licensee MAY NOT:
16
+ * Redistribute, sublicense, sell, lease, rent, or otherwise transfer the
17
+ Software or any derivative works thereof to any third party.
18
+ * Reverse engineer, decompile, or disassemble the Software, except to the
19
+ extent permitted by applicable law notwithstanding this limitation.
20
+ * Remove or alter any proprietary notices.
21
+ * Use the Software to build a competing product or service.
22
+
23
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
+ FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
+ LICENSOR BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY ARISING FROM,
27
+ OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR ITS USE.
28
+
29
+ This license terminates automatically upon any breach. Upon termination,
30
+ Licensee must destroy all copies of the Software in their possession.
31
+
32
+ For licensing inquiries: legal@flur.ng
package/README.md CHANGED
@@ -3,32 +3,38 @@
3
3
  Typed client scaffold aligned to backend OpenAPI.
4
4
 
5
5
  ## Install (local dev)
6
+
6
7
  ```bash
7
- npm ci
8
- npm test
9
- npm run build
8
+ pnpm install --frozen-lockfile
9
+ pnpm test
10
+ pnpm build
10
11
  ```
11
12
 
12
13
  ## Generate types (optional)
14
+
13
15
  This repo includes a minimal OpenAPI file at `openapi/flur.openapi.json`.
14
16
 
15
17
  ```bash
16
- npm run gen
18
+ pnpm gen
17
19
  ```
18
20
 
19
21
  ## E2E test against a running backend (optional)
20
- 1) Start backend locally (see backend README)
21
- 2) Run (E2E executes when RUN_E2E=1 or FLUR_BASE_URL is set):
22
+
23
+ 1. Start backend locally (see backend README)
24
+ 2. Run (E2E executes when RUN_E2E=1 or FLUR_BASE_URL is set):
25
+
22
26
  ```bash
23
- FLUR_BASE_URL=http://localhost:8080 RUN_E2E=1 npm test
27
+ FLUR_BASE_URL=http://localhost:8080 RUN_E2E=1 pnpm test
24
28
  ```
25
29
 
26
30
  Contract-focused E2E only:
31
+
27
32
  ```bash
28
- FLUR_BASE_URL=https://your-oci-gateway.example.com RUN_E2E=1 npm run test:contract
33
+ FLUR_BASE_URL=https://your-oci-gateway.example.com RUN_E2E=1 pnpm test:contract
29
34
  ```
30
35
 
31
36
  Optional envs for full send-money E2E coverage:
37
+
32
38
  - `FLUR_E2E_SESSION_TOKEN` (required for account/transactions/recipient)
33
39
  - `FLUR_E2E_RECIPIENT_IDENTIFIER` (required for recipient resolve / transfer)
34
40
  - `FLUR_E2E_SEND_AUTH_TOKEN` (required for transfer create)
@@ -37,35 +43,36 @@ Optional envs for full send-money E2E coverage:
37
43
  - `FLUR_E2E_CURRENCY` (optional, default `NGN`)
38
44
 
39
45
  Generate real E2E auth inputs against deployed backend:
46
+
40
47
  ```bash
41
48
  # Step 1: start onboarding and get requestId
42
- npm run e2e:bootstrap -- --base-url https://your-oci-gateway --phone +23480xxxxxxx
49
+ pnpm e2e:bootstrap -- --base-url https://your-oci-gateway --phone +23480xxxxxxx
43
50
 
44
51
  # Step 2: rerun with OTP/silent-auth code (and optional recipient)
45
- npm run e2e:bootstrap -- --base-url https://your-oci-gateway --phone +23480xxxxxxx --code 123456 --recipient +23481xxxxxxx
52
+ pnpm e2e:bootstrap -- --base-url https://your-oci-gateway --phone +23480xxxxxxx --code 123456 --recipient +23481xxxxxxx
46
53
 
47
54
  # Script prints PowerShell env exports, then run:
48
- npm run test:contract
55
+ pnpm test:contract
49
56
  ```
50
57
 
51
58
  ## Onboarding flow methods
52
59
 
53
60
  ```ts
54
- import { FlurClient } from "@nokinc-flur/sdk";
61
+ import { FlurClient } from '@nokinc-flur/sdk';
55
62
 
56
- const client = new FlurClient({ baseUrl: "https://api.example.com" });
63
+ const client = new FlurClient({ baseUrl: 'https://api.example.com' });
57
64
 
58
65
  const started = await client.onboardingStart({
59
- phoneE164: "+14155550123",
60
- appInstanceId: "app-instance-1",
61
- platform: "ios",
66
+ phoneE164: '+14155550123',
67
+ appInstanceId: 'app-instance-1',
68
+ platform: 'ios',
62
69
  });
63
70
  // started: { requestId, checkUrl?, expiresInSec, fallback }
64
71
 
65
72
  const completed = await client.onboardingComplete({
66
- requestId: started.requestId,
67
- code: "123456",
68
- appInstanceId: "app-instance-1",
73
+ requestId: started.requestId,
74
+ code: '123456',
75
+ appInstanceId: 'app-instance-1',
69
76
  });
70
77
  // completed: { sessionToken, userId, restricted, risk_reasons }
71
78
  ```
@@ -73,27 +80,36 @@ const completed = await client.onboardingComplete({
73
80
  ## Auth + device security methods
74
81
 
75
82
  ```ts
76
- const registered = await client.registerDevice({
77
- userId: completed.userId,
78
- appInstanceId: "app-instance-1",
79
- platform: "ios",
80
- networkSignals: { ip: "1.2.3.4" },
81
- }, { accessToken: completed.sessionToken });
83
+ const registered = await client.registerDevice(
84
+ {
85
+ userId: completed.userId,
86
+ appInstanceId: 'app-instance-1',
87
+ platform: 'ios',
88
+ networkSignals: { ip: '1.2.3.4' },
89
+ },
90
+ { accessToken: completed.sessionToken },
91
+ );
82
92
  // { deviceId, fingerprintHash, driftScore, trustState, stepUpRequired }
83
93
 
84
94
  const refreshed = await client.authRefresh({
85
- userId: completed.userId,
86
- refreshToken: completed.sessionToken,
87
- appInstanceId: "app-instance-1",
88
- fingerprintHash: registered.fingerprintHash,
95
+ userId: completed.userId,
96
+ refreshToken: completed.sessionToken,
97
+ appInstanceId: 'app-instance-1',
98
+ fingerprintHash: registered.fingerprintHash,
89
99
  });
90
100
  // { refreshToken, stepUpRequired }
91
101
 
92
- await client.pinSet({ userId: completed.userId, pin: "123456" }, { accessToken: completed.sessionToken });
93
- await client.pinVerify({ userId: completed.userId, pin: "123456" }, { accessToken: completed.sessionToken });
102
+ await client.pinSet(
103
+ { userId: completed.userId, pin: '123456' },
104
+ { accessToken: completed.sessionToken },
105
+ );
106
+ await client.pinVerify(
107
+ { userId: completed.userId, pin: '123456' },
108
+ { accessToken: completed.sessionToken },
109
+ );
94
110
  await client.authLogout(
95
- { userId: completed.userId, refreshToken: refreshed.refreshToken },
96
- { accessToken: refreshed.refreshToken }
111
+ { userId: completed.userId, refreshToken: refreshed.refreshToken },
112
+ { accessToken: refreshed.refreshToken },
97
113
  );
98
114
  ```
99
115
 
@@ -101,53 +117,66 @@ await client.authLogout(
101
117
 
102
118
  ```ts
103
119
  // Register per-device signing key for send authorization
104
- await client.registerSendDeviceKey({
105
- userId: completed.userId,
106
- deviceId: registered.deviceId,
107
- publicKey: "-----BEGIN PUBLIC KEY-----...",
108
- }, { accessToken: completed.sessionToken });
120
+ await client.registerSendDeviceKey(
121
+ {
122
+ userId: completed.userId,
123
+ deviceId: registered.deviceId,
124
+ publicKey: '-----BEGIN PUBLIC KEY-----...',
125
+ },
126
+ { accessToken: completed.sessionToken },
127
+ );
109
128
 
110
129
  // Obtain challenge and verify signature to get short-lived send token
111
- const challenge = await client.createSendChallenge({
112
- userId: completed.userId,
113
- deviceId: registered.deviceId,
114
- }, { accessToken: completed.sessionToken });
115
-
116
- const send = await client.verifySendChallenge({
117
- userId: completed.userId,
118
- deviceId: registered.deviceId,
119
- challengeId: challenge.challengeId,
120
- signature: "base64-signature",
121
- }, { accessToken: completed.sessionToken });
130
+ const challenge = await client.createSendChallenge(
131
+ {
132
+ userId: completed.userId,
133
+ deviceId: registered.deviceId,
134
+ },
135
+ { accessToken: completed.sessionToken },
136
+ );
137
+
138
+ const send = await client.verifySendChallenge(
139
+ {
140
+ userId: completed.userId,
141
+ deviceId: registered.deviceId,
142
+ challengeId: challenge.challengeId,
143
+ signature: 'base64-signature',
144
+ },
145
+ { accessToken: completed.sessionToken },
146
+ );
122
147
 
123
148
  // Resolve recipient and create transfer
124
149
  const recipient = await client.resolveRecipient(
125
- { identifier: "+14155550123" },
126
- { accessToken: completed.sessionToken }
150
+ { identifier: '+14155550123' },
151
+ { accessToken: completed.sessionToken },
127
152
  );
128
153
 
129
154
  await client.createTransfer(
130
- {
131
- recipientIdentifier: recipient.normalizedIdentifier,
132
- amountMinor: 5000,
133
- currency: "NGN",
134
- sendAuthToken: send.sendAuthToken,
135
- },
136
- {
137
- accessToken: completed.sessionToken,
138
- deviceId: registered.deviceId,
139
- idempotencyKey: crypto.randomUUID(),
140
- }
155
+ {
156
+ recipientIdentifier: recipient.normalizedIdentifier,
157
+ amountMinor: 5000,
158
+ currency: 'NGN',
159
+ sendAuthToken: send.sendAuthToken,
160
+ },
161
+ {
162
+ accessToken: completed.sessionToken,
163
+ deviceId: registered.deviceId,
164
+ idempotencyKey: crypto.randomUUID(),
165
+ },
141
166
  );
142
167
 
143
168
  // Account + transaction endpoints
144
169
  await client.accountSummary({ accessToken: completed.sessionToken });
145
- await client.listTransactions({ accessToken: completed.sessionToken, limit: 20 });
170
+ await client.listTransactions({
171
+ accessToken: completed.sessionToken,
172
+ limit: 20,
173
+ });
146
174
  ```
147
175
 
148
176
  ## Error code mapping
149
177
 
150
178
  SDK maps backend error payload `code` into typed `FlurError.code` when available:
179
+
151
180
  - `TOKEN_REPLAYED`
152
181
  - `SESSION_MISMATCH`
153
182
  - `PIN_INVALID`
@@ -156,6 +185,7 @@ SDK maps backend error payload `code` into typed `FlurError.code` when available
156
185
  - `STEP_UP_REQUIRED`
157
186
 
158
187
  Fallback codes remain:
188
+
159
189
  - `HTTP_ERROR`, `NETWORK_ERROR`, `TIMEOUT`, `UNKNOWN`
160
190
 
161
191
  ## Lean prod release workflow (one-person team)
@@ -181,18 +211,19 @@ PowerShell script (Windows):
181
211
  ```
182
212
 
183
213
  What it does:
214
+
184
215
  - verifies git working tree is clean
185
- - runs `npm ci`
186
- - runs `npm run lint`, `npm run typecheck`, `npm test`, `npm run build`
216
+ - runs `pnpm install --frozen-lockfile`
217
+ - runs `pnpm lint`, `pnpm typecheck`, `pnpm test`, `pnpm build`
187
218
  - creates tarball via `npm pack` and smoke-tests install in a temp project
188
219
  - bumps version (`patch`/`minor`/`major`) and creates git tag
189
220
  - pushes commit and tag (`git push`, `git push --tags`)
190
221
  - optionally publishes to npm (`-Publish`)
191
222
 
192
- NPM aliases:
223
+ Release script aliases:
193
224
 
194
225
  ```bash
195
- npm run release:patch
196
- npm run release:minor
197
- npm run release:major
226
+ pnpm release:patch
227
+ pnpm release:minor
228
+ pnpm release:major
198
229
  ```