@nokinc-flur/sdk 1.0.0 → 1.0.2
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 +608 -121
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +540 -76
- package/dist/index.d.ts +540 -76
- package/dist/index.js +580 -121
- package/dist/index.js.map +1 -1
- package/package.json +3 -1
package/dist/index.js
CHANGED
|
@@ -1426,6 +1426,111 @@ function decodeAuthorizationQR(s) {
|
|
|
1426
1426
|
return OfflinePaymentAuthorizationSchema.parse(JSON.parse(json));
|
|
1427
1427
|
}
|
|
1428
1428
|
|
|
1429
|
+
// src/offline/settlements.ts
|
|
1430
|
+
import { z as z6 } from "zod";
|
|
1431
|
+
var OfflineTokenSchema = z6.object({
|
|
1432
|
+
tokenId: z6.string().uuid(),
|
|
1433
|
+
tokenSerial: z6.string(),
|
|
1434
|
+
issuerAccountId: z6.string().uuid(),
|
|
1435
|
+
payerUserId: z6.string().uuid(),
|
|
1436
|
+
maxAmountKobo: z6.number().int().positive(),
|
|
1437
|
+
currency: z6.string().length(3),
|
|
1438
|
+
issuedAtMs: z6.number().int().nonnegative(),
|
|
1439
|
+
expiresAtMs: z6.number().int().nonnegative(),
|
|
1440
|
+
issuerSig: z6.string()
|
|
1441
|
+
});
|
|
1442
|
+
var PaymentClaimSchema = z6.object({
|
|
1443
|
+
encounterId: z6.string().regex(/^[0-9a-f]{64}$/i).optional(),
|
|
1444
|
+
tokenSerial: z6.string(),
|
|
1445
|
+
payerUserId: z6.string().uuid(),
|
|
1446
|
+
payeeUserId: z6.string().uuid(),
|
|
1447
|
+
payerNonce: z6.string(),
|
|
1448
|
+
payeeNonce: z6.string(),
|
|
1449
|
+
amountKobo: z6.number().int().positive(),
|
|
1450
|
+
currency: z6.string().length(3).default("NGN"),
|
|
1451
|
+
occurredAtMs: z6.number().int().nonnegative(),
|
|
1452
|
+
completedAtMs: z6.number().int().nonnegative().optional(),
|
|
1453
|
+
contextId: z6.string().optional(),
|
|
1454
|
+
payerPubkey: z6.string().regex(/^[0-9a-f]{64}$/i),
|
|
1455
|
+
payerSignature: z6.string().regex(/^[0-9a-f]+$/i),
|
|
1456
|
+
payeePubkey: z6.string().regex(/^[0-9a-f]{64}$/i).optional(),
|
|
1457
|
+
payeeSignature: z6.string().regex(/^[0-9a-f]+$/i).optional()
|
|
1458
|
+
});
|
|
1459
|
+
var SettlementSchema = z6.object({
|
|
1460
|
+
settlementId: z6.string().uuid(),
|
|
1461
|
+
settlementKey: z6.string().regex(/^[0-9a-f]{64}$/i),
|
|
1462
|
+
encounterId: z6.string().regex(/^[0-9a-f]{64}$/i),
|
|
1463
|
+
issuerAccountId: z6.string().uuid(),
|
|
1464
|
+
tokenSerial: z6.string(),
|
|
1465
|
+
payerUserId: z6.string().uuid(),
|
|
1466
|
+
payeeUserId: z6.string().uuid(),
|
|
1467
|
+
amountKobo: z6.number().int().nonnegative(),
|
|
1468
|
+
currency: z6.string().length(3),
|
|
1469
|
+
receiptId: z6.string().nullable(),
|
|
1470
|
+
status: z6.enum(["SETTLED", "REVIEW", "REJECTED"]),
|
|
1471
|
+
issuerSig: z6.string(),
|
|
1472
|
+
createdAtMs: z6.number().int().nonnegative()
|
|
1473
|
+
});
|
|
1474
|
+
var SettleResponseSchema = z6.object({
|
|
1475
|
+
settlement: SettlementSchema,
|
|
1476
|
+
encounterId: z6.string().regex(/^[0-9a-f]{64}$/i),
|
|
1477
|
+
replayed: z6.boolean()
|
|
1478
|
+
});
|
|
1479
|
+
var ENCOUNTER_DOMAIN = "offline:v1:encounter";
|
|
1480
|
+
async function sha256Hex(input) {
|
|
1481
|
+
const subtle = globalThis.crypto?.subtle;
|
|
1482
|
+
const enc2 = new TextEncoder().encode(input);
|
|
1483
|
+
if (subtle) {
|
|
1484
|
+
const buf = await subtle.digest("SHA-256", enc2);
|
|
1485
|
+
return Array.from(new Uint8Array(buf)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1486
|
+
}
|
|
1487
|
+
const mod = await import("crypto");
|
|
1488
|
+
return mod.createHash("sha256").update(input).digest("hex");
|
|
1489
|
+
}
|
|
1490
|
+
async function computeEncounterId(input) {
|
|
1491
|
+
return sha256Hex(
|
|
1492
|
+
ENCOUNTER_DOMAIN + "|" + [
|
|
1493
|
+
input.payerUserId,
|
|
1494
|
+
input.payeeUserId,
|
|
1495
|
+
input.payerNonce,
|
|
1496
|
+
input.payeeNonce,
|
|
1497
|
+
input.tokenSerial
|
|
1498
|
+
].join("|")
|
|
1499
|
+
);
|
|
1500
|
+
}
|
|
1501
|
+
function createOfflineSettlementsClient(partner) {
|
|
1502
|
+
return {
|
|
1503
|
+
issueOfflineToken: (input) => partner.request({
|
|
1504
|
+
method: "POST",
|
|
1505
|
+
path: "/v1/offline/tokens",
|
|
1506
|
+
body: {
|
|
1507
|
+
payerUserId: input.payerUserId,
|
|
1508
|
+
maxAmountKobo: input.maxAmountKobo,
|
|
1509
|
+
currency: input.currency ?? "NGN",
|
|
1510
|
+
ttlMs: input.ttlMs,
|
|
1511
|
+
...input.tokenSerial ? { tokenSerial: input.tokenSerial } : {}
|
|
1512
|
+
}
|
|
1513
|
+
}),
|
|
1514
|
+
getOfflineToken: (serial) => partner.request({
|
|
1515
|
+
method: "GET",
|
|
1516
|
+
path: `/v1/offline/tokens/${encodeURIComponent(serial)}`
|
|
1517
|
+
}),
|
|
1518
|
+
settle: (claim) => partner.request({
|
|
1519
|
+
method: "POST",
|
|
1520
|
+
path: "/v1/offline/settlements",
|
|
1521
|
+
body: claim
|
|
1522
|
+
}),
|
|
1523
|
+
getSettlement: (id) => partner.request({
|
|
1524
|
+
method: "GET",
|
|
1525
|
+
path: `/v1/offline/settlements/${encodeURIComponent(id)}`
|
|
1526
|
+
}),
|
|
1527
|
+
listConflicts: () => partner.request({
|
|
1528
|
+
method: "GET",
|
|
1529
|
+
path: "/v1/offline/conflicts"
|
|
1530
|
+
})
|
|
1531
|
+
};
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1429
1534
|
// src/auth/hmac.ts
|
|
1430
1535
|
import { hmac } from "@noble/hashes/hmac";
|
|
1431
1536
|
import { sha256 } from "@noble/hashes/sha256";
|
|
@@ -1550,7 +1655,7 @@ function createHmacFetch(opts) {
|
|
|
1550
1655
|
}
|
|
1551
1656
|
|
|
1552
1657
|
// src/passes/pass.ts
|
|
1553
|
-
import { z as
|
|
1658
|
+
import { z as z7 } from "zod";
|
|
1554
1659
|
var PASS_KINDS = [
|
|
1555
1660
|
"ride-ticket",
|
|
1556
1661
|
"transit-pass",
|
|
@@ -1566,41 +1671,41 @@ var PASS_STATES = [
|
|
|
1566
1671
|
"expired",
|
|
1567
1672
|
"revoked"
|
|
1568
1673
|
];
|
|
1569
|
-
var HexString2 = (length) =>
|
|
1674
|
+
var HexString2 = (length) => z7.string().regex(
|
|
1570
1675
|
new RegExp(`^[0-9a-fA-F]{${length * 2}}$`),
|
|
1571
1676
|
`expected ${length}-byte hex string`
|
|
1572
1677
|
);
|
|
1573
|
-
var PassMetadataSchema =
|
|
1574
|
-
|
|
1678
|
+
var PassMetadataSchema = z7.record(
|
|
1679
|
+
z7.union([z7.string(), z7.number(), z7.boolean(), z7.null()])
|
|
1575
1680
|
);
|
|
1576
|
-
var PassSchema =
|
|
1577
|
-
passId:
|
|
1681
|
+
var PassSchema = z7.object({
|
|
1682
|
+
passId: z7.string().min(1),
|
|
1578
1683
|
/** Optional client/template grouping id (server may omit). */
|
|
1579
|
-
templateId:
|
|
1684
|
+
templateId: z7.string().min(1).optional(),
|
|
1580
1685
|
/** Optional human-facing holder identity (server may omit). The cryptographic binding
|
|
1581
1686
|
* is `holderDevicePubkey` below. */
|
|
1582
|
-
holderUserId:
|
|
1583
|
-
kind:
|
|
1584
|
-
issuerId:
|
|
1585
|
-
issuedAtMs:
|
|
1586
|
-
validFromMs:
|
|
1587
|
-
validUntilMs:
|
|
1588
|
-
state:
|
|
1687
|
+
holderUserId: z7.string().min(1).optional(),
|
|
1688
|
+
kind: z7.enum(PASS_KINDS),
|
|
1689
|
+
issuerId: z7.string().min(1),
|
|
1690
|
+
issuedAtMs: z7.number().int().nonnegative(),
|
|
1691
|
+
validFromMs: z7.number().int().nonnegative(),
|
|
1692
|
+
validUntilMs: z7.number().int().positive(),
|
|
1693
|
+
state: z7.enum(PASS_STATES),
|
|
1589
1694
|
metadata: PassMetadataSchema,
|
|
1590
|
-
nonce:
|
|
1695
|
+
nonce: z7.string().min(1),
|
|
1591
1696
|
/** Device id this pass is bound to (FK to backend `device_keys`). */
|
|
1592
|
-
holderDeviceId:
|
|
1697
|
+
holderDeviceId: z7.string().min(1),
|
|
1593
1698
|
/** 32-byte hex Ed25519 public key of the bound device. The redemption signature
|
|
1594
1699
|
* is verified against this key — it is the security-critical binding. */
|
|
1595
1700
|
holderDevicePubkey: HexString2(32),
|
|
1596
1701
|
/** Optional fixed amount for monetary passes (vouchers, gift cards) in kobo. */
|
|
1597
|
-
amountKobo:
|
|
1702
|
+
amountKobo: z7.number().int().nonnegative().optional(),
|
|
1598
1703
|
/** ISO-4217-ish currency code; required on the wire. SDK builders default to NGN. */
|
|
1599
|
-
currency:
|
|
1704
|
+
currency: z7.string().min(3).max(8),
|
|
1600
1705
|
/** Monotonic redemption counter floor. Redemption.counter MUST be > counterSeed. */
|
|
1601
|
-
counterSeed:
|
|
1706
|
+
counterSeed: z7.number().int().nonnegative(),
|
|
1602
1707
|
/** Optional cumulative spend cap in kobo across all redemptions of this pass. */
|
|
1603
|
-
cumulativeCapKobo:
|
|
1708
|
+
cumulativeCapKobo: z7.number().int().nonnegative().optional(),
|
|
1604
1709
|
issuerSig: HexString2(64)
|
|
1605
1710
|
}).refine((v) => v.validUntilMs > v.validFromMs, {
|
|
1606
1711
|
message: "validUntilMs must be greater than validFromMs"
|
|
@@ -1657,18 +1762,18 @@ function isPassWithinValidity(pass, nowMs) {
|
|
|
1657
1762
|
}
|
|
1658
1763
|
|
|
1659
1764
|
// src/passes/redemption.ts
|
|
1660
|
-
import { z as
|
|
1661
|
-
var HexSig2 =
|
|
1662
|
-
var RedemptionSchema =
|
|
1765
|
+
import { z as z8 } from "zod";
|
|
1766
|
+
var HexSig2 = z8.string().regex(/^[0-9a-fA-F]{128}$/, "expected 64-byte hex signature");
|
|
1767
|
+
var RedemptionSchema = z8.object({
|
|
1663
1768
|
pass: PassSchema,
|
|
1664
|
-
redeemerId:
|
|
1665
|
-
redeemedAtMs:
|
|
1769
|
+
redeemerId: z8.string().min(1),
|
|
1770
|
+
redeemedAtMs: z8.number().int().nonnegative(),
|
|
1666
1771
|
/** Strictly monotonic counter scoped to a single pass. Must be > pass.counterSeed
|
|
1667
1772
|
* and > the redeemer's lastSeenCounter for this pass. */
|
|
1668
|
-
counter:
|
|
1773
|
+
counter: z8.number().int().positive(),
|
|
1669
1774
|
/** Amount being redeemed in kobo (0 for non-monetary passes like ride tickets). */
|
|
1670
|
-
amountKobo:
|
|
1671
|
-
nonce:
|
|
1775
|
+
amountKobo: z8.number().int().nonnegative(),
|
|
1776
|
+
nonce: z8.string().min(1),
|
|
1672
1777
|
holderSig: HexSig2
|
|
1673
1778
|
});
|
|
1674
1779
|
var REDEEMABLE_STATES = /* @__PURE__ */ new Set(["issued", "active"]);
|
|
@@ -1753,118 +1858,44 @@ function verifyRedemption(r, issuerPublicKey) {
|
|
|
1753
1858
|
}
|
|
1754
1859
|
}
|
|
1755
1860
|
|
|
1756
|
-
// src/passes/client.ts
|
|
1757
|
-
function createPassesClient(opts) {
|
|
1758
|
-
const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
1759
|
-
if (!fetchImpl)
|
|
1760
|
-
throw new Error("createPassesClient: no fetch implementation available");
|
|
1761
|
-
const baseUrl = opts.baseUrl.replace(/\/$/, "");
|
|
1762
|
-
async function call(method, path, body, parser) {
|
|
1763
|
-
const init2 = {
|
|
1764
|
-
method,
|
|
1765
|
-
headers: {
|
|
1766
|
-
"content-type": "application/json",
|
|
1767
|
-
accept: "application/json"
|
|
1768
|
-
}
|
|
1769
|
-
};
|
|
1770
|
-
if (body !== void 0) init2.body = JSON.stringify(body);
|
|
1771
|
-
const resp = await fetchImpl(`${baseUrl}${path}`, init2);
|
|
1772
|
-
const text = await resp.text();
|
|
1773
|
-
let raw = void 0;
|
|
1774
|
-
if (text) {
|
|
1775
|
-
try {
|
|
1776
|
-
raw = JSON.parse(text);
|
|
1777
|
-
} catch {
|
|
1778
|
-
}
|
|
1779
|
-
}
|
|
1780
|
-
if (!resp.ok) {
|
|
1781
|
-
const code = (raw && typeof raw === "object" && "code" in raw && typeof raw.code === "string" ? raw.code : void 0) ?? `http_${resp.status}`;
|
|
1782
|
-
const message = (raw && typeof raw === "object" && "message" in raw && typeof raw.message === "string" ? raw.message : void 0) ?? `request failed with status ${resp.status}`;
|
|
1783
|
-
throw new FlurApiError(resp.status, code, message, raw);
|
|
1784
|
-
}
|
|
1785
|
-
return parser(raw);
|
|
1786
|
-
}
|
|
1787
|
-
return {
|
|
1788
|
-
issuePass: (input) => call("POST", "/v1/passes", input, (raw) => PassSchema.parse(raw)),
|
|
1789
|
-
listPasses: (input) => {
|
|
1790
|
-
const qs = new URLSearchParams();
|
|
1791
|
-
if (input.holderDeviceId) qs.set("holderDeviceId", input.holderDeviceId);
|
|
1792
|
-
if (input.holderUserId) qs.set("holderUserId", input.holderUserId);
|
|
1793
|
-
if (input.state) qs.set("state", input.state);
|
|
1794
|
-
if (input.kind) qs.set("kind", input.kind);
|
|
1795
|
-
if (input.templateId) qs.set("templateId", input.templateId);
|
|
1796
|
-
if (typeof input.limit === "number") qs.set("limit", String(input.limit));
|
|
1797
|
-
if (input.cursor) qs.set("cursor", input.cursor);
|
|
1798
|
-
const path = `/v1/passes${qs.size > 0 ? `?${qs.toString()}` : ""}`;
|
|
1799
|
-
return call("GET", path, void 0, (raw) => {
|
|
1800
|
-
const obj = raw;
|
|
1801
|
-
const items = obj.items.map(
|
|
1802
|
-
(it) => PassSchema.parse(it)
|
|
1803
|
-
);
|
|
1804
|
-
const nextCursor = typeof obj.nextCursor === "string" ? obj.nextCursor : null;
|
|
1805
|
-
return { items, nextCursor };
|
|
1806
|
-
});
|
|
1807
|
-
},
|
|
1808
|
-
getPass: (passId) => call(
|
|
1809
|
-
"GET",
|
|
1810
|
-
`/v1/passes/${encodeURIComponent(passId)}`,
|
|
1811
|
-
void 0,
|
|
1812
|
-
(raw) => PassSchema.parse(raw)
|
|
1813
|
-
),
|
|
1814
|
-
redeemPass: (passId, redemption) => call(
|
|
1815
|
-
"POST",
|
|
1816
|
-
`/v1/passes/${encodeURIComponent(passId)}/redeem`,
|
|
1817
|
-
RedemptionSchema.parse(redemption),
|
|
1818
|
-
(raw) => PassSchema.parse(raw)
|
|
1819
|
-
),
|
|
1820
|
-
revokePass: (passId, input) => call(
|
|
1821
|
-
"POST",
|
|
1822
|
-
`/v1/passes/${encodeURIComponent(passId)}/revoke`,
|
|
1823
|
-
input,
|
|
1824
|
-
(raw) => PassSchema.parse(raw)
|
|
1825
|
-
),
|
|
1826
|
-
verifyPass: (pass, issuerPublicKey) => verifyPass(pass, issuerPublicKey)
|
|
1827
|
-
};
|
|
1828
|
-
}
|
|
1829
|
-
|
|
1830
1861
|
// src/receipts/receipt.ts
|
|
1831
|
-
import { z as
|
|
1862
|
+
import { z as z9 } from "zod";
|
|
1832
1863
|
var RECEIPT_CHANNELS = ["cash", "pass"];
|
|
1833
1864
|
var RECEIPT_KINDS = RECEIPT_CHANNELS;
|
|
1834
|
-
var HexString3 = (length) =>
|
|
1865
|
+
var HexString3 = (length) => z9.string().regex(
|
|
1835
1866
|
new RegExp(`^[0-9a-fA-F]{${length * 2}}$`),
|
|
1836
1867
|
`expected ${length}-byte hex string`
|
|
1837
1868
|
);
|
|
1838
|
-
var ReceiptPayloadSchema =
|
|
1839
|
-
|
|
1869
|
+
var ReceiptPayloadSchema = z9.record(
|
|
1870
|
+
z9.union([z9.string(), z9.number(), z9.boolean(), z9.null()])
|
|
1840
1871
|
);
|
|
1841
|
-
var ReceiptSchema =
|
|
1842
|
-
receiptId:
|
|
1843
|
-
channel:
|
|
1872
|
+
var ReceiptSchema = z9.object({
|
|
1873
|
+
receiptId: z9.string().min(1),
|
|
1874
|
+
channel: z9.enum(RECEIPT_CHANNELS),
|
|
1844
1875
|
/** Cash-channel: send_intents.id. Required when channel === 'cash'. */
|
|
1845
|
-
intentId:
|
|
1876
|
+
intentId: z9.string().min(1).optional(),
|
|
1846
1877
|
/** Pass-channel: pass_redemptions.id. Required when channel === 'pass'. */
|
|
1847
|
-
passRedemptionId:
|
|
1848
|
-
payerUserId:
|
|
1849
|
-
payeeUserId:
|
|
1850
|
-
amountKobo:
|
|
1851
|
-
currency:
|
|
1852
|
-
issuedAtMs:
|
|
1853
|
-
issuerId:
|
|
1878
|
+
passRedemptionId: z9.string().min(1).optional(),
|
|
1879
|
+
payerUserId: z9.string().min(1),
|
|
1880
|
+
payeeUserId: z9.string().min(1),
|
|
1881
|
+
amountKobo: z9.number().int().nonnegative(),
|
|
1882
|
+
currency: z9.string().min(3).max(8),
|
|
1883
|
+
issuedAtMs: z9.number().int().nonnegative(),
|
|
1884
|
+
issuerId: z9.string().min(1),
|
|
1854
1885
|
payload: ReceiptPayloadSchema,
|
|
1855
1886
|
issuerSig: HexString3(64)
|
|
1856
1887
|
}).superRefine((v, ctx) => {
|
|
1857
1888
|
if (v.channel === "cash") {
|
|
1858
1889
|
if (!v.intentId) {
|
|
1859
1890
|
ctx.addIssue({
|
|
1860
|
-
code:
|
|
1891
|
+
code: z9.ZodIssueCode.custom,
|
|
1861
1892
|
message: "cash receipts require intentId",
|
|
1862
1893
|
path: ["intentId"]
|
|
1863
1894
|
});
|
|
1864
1895
|
}
|
|
1865
1896
|
if (v.passRedemptionId) {
|
|
1866
1897
|
ctx.addIssue({
|
|
1867
|
-
code:
|
|
1898
|
+
code: z9.ZodIssueCode.custom,
|
|
1868
1899
|
message: "cash receipts must not carry passRedemptionId",
|
|
1869
1900
|
path: ["passRedemptionId"]
|
|
1870
1901
|
});
|
|
@@ -1872,14 +1903,14 @@ var ReceiptSchema = z8.object({
|
|
|
1872
1903
|
} else if (v.channel === "pass") {
|
|
1873
1904
|
if (!v.passRedemptionId) {
|
|
1874
1905
|
ctx.addIssue({
|
|
1875
|
-
code:
|
|
1906
|
+
code: z9.ZodIssueCode.custom,
|
|
1876
1907
|
message: "pass receipts require passRedemptionId",
|
|
1877
1908
|
path: ["passRedemptionId"]
|
|
1878
1909
|
});
|
|
1879
1910
|
}
|
|
1880
1911
|
if (v.intentId) {
|
|
1881
1912
|
ctx.addIssue({
|
|
1882
|
-
code:
|
|
1913
|
+
code: z9.ZodIssueCode.custom,
|
|
1883
1914
|
message: "pass receipts must not carry intentId",
|
|
1884
1915
|
path: ["intentId"]
|
|
1885
1916
|
});
|
|
@@ -1937,6 +1968,114 @@ function verifyReceipt(r, issuerPublicKey) {
|
|
|
1937
1968
|
}
|
|
1938
1969
|
}
|
|
1939
1970
|
|
|
1971
|
+
// src/passes/client.ts
|
|
1972
|
+
function createPassesClient(opts) {
|
|
1973
|
+
const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
1974
|
+
if (!fetchImpl)
|
|
1975
|
+
throw new Error("createPassesClient: no fetch implementation available");
|
|
1976
|
+
const baseUrl = opts.baseUrl.replace(/\/$/, "");
|
|
1977
|
+
async function call(method, path, body, parser) {
|
|
1978
|
+
const init2 = {
|
|
1979
|
+
method,
|
|
1980
|
+
headers: {
|
|
1981
|
+
"content-type": "application/json",
|
|
1982
|
+
accept: "application/json"
|
|
1983
|
+
}
|
|
1984
|
+
};
|
|
1985
|
+
if (body !== void 0) init2.body = JSON.stringify(body);
|
|
1986
|
+
const resp = await fetchImpl(`${baseUrl}${path}`, init2);
|
|
1987
|
+
const text = await resp.text();
|
|
1988
|
+
let raw = void 0;
|
|
1989
|
+
if (text) {
|
|
1990
|
+
try {
|
|
1991
|
+
raw = JSON.parse(text);
|
|
1992
|
+
} catch {
|
|
1993
|
+
}
|
|
1994
|
+
}
|
|
1995
|
+
if (!resp.ok) {
|
|
1996
|
+
const code = (raw && typeof raw === "object" && "code" in raw && typeof raw.code === "string" ? raw.code : void 0) ?? `http_${resp.status}`;
|
|
1997
|
+
const message = (raw && typeof raw === "object" && "message" in raw && typeof raw.message === "string" ? raw.message : void 0) ?? `request failed with status ${resp.status}`;
|
|
1998
|
+
throw new FlurApiError(resp.status, code, message, raw);
|
|
1999
|
+
}
|
|
2000
|
+
return parser(raw);
|
|
2001
|
+
}
|
|
2002
|
+
return {
|
|
2003
|
+
issuePass: (input) => call("POST", "/v1/passes", input, (raw) => PassSchema.parse(raw)),
|
|
2004
|
+
listPasses: (input) => {
|
|
2005
|
+
const qs = new URLSearchParams();
|
|
2006
|
+
if (input.holderDeviceId) qs.set("holderDeviceId", input.holderDeviceId);
|
|
2007
|
+
if (input.holderUserId) qs.set("holderUserId", input.holderUserId);
|
|
2008
|
+
if (input.state) qs.set("state", input.state);
|
|
2009
|
+
if (input.kind) qs.set("kind", input.kind);
|
|
2010
|
+
if (input.templateId) qs.set("templateId", input.templateId);
|
|
2011
|
+
if (typeof input.limit === "number") qs.set("limit", String(input.limit));
|
|
2012
|
+
if (input.cursor) qs.set("cursor", input.cursor);
|
|
2013
|
+
const path = `/v1/passes${qs.size > 0 ? `?${qs.toString()}` : ""}`;
|
|
2014
|
+
return call("GET", path, void 0, (raw) => {
|
|
2015
|
+
const obj = raw;
|
|
2016
|
+
const items = obj.items.map(
|
|
2017
|
+
(it) => PassSchema.parse(it)
|
|
2018
|
+
);
|
|
2019
|
+
const nextCursor = typeof obj.nextCursor === "string" ? obj.nextCursor : null;
|
|
2020
|
+
return { items, nextCursor };
|
|
2021
|
+
});
|
|
2022
|
+
},
|
|
2023
|
+
getPass: (passId) => call(
|
|
2024
|
+
"GET",
|
|
2025
|
+
`/v1/passes/${encodeURIComponent(passId)}`,
|
|
2026
|
+
void 0,
|
|
2027
|
+
(raw) => PassSchema.parse(raw)
|
|
2028
|
+
),
|
|
2029
|
+
redeemPass: (passId, redemption) => call(
|
|
2030
|
+
"POST",
|
|
2031
|
+
`/v1/passes/${encodeURIComponent(passId)}/redeem`,
|
|
2032
|
+
RedemptionSchema.parse(redemption),
|
|
2033
|
+
(raw) => {
|
|
2034
|
+
const obj = raw;
|
|
2035
|
+
return {
|
|
2036
|
+
pass: PassSchema.parse(raw),
|
|
2037
|
+
redemptionId: typeof obj.redemptionId === "string" ? obj.redemptionId : ""
|
|
2038
|
+
};
|
|
2039
|
+
}
|
|
2040
|
+
).then((result) => result.pass),
|
|
2041
|
+
redeemPassDetailed: (passId, redemption) => call(
|
|
2042
|
+
"POST",
|
|
2043
|
+
`/v1/passes/${encodeURIComponent(passId)}/redeem`,
|
|
2044
|
+
RedemptionSchema.parse(redemption),
|
|
2045
|
+
(raw) => {
|
|
2046
|
+
const obj = raw;
|
|
2047
|
+
return {
|
|
2048
|
+
pass: PassSchema.parse(raw),
|
|
2049
|
+
redemptionId: typeof obj.redemptionId === "string" ? obj.redemptionId : ""
|
|
2050
|
+
};
|
|
2051
|
+
}
|
|
2052
|
+
),
|
|
2053
|
+
redeemPassWithReceipt: (passId, redemption, receipt) => call(
|
|
2054
|
+
"POST",
|
|
2055
|
+
`/v1/passes/${encodeURIComponent(passId)}/redeem-with-receipt`,
|
|
2056
|
+
{
|
|
2057
|
+
redemption: RedemptionSchema.parse(redemption),
|
|
2058
|
+
receipt
|
|
2059
|
+
},
|
|
2060
|
+
(raw) => {
|
|
2061
|
+
const obj = raw;
|
|
2062
|
+
return {
|
|
2063
|
+
pass: PassSchema.parse(obj.pass),
|
|
2064
|
+
redemptionId: typeof obj.redemptionId === "string" ? obj.redemptionId : "",
|
|
2065
|
+
receipt: ReceiptSchema.parse(obj.receipt)
|
|
2066
|
+
};
|
|
2067
|
+
}
|
|
2068
|
+
),
|
|
2069
|
+
revokePass: (passId, input) => call(
|
|
2070
|
+
"POST",
|
|
2071
|
+
`/v1/passes/${encodeURIComponent(passId)}/revoke`,
|
|
2072
|
+
input,
|
|
2073
|
+
(raw) => PassSchema.parse(raw)
|
|
2074
|
+
),
|
|
2075
|
+
verifyPass: (pass, issuerPublicKey) => verifyPass(pass, issuerPublicKey)
|
|
2076
|
+
};
|
|
2077
|
+
}
|
|
2078
|
+
|
|
1940
2079
|
// src/receipts/client.ts
|
|
1941
2080
|
function createReceiptsClient(opts) {
|
|
1942
2081
|
const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
@@ -2093,8 +2232,315 @@ function init(opts) {
|
|
|
2093
2232
|
receipts
|
|
2094
2233
|
};
|
|
2095
2234
|
}
|
|
2235
|
+
|
|
2236
|
+
// src/accounts/client.ts
|
|
2237
|
+
import { z as z10 } from "zod";
|
|
2238
|
+
var ACCOUNT_TYPES = ["personal", "business", "partner"];
|
|
2239
|
+
var ACCOUNT_STATUSES = ["active", "suspended", "closed"];
|
|
2240
|
+
var MEMBERSHIP_ROLES = ["owner", "admin", "driver", "staff"];
|
|
2241
|
+
var AccountSchema = z10.object({
|
|
2242
|
+
accountId: z10.string().uuid(),
|
|
2243
|
+
type: z10.enum(ACCOUNT_TYPES),
|
|
2244
|
+
displayName: z10.string().min(1),
|
|
2245
|
+
status: z10.enum(ACCOUNT_STATUSES),
|
|
2246
|
+
ownerUserId: z10.string().uuid().nullable(),
|
|
2247
|
+
createdAtMs: z10.number().int().nonnegative()
|
|
2248
|
+
});
|
|
2249
|
+
var AccountMembershipSchema = z10.object({
|
|
2250
|
+
accountId: z10.string().uuid(),
|
|
2251
|
+
userId: z10.string().uuid(),
|
|
2252
|
+
role: z10.enum(MEMBERSHIP_ROLES),
|
|
2253
|
+
createdAtMs: z10.number().int().nonnegative()
|
|
2254
|
+
});
|
|
2255
|
+
function createAccountsClient(opts) {
|
|
2256
|
+
const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
2257
|
+
if (!fetchImpl) {
|
|
2258
|
+
throw new Error("createAccountsClient: no fetch implementation available");
|
|
2259
|
+
}
|
|
2260
|
+
const baseUrl = opts.baseUrl.replace(/\/$/, "");
|
|
2261
|
+
async function call(method, path, body, parser) {
|
|
2262
|
+
const init2 = {
|
|
2263
|
+
method,
|
|
2264
|
+
headers: {
|
|
2265
|
+
"content-type": "application/json",
|
|
2266
|
+
accept: "application/json"
|
|
2267
|
+
}
|
|
2268
|
+
};
|
|
2269
|
+
if (body !== void 0) init2.body = JSON.stringify(body);
|
|
2270
|
+
const resp = await fetchImpl(`${baseUrl}${path}`, init2);
|
|
2271
|
+
const text = await resp.text();
|
|
2272
|
+
let raw = void 0;
|
|
2273
|
+
if (text) {
|
|
2274
|
+
try {
|
|
2275
|
+
raw = JSON.parse(text);
|
|
2276
|
+
} catch {
|
|
2277
|
+
}
|
|
2278
|
+
}
|
|
2279
|
+
if (!resp.ok) {
|
|
2280
|
+
const code = raw && typeof raw === "object" && "code" in raw && typeof raw.code === "string" ? raw.code : `http_${resp.status}`;
|
|
2281
|
+
const message = raw && typeof raw === "object" && "message" in raw && typeof raw.message === "string" ? raw.message : `request failed with status ${resp.status}`;
|
|
2282
|
+
throw new FlurApiError(resp.status, code, message, raw);
|
|
2283
|
+
}
|
|
2284
|
+
return parser(raw);
|
|
2285
|
+
}
|
|
2286
|
+
const itemsSchema = z10.object({ items: z10.array(AccountSchema) });
|
|
2287
|
+
const memberItemsSchema = z10.object({
|
|
2288
|
+
items: z10.array(AccountMembershipSchema)
|
|
2289
|
+
});
|
|
2290
|
+
return {
|
|
2291
|
+
listMyAccounts: () => call(
|
|
2292
|
+
"GET",
|
|
2293
|
+
"/v1/accounts/me",
|
|
2294
|
+
void 0,
|
|
2295
|
+
(raw) => itemsSchema.parse(raw)
|
|
2296
|
+
),
|
|
2297
|
+
getAccount: (accountId) => call(
|
|
2298
|
+
"GET",
|
|
2299
|
+
`/v1/accounts/${encodeURIComponent(accountId)}`,
|
|
2300
|
+
void 0,
|
|
2301
|
+
(raw) => AccountSchema.parse(raw)
|
|
2302
|
+
),
|
|
2303
|
+
listMembers: (accountId) => call(
|
|
2304
|
+
"GET",
|
|
2305
|
+
`/v1/accounts/${encodeURIComponent(accountId)}/members`,
|
|
2306
|
+
void 0,
|
|
2307
|
+
(raw) => memberItemsSchema.parse(raw)
|
|
2308
|
+
),
|
|
2309
|
+
createBusinessAccount: (input) => call("POST", "/v1/accounts", input, (raw) => AccountSchema.parse(raw)),
|
|
2310
|
+
addMember: (accountId, input) => call(
|
|
2311
|
+
"POST",
|
|
2312
|
+
`/v1/accounts/${encodeURIComponent(accountId)}/members`,
|
|
2313
|
+
input,
|
|
2314
|
+
(raw) => AccountMembershipSchema.parse(raw)
|
|
2315
|
+
)
|
|
2316
|
+
};
|
|
2317
|
+
}
|
|
2318
|
+
|
|
2319
|
+
// src/partner/client.ts
|
|
2320
|
+
import { z as z11 } from "zod";
|
|
2321
|
+
var PARTNER_SCOPES = [
|
|
2322
|
+
"passes:write",
|
|
2323
|
+
"passes:read",
|
|
2324
|
+
"passes:redeem",
|
|
2325
|
+
"receipts:write",
|
|
2326
|
+
"receipts:read",
|
|
2327
|
+
"offline:issue",
|
|
2328
|
+
"offline:settle",
|
|
2329
|
+
"offline:read"
|
|
2330
|
+
];
|
|
2331
|
+
var ApiCredentialPublicSchema = z11.object({
|
|
2332
|
+
id: z11.string().uuid(),
|
|
2333
|
+
accountId: z11.string().uuid(),
|
|
2334
|
+
keyId: z11.string(),
|
|
2335
|
+
scopes: z11.array(z11.enum(PARTNER_SCOPES)),
|
|
2336
|
+
label: z11.string().nullable(),
|
|
2337
|
+
createdAtMs: z11.number().int().nonnegative(),
|
|
2338
|
+
lastUsedAtMs: z11.number().int().nonnegative().nullable(),
|
|
2339
|
+
revokedAtMs: z11.number().int().nonnegative().nullable()
|
|
2340
|
+
});
|
|
2341
|
+
var MintedApiCredentialSchema = ApiCredentialPublicSchema.extend({
|
|
2342
|
+
secret: z11.string().min(1)
|
|
2343
|
+
});
|
|
2344
|
+
async function getSubtle() {
|
|
2345
|
+
const c = globalThis.crypto;
|
|
2346
|
+
if (c?.subtle) return c.subtle;
|
|
2347
|
+
const mod = await import("crypto");
|
|
2348
|
+
return mod.webcrypto.subtle;
|
|
2349
|
+
}
|
|
2350
|
+
var enc = new TextEncoder();
|
|
2351
|
+
function bytesToHex3(buf) {
|
|
2352
|
+
const u = new Uint8Array(buf);
|
|
2353
|
+
let s = "";
|
|
2354
|
+
for (let i = 0; i < u.length; i++) {
|
|
2355
|
+
s += u[i].toString(16).padStart(2, "0");
|
|
2356
|
+
}
|
|
2357
|
+
return s;
|
|
2358
|
+
}
|
|
2359
|
+
async function sha256Hex2(input) {
|
|
2360
|
+
const subtle = await getSubtle();
|
|
2361
|
+
const data = typeof input === "string" ? enc.encode(input) : input;
|
|
2362
|
+
const buffer = data.byteOffset === 0 && data.byteLength === data.buffer.byteLength ? data.buffer : data.slice().buffer;
|
|
2363
|
+
const buf = await subtle.digest("SHA-256", buffer);
|
|
2364
|
+
return bytesToHex3(buf);
|
|
2365
|
+
}
|
|
2366
|
+
async function hmacSha256Hex(keyHex, message) {
|
|
2367
|
+
const subtle = await getSubtle();
|
|
2368
|
+
const key = await subtle.importKey(
|
|
2369
|
+
"raw",
|
|
2370
|
+
enc.encode(keyHex),
|
|
2371
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
2372
|
+
false,
|
|
2373
|
+
["sign"]
|
|
2374
|
+
);
|
|
2375
|
+
const sig = await subtle.sign("HMAC", key, enc.encode(message));
|
|
2376
|
+
return bytesToHex3(sig);
|
|
2377
|
+
}
|
|
2378
|
+
function defaultNonce2() {
|
|
2379
|
+
const c = globalThis.crypto;
|
|
2380
|
+
if (c?.randomUUID) return c.randomUUID();
|
|
2381
|
+
return `${Date.now().toString(16)}-${Math.random().toString(16).slice(2)}`;
|
|
2382
|
+
}
|
|
2383
|
+
function canonical(params) {
|
|
2384
|
+
return [
|
|
2385
|
+
params.method.toUpperCase(),
|
|
2386
|
+
params.path,
|
|
2387
|
+
params.ts,
|
|
2388
|
+
params.nonce,
|
|
2389
|
+
params.bodyHash
|
|
2390
|
+
].join("\n");
|
|
2391
|
+
}
|
|
2392
|
+
async function signPartnerRequest(params) {
|
|
2393
|
+
const ts = String(Math.floor((params.nowMs ?? Date.now()) / 1e3));
|
|
2394
|
+
const nonce = params.nonce ?? defaultNonce2();
|
|
2395
|
+
const bodyData = typeof params.body === "string" ? enc.encode(params.body) : params.body ?? new Uint8Array();
|
|
2396
|
+
const bodyHash = await sha256Hex2(bodyData);
|
|
2397
|
+
const message = canonical({
|
|
2398
|
+
method: params.method,
|
|
2399
|
+
path: params.path,
|
|
2400
|
+
ts,
|
|
2401
|
+
nonce,
|
|
2402
|
+
bodyHash
|
|
2403
|
+
});
|
|
2404
|
+
const signingKey = await sha256Hex2(params.secret);
|
|
2405
|
+
const sig = await hmacSha256Hex(signingKey, message);
|
|
2406
|
+
return {
|
|
2407
|
+
authorization: `Flur-Hmac key=${params.keyId}, ts=${ts}, nonce=${nonce}, sig=${sig}`,
|
|
2408
|
+
ts,
|
|
2409
|
+
nonce,
|
|
2410
|
+
bodyHash
|
|
2411
|
+
};
|
|
2412
|
+
}
|
|
2413
|
+
function createFlurPartnerClient(opts) {
|
|
2414
|
+
const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
2415
|
+
if (!fetchImpl) {
|
|
2416
|
+
throw new Error(
|
|
2417
|
+
"createFlurPartnerClient: no fetch implementation available"
|
|
2418
|
+
);
|
|
2419
|
+
}
|
|
2420
|
+
const baseUrl = opts.baseUrl.replace(/\/$/, "");
|
|
2421
|
+
async function makeSignedInit(method, path, body) {
|
|
2422
|
+
const sig = await signPartnerRequest({
|
|
2423
|
+
keyId: opts.keyId,
|
|
2424
|
+
secret: opts.secret,
|
|
2425
|
+
method,
|
|
2426
|
+
path,
|
|
2427
|
+
body: body ?? "",
|
|
2428
|
+
nowMs: opts.nowMs?.(),
|
|
2429
|
+
nonce: opts.nonce?.()
|
|
2430
|
+
});
|
|
2431
|
+
const headers = {
|
|
2432
|
+
authorization: sig.authorization,
|
|
2433
|
+
accept: "application/json"
|
|
2434
|
+
};
|
|
2435
|
+
if (body !== void 0) headers["content-type"] = "application/json";
|
|
2436
|
+
const init2 = { method, headers };
|
|
2437
|
+
if (body !== void 0) init2.body = body;
|
|
2438
|
+
return init2;
|
|
2439
|
+
}
|
|
2440
|
+
async function request(opts2) {
|
|
2441
|
+
const bodyStr = opts2.body === void 0 ? void 0 : JSON.stringify(opts2.body);
|
|
2442
|
+
const init2 = await makeSignedInit(opts2.method, opts2.path, bodyStr);
|
|
2443
|
+
const resp = await fetchImpl(`${baseUrl}${opts2.path}`, init2);
|
|
2444
|
+
const text = await resp.text();
|
|
2445
|
+
let raw;
|
|
2446
|
+
if (text) {
|
|
2447
|
+
try {
|
|
2448
|
+
raw = JSON.parse(text);
|
|
2449
|
+
} catch {
|
|
2450
|
+
}
|
|
2451
|
+
}
|
|
2452
|
+
if (!resp.ok) {
|
|
2453
|
+
const code = raw && typeof raw === "object" && "code" in raw && typeof raw.code === "string" ? raw.code : `http_${resp.status}`;
|
|
2454
|
+
const message = raw && typeof raw === "object" && "message" in raw && typeof raw.message === "string" ? raw.message : `request failed with status ${resp.status}`;
|
|
2455
|
+
throw new FlurApiError(resp.status, code, message, raw);
|
|
2456
|
+
}
|
|
2457
|
+
return raw;
|
|
2458
|
+
}
|
|
2459
|
+
const fetchLike = async (input, init2) => {
|
|
2460
|
+
const url = typeof input === "string" ? input : input.toString();
|
|
2461
|
+
const u = new URL(url, baseUrl);
|
|
2462
|
+
const path = `${u.pathname}${u.search}`;
|
|
2463
|
+
const method = (init2?.method ?? "GET").toUpperCase();
|
|
2464
|
+
let bodyStr;
|
|
2465
|
+
if (init2?.body) {
|
|
2466
|
+
bodyStr = typeof init2.body === "string" ? init2.body : init2.body.toString();
|
|
2467
|
+
}
|
|
2468
|
+
const signed = await makeSignedInit(method, path, bodyStr);
|
|
2469
|
+
return fetchImpl(`${baseUrl}${path}`, {
|
|
2470
|
+
...init2,
|
|
2471
|
+
...signed,
|
|
2472
|
+
headers: {
|
|
2473
|
+
...init2?.headers,
|
|
2474
|
+
...signed.headers
|
|
2475
|
+
}
|
|
2476
|
+
});
|
|
2477
|
+
};
|
|
2478
|
+
return { request, fetch: fetchLike };
|
|
2479
|
+
}
|
|
2480
|
+
function createApiCredentialsAdminClient(opts) {
|
|
2481
|
+
const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
2482
|
+
if (!fetchImpl) {
|
|
2483
|
+
throw new Error(
|
|
2484
|
+
"createApiCredentialsAdminClient: no fetch implementation available"
|
|
2485
|
+
);
|
|
2486
|
+
}
|
|
2487
|
+
const baseUrl = opts.baseUrl.replace(/\/$/, "");
|
|
2488
|
+
async function call(method, path, body, parser) {
|
|
2489
|
+
const init2 = {
|
|
2490
|
+
method,
|
|
2491
|
+
headers: {
|
|
2492
|
+
"content-type": "application/json",
|
|
2493
|
+
accept: "application/json"
|
|
2494
|
+
}
|
|
2495
|
+
};
|
|
2496
|
+
if (body !== void 0) init2.body = JSON.stringify(body);
|
|
2497
|
+
const resp = await fetchImpl(`${baseUrl}${path}`, init2);
|
|
2498
|
+
const text = await resp.text();
|
|
2499
|
+
let raw;
|
|
2500
|
+
if (text) {
|
|
2501
|
+
try {
|
|
2502
|
+
raw = JSON.parse(text);
|
|
2503
|
+
} catch {
|
|
2504
|
+
}
|
|
2505
|
+
}
|
|
2506
|
+
if (!resp.ok) {
|
|
2507
|
+
const code = raw && typeof raw === "object" && "code" in raw && typeof raw.code === "string" ? raw.code : `http_${resp.status}`;
|
|
2508
|
+
const message = raw && typeof raw === "object" && "message" in raw && typeof raw.message === "string" ? raw.message : `request failed with status ${resp.status}`;
|
|
2509
|
+
throw new FlurApiError(resp.status, code, message, raw);
|
|
2510
|
+
}
|
|
2511
|
+
return parser(raw);
|
|
2512
|
+
}
|
|
2513
|
+
const listSchema = z11.object({
|
|
2514
|
+
items: z11.array(ApiCredentialPublicSchema)
|
|
2515
|
+
});
|
|
2516
|
+
return {
|
|
2517
|
+
list: (accountId) => call(
|
|
2518
|
+
"GET",
|
|
2519
|
+
`/v1/accounts/${accountId}/api-credentials`,
|
|
2520
|
+
void 0,
|
|
2521
|
+
(raw) => listSchema.parse(raw)
|
|
2522
|
+
),
|
|
2523
|
+
mint: (accountId, input) => call(
|
|
2524
|
+
"POST",
|
|
2525
|
+
`/v1/accounts/${accountId}/api-credentials`,
|
|
2526
|
+
input,
|
|
2527
|
+
(raw) => MintedApiCredentialSchema.parse(raw)
|
|
2528
|
+
),
|
|
2529
|
+
revoke: (accountId, credentialId) => call(
|
|
2530
|
+
"DELETE",
|
|
2531
|
+
`/v1/accounts/${accountId}/api-credentials/${credentialId}`,
|
|
2532
|
+
void 0,
|
|
2533
|
+
(raw) => ApiCredentialPublicSchema.parse(raw)
|
|
2534
|
+
)
|
|
2535
|
+
};
|
|
2536
|
+
}
|
|
2096
2537
|
export {
|
|
2538
|
+
ACCOUNT_STATUSES,
|
|
2539
|
+
ACCOUNT_TYPES,
|
|
2097
2540
|
ADDITIONAL_DATA_SUBFIELD,
|
|
2541
|
+
AccountMembershipSchema,
|
|
2542
|
+
AccountSchema,
|
|
2543
|
+
ApiCredentialPublicSchema,
|
|
2098
2544
|
FIELD,
|
|
2099
2545
|
FlurApiError,
|
|
2100
2546
|
FlurCapExceededError,
|
|
@@ -2102,6 +2548,8 @@ export {
|
|
|
2102
2548
|
FlurError,
|
|
2103
2549
|
FlurExpiredError,
|
|
2104
2550
|
FlurReplayError,
|
|
2551
|
+
MEMBERSHIP_ROLES,
|
|
2552
|
+
MintedApiCredentialSchema,
|
|
2105
2553
|
NGN_CURRENCY_CODE,
|
|
2106
2554
|
NG_COUNTRY_CODE,
|
|
2107
2555
|
NQRParseError,
|
|
@@ -2111,18 +2559,23 @@ export {
|
|
|
2111
2559
|
OAC_DEFAULT_VALIDITY_MS,
|
|
2112
2560
|
OfflinePaymentAuthorizationSchema,
|
|
2113
2561
|
OfflinePaymentRequestSchema,
|
|
2562
|
+
OfflineTokenSchema,
|
|
2563
|
+
PARTNER_SCOPES,
|
|
2114
2564
|
PASS_KINDS,
|
|
2115
2565
|
PASS_STATES,
|
|
2116
2566
|
PAYLOAD_FORMAT_INDICATOR_VALUE,
|
|
2117
2567
|
POINT_OF_INITIATION,
|
|
2118
2568
|
PassMetadataSchema,
|
|
2119
2569
|
PassSchema,
|
|
2570
|
+
PaymentClaimSchema,
|
|
2120
2571
|
RECEIPT_CHANNELS,
|
|
2121
2572
|
RECEIPT_KINDS,
|
|
2122
2573
|
REPLAY_WINDOW_MS,
|
|
2123
2574
|
ReceiptPayloadSchema,
|
|
2124
2575
|
ReceiptSchema,
|
|
2125
2576
|
RedemptionSchema,
|
|
2577
|
+
SettleResponseSchema,
|
|
2578
|
+
SettlementSchema,
|
|
2126
2579
|
bodySha256Hex,
|
|
2127
2580
|
buildAuthorization,
|
|
2128
2581
|
buildOAC,
|
|
@@ -2133,10 +2586,15 @@ export {
|
|
|
2133
2586
|
canonicalJSONBytes,
|
|
2134
2587
|
canonicalJSONStringify,
|
|
2135
2588
|
canonicalRequestString,
|
|
2589
|
+
computeEncounterId,
|
|
2136
2590
|
constantTimeEqual,
|
|
2137
2591
|
crc16ccitt,
|
|
2138
2592
|
crc16ccittHex,
|
|
2593
|
+
createAccountsClient,
|
|
2594
|
+
createApiCredentialsAdminClient,
|
|
2595
|
+
createFlurPartnerClient,
|
|
2139
2596
|
createHmacFetch,
|
|
2597
|
+
createOfflineSettlementsClient,
|
|
2140
2598
|
createPassesClient,
|
|
2141
2599
|
createReceiptsClient,
|
|
2142
2600
|
decodeAuthorizationQR,
|
|
@@ -2164,6 +2622,7 @@ export {
|
|
|
2164
2622
|
signAuthorization,
|
|
2165
2623
|
signCanonical,
|
|
2166
2624
|
signOAC,
|
|
2625
|
+
signPartnerRequest,
|
|
2167
2626
|
signPass,
|
|
2168
2627
|
signPaymentRequest,
|
|
2169
2628
|
signReceipt,
|