@nokinc-flur/sdk 2.3.0 → 2.4.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/dist/index.cjs +183 -305
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +68 -188
- package/dist/index.d.ts +68 -188
- package/dist/index.js +181 -295
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3581,6 +3581,7 @@ function base64UrlDecodeUtf8(input) {
|
|
|
3581
3581
|
}
|
|
3582
3582
|
|
|
3583
3583
|
// src/me-offline/oac.ts
|
|
3584
|
+
import { z as z15 } from "zod";
|
|
3584
3585
|
var CONSUMER_OAC_DOMAIN = "flur:consumer-offline:v1:oac";
|
|
3585
3586
|
function consumerOacSigningPayload(oac) {
|
|
3586
3587
|
return { domain: CONSUMER_OAC_DOMAIN, ...oac };
|
|
@@ -3623,15 +3624,28 @@ var CONSUMER_OAC_QR_PREFIX = "FLUROAC1.";
|
|
|
3623
3624
|
function isConsumerOacQR(value) {
|
|
3624
3625
|
return value.startsWith(CONSUMER_OAC_QR_PREFIX);
|
|
3625
3626
|
}
|
|
3626
|
-
|
|
3627
|
+
var OacPresentmentRequestSchema = z15.object({
|
|
3628
|
+
/** Requested amount in minor units (kobo). */
|
|
3629
|
+
amountMinor: z15.number().int().positive().max(1e12).optional(),
|
|
3630
|
+
/** Purpose/intent code (mirrors the NIBSS intent vocabulary). */
|
|
3631
|
+
intent: z15.string().min(1).max(32).optional(),
|
|
3632
|
+
/** Free-text reference / note. */
|
|
3633
|
+
reference: z15.string().min(1).max(64).optional()
|
|
3634
|
+
}).strict();
|
|
3635
|
+
function encodeConsumerOacQR(signed, request) {
|
|
3627
3636
|
const parsed = SignedConsumerOACSchema.parse(signed);
|
|
3628
|
-
|
|
3637
|
+
const base = `${CONSUMER_OAC_QR_PREFIX}${base64UrlEncodeUtf82(JSON.stringify(parsed))}`;
|
|
3638
|
+
if (request === void 0) return base;
|
|
3639
|
+
const parsedRequest = OacPresentmentRequestSchema.parse(request);
|
|
3640
|
+
if (Object.keys(parsedRequest).length === 0) return base;
|
|
3641
|
+
return `${base}.${base64UrlEncodeUtf82(JSON.stringify(parsedRequest))}`;
|
|
3629
3642
|
}
|
|
3630
3643
|
function decodeUnverifiedConsumerOacQR(value) {
|
|
3631
3644
|
if (!value.startsWith(CONSUMER_OAC_QR_PREFIX)) {
|
|
3632
3645
|
throw new Error("not a Flur consumer OAC QR");
|
|
3633
3646
|
}
|
|
3634
|
-
const
|
|
3647
|
+
const remainder = value.slice(CONSUMER_OAC_QR_PREFIX.length);
|
|
3648
|
+
const encoded = remainder.split(".", 1)[0];
|
|
3635
3649
|
let raw;
|
|
3636
3650
|
try {
|
|
3637
3651
|
raw = JSON.parse(base64UrlDecodeUtf82(encoded));
|
|
@@ -3640,6 +3654,21 @@ function decodeUnverifiedConsumerOacQR(value) {
|
|
|
3640
3654
|
}
|
|
3641
3655
|
return SignedConsumerOACSchema.parse(raw);
|
|
3642
3656
|
}
|
|
3657
|
+
function decodeConsumerOacRequest(value) {
|
|
3658
|
+
if (!value.startsWith(CONSUMER_OAC_QR_PREFIX)) return null;
|
|
3659
|
+
const remainder = value.slice(CONSUMER_OAC_QR_PREFIX.length);
|
|
3660
|
+
const dot = remainder.indexOf(".");
|
|
3661
|
+
if (dot < 0) return null;
|
|
3662
|
+
const suffix = remainder.slice(dot + 1);
|
|
3663
|
+
if (suffix.length === 0) return null;
|
|
3664
|
+
try {
|
|
3665
|
+
const raw = JSON.parse(base64UrlDecodeUtf82(suffix));
|
|
3666
|
+
const parsed = OacPresentmentRequestSchema.safeParse(raw);
|
|
3667
|
+
return parsed.success ? parsed.data : null;
|
|
3668
|
+
} catch {
|
|
3669
|
+
return null;
|
|
3670
|
+
}
|
|
3671
|
+
}
|
|
3643
3672
|
function base64UrlEncodeUtf82(input) {
|
|
3644
3673
|
const bytes = new TextEncoder().encode(input);
|
|
3645
3674
|
let binary = "";
|
|
@@ -3935,14 +3964,14 @@ function base64UrlToBytes(input) {
|
|
|
3935
3964
|
}
|
|
3936
3965
|
|
|
3937
3966
|
// src/partner-funding/client.ts
|
|
3938
|
-
import { z as
|
|
3939
|
-
var MinorString =
|
|
3940
|
-
var PositiveMinor =
|
|
3941
|
-
|
|
3942
|
-
|
|
3967
|
+
import { z as z16 } from "zod";
|
|
3968
|
+
var MinorString = z16.string().regex(/^-?\d+$/);
|
|
3969
|
+
var PositiveMinor = z16.union([
|
|
3970
|
+
z16.number().int().positive(),
|
|
3971
|
+
z16.string().regex(/^[1-9]\d{0,18}$/)
|
|
3943
3972
|
]);
|
|
3944
|
-
var Currency =
|
|
3945
|
-
var Metadata =
|
|
3973
|
+
var Currency = z16.string().trim().length(3).transform((v) => v.toUpperCase());
|
|
3974
|
+
var Metadata = z16.record(z16.unknown());
|
|
3946
3975
|
var PARTNER_KINDS = ["bank", "merchant"];
|
|
3947
3976
|
var CUSTODIAL_MODES = ["agent_of_bank", "flur_virtual_pool"];
|
|
3948
3977
|
var PARTNER_PROFILE_STATUSES = [
|
|
@@ -3969,126 +3998,126 @@ var WITHDRAWAL_STATES = [
|
|
|
3969
3998
|
"failed",
|
|
3970
3999
|
"reversed"
|
|
3971
4000
|
];
|
|
3972
|
-
var PartnerProfileSchema =
|
|
3973
|
-
partnerAccountId:
|
|
3974
|
-
kind:
|
|
3975
|
-
custodialMode:
|
|
3976
|
-
displayName:
|
|
3977
|
-
bankCode:
|
|
3978
|
-
poolAccountNumber:
|
|
3979
|
-
status:
|
|
4001
|
+
var PartnerProfileSchema = z16.object({
|
|
4002
|
+
partnerAccountId: z16.string().uuid(),
|
|
4003
|
+
kind: z16.enum(PARTNER_KINDS),
|
|
4004
|
+
custodialMode: z16.enum(CUSTODIAL_MODES),
|
|
4005
|
+
displayName: z16.string(),
|
|
4006
|
+
bankCode: z16.string().nullable(),
|
|
4007
|
+
poolAccountNumber: z16.string().nullable(),
|
|
4008
|
+
status: z16.enum(PARTNER_PROFILE_STATUSES),
|
|
3980
4009
|
metadata: Metadata,
|
|
3981
|
-
createdAtMs:
|
|
3982
|
-
updatedAtMs:
|
|
4010
|
+
createdAtMs: z16.number().int().nonnegative(),
|
|
4011
|
+
updatedAtMs: z16.number().int().nonnegative()
|
|
3983
4012
|
});
|
|
3984
|
-
var UpsertPartnerProfileInputSchema =
|
|
3985
|
-
kind:
|
|
3986
|
-
custodialMode:
|
|
3987
|
-
displayName:
|
|
3988
|
-
bankCode:
|
|
3989
|
-
poolAccountNumber:
|
|
4013
|
+
var UpsertPartnerProfileInputSchema = z16.object({
|
|
4014
|
+
kind: z16.enum(PARTNER_KINDS),
|
|
4015
|
+
custodialMode: z16.enum(CUSTODIAL_MODES),
|
|
4016
|
+
displayName: z16.string().trim().min(1).max(200),
|
|
4017
|
+
bankCode: z16.string().trim().min(1).max(64).optional(),
|
|
4018
|
+
poolAccountNumber: z16.string().trim().min(1).max(64).optional(),
|
|
3990
4019
|
metadata: Metadata.optional()
|
|
3991
4020
|
});
|
|
3992
|
-
var PartnerFundingEventInputSchema =
|
|
3993
|
-
externalRef:
|
|
3994
|
-
direction:
|
|
3995
|
-
userId:
|
|
3996
|
-
accountId:
|
|
4021
|
+
var PartnerFundingEventInputSchema = z16.object({
|
|
4022
|
+
externalRef: z16.string().trim().min(8).max(128),
|
|
4023
|
+
direction: z16.enum(PARTNER_FUNDING_DIRECTIONS).optional(),
|
|
4024
|
+
userId: z16.string().uuid().optional(),
|
|
4025
|
+
accountId: z16.string().uuid().optional(),
|
|
3997
4026
|
amountMinor: PositiveMinor,
|
|
3998
4027
|
currency: Currency,
|
|
3999
|
-
fundingSource:
|
|
4028
|
+
fundingSource: z16.string().trim().min(1).max(64).optional(),
|
|
4000
4029
|
providerMetadata: Metadata.optional()
|
|
4001
4030
|
});
|
|
4002
|
-
var PartnerFundingSchema =
|
|
4003
|
-
fundingId:
|
|
4004
|
-
partnerId:
|
|
4005
|
-
accountId:
|
|
4006
|
-
userId:
|
|
4007
|
-
direction:
|
|
4008
|
-
currency:
|
|
4031
|
+
var PartnerFundingSchema = z16.object({
|
|
4032
|
+
fundingId: z16.string().uuid(),
|
|
4033
|
+
partnerId: z16.string().uuid(),
|
|
4034
|
+
accountId: z16.string().uuid(),
|
|
4035
|
+
userId: z16.string().uuid().nullable(),
|
|
4036
|
+
direction: z16.enum(PARTNER_FUNDING_DIRECTIONS),
|
|
4037
|
+
currency: z16.string(),
|
|
4009
4038
|
amountMinor: MinorString,
|
|
4010
|
-
externalRef:
|
|
4011
|
-
status:
|
|
4012
|
-
fundingSource:
|
|
4013
|
-
ledgerRef:
|
|
4039
|
+
externalRef: z16.string(),
|
|
4040
|
+
status: z16.enum(PARTNER_FUNDING_STATUSES),
|
|
4041
|
+
fundingSource: z16.string(),
|
|
4042
|
+
ledgerRef: z16.string(),
|
|
4014
4043
|
providerMetadata: Metadata,
|
|
4015
|
-
createdAtMs:
|
|
4016
|
-
updatedAtMs:
|
|
4044
|
+
createdAtMs: z16.number().int().nonnegative(),
|
|
4045
|
+
updatedAtMs: z16.number().int().nonnegative()
|
|
4017
4046
|
});
|
|
4018
|
-
var IngestFundingResultSchema =
|
|
4047
|
+
var IngestFundingResultSchema = z16.object({
|
|
4019
4048
|
funding: PartnerFundingSchema,
|
|
4020
|
-
replayed:
|
|
4049
|
+
replayed: z16.boolean()
|
|
4021
4050
|
});
|
|
4022
|
-
var PayoutDestinationSchema =
|
|
4023
|
-
destinationId:
|
|
4024
|
-
accountId:
|
|
4025
|
-
partnerId:
|
|
4026
|
-
bankCode:
|
|
4027
|
-
accountNumber:
|
|
4028
|
-
accountName:
|
|
4029
|
-
status:
|
|
4030
|
-
verifiedAtMs:
|
|
4051
|
+
var PayoutDestinationSchema = z16.object({
|
|
4052
|
+
destinationId: z16.string().uuid(),
|
|
4053
|
+
accountId: z16.string().uuid(),
|
|
4054
|
+
partnerId: z16.string().uuid(),
|
|
4055
|
+
bankCode: z16.string(),
|
|
4056
|
+
accountNumber: z16.string(),
|
|
4057
|
+
accountName: z16.string(),
|
|
4058
|
+
status: z16.enum(PAYOUT_DESTINATION_STATUSES),
|
|
4059
|
+
verifiedAtMs: z16.number().int().nonnegative().nullable(),
|
|
4031
4060
|
metadata: Metadata,
|
|
4032
|
-
createdAtMs:
|
|
4033
|
-
updatedAtMs:
|
|
4061
|
+
createdAtMs: z16.number().int().nonnegative(),
|
|
4062
|
+
updatedAtMs: z16.number().int().nonnegative()
|
|
4034
4063
|
});
|
|
4035
|
-
var CreatePayoutDestinationInputSchema =
|
|
4036
|
-
partnerId:
|
|
4037
|
-
bankCode:
|
|
4038
|
-
accountNumber:
|
|
4039
|
-
accountName:
|
|
4064
|
+
var CreatePayoutDestinationInputSchema = z16.object({
|
|
4065
|
+
partnerId: z16.string().uuid(),
|
|
4066
|
+
bankCode: z16.string().trim().min(1).max(32),
|
|
4067
|
+
accountNumber: z16.string().trim().min(4).max(64),
|
|
4068
|
+
accountName: z16.string().trim().min(1).max(200),
|
|
4040
4069
|
metadata: Metadata.optional()
|
|
4041
4070
|
});
|
|
4042
|
-
var ListPayoutDestinationsResultSchema =
|
|
4043
|
-
items:
|
|
4071
|
+
var ListPayoutDestinationsResultSchema = z16.object({
|
|
4072
|
+
items: z16.array(PayoutDestinationSchema)
|
|
4044
4073
|
});
|
|
4045
|
-
var WithdrawalSchema =
|
|
4046
|
-
withdrawalId:
|
|
4047
|
-
accountId:
|
|
4048
|
-
userId:
|
|
4049
|
-
partnerId:
|
|
4050
|
-
destinationId:
|
|
4051
|
-
currency:
|
|
4074
|
+
var WithdrawalSchema = z16.object({
|
|
4075
|
+
withdrawalId: z16.string().uuid(),
|
|
4076
|
+
accountId: z16.string().uuid(),
|
|
4077
|
+
userId: z16.string().uuid(),
|
|
4078
|
+
partnerId: z16.string().uuid(),
|
|
4079
|
+
destinationId: z16.string().uuid(),
|
|
4080
|
+
currency: z16.string(),
|
|
4052
4081
|
amountMinor: MinorString,
|
|
4053
|
-
state:
|
|
4054
|
-
idempotencyKey:
|
|
4055
|
-
providerRef:
|
|
4056
|
-
lastError:
|
|
4057
|
-
ledgerRef:
|
|
4058
|
-
reverseLedgerRef:
|
|
4082
|
+
state: z16.enum(WITHDRAWAL_STATES),
|
|
4083
|
+
idempotencyKey: z16.string(),
|
|
4084
|
+
providerRef: z16.string().nullable(),
|
|
4085
|
+
lastError: z16.string().nullable(),
|
|
4086
|
+
ledgerRef: z16.string(),
|
|
4087
|
+
reverseLedgerRef: z16.string().nullable(),
|
|
4059
4088
|
metadata: Metadata,
|
|
4060
|
-
createdAtMs:
|
|
4061
|
-
updatedAtMs:
|
|
4089
|
+
createdAtMs: z16.number().int().nonnegative(),
|
|
4090
|
+
updatedAtMs: z16.number().int().nonnegative()
|
|
4062
4091
|
});
|
|
4063
|
-
var CreateWithdrawalInputSchema =
|
|
4064
|
-
destinationId:
|
|
4092
|
+
var CreateWithdrawalInputSchema = z16.object({
|
|
4093
|
+
destinationId: z16.string().uuid(),
|
|
4065
4094
|
amountMinor: PositiveMinor,
|
|
4066
4095
|
currency: Currency,
|
|
4067
|
-
idempotencyKey:
|
|
4096
|
+
idempotencyKey: z16.string().trim().min(8).max(128),
|
|
4068
4097
|
metadata: Metadata.optional()
|
|
4069
4098
|
});
|
|
4070
|
-
var CreateWithdrawalResultSchema =
|
|
4099
|
+
var CreateWithdrawalResultSchema = z16.object({
|
|
4071
4100
|
withdrawal: WithdrawalSchema,
|
|
4072
|
-
replayed:
|
|
4101
|
+
replayed: z16.boolean()
|
|
4073
4102
|
});
|
|
4074
|
-
var PayoutEventInputSchema =
|
|
4075
|
-
externalRef:
|
|
4076
|
-
withdrawalId:
|
|
4077
|
-
state:
|
|
4078
|
-
providerRef:
|
|
4079
|
-
failureCode:
|
|
4080
|
-
failureMessage:
|
|
4103
|
+
var PayoutEventInputSchema = z16.object({
|
|
4104
|
+
externalRef: z16.string().trim().min(8).max(128),
|
|
4105
|
+
withdrawalId: z16.string().uuid().optional(),
|
|
4106
|
+
state: z16.enum(["submitted", "processing", "paid", "failed"]),
|
|
4107
|
+
providerRef: z16.string().trim().min(1).max(128).optional(),
|
|
4108
|
+
failureCode: z16.string().trim().max(64).optional(),
|
|
4109
|
+
failureMessage: z16.string().trim().max(512).optional(),
|
|
4081
4110
|
providerMetadata: Metadata.optional()
|
|
4082
4111
|
});
|
|
4083
|
-
var RecordPayoutEventResultSchema =
|
|
4112
|
+
var RecordPayoutEventResultSchema = z16.object({
|
|
4084
4113
|
withdrawal: WithdrawalSchema,
|
|
4085
|
-
replayed:
|
|
4114
|
+
replayed: z16.boolean()
|
|
4086
4115
|
});
|
|
4087
|
-
var ReconciliationReportSchema =
|
|
4088
|
-
partnerId:
|
|
4089
|
-
currency:
|
|
4090
|
-
fromMs:
|
|
4091
|
-
toMs:
|
|
4116
|
+
var ReconciliationReportSchema = z16.object({
|
|
4117
|
+
partnerId: z16.string().uuid(),
|
|
4118
|
+
currency: z16.string(),
|
|
4119
|
+
fromMs: z16.number().int().nonnegative(),
|
|
4120
|
+
toMs: z16.number().int().nonnegative(),
|
|
4092
4121
|
fundingsCreditMinor: MinorString,
|
|
4093
4122
|
fundingsDebitMinor: MinorString,
|
|
4094
4123
|
withdrawalsPaidMinor: MinorString,
|
|
@@ -4097,7 +4126,7 @@ var ReconciliationReportSchema = z15.object({
|
|
|
4097
4126
|
expectedReserveBalanceMinor: MinorString,
|
|
4098
4127
|
actualReserveBalanceMinor: MinorString,
|
|
4099
4128
|
imbalanceMinor: MinorString,
|
|
4100
|
-
generatedAtMs:
|
|
4129
|
+
generatedAtMs: z16.number().int().nonnegative()
|
|
4101
4130
|
});
|
|
4102
4131
|
function createPartnerFundingClient(partner) {
|
|
4103
4132
|
return {
|
|
@@ -4249,19 +4278,19 @@ function createPartnerProfileAdminClient(opts) {
|
|
|
4249
4278
|
}
|
|
4250
4279
|
|
|
4251
4280
|
// src/artifacts/envelope.ts
|
|
4252
|
-
import { z as
|
|
4281
|
+
import { z as z17 } from "zod";
|
|
4253
4282
|
var FLUR_ARTIFACT_URI_SCHEME = "flur";
|
|
4254
4283
|
var FLUR_ARTIFACT_VERSION = 1;
|
|
4255
4284
|
var FLUR_ARTIFACT_URI_PREFIX = `${FLUR_ARTIFACT_URI_SCHEME}://v${FLUR_ARTIFACT_VERSION}/`;
|
|
4256
4285
|
var ArtifactTypeRe = /^[a-z][a-z0-9_]{1,63}$/;
|
|
4257
|
-
var ArtifactHeaderSchema =
|
|
4258
|
-
v:
|
|
4259
|
-
t:
|
|
4260
|
-
iss:
|
|
4261
|
-
kid:
|
|
4262
|
-
iat:
|
|
4263
|
-
exp:
|
|
4264
|
-
nonce:
|
|
4286
|
+
var ArtifactHeaderSchema = z17.object({
|
|
4287
|
+
v: z17.literal(FLUR_ARTIFACT_VERSION),
|
|
4288
|
+
t: z17.string().regex(ArtifactTypeRe, "invalid artifact type"),
|
|
4289
|
+
iss: z17.string().min(1).max(128),
|
|
4290
|
+
kid: z17.string().min(1).max(128),
|
|
4291
|
+
iat: z17.number().int().nonnegative(),
|
|
4292
|
+
exp: z17.number().int().positive().optional(),
|
|
4293
|
+
nonce: z17.string().min(8).max(64).regex(/^[A-Za-z0-9_-]+$/, "nonce must be url-safe")
|
|
4265
4294
|
});
|
|
4266
4295
|
var FlurArtifactError = class extends Error {
|
|
4267
4296
|
constructor(message, code) {
|
|
@@ -4400,7 +4429,7 @@ function verifyArtifactSignature(decoded, publicKeySpkiB64, options = {}) {
|
|
|
4400
4429
|
}
|
|
4401
4430
|
|
|
4402
4431
|
// src/artifacts/types.ts
|
|
4403
|
-
import { z as
|
|
4432
|
+
import { z as z18 } from "zod";
|
|
4404
4433
|
var ARTIFACT_TYPES = {
|
|
4405
4434
|
OFFLINE_PAYMENT_AUTHORIZATION: "offline_payment_authorization",
|
|
4406
4435
|
RECEIPT: "receipt",
|
|
@@ -4413,37 +4442,34 @@ var ARTIFACT_TYPES = {
|
|
|
4413
4442
|
LEDGER_JOURNAL_ENTRY: "ledger_journal_entry",
|
|
4414
4443
|
STATEMENT: "statement",
|
|
4415
4444
|
PASS: "pass",
|
|
4416
|
-
IDENTITY: "identity"
|
|
4417
|
-
// Tier B: holder-signed identity attestation for offline trust. The
|
|
4418
|
-
// envelope.iat / envelope.exp express the card's canonical lifetime.
|
|
4419
|
-
PAY_CARD: "pay_card"
|
|
4445
|
+
IDENTITY: "identity"
|
|
4420
4446
|
};
|
|
4421
|
-
var HexString = (length) =>
|
|
4447
|
+
var HexString = (length) => z18.string().regex(
|
|
4422
4448
|
new RegExp(`^[0-9a-fA-F]{${length * 2}}$`),
|
|
4423
4449
|
`expected ${length}-byte hex string`
|
|
4424
4450
|
);
|
|
4425
|
-
var OfflinePaymentAuthorizationArtifactSchema =
|
|
4451
|
+
var OfflinePaymentAuthorizationArtifactSchema = z18.object({
|
|
4426
4452
|
authorization: OfflinePaymentAuthorizationSchema
|
|
4427
4453
|
});
|
|
4428
|
-
var ReceiptArtifactSchema =
|
|
4429
|
-
receiptId:
|
|
4430
|
-
paymentReference:
|
|
4431
|
-
payerUserId:
|
|
4432
|
-
payeeUserId:
|
|
4433
|
-
amountKobo:
|
|
4434
|
-
currency:
|
|
4435
|
-
channel:
|
|
4436
|
-
settledAtMs:
|
|
4437
|
-
ledgerTxnId:
|
|
4438
|
-
memo:
|
|
4454
|
+
var ReceiptArtifactSchema = z18.object({
|
|
4455
|
+
receiptId: z18.string().min(1).max(64),
|
|
4456
|
+
paymentReference: z18.string().min(1).max(64),
|
|
4457
|
+
payerUserId: z18.string().min(1).max(64).optional(),
|
|
4458
|
+
payeeUserId: z18.string().min(1).max(64),
|
|
4459
|
+
amountKobo: z18.number().int().positive(),
|
|
4460
|
+
currency: z18.literal("NGN"),
|
|
4461
|
+
channel: z18.enum(["online", "offline_reconciled", "pay_link", "nqr"]),
|
|
4462
|
+
settledAtMs: z18.number().int().positive(),
|
|
4463
|
+
ledgerTxnId: z18.string().min(1).max(64).optional(),
|
|
4464
|
+
memo: z18.string().max(140).optional(),
|
|
4439
4465
|
hashChainPrev: HexString(32).optional()
|
|
4440
4466
|
});
|
|
4441
|
-
var ShortId =
|
|
4442
|
-
var PositiveInt =
|
|
4443
|
-
var NonNegativeInt =
|
|
4444
|
-
var Currency2 =
|
|
4445
|
-
var Memo =
|
|
4446
|
-
var NqrPaymentRequestArtifactSchema =
|
|
4467
|
+
var ShortId = z18.string().min(1).max(64);
|
|
4468
|
+
var PositiveInt = z18.number().int().positive();
|
|
4469
|
+
var NonNegativeInt = z18.number().int().nonnegative();
|
|
4470
|
+
var Currency2 = z18.literal("NGN");
|
|
4471
|
+
var Memo = z18.string().max(140);
|
|
4472
|
+
var NqrPaymentRequestArtifactSchema = z18.object({
|
|
4447
4473
|
requestId: ShortId,
|
|
4448
4474
|
payeeUserId: ShortId,
|
|
4449
4475
|
amountKobo: PositiveInt.optional(),
|
|
@@ -4451,7 +4477,7 @@ var NqrPaymentRequestArtifactSchema = z17.object({
|
|
|
4451
4477
|
memo: Memo.optional(),
|
|
4452
4478
|
expiresAtMs: PositiveInt.optional()
|
|
4453
4479
|
});
|
|
4454
|
-
var PaymentIntentArtifactSchema =
|
|
4480
|
+
var PaymentIntentArtifactSchema = z18.object({
|
|
4455
4481
|
intentId: ShortId,
|
|
4456
4482
|
payerUserId: ShortId,
|
|
4457
4483
|
payeeUserId: ShortId,
|
|
@@ -4460,7 +4486,7 @@ var PaymentIntentArtifactSchema = z17.object({
|
|
|
4460
4486
|
idempotencyKey: ShortId,
|
|
4461
4487
|
createdAtMs: PositiveInt
|
|
4462
4488
|
});
|
|
4463
|
-
var OfflineClaimArtifactSchema =
|
|
4489
|
+
var OfflineClaimArtifactSchema = z18.object({
|
|
4464
4490
|
claimId: ShortId,
|
|
4465
4491
|
authorizationId: ShortId,
|
|
4466
4492
|
payeeUserId: ShortId,
|
|
@@ -4469,10 +4495,10 @@ var OfflineClaimArtifactSchema = z17.object({
|
|
|
4469
4495
|
claimedAtMs: PositiveInt,
|
|
4470
4496
|
paymentReference: ShortId.optional()
|
|
4471
4497
|
});
|
|
4472
|
-
var SettlementRecordArtifactSchema =
|
|
4498
|
+
var SettlementRecordArtifactSchema = z18.object({
|
|
4473
4499
|
settlementId: ShortId,
|
|
4474
4500
|
ledgerTxnId: ShortId,
|
|
4475
|
-
sourceRefType:
|
|
4501
|
+
sourceRefType: z18.enum([
|
|
4476
4502
|
"offline_authorization",
|
|
4477
4503
|
"offline_claim",
|
|
4478
4504
|
"transfer",
|
|
@@ -4483,12 +4509,12 @@ var SettlementRecordArtifactSchema = z17.object({
|
|
|
4483
4509
|
currency: Currency2,
|
|
4484
4510
|
settledAtMs: PositiveInt
|
|
4485
4511
|
});
|
|
4486
|
-
var ReversalRecordArtifactSchema =
|
|
4512
|
+
var ReversalRecordArtifactSchema = z18.object({
|
|
4487
4513
|
reversalId: ShortId,
|
|
4488
4514
|
originalTxnId: ShortId,
|
|
4489
4515
|
amountKobo: PositiveInt,
|
|
4490
4516
|
currency: Currency2,
|
|
4491
|
-
reason:
|
|
4517
|
+
reason: z18.enum([
|
|
4492
4518
|
"user_dispute",
|
|
4493
4519
|
"fraud",
|
|
4494
4520
|
"duplicate",
|
|
@@ -4498,7 +4524,7 @@ var ReversalRecordArtifactSchema = z17.object({
|
|
|
4498
4524
|
reversedAtMs: PositiveInt,
|
|
4499
4525
|
memo: Memo.optional()
|
|
4500
4526
|
});
|
|
4501
|
-
var LedgerJournalEntryArtifactSchema =
|
|
4527
|
+
var LedgerJournalEntryArtifactSchema = z18.object({
|
|
4502
4528
|
entryId: ShortId,
|
|
4503
4529
|
journalId: ShortId,
|
|
4504
4530
|
debitAccountId: ShortId,
|
|
@@ -4509,13 +4535,13 @@ var LedgerJournalEntryArtifactSchema = z17.object({
|
|
|
4509
4535
|
refType: ShortId.optional(),
|
|
4510
4536
|
refId: ShortId.optional()
|
|
4511
4537
|
});
|
|
4512
|
-
var StatementArtifactSchema =
|
|
4538
|
+
var StatementArtifactSchema = z18.object({
|
|
4513
4539
|
statementId: ShortId,
|
|
4514
4540
|
userId: ShortId,
|
|
4515
4541
|
periodStartMs: PositiveInt,
|
|
4516
4542
|
periodEndMs: PositiveInt,
|
|
4517
|
-
openingBalanceKobo:
|
|
4518
|
-
closingBalanceKobo:
|
|
4543
|
+
openingBalanceKobo: z18.number().int(),
|
|
4544
|
+
closingBalanceKobo: z18.number().int(),
|
|
4519
4545
|
transactionCount: NonNegativeInt,
|
|
4520
4546
|
currency: Currency2,
|
|
4521
4547
|
hashChainPrev: HexString(32).optional()
|
|
@@ -4523,16 +4549,16 @@ var StatementArtifactSchema = z17.object({
|
|
|
4523
4549
|
message: "periodEndMs must be greater than periodStartMs",
|
|
4524
4550
|
path: ["periodEndMs"]
|
|
4525
4551
|
});
|
|
4526
|
-
var PassArtifactSchema =
|
|
4552
|
+
var PassArtifactSchema = z18.object({
|
|
4527
4553
|
passId: ShortId,
|
|
4528
4554
|
holderId: ShortId,
|
|
4529
|
-
category:
|
|
4530
|
-
title:
|
|
4555
|
+
category: z18.enum(["membership", "ticket", "loyalty", "access", "voucher"]),
|
|
4556
|
+
title: z18.string().min(1).max(120),
|
|
4531
4557
|
validFromMs: PositiveInt,
|
|
4532
4558
|
validUntilMs: PositiveInt.optional(),
|
|
4533
|
-
metadata:
|
|
4534
|
-
|
|
4535
|
-
|
|
4559
|
+
metadata: z18.record(
|
|
4560
|
+
z18.string().min(1).max(64),
|
|
4561
|
+
z18.union([z18.string().max(280), z18.number(), z18.boolean()])
|
|
4536
4562
|
).optional()
|
|
4537
4563
|
}).refine(
|
|
4538
4564
|
(v) => v.validUntilMs === void 0 || v.validUntilMs > v.validFromMs,
|
|
@@ -4541,10 +4567,10 @@ var PassArtifactSchema = z17.object({
|
|
|
4541
4567
|
path: ["validUntilMs"]
|
|
4542
4568
|
}
|
|
4543
4569
|
);
|
|
4544
|
-
var IdentityArtifactSchema =
|
|
4570
|
+
var IdentityArtifactSchema = z18.object({
|
|
4545
4571
|
attestationId: ShortId,
|
|
4546
4572
|
subjectId: ShortId,
|
|
4547
|
-
claimType:
|
|
4573
|
+
claimType: z18.enum([
|
|
4548
4574
|
"phone_verified",
|
|
4549
4575
|
"email_verified",
|
|
4550
4576
|
"bvn_verified",
|
|
@@ -4554,12 +4580,6 @@ var IdentityArtifactSchema = z17.object({
|
|
|
4554
4580
|
claimValueHash: HexString(32),
|
|
4555
4581
|
attestedAtMs: PositiveInt
|
|
4556
4582
|
});
|
|
4557
|
-
var PayCardArtifactSchema = z17.object({
|
|
4558
|
-
userId: ShortId,
|
|
4559
|
-
phoneE164: z17.string().regex(/^\+[1-9]\d{7,14}$/, "phoneE164 must be normalised E.164"),
|
|
4560
|
-
displayName: z17.string().min(1).max(64),
|
|
4561
|
-
devicePubKeySpkiB64: z17.string().min(64).max(256).regex(/^[A-Za-z0-9+/]+=*$/, "devicePubKeySpkiB64 must be standard base64")
|
|
4562
|
-
});
|
|
4563
4583
|
var ARTIFACT_BODY_SCHEMAS = {
|
|
4564
4584
|
[ARTIFACT_TYPES.OFFLINE_PAYMENT_AUTHORIZATION]: OfflinePaymentAuthorizationArtifactSchema,
|
|
4565
4585
|
[ARTIFACT_TYPES.RECEIPT]: ReceiptArtifactSchema,
|
|
@@ -4571,8 +4591,7 @@ var ARTIFACT_BODY_SCHEMAS = {
|
|
|
4571
4591
|
[ARTIFACT_TYPES.LEDGER_JOURNAL_ENTRY]: LedgerJournalEntryArtifactSchema,
|
|
4572
4592
|
[ARTIFACT_TYPES.STATEMENT]: StatementArtifactSchema,
|
|
4573
4593
|
[ARTIFACT_TYPES.PASS]: PassArtifactSchema,
|
|
4574
|
-
[ARTIFACT_TYPES.IDENTITY]: IdentityArtifactSchema
|
|
4575
|
-
[ARTIFACT_TYPES.PAY_CARD]: PayCardArtifactSchema
|
|
4594
|
+
[ARTIFACT_TYPES.IDENTITY]: IdentityArtifactSchema
|
|
4576
4595
|
};
|
|
4577
4596
|
var HARDENED_ARTIFACT_TYPES = /* @__PURE__ */ new Set([
|
|
4578
4597
|
ARTIFACT_TYPES.OFFLINE_PAYMENT_AUTHORIZATION,
|
|
@@ -4585,8 +4604,7 @@ var HARDENED_ARTIFACT_TYPES = /* @__PURE__ */ new Set([
|
|
|
4585
4604
|
ARTIFACT_TYPES.LEDGER_JOURNAL_ENTRY,
|
|
4586
4605
|
ARTIFACT_TYPES.STATEMENT,
|
|
4587
4606
|
ARTIFACT_TYPES.PASS,
|
|
4588
|
-
ARTIFACT_TYPES.IDENTITY
|
|
4589
|
-
ARTIFACT_TYPES.PAY_CARD
|
|
4607
|
+
ARTIFACT_TYPES.IDENTITY
|
|
4590
4608
|
]);
|
|
4591
4609
|
function isKnownArtifactType(t) {
|
|
4592
4610
|
return Object.values(ARTIFACT_TYPES).includes(t);
|
|
@@ -4671,130 +4689,6 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
|
|
|
4671
4689
|
type: ARTIFACT_TYPES.OFFLINE_PAYMENT_AUTHORIZATION
|
|
4672
4690
|
});
|
|
4673
4691
|
}
|
|
4674
|
-
|
|
4675
|
-
// src/artifacts/paycard.ts
|
|
4676
|
-
var PAY_CARD_DEFAULT_TTL_MS = 90 * 24 * 60 * 60 * 1e3;
|
|
4677
|
-
var PAY_CARD_REFRESH_THRESHOLD_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
4678
|
-
var PAY_CARD_URI_PREFIX = `${FLUR_ARTIFACT_URI_PREFIX}${ARTIFACT_TYPES.PAY_CARD}/`;
|
|
4679
|
-
function createPayCardArtifactUri(input) {
|
|
4680
|
-
if (input.data.userId !== input.issuer) {
|
|
4681
|
-
throw new FlurArtifactError(
|
|
4682
|
-
"pay_card.data.userId must equal envelope issuer",
|
|
4683
|
-
"INVALID_BODY"
|
|
4684
|
-
);
|
|
4685
|
-
}
|
|
4686
|
-
const iat = input.issuedAtSeconds ?? Math.floor(Date.now() / 1e3);
|
|
4687
|
-
const exp = input.expiresAtSeconds ?? iat + Math.floor(PAY_CARD_DEFAULT_TTL_MS / 1e3);
|
|
4688
|
-
return createArtifactUri({
|
|
4689
|
-
type: ARTIFACT_TYPES.PAY_CARD,
|
|
4690
|
-
issuer: input.issuer,
|
|
4691
|
-
keyId: input.keyId,
|
|
4692
|
-
privateKey: input.privateKey,
|
|
4693
|
-
nonce: input.nonce,
|
|
4694
|
-
issuedAtSeconds: iat,
|
|
4695
|
-
expiresAtSeconds: exp,
|
|
4696
|
-
data: input.data
|
|
4697
|
-
});
|
|
4698
|
-
}
|
|
4699
|
-
function isPayCardArtifactUri(uri) {
|
|
4700
|
-
return typeof uri === "string" && uri.startsWith(PAY_CARD_URI_PREFIX);
|
|
4701
|
-
}
|
|
4702
|
-
function decodePayCardArtifact(uri) {
|
|
4703
|
-
if (!isPayCardArtifactUri(uri)) {
|
|
4704
|
-
throw new FlurArtifactError(
|
|
4705
|
-
`URI does not start with ${PAY_CARD_URI_PREFIX}`,
|
|
4706
|
-
"INVALID_URI"
|
|
4707
|
-
);
|
|
4708
|
-
}
|
|
4709
|
-
const decoded = decodeArtifactUri(uri);
|
|
4710
|
-
if (decoded.type !== ARTIFACT_TYPES.PAY_CARD) {
|
|
4711
|
-
throw new FlurArtifactError(
|
|
4712
|
-
`Expected pay_card, got ${decoded.type}`,
|
|
4713
|
-
"TYPE_MISMATCH"
|
|
4714
|
-
);
|
|
4715
|
-
}
|
|
4716
|
-
const parsed = PayCardArtifactSchema.safeParse(decoded.body.data);
|
|
4717
|
-
if (!parsed.success) {
|
|
4718
|
-
throw new FlurArtifactError(
|
|
4719
|
-
`pay_card body invalid: ${parsed.error.message}`,
|
|
4720
|
-
"INVALID_BODY"
|
|
4721
|
-
);
|
|
4722
|
-
}
|
|
4723
|
-
if (parsed.data.userId !== decoded.body.iss) {
|
|
4724
|
-
throw new FlurArtifactError(
|
|
4725
|
-
"pay_card.data.userId must equal envelope issuer",
|
|
4726
|
-
"INVALID_BODY"
|
|
4727
|
-
);
|
|
4728
|
-
}
|
|
4729
|
-
return {
|
|
4730
|
-
body: {
|
|
4731
|
-
...decoded.body,
|
|
4732
|
-
data: parsed.data
|
|
4733
|
-
},
|
|
4734
|
-
sig: decoded.sig,
|
|
4735
|
-
decoded
|
|
4736
|
-
};
|
|
4737
|
-
}
|
|
4738
|
-
function verifyPayCardArtifact(uri, publicKeySpkiB64, options = {}) {
|
|
4739
|
-
if (!isPayCardArtifactUri(uri)) {
|
|
4740
|
-
throw new FlurArtifactError(
|
|
4741
|
-
`URI does not start with ${PAY_CARD_URI_PREFIX}`,
|
|
4742
|
-
"INVALID_URI"
|
|
4743
|
-
);
|
|
4744
|
-
}
|
|
4745
|
-
const verified = verifyArtifactUri(
|
|
4746
|
-
uri,
|
|
4747
|
-
publicKeySpkiB64,
|
|
4748
|
-
options
|
|
4749
|
-
);
|
|
4750
|
-
if (verified.decoded.type !== ARTIFACT_TYPES.PAY_CARD) {
|
|
4751
|
-
throw new FlurArtifactError(
|
|
4752
|
-
`Expected pay_card, got ${verified.decoded.type}`,
|
|
4753
|
-
"TYPE_MISMATCH"
|
|
4754
|
-
);
|
|
4755
|
-
}
|
|
4756
|
-
if (verified.body.data.userId !== verified.body.iss) {
|
|
4757
|
-
throw new FlurArtifactError(
|
|
4758
|
-
"pay_card.data.userId must equal envelope issuer",
|
|
4759
|
-
"INVALID_BODY"
|
|
4760
|
-
);
|
|
4761
|
-
}
|
|
4762
|
-
return {
|
|
4763
|
-
body: verified.body,
|
|
4764
|
-
sig: verified.sig,
|
|
4765
|
-
decoded: verified.decoded
|
|
4766
|
-
};
|
|
4767
|
-
}
|
|
4768
|
-
function inspectPayCardFreshness(decoded, nowMs = Date.now()) {
|
|
4769
|
-
const exp = decoded.body.exp;
|
|
4770
|
-
if (exp === void 0) return "no_expiry";
|
|
4771
|
-
const remainingMs = exp * 1e3 - nowMs;
|
|
4772
|
-
if (remainingMs <= 0) return "expired";
|
|
4773
|
-
if (remainingMs <= PAY_CARD_REFRESH_THRESHOLD_MS)
|
|
4774
|
-
return "refresh_recommended";
|
|
4775
|
-
return "fresh";
|
|
4776
|
-
}
|
|
4777
|
-
function buildPayCardSigningInput(input) {
|
|
4778
|
-
if (input.data.userId !== input.issuer) {
|
|
4779
|
-
throw new FlurArtifactError(
|
|
4780
|
-
"pay_card.data.userId must equal envelope issuer",
|
|
4781
|
-
"INVALID_BODY"
|
|
4782
|
-
);
|
|
4783
|
-
}
|
|
4784
|
-
const parsedData = PayCardArtifactSchema.parse(input.data);
|
|
4785
|
-
const iat = input.issuedAtSeconds ?? Math.floor(Date.now() / 1e3);
|
|
4786
|
-
const exp = input.expiresAtSeconds ?? iat + Math.floor(PAY_CARD_DEFAULT_TTL_MS / 1e3);
|
|
4787
|
-
const body = buildArtifactBody({
|
|
4788
|
-
type: ARTIFACT_TYPES.PAY_CARD,
|
|
4789
|
-
issuer: input.issuer,
|
|
4790
|
-
keyId: input.keyId,
|
|
4791
|
-
data: parsedData,
|
|
4792
|
-
nonce: input.nonce,
|
|
4793
|
-
issuedAtSeconds: iat,
|
|
4794
|
-
expiresAtSeconds: exp
|
|
4795
|
-
});
|
|
4796
|
-
return { body, bodyBytes: canonicalJSONBytes(body) };
|
|
4797
|
-
}
|
|
4798
4692
|
export {
|
|
4799
4693
|
ACCOUNT_FUNDED_OAC_MAX_TTL_MS,
|
|
4800
4694
|
ACCOUNT_STATUSES,
|
|
@@ -4875,6 +4769,7 @@ export {
|
|
|
4875
4769
|
OFFLINE_SMS_SETTLE_SIGNATURE_BYTES,
|
|
4876
4770
|
OFFLINE_SMS_SETTLE_TOKEN_BYTES,
|
|
4877
4771
|
OFFLINE_SMS_SETTLE_VERSION,
|
|
4772
|
+
OacPresentmentRequestSchema,
|
|
4878
4773
|
OfflineClaimArtifactSchema,
|
|
4879
4774
|
OfflinePaymentAuthorizationArtifactSchema,
|
|
4880
4775
|
OfflinePaymentAuthorizationSchema,
|
|
@@ -4892,9 +4787,6 @@ export {
|
|
|
4892
4787
|
PASS_STATES,
|
|
4893
4788
|
PAYLOAD_FORMAT_INDICATOR_VALUE,
|
|
4894
4789
|
PAYOUT_DESTINATION_STATUSES,
|
|
4895
|
-
PAY_CARD_DEFAULT_TTL_MS,
|
|
4896
|
-
PAY_CARD_REFRESH_THRESHOLD_MS,
|
|
4897
|
-
PAY_CARD_URI_PREFIX,
|
|
4898
4790
|
POINT_OF_INITIATION,
|
|
4899
4791
|
PartnerFundingEventInputSchema,
|
|
4900
4792
|
PartnerFundingSchema,
|
|
@@ -4902,7 +4794,6 @@ export {
|
|
|
4902
4794
|
PassArtifactSchema,
|
|
4903
4795
|
PassMetadataSchema,
|
|
4904
4796
|
PassSchema,
|
|
4905
|
-
PayCardArtifactSchema,
|
|
4906
4797
|
PayCollectionInputSchema,
|
|
4907
4798
|
PaymentClaimSchema,
|
|
4908
4799
|
PaymentIntentArtifactSchema,
|
|
@@ -4941,7 +4832,6 @@ export {
|
|
|
4941
4832
|
buildConsumerPaymentRequest,
|
|
4942
4833
|
buildOAC,
|
|
4943
4834
|
buildPass,
|
|
4944
|
-
buildPayCardSigningInput,
|
|
4945
4835
|
buildPaymentRequest,
|
|
4946
4836
|
buildReceipt,
|
|
4947
4837
|
buildRedemption,
|
|
@@ -4976,17 +4866,16 @@ export {
|
|
|
4976
4866
|
createPartnerFundingClient,
|
|
4977
4867
|
createPartnerProfileAdminClient,
|
|
4978
4868
|
createPassesClient,
|
|
4979
|
-
createPayCardArtifactUri,
|
|
4980
4869
|
createReceiptArtifactUri,
|
|
4981
4870
|
createReceiptsClient,
|
|
4982
4871
|
createSoftwareP256Signer,
|
|
4983
4872
|
decodeArtifactUri,
|
|
4984
4873
|
decodeAuthorizationQR,
|
|
4985
4874
|
decodeBase45,
|
|
4875
|
+
decodeConsumerOacRequest,
|
|
4986
4876
|
decodeConsumerSettlementReceiptQR,
|
|
4987
4877
|
decodeOfflineClaimSmsMessage,
|
|
4988
4878
|
decodeOfflineSmsSettleToken,
|
|
4989
|
-
decodePayCardArtifact,
|
|
4990
4879
|
decodePaymentRequestQR,
|
|
4991
4880
|
decodeUnverifiedConsumerOacQR,
|
|
4992
4881
|
decodeUnverifiedConsumerSettlementReceiptQR,
|
|
@@ -5006,13 +4895,11 @@ export {
|
|
|
5006
4895
|
generateDynamicQR,
|
|
5007
4896
|
generateStaticQR,
|
|
5008
4897
|
init,
|
|
5009
|
-
inspectPayCardFreshness,
|
|
5010
4898
|
isConsumerOacQR,
|
|
5011
4899
|
isConsumerPaymentRequestExpired,
|
|
5012
4900
|
isHardenedArtifactType,
|
|
5013
4901
|
isKnownArtifactType,
|
|
5014
4902
|
isPassWithinValidity,
|
|
5015
|
-
isPayCardArtifactUri,
|
|
5016
4903
|
moneyMinorToNumber,
|
|
5017
4904
|
normalizeE164,
|
|
5018
4905
|
parseAmountInput,
|
|
@@ -5041,7 +4928,6 @@ export {
|
|
|
5041
4928
|
verifyOacOffline,
|
|
5042
4929
|
verifyOfflineSmsSettleToken,
|
|
5043
4930
|
verifyPass,
|
|
5044
|
-
verifyPayCardArtifact,
|
|
5045
4931
|
verifyPaymentRequest,
|
|
5046
4932
|
verifyReceipt,
|
|
5047
4933
|
verifyRedemption,
|