@nokinc-flur/sdk 1.0.4 → 1.0.5

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/dist/index.js CHANGED
@@ -41,7 +41,9 @@ var OnboardingCompleteResponseSchema = z.object({
41
41
  sessionToken: z.string().min(1),
42
42
  userId: UuidSchema,
43
43
  restricted: z.boolean(),
44
- risk_reasons: z.array(z.enum(["SIM_SWAP_RECENT", "ROAMING", "CARRIER_CHANGED"])),
44
+ risk_reasons: z.array(
45
+ z.enum(["SIM_SWAP_RECENT", "ROAMING", "CARRIER_CHANGED"])
46
+ ),
45
47
  stepUpRequired: z.boolean().optional(),
46
48
  riskStatus: z.enum(["ok", "unavailable"]).optional()
47
49
  });
@@ -94,9 +96,11 @@ var RegisterSendDeviceKeyRequestSchema = z.object({
94
96
  deviceId: z.string().min(3),
95
97
  publicKey: z.string().min(32)
96
98
  });
99
+ var SEND_AUTH_PURPOSES = ["send_money", "offline_revoke"];
97
100
  var SendChallengeRequestSchema = z.object({
98
101
  userId: UuidSchema,
99
- deviceId: z.string().min(3)
102
+ deviceId: z.string().min(3),
103
+ purpose: z.enum(SEND_AUTH_PURPOSES).optional()
100
104
  });
101
105
  var SendChallengeResponseSchema = z.object({
102
106
  challengeId: UuidSchema,
@@ -396,10 +400,20 @@ var FlurClient = class {
396
400
  this.getExtraHeaders = opts.getExtraHeaders;
397
401
  }
398
402
  async health() {
399
- return this.requestJson("/health", { method: "GET" }, void 0, HealthResponseSchema);
403
+ return this.requestJson(
404
+ "/health",
405
+ { method: "GET" },
406
+ void 0,
407
+ HealthResponseSchema
408
+ );
400
409
  }
401
410
  async welcome() {
402
- return this.requestJson("/welcome", { method: "GET" }, void 0, WelcomeResponseSchema);
411
+ return this.requestJson(
412
+ "/welcome",
413
+ { method: "GET" },
414
+ void 0,
415
+ WelcomeResponseSchema
416
+ );
403
417
  }
404
418
  async onboardingStart(input) {
405
419
  return this.requestJson(
@@ -544,24 +558,33 @@ var FlurClient = class {
544
558
  }
545
559
  async registerBiometricDeviceKey(input) {
546
560
  const publicKey = await input.signer.getOrCreateKeyPair(input.deviceId);
547
- return this.registerSendDeviceKey({
548
- userId: input.userId,
549
- deviceId: input.deviceId,
550
- publicKey
551
- }, { accessToken: input.accessToken });
561
+ return this.registerSendDeviceKey(
562
+ {
563
+ userId: input.userId,
564
+ deviceId: input.deviceId,
565
+ publicKey
566
+ },
567
+ { accessToken: input.accessToken }
568
+ );
552
569
  }
553
570
  async authorizeSendWithBiometric(input) {
554
- const challenge = await this.createSendChallenge({
555
- userId: input.userId,
556
- deviceId: input.deviceId
557
- }, { accessToken: input.accessToken });
571
+ const challenge = await this.createSendChallenge(
572
+ {
573
+ userId: input.userId,
574
+ deviceId: input.deviceId
575
+ },
576
+ { accessToken: input.accessToken }
577
+ );
558
578
  const signature = await input.signer.sign(challenge.nonce);
559
- return this.verifySendChallenge({
560
- userId: input.userId,
561
- deviceId: input.deviceId,
562
- challengeId: challenge.challengeId,
563
- signature
564
- }, { accessToken: input.accessToken });
579
+ return this.verifySendChallenge(
580
+ {
581
+ userId: input.userId,
582
+ deviceId: input.deviceId,
583
+ challengeId: challenge.challengeId,
584
+ signature
585
+ },
586
+ { accessToken: input.accessToken }
587
+ );
565
588
  }
566
589
  async resolveRecipient(input, options) {
567
590
  return this.requestJson(
@@ -726,7 +749,12 @@ var FlurClient = class {
726
749
  ...init2.headers,
727
750
  ...extraHeaders
728
751
  };
729
- const res = await this.fetchImpl(url, { ...init2, headers: finalHeaders, body, signal: controller.signal });
752
+ const res = await this.fetchImpl(url, {
753
+ ...init2,
754
+ headers: finalHeaders,
755
+ body,
756
+ signal: controller.signal
757
+ });
730
758
  if (!res.ok) throw await mapToFlurError(res);
731
759
  const payload = await res.json();
732
760
  if (!responseSchema) return payload;
@@ -734,9 +762,13 @@ var FlurClient = class {
734
762
  return responseSchema.parse(payload);
735
763
  } catch (err) {
736
764
  if (err instanceof z3.ZodError) {
737
- throw new FlurError("SDK contract validation failed", "INVALID_REQUEST", {
738
- details: err.flatten()
739
- });
765
+ throw new FlurError(
766
+ "SDK contract validation failed",
767
+ "INVALID_REQUEST",
768
+ {
769
+ details: err.flatten()
770
+ }
771
+ );
740
772
  }
741
773
  throw err;
742
774
  }
@@ -745,7 +777,9 @@ var FlurClient = class {
745
777
  throw new FlurError("Request timed out", "TIMEOUT");
746
778
  }
747
779
  if (err instanceof FlurError) throw err;
748
- throw new FlurError("Network error", "NETWORK_ERROR", { details: String(err) });
780
+ throw new FlurError("Network error", "NETWORK_ERROR", {
781
+ details: String(err)
782
+ });
749
783
  } finally {
750
784
  clearTimeout(t);
751
785
  }
@@ -755,7 +789,10 @@ function getSecureRandomUuid() {
755
789
  if (typeof globalThis.crypto?.randomUUID === "function") {
756
790
  return globalThis.crypto.randomUUID();
757
791
  }
758
- throw new FlurError("Secure UUID generator unavailable; provide idempotencyKey", "INVALID_REQUEST");
792
+ throw new FlurError(
793
+ "Secure UUID generator unavailable; provide idempotencyKey",
794
+ "INVALID_REQUEST"
795
+ );
759
796
  }
760
797
 
761
798
  // src/nqr/fields.ts
@@ -2506,6 +2543,260 @@ function createApiCredentialsAdminClient(opts) {
2506
2543
  )
2507
2544
  };
2508
2545
  }
2546
+
2547
+ // src/me-offline/client.ts
2548
+ import { z as z12 } from "zod";
2549
+ var Hex64 = z12.string().regex(/^[0-9a-f]{64}$/i);
2550
+ var HexAny = z12.string().regex(/^[0-9a-f]+$/i);
2551
+ var Sha256Hex = z12.string().regex(/^[0-9a-f]{64}$/i);
2552
+ var RegisterDeviceKeyInputSchema = z12.object({
2553
+ deviceId: z12.string().min(1).max(128),
2554
+ publicKeyHex: Hex64
2555
+ });
2556
+ var DeviceKeyRecordSchema = z12.object({
2557
+ id: z12.string().uuid(),
2558
+ userId: z12.string().uuid(),
2559
+ deviceId: z12.string(),
2560
+ publicKeyHex: Hex64,
2561
+ createdAtMs: z12.number().int().nonnegative(),
2562
+ revokedAtMs: z12.number().int().nonnegative().nullable()
2563
+ });
2564
+ var ConsumerOACSchema = z12.object({
2565
+ oacId: z12.string().uuid(),
2566
+ issuerId: z12.string().min(1).max(64),
2567
+ userId: z12.string().uuid(),
2568
+ deviceId: z12.string().min(1).max(128),
2569
+ devicePubkeyHex: Hex64,
2570
+ perTxCapKobo: z12.number().int().positive(),
2571
+ cumulativeCapKobo: z12.number().int().positive(),
2572
+ currency: z12.string().length(3),
2573
+ validFromMs: z12.number().int().nonnegative(),
2574
+ validUntilMs: z12.number().int().nonnegative(),
2575
+ counterSeed: z12.number().int().nonnegative(),
2576
+ issuedAtMs: z12.number().int().nonnegative()
2577
+ });
2578
+ var SignedConsumerOACSchema = z12.object({
2579
+ oac: ConsumerOACSchema,
2580
+ issuerSig: HexAny,
2581
+ issuerPublicKeyHex: Hex64
2582
+ });
2583
+ var OACRecordSchema = SignedConsumerOACSchema.extend({
2584
+ currentOfflineSpentKobo: z12.number().int().nonnegative(),
2585
+ status: z12.enum([
2586
+ "active",
2587
+ "superseded",
2588
+ "expired",
2589
+ "revoked",
2590
+ "disabling",
2591
+ "draining",
2592
+ "closed"
2593
+ ]),
2594
+ supersededAtMs: z12.number().int().nonnegative().nullable(),
2595
+ revokedAtMs: z12.number().int().nonnegative().nullable(),
2596
+ holdId: z12.string().uuid().nullable().optional()
2597
+ });
2598
+ var IssueOACInputSchema = z12.object({
2599
+ deviceId: z12.string().min(1).max(128),
2600
+ perTxCapKobo: z12.number().int().positive().optional(),
2601
+ cumulativeCapKobo: z12.number().int().positive().optional(),
2602
+ ttlMs: z12.number().int().min(6e4).max(1e3 * 60 * 60 * 24 * 7).optional(),
2603
+ spendableOnlineKobo: z12.number().int().nonnegative().optional()
2604
+ });
2605
+ var EnableOfflineInputSchema = z12.object({
2606
+ deviceId: z12.string().min(1).max(128),
2607
+ amountKobo: z12.number().int().positive(),
2608
+ perTxCapKobo: z12.number().int().positive().optional(),
2609
+ ttlMs: z12.number().int().min(6e4).max(1e3 * 60 * 60 * 24 * 7).optional(),
2610
+ installId: z12.string().min(1).max(128),
2611
+ partnerId: z12.string().min(1).max(64).optional()
2612
+ });
2613
+ var DisableOfflineInputSchema = z12.object({
2614
+ deviceId: z12.string().min(1).max(128),
2615
+ installId: z12.string().min(1).max(128).optional(),
2616
+ claims: z12.array(z12.unknown()).max(256).optional()
2617
+ });
2618
+ var OfflineHoldRecordSchema = z12.object({
2619
+ holdId: z12.string().uuid(),
2620
+ userId: z12.string().uuid(),
2621
+ deviceId: z12.string(),
2622
+ partnerId: z12.string(),
2623
+ adapterKind: z12.string(),
2624
+ externalHoldRef: z12.string().nullable(),
2625
+ amountKobo: z12.number().int().nonnegative(),
2626
+ capturedKobo: z12.number().int().nonnegative(),
2627
+ releasedKobo: z12.number().int().nonnegative(),
2628
+ remainingKobo: z12.number().int().nonnegative(),
2629
+ currency: z12.string().length(3),
2630
+ status: z12.enum([
2631
+ "placing",
2632
+ "active",
2633
+ "disabling",
2634
+ "draining",
2635
+ "closed",
2636
+ "revoked",
2637
+ "failed"
2638
+ ]),
2639
+ installId: z12.string().nullable(),
2640
+ drainDeadlineMs: z12.number().int().nonnegative(),
2641
+ disableRequestedAtMs: z12.number().int().nonnegative().nullable(),
2642
+ createdAtMs: z12.number().int().nonnegative(),
2643
+ closedAtMs: z12.number().int().nonnegative().nullable(),
2644
+ isTrusted: z12.boolean().optional()
2645
+ });
2646
+ var EnableOfflineResultSchema = z12.object({
2647
+ hold: OfflineHoldRecordSchema,
2648
+ oac: OACRecordSchema
2649
+ });
2650
+ var DisableOfflineResultSchema = z12.object({
2651
+ hold: OfflineHoldRecordSchema,
2652
+ trusted: z12.boolean(),
2653
+ settledClaims: z12.number().int().nonnegative()
2654
+ });
2655
+ var OfflineStatusResultSchema = z12.object({
2656
+ hold: OfflineHoldRecordSchema.nullable(),
2657
+ active: OACRecordSchema.nullable()
2658
+ });
2659
+ var OfflineStateResultSchema = z12.object({
2660
+ active: OACRecordSchema.nullable()
2661
+ });
2662
+ var ConsumerPaymentClaimSchema = z12.object({
2663
+ oacId: z12.string().uuid(),
2664
+ encounterId: Sha256Hex.optional(),
2665
+ payerUserId: z12.string().uuid(),
2666
+ payeeUserId: z12.string().uuid(),
2667
+ payerDeviceId: z12.string().min(1).max(128),
2668
+ payerNonce: z12.string().min(8).max(128),
2669
+ payeeNonce: z12.string().min(8).max(128),
2670
+ amountKobo: z12.number().int().positive(),
2671
+ currency: z12.string().length(3).default("NGN"),
2672
+ occurredAtMs: z12.number().int().nonnegative(),
2673
+ completedAtMs: z12.number().int().nonnegative().optional(),
2674
+ contextId: z12.string().max(128).optional(),
2675
+ payerPubkeyHex: Hex64,
2676
+ payerSignature: HexAny,
2677
+ payeePubkeyHex: Hex64.optional(),
2678
+ payeeSignature: HexAny.optional()
2679
+ });
2680
+ var ConsumerSettlementSchema = z12.object({
2681
+ settlementId: z12.string().uuid(),
2682
+ settlementKey: Sha256Hex,
2683
+ encounterId: Sha256Hex,
2684
+ oacId: z12.string().uuid(),
2685
+ payerUserId: z12.string().uuid(),
2686
+ payeeUserId: z12.string().uuid(),
2687
+ amountKobo: z12.number().int().positive(),
2688
+ currency: z12.string().length(3),
2689
+ status: z12.enum(["SETTLED", "REVIEW"]),
2690
+ reviewReason: z12.string().nullable(),
2691
+ ledgerRef: z12.string().nullable(),
2692
+ issuerSig: HexAny,
2693
+ createdAtMs: z12.number().int().nonnegative()
2694
+ });
2695
+ var ConsumerSettleResultSchema = z12.object({
2696
+ settlement: ConsumerSettlementSchema,
2697
+ encounterId: Sha256Hex,
2698
+ replayed: z12.boolean()
2699
+ });
2700
+ var RevokeDeviceKeyInputSchema = z12.object({
2701
+ deviceId: z12.string().min(1).max(128),
2702
+ /** Step-up token from /api/v1/auth/send/verify with purpose='offline_revoke'. */
2703
+ sendAuthToken: z12.string().min(16)
2704
+ });
2705
+ function createMeOfflineClient(opts) {
2706
+ const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
2707
+ if (!fetchImpl) {
2708
+ throw new Error("createMeOfflineClient: no fetch implementation available");
2709
+ }
2710
+ const baseUrl = opts.baseUrl.replace(/\/$/, "");
2711
+ async function call(method, path, body, parser) {
2712
+ const init2 = {
2713
+ method,
2714
+ headers: {
2715
+ "content-type": "application/json",
2716
+ accept: "application/json"
2717
+ }
2718
+ };
2719
+ if (body !== void 0) init2.body = JSON.stringify(body);
2720
+ const resp = await fetchImpl(`${baseUrl}${path}`, init2);
2721
+ const text = await resp.text();
2722
+ let raw = void 0;
2723
+ if (text) {
2724
+ try {
2725
+ raw = JSON.parse(text);
2726
+ } catch {
2727
+ }
2728
+ }
2729
+ if (!resp.ok) {
2730
+ const code = raw && typeof raw === "object" && "code" in raw && typeof raw.code === "string" ? raw.code : `http_${resp.status}`;
2731
+ const message = raw && typeof raw === "object" && "message" in raw && typeof raw.message === "string" ? raw.message : `request failed with status ${resp.status}`;
2732
+ throw new FlurApiError(resp.status, code, message, raw);
2733
+ }
2734
+ return parser(raw);
2735
+ }
2736
+ const deviceKeyItems = z12.object({ items: z12.array(DeviceKeyRecordSchema) });
2737
+ return {
2738
+ registerDeviceKey: (input) => call(
2739
+ "POST",
2740
+ "/v1/me/offline/keys",
2741
+ RegisterDeviceKeyInputSchema.parse(input),
2742
+ (raw) => DeviceKeyRecordSchema.parse(raw)
2743
+ ),
2744
+ listDeviceKeys: () => call(
2745
+ "GET",
2746
+ "/v1/me/offline/keys",
2747
+ void 0,
2748
+ (raw) => deviceKeyItems.parse(raw)
2749
+ ),
2750
+ revokeDeviceKey: (input) => call(
2751
+ "POST",
2752
+ "/v1/me/offline/keys/revoke",
2753
+ RevokeDeviceKeyInputSchema.parse(input),
2754
+ () => void 0
2755
+ ),
2756
+ enable: (input) => call(
2757
+ "POST",
2758
+ "/v1/me/offline/enable",
2759
+ EnableOfflineInputSchema.parse(input),
2760
+ (raw) => EnableOfflineResultSchema.parse(raw)
2761
+ ),
2762
+ refresh: (input) => call(
2763
+ "POST",
2764
+ "/v1/me/offline/refresh",
2765
+ IssueOACInputSchema.parse(input),
2766
+ (raw) => OACRecordSchema.parse(raw)
2767
+ ),
2768
+ disable: (input) => call(
2769
+ "POST",
2770
+ "/v1/me/offline/disable",
2771
+ DisableOfflineInputSchema.parse(input),
2772
+ (raw) => DisableOfflineResultSchema.parse(raw)
2773
+ ),
2774
+ getStatus: (deviceId) => {
2775
+ const qs = deviceId ? `?deviceId=${encodeURIComponent(deviceId)}` : "";
2776
+ return call(
2777
+ "GET",
2778
+ `/v1/me/offline/status${qs}`,
2779
+ void 0,
2780
+ (raw) => OfflineStatusResultSchema.parse(raw)
2781
+ );
2782
+ },
2783
+ getState: (deviceId) => {
2784
+ const qs = deviceId ? `?deviceId=${encodeURIComponent(deviceId)}` : "";
2785
+ return call(
2786
+ "GET",
2787
+ `/v1/me/offline/state${qs}`,
2788
+ void 0,
2789
+ (raw) => OfflineStateResultSchema.parse(raw)
2790
+ );
2791
+ },
2792
+ submitClaim: (claim) => call(
2793
+ "POST",
2794
+ "/v1/me/offline/claims",
2795
+ ConsumerPaymentClaimSchema.parse(claim),
2796
+ (raw) => ConsumerSettleResultSchema.parse(raw)
2797
+ )
2798
+ };
2799
+ }
2509
2800
  export {
2510
2801
  ACCOUNT_STATUSES,
2511
2802
  ACCOUNT_TYPES,
@@ -2513,6 +2804,16 @@ export {
2513
2804
  AccountMembershipSchema,
2514
2805
  AccountSchema,
2515
2806
  ApiCredentialPublicSchema,
2807
+ OACRecordSchema as ConsumerOACRecordSchema,
2808
+ ConsumerOACSchema,
2809
+ ConsumerPaymentClaimSchema,
2810
+ ConsumerSettleResultSchema,
2811
+ ConsumerSettlementSchema,
2812
+ DeviceKeyRecordSchema,
2813
+ DisableOfflineInputSchema,
2814
+ DisableOfflineResultSchema,
2815
+ EnableOfflineInputSchema,
2816
+ EnableOfflineResultSchema,
2516
2817
  FIELD,
2517
2818
  FlurApiError,
2518
2819
  FlurCapExceededError,
@@ -2520,6 +2821,7 @@ export {
2520
2821
  FlurError,
2521
2822
  FlurExpiredError,
2522
2823
  FlurReplayError,
2824
+ IssueOACInputSchema,
2523
2825
  MEMBERSHIP_ROLES,
2524
2826
  MintedApiCredentialSchema,
2525
2827
  NGN_CURRENCY_CODE,
@@ -2529,8 +2831,11 @@ export {
2529
2831
  OAC_DEFAULT_CUMULATIVE_KOBO,
2530
2832
  OAC_DEFAULT_PER_TX_KOBO,
2531
2833
  OAC_DEFAULT_VALIDITY_MS,
2834
+ OfflineHoldRecordSchema,
2532
2835
  OfflinePaymentAuthorizationSchema,
2533
2836
  OfflinePaymentRequestSchema,
2837
+ OfflineStateResultSchema,
2838
+ OfflineStatusResultSchema,
2534
2839
  OfflineTokenSchema,
2535
2840
  PARTNER_SCOPES,
2536
2841
  PASS_KINDS,
@@ -2546,8 +2851,11 @@ export {
2546
2851
  ReceiptPayloadSchema,
2547
2852
  ReceiptSchema,
2548
2853
  RedemptionSchema,
2854
+ RegisterDeviceKeyInputSchema,
2855
+ RevokeDeviceKeyInputSchema,
2549
2856
  SettleResponseSchema,
2550
2857
  SettlementSchema,
2858
+ SignedConsumerOACSchema,
2551
2859
  bodySha256Hex,
2552
2860
  buildAuthorization,
2553
2861
  buildOAC,
@@ -2566,6 +2874,7 @@ export {
2566
2874
  createApiCredentialsAdminClient,
2567
2875
  createFlurPartnerClient,
2568
2876
  createHmacFetch,
2877
+ createMeOfflineClient,
2569
2878
  createOfflineSettlementsClient,
2570
2879
  createPassesClient,
2571
2880
  createReceiptsClient,