@nokinc-flur/sdk 1.1.1 → 1.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/dist/index.js CHANGED
@@ -2920,15 +2920,45 @@ import { z as z13 } from "zod";
2920
2920
  var Hex64 = z13.string().regex(/^[0-9a-f]{64}$/i);
2921
2921
  var HexAny = z13.string().regex(/^[0-9a-f]+$/i);
2922
2922
  var Sha256Hex = z13.string().regex(/^[0-9a-f]{64}$/i);
2923
+ var Base64Std = z13.string().regex(/^[A-Za-z0-9+/]+={0,2}$/);
2923
2924
  var RegisterDeviceKeyInputSchema = z13.object({
2924
2925
  deviceId: z13.string().min(1).max(128),
2925
2926
  publicKeyHex: Hex64
2926
2927
  });
2928
+ var AttestationSecurityLevelSchema = z13.enum([
2929
+ "STRONGBOX",
2930
+ "TEE",
2931
+ "SECURE_ENCLAVE",
2932
+ "SOFTWARE"
2933
+ ]);
2934
+ var DeviceKeyAlgSchema = z13.enum(["ed25519", "p256"]);
2935
+ var RegisterDeviceKeyP256InputSchema = z13.object({
2936
+ deviceId: z13.string().min(1).max(128),
2937
+ /** P-256 SubjectPublicKeyInfo DER, base64. */
2938
+ publicKeySpkiB64: Base64Std.min(64).max(4096),
2939
+ /** Base64 of the server-issued enrollment challenge string. */
2940
+ challengeB64: Base64Std.min(8).max(1024),
2941
+ /** iOS App Attest payload or Android X.509 Key Attestation chain. */
2942
+ attestationChainB64: z13.array(Base64Std.min(16).max(16384)).min(1).max(16),
2943
+ securityLevel: AttestationSecurityLevelSchema
2944
+ });
2945
+ var P256EnrollmentChallengeInputSchema = z13.object({
2946
+ deviceId: z13.string().min(1).max(128)
2947
+ });
2948
+ var P256EnrollmentChallengeResultSchema = z13.object({
2949
+ challenge: z13.string().min(16),
2950
+ expiresAtMs: z13.number().int().positive()
2951
+ });
2927
2952
  var DeviceKeyRecordSchema = z13.object({
2928
2953
  id: z13.string().uuid(),
2929
2954
  userId: z13.string().uuid(),
2930
2955
  deviceId: z13.string(),
2931
- publicKeyHex: Hex64,
2956
+ alg: DeviceKeyAlgSchema.default("ed25519"),
2957
+ publicKeyHex: Hex64.nullable().default(null),
2958
+ publicKeySpkiB64: Base64Std.nullable().default(null),
2959
+ securityLevel: AttestationSecurityLevelSchema.nullable().default(null),
2960
+ hardwareBacked: z13.boolean().default(false),
2961
+ attestedAtMs: z13.number().int().nonnegative().nullable().default(null),
2932
2962
  createdAtMs: z13.number().int().nonnegative(),
2933
2963
  revokedAtMs: z13.number().int().nonnegative().nullable()
2934
2964
  });
@@ -2937,7 +2967,9 @@ var ConsumerOACSchema = z13.object({
2937
2967
  issuerId: z13.string().min(1).max(64),
2938
2968
  userId: z13.string().uuid(),
2939
2969
  deviceId: z13.string().min(1).max(128),
2940
- devicePubkeyHex: Hex64,
2970
+ alg: z13.enum(["ed25519", "p256"]).optional(),
2971
+ devicePubkeyHex: Hex64.optional(),
2972
+ devicePubkeySpkiB64: Base64Std.min(64).max(4096).optional(),
2941
2973
  perTxCapKobo: z13.number().int().positive(),
2942
2974
  cumulativeCapKobo: z13.number().int().positive(),
2943
2975
  currency: z13.string().length(3),
@@ -2945,7 +2977,16 @@ var ConsumerOACSchema = z13.object({
2945
2977
  validUntilMs: z13.number().int().nonnegative(),
2946
2978
  counterSeed: z13.number().int().nonnegative(),
2947
2979
  issuedAtMs: z13.number().int().nonnegative()
2948
- });
2980
+ }).refine(
2981
+ (o) => {
2982
+ const alg = o.alg ?? "ed25519";
2983
+ if (alg === "ed25519") {
2984
+ return Boolean(o.devicePubkeyHex) && !o.devicePubkeySpkiB64;
2985
+ }
2986
+ return Boolean(o.devicePubkeySpkiB64) && !o.devicePubkeyHex;
2987
+ },
2988
+ { message: "OAC device pubkey shape must match alg" }
2989
+ );
2949
2990
  var SignedConsumerOACSchema = z13.object({
2950
2991
  oac: ConsumerOACSchema,
2951
2992
  issuerSig: HexAny,
@@ -2981,6 +3022,7 @@ var EnableOfflineInputSchema = z13.object({
2981
3022
  installId: z13.string().min(1).max(128),
2982
3023
  partnerId: z13.string().min(1).max(64).optional()
2983
3024
  });
3025
+ var ProvisionOfflineAllowanceInputSchema = EnableOfflineInputSchema;
2984
3026
  var DisableOfflineInputSchema = z13.object({
2985
3027
  deviceId: z13.string().min(1).max(128),
2986
3028
  installId: z13.string().min(1).max(128).optional(),
@@ -3018,6 +3060,7 @@ var EnableOfflineResultSchema = z13.object({
3018
3060
  hold: OfflineHoldRecordSchema,
3019
3061
  oac: OACRecordSchema
3020
3062
  });
3063
+ var ProvisionOfflineAllowanceResultSchema = EnableOfflineResultSchema;
3021
3064
  var DisableOfflineResultSchema = z13.object({
3022
3065
  hold: OfflineHoldRecordSchema,
3023
3066
  trusted: z13.boolean(),
@@ -3030,7 +3073,10 @@ var OfflineStatusResultSchema = z13.object({
3030
3073
  var OfflineStateResultSchema = z13.object({
3031
3074
  active: OACRecordSchema.nullable()
3032
3075
  });
3076
+ var ClaimAlgSchema = z13.enum(["ed25519", "p256"]);
3033
3077
  var ConsumerPaymentClaimSchema = z13.object({
3078
+ /** Algorithm discriminator. Omit / 'ed25519' for V1 clients. */
3079
+ alg: ClaimAlgSchema.optional(),
3034
3080
  oacId: z13.string().uuid(),
3035
3081
  encounterId: Sha256Hex.optional(),
3036
3082
  payerUserId: z13.string().uuid(),
@@ -3043,11 +3089,28 @@ var ConsumerPaymentClaimSchema = z13.object({
3043
3089
  occurredAtMs: z13.number().int().nonnegative(),
3044
3090
  completedAtMs: z13.number().int().nonnegative().optional(),
3045
3091
  contextId: z13.string().max(128).optional(),
3046
- payerPubkeyHex: Hex64,
3047
- payerSignature: HexAny,
3092
+ // ed25519 path
3093
+ payerPubkeyHex: Hex64.optional(),
3094
+ payerSignature: HexAny.optional(),
3048
3095
  payeePubkeyHex: Hex64.optional(),
3049
- payeeSignature: HexAny.optional()
3050
- });
3096
+ payeeSignature: HexAny.optional(),
3097
+ // p256 path
3098
+ payerPubkeySpkiB64: z13.string().min(64).max(4096).optional(),
3099
+ payerSignatureDerB64: z13.string().min(16).max(2048).optional(),
3100
+ payeePubkeySpkiB64: z13.string().min(64).max(4096).optional(),
3101
+ payeeSignatureDerB64: z13.string().min(16).max(2048).optional()
3102
+ }).refine(
3103
+ (c) => {
3104
+ const alg = c.alg ?? "ed25519";
3105
+ if (alg === "ed25519") {
3106
+ return Boolean(c.payerPubkeyHex) && Boolean(c.payerSignature);
3107
+ }
3108
+ return Boolean(c.payerPubkeySpkiB64) && Boolean(c.payerSignatureDerB64);
3109
+ },
3110
+ {
3111
+ message: "payer key/signature fields must match alg (ed25519: hex; p256: SPKI+DER b64)"
3112
+ }
3113
+ );
3051
3114
  var ConsumerSettlementSchema = z13.object({
3052
3115
  settlementId: z13.string().uuid(),
3053
3116
  settlementKey: Sha256Hex,
@@ -3112,6 +3175,18 @@ function createMeOfflineClient(opts) {
3112
3175
  RegisterDeviceKeyInputSchema.parse(input),
3113
3176
  (raw) => DeviceKeyRecordSchema.parse(raw)
3114
3177
  ),
3178
+ issueP256EnrollmentChallenge: (input) => call(
3179
+ "POST",
3180
+ "/v1/me/offline/keys/p256/challenge",
3181
+ P256EnrollmentChallengeInputSchema.parse(input),
3182
+ (raw) => P256EnrollmentChallengeResultSchema.parse(raw)
3183
+ ),
3184
+ registerDeviceKeyP256: (input) => call(
3185
+ "POST",
3186
+ "/v1/me/offline/keys/p256",
3187
+ RegisterDeviceKeyP256InputSchema.parse(input),
3188
+ (raw) => DeviceKeyRecordSchema.parse(raw)
3189
+ ),
3115
3190
  listDeviceKeys: () => call(
3116
3191
  "GET",
3117
3192
  "/v1/me/offline/keys",
@@ -3124,6 +3199,12 @@ function createMeOfflineClient(opts) {
3124
3199
  RevokeDeviceKeyInputSchema.parse(input),
3125
3200
  () => void 0
3126
3201
  ),
3202
+ provisionAllowance: (input) => call(
3203
+ "POST",
3204
+ "/v1/me/offline/allowance",
3205
+ ProvisionOfflineAllowanceInputSchema.parse(input),
3206
+ (raw) => ProvisionOfflineAllowanceResultSchema.parse(raw)
3207
+ ),
3127
3208
  enable: (input) => call(
3128
3209
  "POST",
3129
3210
  "/v1/me/offline/enable",
@@ -3169,6 +3250,148 @@ function createMeOfflineClient(opts) {
3169
3250
  };
3170
3251
  }
3171
3252
 
3253
+ // src/me-offline/signer.ts
3254
+ import { ed25519 as ed255192 } from "@noble/curves/ed25519";
3255
+ import { p256 } from "@noble/curves/nist";
3256
+ import { bytesToHex as bytesToHex5, hexToBytes as hexToBytes2 } from "@noble/hashes/utils";
3257
+ var CLAIM_DOMAIN_V2 = "flur:consumer-offline:v2:claim";
3258
+ function canonicalClaimSigningPayload(claim) {
3259
+ return {
3260
+ domain: CLAIM_DOMAIN_V2,
3261
+ alg: claim.alg,
3262
+ oacId: claim.oacId,
3263
+ payerUserId: claim.payerUserId,
3264
+ payeeUserId: claim.payeeUserId,
3265
+ payerDeviceId: claim.payerDeviceId,
3266
+ payerNonce: claim.payerNonce,
3267
+ payeeNonce: claim.payeeNonce,
3268
+ amountKobo: claim.amountKobo,
3269
+ currency: claim.currency,
3270
+ occurredAtMs: claim.occurredAtMs,
3271
+ completedAtMs: claim.completedAtMs ?? null,
3272
+ contextId: claim.contextId ?? null
3273
+ };
3274
+ }
3275
+ function canonicalClaimSigningBytes(claim) {
3276
+ return canonicalJSONBytes(canonicalClaimSigningPayload(claim));
3277
+ }
3278
+ function bytesToBase64(bytes) {
3279
+ if (typeof Buffer !== "undefined") {
3280
+ return Buffer.from(bytes).toString("base64");
3281
+ }
3282
+ let bin = "";
3283
+ for (let i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i]);
3284
+ return btoa(bin);
3285
+ }
3286
+ function base64ToBytes(b64) {
3287
+ if (typeof Buffer !== "undefined") {
3288
+ return new Uint8Array(Buffer.from(b64, "base64"));
3289
+ }
3290
+ const bin = atob(b64);
3291
+ const out = new Uint8Array(bin.length);
3292
+ for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
3293
+ return out;
3294
+ }
3295
+ var P256_SPKI_HEADER = new Uint8Array([
3296
+ 48,
3297
+ 89,
3298
+ 48,
3299
+ 19,
3300
+ 6,
3301
+ 7,
3302
+ 42,
3303
+ 134,
3304
+ 72,
3305
+ 206,
3306
+ 61,
3307
+ 2,
3308
+ 1,
3309
+ 6,
3310
+ 8,
3311
+ 42,
3312
+ 134,
3313
+ 72,
3314
+ 206,
3315
+ 61,
3316
+ 3,
3317
+ 1,
3318
+ 7,
3319
+ 3,
3320
+ 66,
3321
+ 0
3322
+ ]);
3323
+ function p256PublicKeyToSpkiB64(rawUncompressed) {
3324
+ if (rawUncompressed.length !== 65 || rawUncompressed[0] !== 4) {
3325
+ throw new Error("p256: expected 65-byte uncompressed point");
3326
+ }
3327
+ const out = new Uint8Array(P256_SPKI_HEADER.length + rawUncompressed.length);
3328
+ out.set(P256_SPKI_HEADER, 0);
3329
+ out.set(rawUncompressed, P256_SPKI_HEADER.length);
3330
+ return bytesToBase64(out);
3331
+ }
3332
+ function p256SpkiB64ToPublicKey(spkiB64) {
3333
+ const spki = base64ToBytes(spkiB64);
3334
+ if (spki.length !== P256_SPKI_HEADER.length + 65) {
3335
+ throw new Error("p256: invalid SPKI length");
3336
+ }
3337
+ for (let i = 0; i < P256_SPKI_HEADER.length; i++) {
3338
+ if (spki[i] !== P256_SPKI_HEADER[i]) {
3339
+ throw new Error("p256: invalid SPKI header");
3340
+ }
3341
+ }
3342
+ return spki.slice(P256_SPKI_HEADER.length);
3343
+ }
3344
+ function createSoftwareEd25519Signer(privateKey) {
3345
+ const pub = ed255192.getPublicKey(privateKey);
3346
+ return {
3347
+ alg: "ed25519",
3348
+ async getPublicKey() {
3349
+ return { alg: "ed25519", publicKey: bytesToHex5(pub) };
3350
+ },
3351
+ async sign(bytes) {
3352
+ const sig = ed255192.sign(bytes, privateKey);
3353
+ return { alg: "ed25519", signature: bytesToHex5(sig) };
3354
+ }
3355
+ };
3356
+ }
3357
+ function createSoftwareP256Signer(privateKey) {
3358
+ const raw = p256.getPublicKey(privateKey, false);
3359
+ const spkiB64 = p256PublicKeyToSpkiB64(raw);
3360
+ return {
3361
+ alg: "p256",
3362
+ async getPublicKey() {
3363
+ return { alg: "p256", publicKey: spkiB64 };
3364
+ },
3365
+ async sign(bytes) {
3366
+ const sig = p256.sign(bytes, privateKey, { prehash: true });
3367
+ const der = sig.toBytes("der");
3368
+ return { alg: "p256", signature: bytesToBase64(der) };
3369
+ }
3370
+ };
3371
+ }
3372
+ function verifyClaimSignature(input) {
3373
+ try {
3374
+ if (input.alg === "ed25519") {
3375
+ return ed255192.verify(
3376
+ hexToBytes2(input.signature),
3377
+ input.bytes,
3378
+ hexToBytes2(input.publicKey)
3379
+ );
3380
+ }
3381
+ if (input.alg === "p256") {
3382
+ const sigDer = base64ToBytes(input.signature);
3383
+ const pub = p256SpkiB64ToPublicKey(input.publicKey);
3384
+ return p256.verify(sigDer, input.bytes, pub, {
3385
+ prehash: true,
3386
+ format: "der"
3387
+ });
3388
+ }
3389
+ return false;
3390
+ } catch {
3391
+ return false;
3392
+ }
3393
+ }
3394
+
3172
3395
  // src/partner-funding/client.ts
3173
3396
  import { z as z14 } from "zod";
3174
3397
  var MinorString = z14.string().regex(/^-?\d+$/);
@@ -3895,6 +4118,8 @@ export {
3895
4118
  AccountSchema,
3896
4119
  ApiCredentialPublicSchema,
3897
4120
  ArtifactHeaderSchema,
4121
+ AttestationSecurityLevelSchema,
4122
+ CLAIM_DOMAIN_V2,
3898
4123
  COLLECTION_INTENT_STATUSES,
3899
4124
  COLLECTION_PAYMENT_STATUSES,
3900
4125
  CUSTODIAL_MODES,
@@ -3913,6 +4138,7 @@ export {
3913
4138
  CreatePayoutInputSchema,
3914
4139
  CreateWithdrawalInputSchema,
3915
4140
  CreateWithdrawalResultSchema,
4141
+ DeviceKeyAlgSchema,
3916
4142
  DeviceKeyRecordSchema,
3917
4143
  DisableOfflineInputSchema,
3918
4144
  DisableOfflineResultSchema,
@@ -3957,6 +4183,8 @@ export {
3957
4183
  OfflineStateResultSchema,
3958
4184
  OfflineStatusResultSchema,
3959
4185
  OfflineTokenSchema,
4186
+ P256EnrollmentChallengeInputSchema,
4187
+ P256EnrollmentChallengeResultSchema,
3960
4188
  PARTNER_FUNDING_DIRECTIONS,
3961
4189
  PARTNER_FUNDING_STATUSES,
3962
4190
  PARTNER_KINDS,
@@ -3980,6 +4208,8 @@ export {
3980
4208
  PayoutEventInputSchema,
3981
4209
  ProviderEventInputSchema,
3982
4210
  ProviderEventRecordSchema,
4211
+ ProvisionOfflineAllowanceInputSchema,
4212
+ ProvisionOfflineAllowanceResultSchema,
3983
4213
  PublicCollectionIntentSchema,
3984
4214
  RECEIPT_CHANNELS,
3985
4215
  RECEIPT_KINDS,
@@ -3991,6 +4221,7 @@ export {
3991
4221
  RecordPayoutEventResultSchema,
3992
4222
  RedemptionSchema,
3993
4223
  RegisterDeviceKeyInputSchema,
4224
+ RegisterDeviceKeyP256InputSchema,
3994
4225
  ReversalRecordArtifactSchema,
3995
4226
  RevokeDeviceKeyInputSchema,
3996
4227
  SETTLEMENT_SCHEDULES,
@@ -4013,6 +4244,8 @@ export {
4013
4244
  buildPaymentRequest,
4014
4245
  buildReceipt,
4015
4246
  buildRedemption,
4247
+ canonicalClaimSigningBytes,
4248
+ canonicalClaimSigningPayload,
4016
4249
  canonicalJSONBytes,
4017
4250
  canonicalJSONStringify,
4018
4251
  canonicalRequestString,
@@ -4037,6 +4270,8 @@ export {
4037
4270
  createPassesClient,
4038
4271
  createReceiptArtifactUri,
4039
4272
  createReceiptsClient,
4273
+ createSoftwareEd25519Signer,
4274
+ createSoftwareP256Signer,
4040
4275
  decodeArtifactUri,
4041
4276
  decodeAuthorizationQR,
4042
4277
  decodeBase45,
@@ -4078,6 +4313,7 @@ export {
4078
4313
  verifyArtifactUri,
4079
4314
  verifyAuthorization,
4080
4315
  verifyCanonical,
4316
+ verifyClaimSignature,
4081
4317
  verifyOAC,
4082
4318
  verifyPass,
4083
4319
  verifyPaymentRequest,