@nokinc-flur/sdk 2.1.0 → 2.2.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 CHANGED
@@ -122,6 +122,9 @@ __export(index_exports, {
122
122
  PASS_STATES: () => PASS_STATES,
123
123
  PAYLOAD_FORMAT_INDICATOR_VALUE: () => PAYLOAD_FORMAT_INDICATOR_VALUE,
124
124
  PAYOUT_DESTINATION_STATUSES: () => PAYOUT_DESTINATION_STATUSES,
125
+ PAY_CARD_DEFAULT_TTL_MS: () => PAY_CARD_DEFAULT_TTL_MS,
126
+ PAY_CARD_REFRESH_THRESHOLD_MS: () => PAY_CARD_REFRESH_THRESHOLD_MS,
127
+ PAY_CARD_URI_PREFIX: () => PAY_CARD_URI_PREFIX,
125
128
  POINT_OF_INITIATION: () => POINT_OF_INITIATION,
126
129
  PartnerFundingEventInputSchema: () => PartnerFundingEventInputSchema,
127
130
  PartnerFundingSchema: () => PartnerFundingSchema,
@@ -129,6 +132,7 @@ __export(index_exports, {
129
132
  PassArtifactSchema: () => PassArtifactSchema,
130
133
  PassMetadataSchema: () => PassMetadataSchema,
131
134
  PassSchema: () => PassSchema,
135
+ PayCardArtifactSchema: () => PayCardArtifactSchema,
132
136
  PayCollectionInputSchema: () => PayCollectionInputSchema,
133
137
  PaymentClaimSchema: () => PaymentClaimSchema,
134
138
  PaymentIntentArtifactSchema: () => PaymentIntentArtifactSchema,
@@ -167,6 +171,7 @@ __export(index_exports, {
167
171
  buildConsumerPaymentRequest: () => buildConsumerPaymentRequest,
168
172
  buildOAC: () => buildOAC,
169
173
  buildPass: () => buildPass,
174
+ buildPayCardSigningInput: () => buildPayCardSigningInput,
170
175
  buildPaymentRequest: () => buildPaymentRequest,
171
176
  buildReceipt: () => buildReceipt,
172
177
  buildRedemption: () => buildRedemption,
@@ -200,6 +205,7 @@ __export(index_exports, {
200
205
  createPartnerFundingClient: () => createPartnerFundingClient,
201
206
  createPartnerProfileAdminClient: () => createPartnerProfileAdminClient,
202
207
  createPassesClient: () => createPassesClient,
208
+ createPayCardArtifactUri: () => createPayCardArtifactUri,
203
209
  createReceiptArtifactUri: () => createReceiptArtifactUri,
204
210
  createReceiptsClient: () => createReceiptsClient,
205
211
  createSoftwareP256Signer: () => createSoftwareP256Signer,
@@ -209,6 +215,7 @@ __export(index_exports, {
209
215
  decodeConsumerSettlementReceiptQR: () => decodeConsumerSettlementReceiptQR,
210
216
  decodeOfflineClaimSmsMessage: () => decodeOfflineClaimSmsMessage,
211
217
  decodeOfflineSmsSettleToken: () => decodeOfflineSmsSettleToken,
218
+ decodePayCardArtifact: () => decodePayCardArtifact,
212
219
  decodePaymentRequestQR: () => decodePaymentRequestQR,
213
220
  decodeUnverifiedConsumerSettlementReceiptQR: () => decodeUnverifiedConsumerSettlementReceiptQR,
214
221
  derToRawP256Signature: () => derToRawP256Signature,
@@ -226,10 +233,12 @@ __export(index_exports, {
226
233
  generateDynamicQR: () => generateDynamicQR,
227
234
  generateStaticQR: () => generateStaticQR,
228
235
  init: () => init,
236
+ inspectPayCardFreshness: () => inspectPayCardFreshness,
229
237
  isConsumerPaymentRequestExpired: () => isConsumerPaymentRequestExpired,
230
238
  isHardenedArtifactType: () => isHardenedArtifactType,
231
239
  isKnownArtifactType: () => isKnownArtifactType,
232
240
  isPassWithinValidity: () => isPassWithinValidity,
241
+ isPayCardArtifactUri: () => isPayCardArtifactUri,
233
242
  moneyMinorToNumber: () => moneyMinorToNumber,
234
243
  normalizeE164: () => normalizeE164,
235
244
  parseAmountInput: () => parseAmountInput,
@@ -257,6 +266,7 @@ __export(index_exports, {
257
266
  verifyOAC: () => verifyOAC,
258
267
  verifyOfflineSmsSettleToken: () => verifyOfflineSmsSettleToken,
259
268
  verifyPass: () => verifyPass,
269
+ verifyPayCardArtifact: () => verifyPayCardArtifact,
260
270
  verifyPaymentRequest: () => verifyPaymentRequest,
261
271
  verifyReceipt: () => verifyReceipt,
262
272
  verifyRedemption: () => verifyRedemption,
@@ -4561,7 +4571,10 @@ var ARTIFACT_TYPES = {
4561
4571
  LEDGER_JOURNAL_ENTRY: "ledger_journal_entry",
4562
4572
  STATEMENT: "statement",
4563
4573
  PASS: "pass",
4564
- IDENTITY: "identity"
4574
+ IDENTITY: "identity",
4575
+ // Tier B: holder-signed identity attestation for offline trust. The
4576
+ // envelope.iat / envelope.exp express the card's canonical lifetime.
4577
+ PAY_CARD: "pay_card"
4565
4578
  };
4566
4579
  var HexString = (length) => import_zod17.z.string().regex(
4567
4580
  new RegExp(`^[0-9a-fA-F]{${length * 2}}$`),
@@ -4699,6 +4712,12 @@ var IdentityArtifactSchema = import_zod17.z.object({
4699
4712
  claimValueHash: HexString(32),
4700
4713
  attestedAtMs: PositiveInt
4701
4714
  });
4715
+ var PayCardArtifactSchema = import_zod17.z.object({
4716
+ userId: ShortId,
4717
+ phoneE164: import_zod17.z.string().regex(/^\+[1-9]\d{7,14}$/, "phoneE164 must be normalised E.164"),
4718
+ displayName: import_zod17.z.string().min(1).max(64),
4719
+ devicePubKeySpkiB64: import_zod17.z.string().min(64).max(256).regex(/^[A-Za-z0-9+/]+=*$/, "devicePubKeySpkiB64 must be standard base64")
4720
+ });
4702
4721
  var ARTIFACT_BODY_SCHEMAS = {
4703
4722
  [ARTIFACT_TYPES.OFFLINE_PAYMENT_AUTHORIZATION]: OfflinePaymentAuthorizationArtifactSchema,
4704
4723
  [ARTIFACT_TYPES.RECEIPT]: ReceiptArtifactSchema,
@@ -4710,7 +4729,8 @@ var ARTIFACT_BODY_SCHEMAS = {
4710
4729
  [ARTIFACT_TYPES.LEDGER_JOURNAL_ENTRY]: LedgerJournalEntryArtifactSchema,
4711
4730
  [ARTIFACT_TYPES.STATEMENT]: StatementArtifactSchema,
4712
4731
  [ARTIFACT_TYPES.PASS]: PassArtifactSchema,
4713
- [ARTIFACT_TYPES.IDENTITY]: IdentityArtifactSchema
4732
+ [ARTIFACT_TYPES.IDENTITY]: IdentityArtifactSchema,
4733
+ [ARTIFACT_TYPES.PAY_CARD]: PayCardArtifactSchema
4714
4734
  };
4715
4735
  var HARDENED_ARTIFACT_TYPES = /* @__PURE__ */ new Set([
4716
4736
  ARTIFACT_TYPES.OFFLINE_PAYMENT_AUTHORIZATION,
@@ -4723,7 +4743,8 @@ var HARDENED_ARTIFACT_TYPES = /* @__PURE__ */ new Set([
4723
4743
  ARTIFACT_TYPES.LEDGER_JOURNAL_ENTRY,
4724
4744
  ARTIFACT_TYPES.STATEMENT,
4725
4745
  ARTIFACT_TYPES.PASS,
4726
- ARTIFACT_TYPES.IDENTITY
4746
+ ARTIFACT_TYPES.IDENTITY,
4747
+ ARTIFACT_TYPES.PAY_CARD
4727
4748
  ]);
4728
4749
  function isKnownArtifactType(t) {
4729
4750
  return Object.values(ARTIFACT_TYPES).includes(t);
@@ -4808,6 +4829,130 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
4808
4829
  type: ARTIFACT_TYPES.OFFLINE_PAYMENT_AUTHORIZATION
4809
4830
  });
4810
4831
  }
4832
+
4833
+ // src/artifacts/paycard.ts
4834
+ var PAY_CARD_DEFAULT_TTL_MS = 90 * 24 * 60 * 60 * 1e3;
4835
+ var PAY_CARD_REFRESH_THRESHOLD_MS = 30 * 24 * 60 * 60 * 1e3;
4836
+ var PAY_CARD_URI_PREFIX = `${FLUR_ARTIFACT_URI_PREFIX}${ARTIFACT_TYPES.PAY_CARD}/`;
4837
+ function createPayCardArtifactUri(input) {
4838
+ if (input.data.userId !== input.issuer) {
4839
+ throw new FlurArtifactError(
4840
+ "pay_card.data.userId must equal envelope issuer",
4841
+ "INVALID_BODY"
4842
+ );
4843
+ }
4844
+ const iat = input.issuedAtSeconds ?? Math.floor(Date.now() / 1e3);
4845
+ const exp = input.expiresAtSeconds ?? iat + Math.floor(PAY_CARD_DEFAULT_TTL_MS / 1e3);
4846
+ return createArtifactUri({
4847
+ type: ARTIFACT_TYPES.PAY_CARD,
4848
+ issuer: input.issuer,
4849
+ keyId: input.keyId,
4850
+ privateKey: input.privateKey,
4851
+ nonce: input.nonce,
4852
+ issuedAtSeconds: iat,
4853
+ expiresAtSeconds: exp,
4854
+ data: input.data
4855
+ });
4856
+ }
4857
+ function isPayCardArtifactUri(uri) {
4858
+ return typeof uri === "string" && uri.startsWith(PAY_CARD_URI_PREFIX);
4859
+ }
4860
+ function decodePayCardArtifact(uri) {
4861
+ if (!isPayCardArtifactUri(uri)) {
4862
+ throw new FlurArtifactError(
4863
+ `URI does not start with ${PAY_CARD_URI_PREFIX}`,
4864
+ "INVALID_URI"
4865
+ );
4866
+ }
4867
+ const decoded = decodeArtifactUri(uri);
4868
+ if (decoded.type !== ARTIFACT_TYPES.PAY_CARD) {
4869
+ throw new FlurArtifactError(
4870
+ `Expected pay_card, got ${decoded.type}`,
4871
+ "TYPE_MISMATCH"
4872
+ );
4873
+ }
4874
+ const parsed = PayCardArtifactSchema.safeParse(decoded.body.data);
4875
+ if (!parsed.success) {
4876
+ throw new FlurArtifactError(
4877
+ `pay_card body invalid: ${parsed.error.message}`,
4878
+ "INVALID_BODY"
4879
+ );
4880
+ }
4881
+ if (parsed.data.userId !== decoded.body.iss) {
4882
+ throw new FlurArtifactError(
4883
+ "pay_card.data.userId must equal envelope issuer",
4884
+ "INVALID_BODY"
4885
+ );
4886
+ }
4887
+ return {
4888
+ body: {
4889
+ ...decoded.body,
4890
+ data: parsed.data
4891
+ },
4892
+ sig: decoded.sig,
4893
+ decoded
4894
+ };
4895
+ }
4896
+ function verifyPayCardArtifact(uri, publicKeySpkiB64, options = {}) {
4897
+ if (!isPayCardArtifactUri(uri)) {
4898
+ throw new FlurArtifactError(
4899
+ `URI does not start with ${PAY_CARD_URI_PREFIX}`,
4900
+ "INVALID_URI"
4901
+ );
4902
+ }
4903
+ const verified = verifyArtifactUri(
4904
+ uri,
4905
+ publicKeySpkiB64,
4906
+ options
4907
+ );
4908
+ if (verified.decoded.type !== ARTIFACT_TYPES.PAY_CARD) {
4909
+ throw new FlurArtifactError(
4910
+ `Expected pay_card, got ${verified.decoded.type}`,
4911
+ "TYPE_MISMATCH"
4912
+ );
4913
+ }
4914
+ if (verified.body.data.userId !== verified.body.iss) {
4915
+ throw new FlurArtifactError(
4916
+ "pay_card.data.userId must equal envelope issuer",
4917
+ "INVALID_BODY"
4918
+ );
4919
+ }
4920
+ return {
4921
+ body: verified.body,
4922
+ sig: verified.sig,
4923
+ decoded: verified.decoded
4924
+ };
4925
+ }
4926
+ function inspectPayCardFreshness(decoded, nowMs = Date.now()) {
4927
+ const exp = decoded.body.exp;
4928
+ if (exp === void 0) return "no_expiry";
4929
+ const remainingMs = exp * 1e3 - nowMs;
4930
+ if (remainingMs <= 0) return "expired";
4931
+ if (remainingMs <= PAY_CARD_REFRESH_THRESHOLD_MS)
4932
+ return "refresh_recommended";
4933
+ return "fresh";
4934
+ }
4935
+ function buildPayCardSigningInput(input) {
4936
+ if (input.data.userId !== input.issuer) {
4937
+ throw new FlurArtifactError(
4938
+ "pay_card.data.userId must equal envelope issuer",
4939
+ "INVALID_BODY"
4940
+ );
4941
+ }
4942
+ const parsedData = PayCardArtifactSchema.parse(input.data);
4943
+ const iat = input.issuedAtSeconds ?? Math.floor(Date.now() / 1e3);
4944
+ const exp = input.expiresAtSeconds ?? iat + Math.floor(PAY_CARD_DEFAULT_TTL_MS / 1e3);
4945
+ const body = buildArtifactBody({
4946
+ type: ARTIFACT_TYPES.PAY_CARD,
4947
+ issuer: input.issuer,
4948
+ keyId: input.keyId,
4949
+ data: parsedData,
4950
+ nonce: input.nonce,
4951
+ issuedAtSeconds: iat,
4952
+ expiresAtSeconds: exp
4953
+ });
4954
+ return { body, bodyBytes: canonicalJSONBytes(body) };
4955
+ }
4811
4956
  // Annotate the CommonJS export names for ESM import in node:
4812
4957
  0 && (module.exports = {
4813
4958
  ACCOUNT_FUNDED_OAC_MAX_TTL_MS,
@@ -4902,6 +5047,9 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
4902
5047
  PASS_STATES,
4903
5048
  PAYLOAD_FORMAT_INDICATOR_VALUE,
4904
5049
  PAYOUT_DESTINATION_STATUSES,
5050
+ PAY_CARD_DEFAULT_TTL_MS,
5051
+ PAY_CARD_REFRESH_THRESHOLD_MS,
5052
+ PAY_CARD_URI_PREFIX,
4905
5053
  POINT_OF_INITIATION,
4906
5054
  PartnerFundingEventInputSchema,
4907
5055
  PartnerFundingSchema,
@@ -4909,6 +5057,7 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
4909
5057
  PassArtifactSchema,
4910
5058
  PassMetadataSchema,
4911
5059
  PassSchema,
5060
+ PayCardArtifactSchema,
4912
5061
  PayCollectionInputSchema,
4913
5062
  PaymentClaimSchema,
4914
5063
  PaymentIntentArtifactSchema,
@@ -4947,6 +5096,7 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
4947
5096
  buildConsumerPaymentRequest,
4948
5097
  buildOAC,
4949
5098
  buildPass,
5099
+ buildPayCardSigningInput,
4950
5100
  buildPaymentRequest,
4951
5101
  buildReceipt,
4952
5102
  buildRedemption,
@@ -4980,6 +5130,7 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
4980
5130
  createPartnerFundingClient,
4981
5131
  createPartnerProfileAdminClient,
4982
5132
  createPassesClient,
5133
+ createPayCardArtifactUri,
4983
5134
  createReceiptArtifactUri,
4984
5135
  createReceiptsClient,
4985
5136
  createSoftwareP256Signer,
@@ -4989,6 +5140,7 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
4989
5140
  decodeConsumerSettlementReceiptQR,
4990
5141
  decodeOfflineClaimSmsMessage,
4991
5142
  decodeOfflineSmsSettleToken,
5143
+ decodePayCardArtifact,
4992
5144
  decodePaymentRequestQR,
4993
5145
  decodeUnverifiedConsumerSettlementReceiptQR,
4994
5146
  derToRawP256Signature,
@@ -5006,10 +5158,12 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
5006
5158
  generateDynamicQR,
5007
5159
  generateStaticQR,
5008
5160
  init,
5161
+ inspectPayCardFreshness,
5009
5162
  isConsumerPaymentRequestExpired,
5010
5163
  isHardenedArtifactType,
5011
5164
  isKnownArtifactType,
5012
5165
  isPassWithinValidity,
5166
+ isPayCardArtifactUri,
5013
5167
  moneyMinorToNumber,
5014
5168
  normalizeE164,
5015
5169
  parseAmountInput,
@@ -5037,6 +5191,7 @@ function createOfflinePaymentAuthorizationArtifactUri(input) {
5037
5191
  verifyOAC,
5038
5192
  verifyOfflineSmsSettleToken,
5039
5193
  verifyPass,
5194
+ verifyPayCardArtifact,
5040
5195
  verifyPaymentRequest,
5041
5196
  verifyReceipt,
5042
5197
  verifyRedemption,