@nokinc-flur/sdk 0.1.1 → 0.1.3

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 CHANGED
@@ -40,6 +40,43 @@ const completed = await client.onboardingComplete({
40
40
  // completed: { sessionToken, userId, restricted, risk_reasons }
41
41
  ```
42
42
 
43
+ ## Auth + device security methods
44
+
45
+ ```ts
46
+ const registered = await client.registerDevice({
47
+ userId: completed.userId,
48
+ appInstanceId: "app-instance-1",
49
+ platform: "ios",
50
+ networkSignals: { ip: "1.2.3.4" },
51
+ });
52
+ // { deviceId, fingerprintHash, driftScore, trustState, stepUpRequired }
53
+
54
+ const refreshed = await client.authRefresh({
55
+ userId: completed.userId,
56
+ refreshToken: completed.sessionToken,
57
+ appInstanceId: "app-instance-1",
58
+ fingerprintHash: registered.fingerprintHash,
59
+ });
60
+ // { refreshToken, stepUpRequired }
61
+
62
+ await client.pinSet({ userId: completed.userId, pin: "123456" });
63
+ await client.pinVerify({ userId: completed.userId, pin: "123456" });
64
+ await client.authLogout({ userId: completed.userId, refreshToken: refreshed.refreshToken });
65
+ ```
66
+
67
+ ## Error code mapping
68
+
69
+ SDK maps backend error payload `code` into typed `FlurError.code` when available:
70
+ - `TOKEN_REPLAYED`
71
+ - `SESSION_MISMATCH`
72
+ - `PIN_INVALID`
73
+ - `PIN_LOCKED`
74
+ - `PIN_NOT_SET`
75
+ - `STEP_UP_REQUIRED`
76
+
77
+ Fallback codes remain:
78
+ - `HTTP_ERROR`, `NETWORK_ERROR`, `TIMEOUT`, `UNKNOWN`
79
+
43
80
  ## Lean prod release workflow (one-person team)
44
81
 
45
82
  PowerShell script (Windows):
package/dist/index.d.ts CHANGED
@@ -6,6 +6,8 @@ type FlurClientOptions = {
6
6
  type OnboardingFallback = "SILENT_AUTH" | "OTP";
7
7
  type OnboardingStartInput = {
8
8
  phoneE164: string;
9
+ firstName?: string;
10
+ lastName?: string;
9
11
  };
10
12
  type OnboardingStartResponse = {
11
13
  requestId: string;
@@ -17,12 +19,58 @@ type OnboardingRiskReason = "SIM_SWAP_RECENT" | "ROAMING" | "CARRIER_CHANGED";
17
19
  type OnboardingCompleteInput = {
18
20
  requestId: string;
19
21
  code: string;
22
+ appInstanceId?: string;
23
+ fingerprintHash?: string;
20
24
  };
21
25
  type OnboardingCompleteResponse = {
22
26
  sessionToken: string;
23
27
  userId: string;
24
28
  restricted: boolean;
25
29
  risk_reasons: OnboardingRiskReason[];
30
+ stepUpRequired?: boolean;
31
+ riskStatus?: "ok" | "unavailable";
32
+ };
33
+ type RegisterDeviceInput = {
34
+ userId: string;
35
+ appInstanceId: string;
36
+ platform: string;
37
+ model?: string;
38
+ networkSignals: {
39
+ ip: string;
40
+ asn?: number;
41
+ country?: string;
42
+ carrier?: string;
43
+ };
44
+ };
45
+ type DeviceTrustState = "TRUSTED_PRIMARY" | "TRUSTED_SECONDARY" | "UNVERIFIED";
46
+ type RegisterDeviceResponse = {
47
+ deviceId: string;
48
+ fingerprintHash: string;
49
+ driftScore: number;
50
+ trustState: DeviceTrustState;
51
+ stepUpRequired: boolean;
52
+ };
53
+ type AuthRefreshInput = {
54
+ userId: string;
55
+ refreshToken: string;
56
+ appInstanceId: string;
57
+ fingerprintHash: string;
58
+ };
59
+ type AuthRefreshResponse = {
60
+ refreshToken: string;
61
+ stepUpRequired: boolean;
62
+ };
63
+ type AuthLogoutInput = {
64
+ userId: string;
65
+ refreshToken: string;
66
+ };
67
+ type PinSetInput = {
68
+ userId: string;
69
+ pin: string;
70
+ };
71
+ type PinVerifyInput = {
72
+ userId: string;
73
+ pin: string;
26
74
  };
27
75
  declare class FlurClient {
28
76
  private readonly baseUrl;
@@ -37,10 +85,21 @@ declare class FlurClient {
37
85
  }>;
38
86
  onboardingStart(input: OnboardingStartInput): Promise<OnboardingStartResponse>;
39
87
  onboardingComplete(input: OnboardingCompleteInput): Promise<OnboardingCompleteResponse>;
88
+ registerDevice(input: RegisterDeviceInput): Promise<RegisterDeviceResponse>;
89
+ authRefresh(input: AuthRefreshInput): Promise<AuthRefreshResponse>;
90
+ authLogout(input: AuthLogoutInput): Promise<{
91
+ ok: boolean;
92
+ }>;
93
+ pinSet(input: PinSetInput): Promise<{
94
+ ok: boolean;
95
+ }>;
96
+ pinVerify(input: PinVerifyInput): Promise<{
97
+ ok: boolean;
98
+ }>;
40
99
  private requestJson;
41
100
  }
42
101
 
43
- type FlurErrorCode = "NETWORK_ERROR" | "HTTP_ERROR" | "TIMEOUT" | "UNKNOWN";
102
+ type FlurErrorCode = "NETWORK_ERROR" | "HTTP_ERROR" | "TIMEOUT" | "UNKNOWN" | "TOKEN_REPLAYED" | "SESSION_MISMATCH" | "PIN_INVALID" | "PIN_LOCKED" | "PIN_NOT_SET" | "STEP_UP_REQUIRED";
44
103
  declare class FlurError extends Error {
45
104
  readonly code: FlurErrorCode;
46
105
  readonly status?: number;
@@ -51,4 +110,4 @@ declare class FlurError extends Error {
51
110
  });
52
111
  }
53
112
 
54
- export { FlurClient, type FlurClientOptions, FlurError, type OnboardingCompleteInput, type OnboardingCompleteResponse, type OnboardingFallback, type OnboardingRiskReason, type OnboardingStartInput, type OnboardingStartResponse };
113
+ export { type AuthLogoutInput, type AuthRefreshInput, type AuthRefreshResponse, type DeviceTrustState, FlurClient, type FlurClientOptions, FlurError, type OnboardingCompleteInput, type OnboardingCompleteResponse, type OnboardingFallback, type OnboardingRiskReason, type OnboardingStartInput, type OnboardingStartResponse, type PinSetInput, type PinVerifyInput, type RegisterDeviceInput, type RegisterDeviceResponse };
package/dist/index.js CHANGED
@@ -1,4 +1,12 @@
1
1
  // src/errors.ts
2
+ var backendErrorCodeSet = /* @__PURE__ */ new Set([
3
+ "TOKEN_REPLAYED",
4
+ "SESSION_MISMATCH",
5
+ "PIN_INVALID",
6
+ "PIN_LOCKED",
7
+ "PIN_NOT_SET",
8
+ "STEP_UP_REQUIRED"
9
+ ]);
2
10
  var FlurError = class extends Error {
3
11
  code;
4
12
  status;
@@ -13,12 +21,27 @@ var FlurError = class extends Error {
13
21
  };
14
22
  async function mapToFlurError(res) {
15
23
  let details = void 0;
24
+ let mappedCode = "HTTP_ERROR";
25
+ let mappedMessage = `HTTP ${res.status}`;
16
26
  try {
17
27
  const ct = res.headers.get("content-type") ?? "";
18
28
  details = ct.includes("application/json") ? await res.json() : await res.text();
29
+ if (details && typeof details === "object") {
30
+ const candidateCode = details.code;
31
+ const candidateMessage = details.message;
32
+ const fallbackMessage = details.error;
33
+ if (typeof candidateCode === "string" && backendErrorCodeSet.has(candidateCode)) {
34
+ mappedCode = candidateCode;
35
+ }
36
+ if (typeof candidateMessage === "string" && candidateMessage.length > 0) {
37
+ mappedMessage = candidateMessage;
38
+ } else if (typeof fallbackMessage === "string" && fallbackMessage.length > 0) {
39
+ mappedMessage = fallbackMessage;
40
+ }
41
+ }
19
42
  } catch {
20
43
  }
21
- return new FlurError(`HTTP ${res.status}`, "HTTP_ERROR", { status: res.status, details });
44
+ return new FlurError(mappedMessage, mappedCode, { status: res.status, details });
22
45
  }
23
46
 
24
47
  // src/client.ts
@@ -51,6 +74,41 @@ var FlurClient = class {
51
74
  body: JSON.stringify(input)
52
75
  });
53
76
  }
77
+ async registerDevice(input) {
78
+ return this.requestJson("/v1/devices/register", {
79
+ method: "POST",
80
+ headers: { "content-type": "application/json" },
81
+ body: JSON.stringify(input)
82
+ });
83
+ }
84
+ async authRefresh(input) {
85
+ return this.requestJson("/v1/auth/refresh", {
86
+ method: "POST",
87
+ headers: { "content-type": "application/json" },
88
+ body: JSON.stringify(input)
89
+ });
90
+ }
91
+ async authLogout(input) {
92
+ return this.requestJson("/v1/auth/logout", {
93
+ method: "POST",
94
+ headers: { "content-type": "application/json" },
95
+ body: JSON.stringify(input)
96
+ });
97
+ }
98
+ async pinSet(input) {
99
+ return this.requestJson("/v1/auth/pin/set", {
100
+ method: "POST",
101
+ headers: { "content-type": "application/json" },
102
+ body: JSON.stringify(input)
103
+ });
104
+ }
105
+ async pinVerify(input) {
106
+ return this.requestJson("/v1/auth/pin/verify", {
107
+ method: "POST",
108
+ headers: { "content-type": "application/json" },
109
+ body: JSON.stringify(input)
110
+ });
111
+ }
54
112
  async requestJson(path, init) {
55
113
  const url = `${this.baseUrl}${path}`;
56
114
  const controller = new AbortController();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nokinc-flur/sdk",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Flur Wallet SDK (sprint 1 scaffold)",
5
5
  "license": "MIT",
6
6
  "type": "module",