@nokinc-flur/sdk 0.1.7 → 1.0.2

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
1
+ Copyright (c) 2026 NokInc / Flur. All rights reserved.
2
2
 
3
- Copyright (c) 2026 NokInc Flur
3
+ PROPRIETARY AND CONFIDENTIAL
4
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:
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.
11
9
 
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
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.
14
22
 
15
23
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
24
  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.
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
@@ -1,198 +1,229 @@
1
- # flur-sdk (Sprint 1 / Week 1)
2
-
3
- Typed client scaffold aligned to backend OpenAPI.
4
-
5
- ## Install (local dev)
6
- ```bash
7
- npm ci
8
- npm test
9
- npm run build
10
- ```
11
-
12
- ## Generate types (optional)
13
- This repo includes a minimal OpenAPI file at `openapi/flur.openapi.json`.
14
-
15
- ```bash
16
- npm run gen
17
- ```
18
-
19
- ## 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
- ```bash
23
- FLUR_BASE_URL=http://localhost:8080 RUN_E2E=1 npm test
24
- ```
25
-
26
- Contract-focused E2E only:
27
- ```bash
28
- FLUR_BASE_URL=https://your-oci-gateway.example.com RUN_E2E=1 npm run test:contract
29
- ```
30
-
31
- Optional envs for full send-money E2E coverage:
32
- - `FLUR_E2E_SESSION_TOKEN` (required for account/transactions/recipient)
33
- - `FLUR_E2E_RECIPIENT_IDENTIFIER` (required for recipient resolve / transfer)
34
- - `FLUR_E2E_SEND_AUTH_TOKEN` (required for transfer create)
35
- - `FLUR_E2E_DEVICE_ID` (required for transfer create)
36
- - `FLUR_E2E_AMOUNT_MINOR` (optional, default `100`)
37
- - `FLUR_E2E_CURRENCY` (optional, default `NGN`)
38
-
39
- Generate real E2E auth inputs against deployed backend:
40
- ```bash
41
- # Step 1: start onboarding and get requestId
42
- npm run e2e:bootstrap -- --base-url https://your-oci-gateway --phone +23480xxxxxxx
43
-
44
- # 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
46
-
47
- # Script prints PowerShell env exports, then run:
48
- npm run test:contract
49
- ```
50
-
51
- ## Onboarding flow methods
52
-
53
- ```ts
54
- import { FlurClient } from "@nokinc-flur/sdk";
55
-
56
- const client = new FlurClient({ baseUrl: "https://api.example.com" });
57
-
58
- const started = await client.onboardingStart({
59
- phoneE164: "+14155550123",
60
- appInstanceId: "app-instance-1",
61
- platform: "ios",
62
- });
63
- // started: { requestId, checkUrl?, expiresInSec, fallback }
64
-
65
- const completed = await client.onboardingComplete({
66
- requestId: started.requestId,
67
- code: "123456",
68
- appInstanceId: "app-instance-1",
69
- });
70
- // completed: { sessionToken, userId, restricted, risk_reasons }
71
- ```
72
-
73
- ## Auth + device security methods
74
-
75
- ```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 });
82
- // { deviceId, fingerprintHash, driftScore, trustState, stepUpRequired }
83
-
84
- const refreshed = await client.authRefresh({
85
- userId: completed.userId,
86
- refreshToken: completed.sessionToken,
87
- appInstanceId: "app-instance-1",
88
- fingerprintHash: registered.fingerprintHash,
89
- });
90
- // { refreshToken, stepUpRequired }
91
-
92
- await client.pinSet({ userId: completed.userId, pin: "123456" }, { accessToken: completed.sessionToken });
93
- await client.pinVerify({ userId: completed.userId, pin: "123456" }, { accessToken: completed.sessionToken });
94
- await client.authLogout(
95
- { userId: completed.userId, refreshToken: refreshed.refreshToken },
96
- { accessToken: refreshed.refreshToken }
97
- );
98
- ```
99
-
100
- ## Send-money methods
101
-
102
- ```ts
103
- // 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 });
109
-
110
- // 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 });
122
-
123
- // Resolve recipient and create transfer
124
- const recipient = await client.resolveRecipient(
125
- { identifier: "+14155550123" },
126
- { accessToken: completed.sessionToken }
127
- );
128
-
129
- 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
- }
141
- );
142
-
143
- // Account + transaction endpoints
144
- await client.accountSummary({ accessToken: completed.sessionToken });
145
- await client.listTransactions({ accessToken: completed.sessionToken, limit: 20 });
146
- ```
147
-
148
- ## Error code mapping
149
-
150
- SDK maps backend error payload `code` into typed `FlurError.code` when available:
151
- - `TOKEN_REPLAYED`
152
- - `SESSION_MISMATCH`
153
- - `PIN_INVALID`
154
- - `PIN_LOCKED`
155
- - `PIN_NOT_SET`
156
- - `STEP_UP_REQUIRED`
157
-
158
- Fallback codes remain:
159
- - `HTTP_ERROR`, `NETWORK_ERROR`, `TIMEOUT`, `UNKNOWN`
160
-
161
- ## Lean prod release workflow (one-person team)
162
-
163
- PowerShell script (Windows):
164
-
165
- ```powershell
166
- # patch release (recommended for this onboarding addition)
167
- ./scripts/release.ps1 -Bump patch
168
-
169
- # exact version release (example: 1.0.1)
170
- ./scripts/release.ps1 -Version 1.0.1
171
-
172
- # include E2E run (uses default OCI API Gateway URL from release script)
173
- ./scripts/release.ps1 -Version 1.0.1 -RunE2E
174
-
175
- # include E2E run with override URL
176
- ./scripts/release.ps1 -Version 1.0.1 -RunE2E -E2EBaseUrl https://your-api.example.com
177
-
178
- # publish to npm after all checks pass
179
- ./scripts/release.ps1 -Bump patch -Publish
180
- ./scripts/release.ps1 -Version 1.0.1 -Publish
181
- ```
182
-
183
- What it does:
184
- - verifies git working tree is clean
185
- - runs `npm ci`
186
- - runs `npm run lint`, `npm run typecheck`, `npm test`, `npm run build`
187
- - creates tarball via `npm pack` and smoke-tests install in a temp project
188
- - bumps version (`patch`/`minor`/`major`) and creates git tag
189
- - pushes commit and tag (`git push`, `git push --tags`)
190
- - optionally publishes to npm (`-Publish`)
191
-
192
- NPM aliases:
193
-
194
- ```bash
195
- npm run release:patch
196
- npm run release:minor
197
- npm run release:major
198
- ```
1
+ # flur-sdk (Sprint 1 / Week 1)
2
+
3
+ Typed client scaffold aligned to backend OpenAPI.
4
+
5
+ ## Install (local dev)
6
+
7
+ ```bash
8
+ pnpm install --frozen-lockfile
9
+ pnpm test
10
+ pnpm build
11
+ ```
12
+
13
+ ## Generate types (optional)
14
+
15
+ This repo includes a minimal OpenAPI file at `openapi/flur.openapi.json`.
16
+
17
+ ```bash
18
+ pnpm gen
19
+ ```
20
+
21
+ ## E2E test against a running backend (optional)
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
+
26
+ ```bash
27
+ FLUR_BASE_URL=http://localhost:8080 RUN_E2E=1 pnpm test
28
+ ```
29
+
30
+ Contract-focused E2E only:
31
+
32
+ ```bash
33
+ FLUR_BASE_URL=https://your-oci-gateway.example.com RUN_E2E=1 pnpm test:contract
34
+ ```
35
+
36
+ Optional envs for full send-money E2E coverage:
37
+
38
+ - `FLUR_E2E_SESSION_TOKEN` (required for account/transactions/recipient)
39
+ - `FLUR_E2E_RECIPIENT_IDENTIFIER` (required for recipient resolve / transfer)
40
+ - `FLUR_E2E_SEND_AUTH_TOKEN` (required for transfer create)
41
+ - `FLUR_E2E_DEVICE_ID` (required for transfer create)
42
+ - `FLUR_E2E_AMOUNT_MINOR` (optional, default `100`)
43
+ - `FLUR_E2E_CURRENCY` (optional, default `NGN`)
44
+
45
+ Generate real E2E auth inputs against deployed backend:
46
+
47
+ ```bash
48
+ # Step 1: start onboarding and get requestId
49
+ pnpm e2e:bootstrap -- --base-url https://your-oci-gateway --phone +23480xxxxxxx
50
+
51
+ # Step 2: rerun with OTP/silent-auth code (and optional recipient)
52
+ pnpm e2e:bootstrap -- --base-url https://your-oci-gateway --phone +23480xxxxxxx --code 123456 --recipient +23481xxxxxxx
53
+
54
+ # Script prints PowerShell env exports, then run:
55
+ pnpm test:contract
56
+ ```
57
+
58
+ ## Onboarding flow methods
59
+
60
+ ```ts
61
+ import { FlurClient } from '@nokinc-flur/sdk';
62
+
63
+ const client = new FlurClient({ baseUrl: 'https://api.example.com' });
64
+
65
+ const started = await client.onboardingStart({
66
+ phoneE164: '+14155550123',
67
+ appInstanceId: 'app-instance-1',
68
+ platform: 'ios',
69
+ });
70
+ // started: { requestId, checkUrl?, expiresInSec, fallback }
71
+
72
+ const completed = await client.onboardingComplete({
73
+ requestId: started.requestId,
74
+ code: '123456',
75
+ appInstanceId: 'app-instance-1',
76
+ });
77
+ // completed: { sessionToken, userId, restricted, risk_reasons }
78
+ ```
79
+
80
+ ## Auth + device security methods
81
+
82
+ ```ts
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
+ );
92
+ // { deviceId, fingerprintHash, driftScore, trustState, stepUpRequired }
93
+
94
+ const refreshed = await client.authRefresh({
95
+ userId: completed.userId,
96
+ refreshToken: completed.sessionToken,
97
+ appInstanceId: 'app-instance-1',
98
+ fingerprintHash: registered.fingerprintHash,
99
+ });
100
+ // { refreshToken, stepUpRequired }
101
+
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
+ );
110
+ await client.authLogout(
111
+ { userId: completed.userId, refreshToken: refreshed.refreshToken },
112
+ { accessToken: refreshed.refreshToken },
113
+ );
114
+ ```
115
+
116
+ ## Send-money methods
117
+
118
+ ```ts
119
+ // Register per-device signing key for send authorization
120
+ await client.registerSendDeviceKey(
121
+ {
122
+ userId: completed.userId,
123
+ deviceId: registered.deviceId,
124
+ publicKey: '-----BEGIN PUBLIC KEY-----...',
125
+ },
126
+ { accessToken: completed.sessionToken },
127
+ );
128
+
129
+ // Obtain challenge and verify signature to get short-lived send token
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
+ );
147
+
148
+ // Resolve recipient and create transfer
149
+ const recipient = await client.resolveRecipient(
150
+ { identifier: '+14155550123' },
151
+ { accessToken: completed.sessionToken },
152
+ );
153
+
154
+ await client.createTransfer(
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
+ },
166
+ );
167
+
168
+ // Account + transaction endpoints
169
+ await client.accountSummary({ accessToken: completed.sessionToken });
170
+ await client.listTransactions({
171
+ accessToken: completed.sessionToken,
172
+ limit: 20,
173
+ });
174
+ ```
175
+
176
+ ## Error code mapping
177
+
178
+ SDK maps backend error payload `code` into typed `FlurError.code` when available:
179
+
180
+ - `TOKEN_REPLAYED`
181
+ - `SESSION_MISMATCH`
182
+ - `PIN_INVALID`
183
+ - `PIN_LOCKED`
184
+ - `PIN_NOT_SET`
185
+ - `STEP_UP_REQUIRED`
186
+
187
+ Fallback codes remain:
188
+
189
+ - `HTTP_ERROR`, `NETWORK_ERROR`, `TIMEOUT`, `UNKNOWN`
190
+
191
+ ## Lean prod release workflow (one-person team)
192
+
193
+ PowerShell script (Windows):
194
+
195
+ ```powershell
196
+ # patch release (recommended for this onboarding addition)
197
+ ./scripts/release.ps1 -Bump patch
198
+
199
+ # exact version release (example: 1.0.1)
200
+ ./scripts/release.ps1 -Version 1.0.1
201
+
202
+ # include E2E run (uses default OCI API Gateway URL from release script)
203
+ ./scripts/release.ps1 -Version 1.0.1 -RunE2E
204
+
205
+ # include E2E run with override URL
206
+ ./scripts/release.ps1 -Version 1.0.1 -RunE2E -E2EBaseUrl https://your-api.example.com
207
+
208
+ # publish to npm after all checks pass
209
+ ./scripts/release.ps1 -Bump patch -Publish
210
+ ./scripts/release.ps1 -Version 1.0.1 -Publish
211
+ ```
212
+
213
+ What it does:
214
+
215
+ - verifies git working tree is clean
216
+ - runs `pnpm install --frozen-lockfile`
217
+ - runs `pnpm lint`, `pnpm typecheck`, `pnpm test`, `pnpm build`
218
+ - creates tarball via `npm pack` and smoke-tests install in a temp project
219
+ - bumps version (`patch`/`minor`/`major`) and creates git tag
220
+ - pushes commit and tag (`git push`, `git push --tags`)
221
+ - optionally publishes to npm (`-Publish`)
222
+
223
+ Release script aliases:
224
+
225
+ ```bash
226
+ pnpm release:patch
227
+ pnpm release:minor
228
+ pnpm release:major
229
+ ```