diff options
Diffstat (limited to 'backoffice/index.js')
-rw-r--r-- | backoffice/index.js | 13008 |
1 files changed, 7946 insertions, 5062 deletions
diff --git a/backoffice/index.js b/backoffice/index.js index 0f6480523..915c5dba0 100644 --- a/backoffice/index.js +++ b/backoffice/index.js @@ -9504,12 +9504,21 @@ var TalerErrorCode; TalerErrorCode2[TalerErrorCode2["MERCHANT_POST_ORDERS_ID_PAY_WIRE_METHOD_UNSUPPORTED"] = 2175] = "MERCHANT_POST_ORDERS_ID_PAY_WIRE_METHOD_UNSUPPORTED"; TalerErrorCode2[TalerErrorCode2["MERCHANT_POST_ORDERS_ID_PAID_CONTRACT_HASH_MISMATCH"] = 2200] = "MERCHANT_POST_ORDERS_ID_PAID_CONTRACT_HASH_MISMATCH"; TalerErrorCode2[TalerErrorCode2["MERCHANT_POST_ORDERS_ID_PAID_COIN_SIGNATURE_INVALID"] = 2201] = "MERCHANT_POST_ORDERS_ID_PAID_COIN_SIGNATURE_INVALID"; + TalerErrorCode2[TalerErrorCode2["MERCHANT_POST_TOKEN_FAMILY_CONFLICT"] = 2225] = "MERCHANT_POST_TOKEN_FAMILY_CONFLICT"; + TalerErrorCode2[TalerErrorCode2["MERCHANT_PATCH_TOKEN_FAMILY_NOT_FOUND"] = 2226] = "MERCHANT_PATCH_TOKEN_FAMILY_NOT_FOUND"; TalerErrorCode2[TalerErrorCode2["MERCHANT_POST_ORDERS_ID_ABORT_EXCHANGE_REFUND_FAILED"] = 2251] = "MERCHANT_POST_ORDERS_ID_ABORT_EXCHANGE_REFUND_FAILED"; TalerErrorCode2[TalerErrorCode2["MERCHANT_POST_ORDERS_ID_ABORT_EXCHANGE_LOOKUP_FAILED"] = 2252] = "MERCHANT_POST_ORDERS_ID_ABORT_EXCHANGE_LOOKUP_FAILED"; TalerErrorCode2[TalerErrorCode2["MERCHANT_POST_ORDERS_ID_ABORT_CONTRACT_NOT_FOUND"] = 2253] = "MERCHANT_POST_ORDERS_ID_ABORT_CONTRACT_NOT_FOUND"; TalerErrorCode2[TalerErrorCode2["MERCHANT_POST_ORDERS_ID_ABORT_REFUND_REFUSED_PAYMENT_COMPLETE"] = 2254] = "MERCHANT_POST_ORDERS_ID_ABORT_REFUND_REFUSED_PAYMENT_COMPLETE"; TalerErrorCode2[TalerErrorCode2["MERCHANT_POST_ORDERS_ID_ABORT_CONTRACT_HASH_MISSMATCH"] = 2255] = "MERCHANT_POST_ORDERS_ID_ABORT_CONTRACT_HASH_MISSMATCH"; TalerErrorCode2[TalerErrorCode2["MERCHANT_POST_ORDERS_ID_ABORT_COINS_ARRAY_EMPTY"] = 2256] = "MERCHANT_POST_ORDERS_ID_ABORT_COINS_ARRAY_EMPTY"; + TalerErrorCode2[TalerErrorCode2["MERCHANT_EXCHANGE_TRANSFERS_AWAITING_KEYS"] = 2258] = "MERCHANT_EXCHANGE_TRANSFERS_AWAITING_KEYS"; + TalerErrorCode2[TalerErrorCode2["MERCHANT_EXCHANGE_TRANSFERS_AWAITING_LIST"] = 2259] = "MERCHANT_EXCHANGE_TRANSFERS_AWAITING_LIST"; + TalerErrorCode2[TalerErrorCode2["MERCHANT_EXCHANGE_TRANSFERS_FATAL_NO_EXCHANGE"] = 2260] = "MERCHANT_EXCHANGE_TRANSFERS_FATAL_NO_EXCHANGE"; + TalerErrorCode2[TalerErrorCode2["MERCHANT_EXCHANGE_TRANSFERS_FATAL_NOT_FOUND"] = 2261] = "MERCHANT_EXCHANGE_TRANSFERS_FATAL_NOT_FOUND"; + TalerErrorCode2[TalerErrorCode2["MERCHANT_EXCHANGE_TRANSFERS_RATE_LIMITED"] = 2262] = "MERCHANT_EXCHANGE_TRANSFERS_RATE_LIMITED"; + TalerErrorCode2[TalerErrorCode2["MERCHANT_EXCHANGE_TRANSFERS_TRANSIENT_FAILURE"] = 2263] = "MERCHANT_EXCHANGE_TRANSFERS_TRANSIENT_FAILURE"; + TalerErrorCode2[TalerErrorCode2["MERCHANT_EXCHANGE_TRANSFERS_HARD_FAILURE"] = 2264] = "MERCHANT_EXCHANGE_TRANSFERS_HARD_FAILURE"; TalerErrorCode2[TalerErrorCode2["MERCHANT_POST_ORDERS_ID_CLAIM_NOT_FOUND"] = 2300] = "MERCHANT_POST_ORDERS_ID_CLAIM_NOT_FOUND"; TalerErrorCode2[TalerErrorCode2["MERCHANT_POST_ORDERS_ID_CLAIM_ALREADY_CLAIMED"] = 2301] = "MERCHANT_POST_ORDERS_ID_CLAIM_ALREADY_CLAIMED"; TalerErrorCode2[TalerErrorCode2["MERCHANT_POST_ORDERS_ID_CLAIM_CLIENT_INTERNAL_FAILURE"] = 2302] = "MERCHANT_POST_ORDERS_ID_CLAIM_CLIENT_INTERNAL_FAILURE"; @@ -9545,13 +9554,6 @@ var TalerErrorCode; TalerErrorCode2[TalerErrorCode2["MERCHANT_PRIVATE_POST_TRANSFERS_ACCOUNT_NOT_FOUND"] = 2555] = "MERCHANT_PRIVATE_POST_TRANSFERS_ACCOUNT_NOT_FOUND"; TalerErrorCode2[TalerErrorCode2["MERCHANT_PRIVATE_DELETE_TRANSFERS_ALREADY_CONFIRMED"] = 2556] = "MERCHANT_PRIVATE_DELETE_TRANSFERS_ALREADY_CONFIRMED"; TalerErrorCode2[TalerErrorCode2["MERCHANT_PRIVATE_POST_TRANSFERS_CONFLICTING_SUBMISSION"] = 2557] = "MERCHANT_PRIVATE_POST_TRANSFERS_CONFLICTING_SUBMISSION"; - TalerErrorCode2[TalerErrorCode2["MERCHANT_EXCHANGE_TRANSFERS_AWAITING_KEYS"] = 2258] = "MERCHANT_EXCHANGE_TRANSFERS_AWAITING_KEYS"; - TalerErrorCode2[TalerErrorCode2["MERCHANT_EXCHANGE_TRANSFERS_AWAITING_LIST"] = 2259] = "MERCHANT_EXCHANGE_TRANSFERS_AWAITING_LIST"; - TalerErrorCode2[TalerErrorCode2["MERCHANT_EXCHANGE_TRANSFERS_FATAL_NO_EXCHANGE"] = 2260] = "MERCHANT_EXCHANGE_TRANSFERS_FATAL_NO_EXCHANGE"; - TalerErrorCode2[TalerErrorCode2["MERCHANT_EXCHANGE_TRANSFERS_FATAL_NOT_FOUND"] = 2261] = "MERCHANT_EXCHANGE_TRANSFERS_FATAL_NOT_FOUND"; - TalerErrorCode2[TalerErrorCode2["MERCHANT_EXCHANGE_TRANSFERS_RATE_LIMITED"] = 2262] = "MERCHANT_EXCHANGE_TRANSFERS_RATE_LIMITED"; - TalerErrorCode2[TalerErrorCode2["MERCHANT_EXCHANGE_TRANSFERS_TRANSIENT_FAILURE"] = 2263] = "MERCHANT_EXCHANGE_TRANSFERS_TRANSIENT_FAILURE"; - TalerErrorCode2[TalerErrorCode2["MERCHANT_EXCHANGE_TRANSFERS_HARD_FAILURE"] = 2264] = "MERCHANT_EXCHANGE_TRANSFERS_HARD_FAILURE"; TalerErrorCode2[TalerErrorCode2["MERCHANT_EXCHANGE_TRANSFERS_CONFLICTING_TRANSFERS"] = 2563] = "MERCHANT_EXCHANGE_TRANSFERS_CONFLICTING_TRANSFERS"; TalerErrorCode2[TalerErrorCode2["MERCHANT_PRIVATE_POST_INSTANCES_ALREADY_EXISTS"] = 2600] = "MERCHANT_PRIVATE_POST_INSTANCES_ALREADY_EXISTS"; TalerErrorCode2[TalerErrorCode2["MERCHANT_PRIVATE_POST_INSTANCES_BAD_AUTH"] = 2601] = "MERCHANT_PRIVATE_POST_INSTANCES_BAD_AUTH"; @@ -9679,6 +9681,8 @@ var TalerErrorCode; TalerErrorCode2[TalerErrorCode2["WALLET_EXCHANGE_UNAVAILABLE"] = 7032] = "WALLET_EXCHANGE_UNAVAILABLE"; TalerErrorCode2[TalerErrorCode2["WALLET_EXCHANGE_ENTRY_USED"] = 7033] = "WALLET_EXCHANGE_ENTRY_USED"; TalerErrorCode2[TalerErrorCode2["WALLET_DB_UNAVAILABLE"] = 7034] = "WALLET_DB_UNAVAILABLE"; + TalerErrorCode2[TalerErrorCode2["WALLET_TALER_URI_MALFORMED"] = 7035] = "WALLET_TALER_URI_MALFORMED"; + TalerErrorCode2[TalerErrorCode2["WALLET_CORE_REQUEST_CANCELLED"] = 7036] = "WALLET_CORE_REQUEST_CANCELLED"; TalerErrorCode2[TalerErrorCode2["ANASTASIS_GENERIC_BACKEND_TIMEOUT"] = 8e3] = "ANASTASIS_GENERIC_BACKEND_TIMEOUT"; TalerErrorCode2[TalerErrorCode2["ANASTASIS_GENERIC_INVALID_PAYMENT_REQUEST"] = 8001] = "ANASTASIS_GENERIC_INVALID_PAYMENT_REQUEST"; TalerErrorCode2[TalerErrorCode2["ANASTASIS_GENERIC_BACKEND_ERROR"] = 8002] = "ANASTASIS_GENERIC_BACKEND_ERROR"; @@ -9746,6 +9750,8 @@ var TalerErrorCode; TalerErrorCode2[TalerErrorCode2["ANASTASIS_REDUCER_INTERNAL_ERROR"] = 8419] = "ANASTASIS_REDUCER_INTERNAL_ERROR"; TalerErrorCode2[TalerErrorCode2["ANASTASIS_REDUCER_PROVIDERS_ALREADY_SYNCED"] = 8420] = "ANASTASIS_REDUCER_PROVIDERS_ALREADY_SYNCED"; TalerErrorCode2[TalerErrorCode2["DONAU_GENERIC_KEYS_MISSING"] = 8607] = "DONAU_GENERIC_KEYS_MISSING"; + TalerErrorCode2[TalerErrorCode2["DONAU_CHARITY_SIGNATURE_INVALID"] = 8608] = "DONAU_CHARITY_SIGNATURE_INVALID"; + TalerErrorCode2[TalerErrorCode2["DONAU_CHARITY_NOT_FOUND"] = 8609] = "DONAU_CHARITY_NOT_FOUND"; TalerErrorCode2[TalerErrorCode2["LIBEUFIN_NEXUS_GENERIC_ERROR"] = 9e3] = "LIBEUFIN_NEXUS_GENERIC_ERROR"; TalerErrorCode2[TalerErrorCode2["LIBEUFIN_NEXUS_UNCAUGHT_EXCEPTION"] = 9001] = "LIBEUFIN_NEXUS_UNCAUGHT_EXCEPTION"; TalerErrorCode2[TalerErrorCode2["LIBEUFIN_SANDBOX_GENERIC_ERROR"] = 9500] = "LIBEUFIN_SANDBOX_GENERIC_ERROR"; @@ -9941,6 +9947,38 @@ var amountFractionalBase = 1e8; var amountFractionalLength = 8; var amountMaxValue = 2 ** 52; var FRAC_SEPARATOR = "."; +var Amount = class _Amount { + static from(a5) { + return new _Amount(Amounts.parseOrThrow(a5), 0); + } + static zeroOfCurrency(currency) { + return new _Amount(Amounts.zeroOfCurrency(currency), 0); + } + add(...a5) { + if (this.saturated) { + return this; + } + const r3 = Amounts.add(this.val, ...a5); + return new _Amount(r3.amount, r3.saturated ? 1 : 0); + } + mult(n2) { + if (this.saturated) { + return this; + } + const r3 = Amounts.mult(this, n2); + return new _Amount(r3.amount, r3.saturated ? 1 : 0); + } + toJson() { + return { ...this.val }; + } + toString() { + return Amounts.stringify(this.val); + } + constructor(val, saturated) { + this.val = val; + this.saturated = saturated; + } +}; function codecForAmountString() { return { decode(x6, c4) { @@ -9984,6 +10022,9 @@ var Amounts = class _Amounts { if (typeof amt === "string") { return _Amounts.parseOrThrow(amt); } + if (amt instanceof Amount) { + return amt.toJson(); + } return amt; } static divmod(a1, a22) { @@ -10203,6 +10244,9 @@ var Amounts = class _Amounts { * throw if the input is not a valid amount. */ static parseOrThrow(s5) { + if (s5 instanceof Amount) { + return s5.toJson(); + } if (typeof s5 === "object") { if (typeof s5.currency !== "string") { throw Error("invalid amount object"); @@ -11977,14 +12021,21 @@ function parseURL(input, options) { }); } var URLImpl = class { + //Include URL type for "url" and "base" params. constructor(url, base2) { let parsedBase = null; if (base2 !== void 0) { + if (base2 instanceof URL) { + base2 = base2.href; + } parsedBase = basicURLParse(base2); if (parsedBase === null) { throw new TypeError(`Invalid base URL: ${base2}`); } } + if (url instanceof URL) { + url = url.href; + } const parsedURL = basicURLParse(url, { baseURL: parsedBase }); if (parsedURL === null) { throw new TypeError(`Invalid URL: ${url}`); @@ -12162,7 +12213,7 @@ if (useOwnUrlImp || !_URLSearchParams) { globalThis.URLSearchParams = URLSearchParamsImpl; _URLSearchParams = URLSearchParamsImpl; } -var URLSearchParams = _URLSearchParams; +var URLSearchParams2 = _URLSearchParams; // ../taler-util/lib/helpers.js function canonicalizeBaseUrl(url) { @@ -12467,9 +12518,69 @@ var ObjectCodecBuilder = class { }; } }; +var UnionCodecBuilder = class { + constructor(discriminator, baseCodec) { + this.discriminator = discriminator; + this.baseCodec = baseCodec; + this.alternatives = /* @__PURE__ */ new Map(); + } + /** + * Define a property for the object. + */ + alternative(tagValue, codec) { + if (!codec) { + throw Error("inner codec must be defined"); + } + this.alternatives.set(tagValue, { codec, tagValue }); + return this; + } + /** + * Return the built codec. + * + * @param objectDisplayName name of the object that this codec operates on, + * used in error messages. + */ + build(objectDisplayName) { + const alternatives = this.alternatives; + const discriminator = this.discriminator; + const baseCodec = this.baseCodec; + return { + decode(x6, c4) { + if (!c4) { + c4 = { + path: [`(${objectDisplayName})`] + }; + } + const d5 = x6[discriminator]; + if (d5 === void 0) { + throw new DecodingError(`expected tag for ${objectDisplayName} at ${renderContext(c4)}.${String(discriminator)}`); + } + const alt = alternatives.get(d5); + if (!alt) { + throw new DecodingError(`unknown tag for ${objectDisplayName} ${d5} at ${renderContext(c4)}.${String(discriminator)}`); + } + const altDecoded = alt.codec.decode(x6); + if (baseCodec) { + const baseDecoded = baseCodec.decode(x6, c4); + return { ...baseDecoded, ...altDecoded }; + } else { + return altDecoded; + } + } + }; + } +}; +var UnionCodecPreBuilder = class { + discriminateOn(discriminator, baseCodec) { + return new UnionCodecBuilder(discriminator, baseCodec); + } +}; function buildCodecForObject() { return new ObjectCodecBuilder(); } +function buildCodecForUnion() { + return new UnionCodecPreBuilder(); +} function codecForMap(innerCodec) { if (!innerCodec) { throw Error("inner codec must be defined"); @@ -12487,6 +12598,23 @@ function codecForMap(innerCodec) { } }; } +function codecForList(innerCodec) { + if (!innerCodec) { + throw Error("inner codec must be defined"); + } + return { + decode(x6, c4) { + const arr = []; + if (!Array.isArray(x6)) { + throw new DecodingError(`expected array at ${renderContext(c4)}`); + } + for (const i4 in x6) { + arr.push(innerCodec.decode(x6[i4], joinContext(c4, `[${i4}]`))); + } + return arr; + } + }; +} function codecForNumber() { return { decode(x6, c4) { @@ -12537,6 +12665,16 @@ function codecForConstString(s5) { } }; } +function codecForConstNumber(n2) { + return { + decode(x6, c4) { + if (x6 === n2) { + return x6; + } + throw new DecodingError(`expected number constant "${n2}" at ${renderContext(c4)} but got ${typeof x6}`); + } + }; +} function codecOptional(innerCodec) { return { decode(x6, c4) { @@ -13031,7 +13169,17 @@ var Duration; return Math.ceil(d5.d_ms / 1e3 / 60 / 60 / 24 / 365); } Duration2.toIntegerYears = toIntegerYears; - Duration2.fromSpec = durationFromSpec; + function fromSpec(spec) { + let d_ms = 0; + d_ms += (spec.seconds ?? 0) * SECONDS; + d_ms += (spec.minutes ?? 0) * MINUTES; + d_ms += (spec.hours ?? 0) * HOURS; + d_ms += (spec.days ?? 0) * DAYS; + d_ms += (spec.months ?? 0) * MONTHS; + d_ms += (spec.years ?? 0) * YEARS; + return { d_ms }; + } + Duration2.fromSpec = fromSpec; function getForever() { return { d_ms: "forever" }; } @@ -13074,36 +13222,36 @@ var Duration; Duration2.clamp = clamp; })(Duration || (Duration = {})); var AbsoluteTime; -(function(AbsoluteTime2) { +(function(AbsoluteTime3) { function getStampMsNow() { return (/* @__PURE__ */ new Date()).getTime(); } - AbsoluteTime2.getStampMsNow = getStampMsNow; + AbsoluteTime3.getStampMsNow = getStampMsNow; function getStampMsNever() { return Number.MAX_SAFE_INTEGER; } - AbsoluteTime2.getStampMsNever = getStampMsNever; + AbsoluteTime3.getStampMsNever = getStampMsNever; function now2() { return { t_ms: (/* @__PURE__ */ new Date()).getTime() + timeshift, [opaque_AbsoluteTime]: true }; } - AbsoluteTime2.now = now2; + AbsoluteTime3.now = now2; function never() { return { t_ms: "never", [opaque_AbsoluteTime]: true }; } - AbsoluteTime2.never = never; + AbsoluteTime3.never = never; function fromMilliseconds(ms) { return { t_ms: ms, [opaque_AbsoluteTime]: true }; } - AbsoluteTime2.fromMilliseconds = fromMilliseconds; + AbsoluteTime3.fromMilliseconds = fromMilliseconds; function cmp(t1, t22) { if (t1.t_ms === "never") { if (t22.t_ms === "never") { @@ -13122,7 +13270,7 @@ var AbsoluteTime; } return -1; } - AbsoluteTime2.cmp = cmp; + AbsoluteTime3.cmp = cmp; function min(t1, t22) { if (t1.t_ms === "never") { return { t_ms: t22.t_ms, [opaque_AbsoluteTime]: true }; @@ -13132,7 +13280,7 @@ var AbsoluteTime; } return { t_ms: Math.min(t1.t_ms, t22.t_ms), [opaque_AbsoluteTime]: true }; } - AbsoluteTime2.min = min; + AbsoluteTime3.min = min; function max(t1, t22) { if (t1.t_ms === "never") { return { t_ms: "never", [opaque_AbsoluteTime]: true }; @@ -13142,7 +13290,7 @@ var AbsoluteTime; } return { t_ms: Math.max(t1.t_ms, t22.t_ms), [opaque_AbsoluteTime]: true }; } - AbsoluteTime2.max = max; + AbsoluteTime3.max = max; function difference2(t1, t22) { if (t1.t_ms === "never") { return { d_ms: "forever" }; @@ -13152,15 +13300,15 @@ var AbsoluteTime; } return { d_ms: Math.abs(t1.t_ms - t22.t_ms) }; } - AbsoluteTime2.difference = difference2; + AbsoluteTime3.difference = difference2; function isExpired(t4) { return cmp(t4, now2()) <= 0; } - AbsoluteTime2.isExpired = isExpired; + AbsoluteTime3.isExpired = isExpired; function isNever(t4) { return t4.t_ms === "never"; } - AbsoluteTime2.isNever = isNever; + AbsoluteTime3.isNever = isNever; function fromProtocolTimestamp(t4) { if (t4.t_s === "never") { return { t_ms: "never", [opaque_AbsoluteTime]: true }; @@ -13170,14 +13318,14 @@ var AbsoluteTime; [opaque_AbsoluteTime]: true }; } - AbsoluteTime2.fromProtocolTimestamp = fromProtocolTimestamp; + AbsoluteTime3.fromProtocolTimestamp = fromProtocolTimestamp; function fromStampMs(stampMs) { return { t_ms: stampMs, [opaque_AbsoluteTime]: true }; } - AbsoluteTime2.fromStampMs = fromStampMs; + AbsoluteTime3.fromStampMs = fromStampMs; function fromPreciseTimestamp(t4) { if (t4.t_s === "never") { return { t_ms: "never", [opaque_AbsoluteTime]: true }; @@ -13188,14 +13336,14 @@ var AbsoluteTime; [opaque_AbsoluteTime]: true }; } - AbsoluteTime2.fromPreciseTimestamp = fromPreciseTimestamp; + AbsoluteTime3.fromPreciseTimestamp = fromPreciseTimestamp; function toStampMs(at2) { if (at2.t_ms === "never") { return Number.MAX_SAFE_INTEGER; } return at2.t_ms; } - AbsoluteTime2.toStampMs = toStampMs; + AbsoluteTime3.toStampMs = toStampMs; function toPreciseTimestamp(at2) { if (at2.t_ms == "never") { return { @@ -13209,7 +13357,7 @@ var AbsoluteTime; off_us }; } - AbsoluteTime2.toPreciseTimestamp = toPreciseTimestamp; + AbsoluteTime3.toPreciseTimestamp = toPreciseTimestamp; function toProtocolTimestamp(at2) { if (at2.t_ms === "never") { return { t_s: "never" }; @@ -13218,7 +13366,7 @@ var AbsoluteTime; t_s: Math.floor(at2.t_ms / 1e3) }; } - AbsoluteTime2.toProtocolTimestamp = toProtocolTimestamp; + AbsoluteTime3.toProtocolTimestamp = toProtocolTimestamp; function isBetween(t4, start, end) { if (cmp(t4, start) < 0) { return false; @@ -13228,7 +13376,7 @@ var AbsoluteTime; } return true; } - AbsoluteTime2.isBetween = isBetween; + AbsoluteTime3.isBetween = isBetween; function toIsoString(t4) { if (t4.t_ms === "never") { return "<never>"; @@ -13236,14 +13384,14 @@ var AbsoluteTime; return new Date(t4.t_ms).toISOString(); } } - AbsoluteTime2.toIsoString = toIsoString; + AbsoluteTime3.toIsoString = toIsoString; function addDuration(t1, d5) { if (t1.t_ms === "never" || d5.d_ms === "forever") { return { t_ms: "never", [opaque_AbsoluteTime]: true }; } return { t_ms: t1.t_ms + d5.d_ms, [opaque_AbsoluteTime]: true }; } - AbsoluteTime2.addDuration = addDuration; + AbsoluteTime3.addDuration = addDuration; function remaining(t1) { if (t1.t_ms === "never") { return Duration.getForever(); @@ -13254,7 +13402,7 @@ var AbsoluteTime; } return Duration.fromMilliseconds(Math.max(0, t1.t_ms - stampNow.t_ms)); } - AbsoluteTime2.remaining = remaining; + AbsoluteTime3.remaining = remaining; function subtractDuraction(t1, d5) { if (t1.t_ms === "never") { return { t_ms: "never", [opaque_AbsoluteTime]: true }; @@ -13264,14 +13412,14 @@ var AbsoluteTime; } return { t_ms: Math.max(0, t1.t_ms - d5.d_ms), [opaque_AbsoluteTime]: true }; } - AbsoluteTime2.subtractDuraction = subtractDuraction; + AbsoluteTime3.subtractDuraction = subtractDuraction; function stringify(t4) { if (t4.t_ms === "never") { return "never"; } return new Date(t4.t_ms).toISOString(); } - AbsoluteTime2.stringify = stringify; + AbsoluteTime3.stringify = stringify; })(AbsoluteTime || (AbsoluteTime = {})); var SECONDS = 1e3; var MINUTES = SECONDS * 60; @@ -13279,16 +13427,6 @@ var HOURS = MINUTES * 60; var DAYS = HOURS * 24; var MONTHS = DAYS * 30; var YEARS = DAYS * 365; -function durationFromSpec(spec) { - let d_ms = 0; - d_ms += (spec.seconds ?? 0) * SECONDS; - d_ms += (spec.minutes ?? 0) * MINUTES; - d_ms += (spec.hours ?? 0) * HOURS; - d_ms += (spec.days ?? 0) * DAYS; - d_ms += (spec.months ?? 0) * MONTHS; - d_ms += (spec.years ?? 0) * YEARS; - return { d_ms }; -} function durationMin(d1, d22) { if (d1.d_ms === "forever") { return { d_ms: d22.d_ms }; @@ -13313,8 +13451,27 @@ function durationMul(d5, n2) { } return { d_ms: Math.round(d5.d_ms * n2) }; } +var codecForAbsoluteTime = { + decode(x6, c4) { + if (x6 === void 0) { + throw Error(`got undefined and expected absolute time at ${renderContext(c4)}`); + } + const t_ms = x6.t_ms; + if (typeof t_ms === "string") { + if (t_ms === "never") { + return { t_ms: "never", [opaque_AbsoluteTime]: true }; + } + } else if (typeof t_ms === "number") { + return { t_ms, [opaque_AbsoluteTime]: true }; + } + throw Error(`expected timestamp at ${renderContext(c4)}`); + } +}; var codecForTimestamp = { decode(x6, c4) { + if (x6 === void 0) { + throw Error(`got undefined and expected timestamp at ${renderContext(c4)}`); + } const t_ms = x6.t_ms; if (typeof t_ms === "string") { if (t_ms === "never") { @@ -13336,6 +13493,21 @@ var codecForTimestamp = { throw Error(`expected protocol timestamp at ${renderContext(c4)}`); } }; +var codecForDuration = { + decode(x6, c4) { + const d_us = x6.d_us; + if (typeof d_us === "string") { + if (d_us === "forever") { + return { d_us: "forever" }; + } + throw Error(`expected duration at ${renderContext(c4)}`); + } + if (typeof d_us === "number") { + return { d_us }; + } + throw Error(`expected duration at ${renderContext(c4)}`); + } +}; // ../taler-util/lib/taler-types.js var DenomKeyType; @@ -13381,6 +13553,8 @@ var DenominationPubKey; } DenominationPubKey2.cmp = cmp; })(DenominationPubKey || (DenominationPubKey = {})); +var codecForLocation = () => buildCodecForObject().property("country", codecOptional(codecForString())).property("country_subdivision", codecOptional(codecForString())).property("building_name", codecOptional(codecForString())).property("building_number", codecOptional(codecForString())).property("district", codecOptional(codecForString())).property("street", codecOptional(codecForString())).property("post_code", codecOptional(codecForString())).property("town", codecOptional(codecForString())).property("town_location", codecOptional(codecForString())).property("address_lines", codecOptional(codecForList(codecForString()))).build("Location"); +var codecForInternationalizedString = () => codecForMap(codecForString()); var codecForNgDenominations = codecForAny(); var ExchangeProtocolVersion; (function(ExchangeProtocolVersion2) { @@ -14123,6 +14297,19 @@ function generateFakeSegwitAddress(reservePub, addr) { } // ../taler-util/lib/payto.js +function codecForPaytoString() { + return { + decode(x6, c4) { + if (typeof x6 !== "string") { + throw new DecodingError(`expected string at ${renderContext(c4)} but got ${typeof x6}`); + } + if (!x6.startsWith(paytoPfx)) { + throw new DecodingError(`expected start with payto at ${renderContext(c4)} but got "${x6}"`); + } + return x6; + } + }; +} var paytoPfx = "payto://"; function stringifyPaytoUri(p4) { const url = new URL(`${paytoPfx}${p4.targetType}/${p4.targetPath}`); @@ -14144,7 +14331,7 @@ function parsePaytoUri(s5) { const targetType = acct.slice(0, firstSlashPos); const targetPath = acct.slice(firstSlashPos + 1); const params = {}; - const searchParams = new URLSearchParams(search || ""); + const searchParams = new URLSearchParams2(search || ""); searchParams.forEach((v3, k5) => { params[k5] = v3; }); @@ -14187,10 +14374,12 @@ function parsePaytoUri(s5) { const msg = /\b([A-Z0-9]{52})\b/.exec(params["message"]); const reserve = !msg ? params["subject"] : msg[0]; const segwitAddrs = !reserve ? [] : generateFakeSegwitAddress(reserve, targetPath); + const uppercased = targetType.toUpperCase(); const result = { isKnown: true, targetPath, targetType, + address: uppercased, params, segwitAddrs }; @@ -14204,25 +14393,244 @@ function parsePaytoUri(s5) { }; } +// ../taler-util/lib/http-common.js +var textEncoder = new TextEncoder(); +var logger3 = new Logger("http.ts"); +var DEFAULT_REQUEST_TIMEOUT_MS = 6e4; +var Headers2 = class { + constructor() { + this.headerMap = /* @__PURE__ */ new Map(); + } + get(name) { + const r3 = this.headerMap.get(name.toLowerCase()); + if (r3) { + return r3; + } + return null; + } + set(name, value) { + const normalizedName = name.toLowerCase(); + const existing = this.headerMap.get(normalizedName); + if (existing !== void 0) { + this.headerMap.set(normalizedName, existing + "," + value); + } else { + this.headerMap.set(normalizedName, value); + } + } + toJSON() { + const m5 = {}; + this.headerMap.forEach((v3, k5) => m5[k5] = v3); + return m5; + } +}; +async function readTalerErrorResponse(httpResponse) { + const contentType = httpResponse.headers.get("content-type"); + if (contentType !== "application/json") { + throw TalerError.fromDetail(TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE, { + requestUrl: httpResponse.requestUrl, + requestMethod: httpResponse.requestMethod, + httpStatusCode: httpResponse.status, + contentType: contentType || "<null>" + }, "Error response did not even contain JSON. The request URL might be wrong or the service might be unavailable."); + } + let errJson; + try { + errJson = await httpResponse.json(); + } catch (e4) { + throw TalerError.fromDetail(TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE, { + requestUrl: httpResponse.requestUrl, + requestMethod: httpResponse.requestMethod, + httpStatusCode: httpResponse.status, + validationError: e4.toString() + }, "Couldn't parse JSON format from error response"); + } + const talerErrorCode = errJson.code; + if (typeof talerErrorCode !== "number") { + logger3.warn(`malformed error response (status ${httpResponse.status}): ${j2s(errJson)}`); + throw TalerError.fromDetail(TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE, { + requestUrl: httpResponse.requestUrl, + requestMethod: httpResponse.requestMethod, + httpStatusCode: httpResponse.status + }, "Error response did not contain error code"); + } + return errJson; +} +async function readSuccessResponseJsonOrErrorCode(httpResponse, codec) { + if (!(httpResponse.status >= 200 && httpResponse.status < 300)) { + return { + isError: true, + talerErrorResponse: await readTalerErrorResponse(httpResponse) + }; + } + let respJson; + try { + respJson = await httpResponse.json(); + } catch (e4) { + throw TalerError.fromDetail(TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE, { + requestUrl: httpResponse.requestUrl, + requestMethod: httpResponse.requestMethod, + httpStatusCode: httpResponse.status, + validationError: e4.toString() + }, "Couldn't parse JSON format from response"); + } + let parsedResponse; + try { + parsedResponse = codec.decode(respJson); + } catch (e4) { + throw TalerError.fromDetail(TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE, { + requestUrl: httpResponse.requestUrl, + requestMethod: httpResponse.requestMethod, + httpStatusCode: httpResponse.status, + validationError: e4.toString() + }, "Response invalid"); + } + return { + isError: false, + response: parsedResponse + }; +} +function throwUnexpectedRequestError(httpResponse, talerErrorResponse) { + throw TalerError.fromDetail(TalerErrorCode.WALLET_UNEXPECTED_REQUEST_ERROR, { + requestUrl: httpResponse.requestUrl, + requestMethod: httpResponse.requestMethod, + httpStatusCode: httpResponse.status, + errorResponse: talerErrorResponse + }, `Unexpected HTTP status ${httpResponse.status} in response`); +} +async function readSuccessResponseJsonOrThrow(httpResponse, codec) { + const r3 = await readSuccessResponseJsonOrErrorCode(httpResponse, codec); + if (!r3.isError) { + return r3.response; + } + throwUnexpectedRequestError(httpResponse, r3.talerErrorResponse); +} +function encodeBody(body) { + if (body == null) { + return new ArrayBuffer(0); + } + if (typeof body === "string") { + return textEncoder.encode(body).buffer; + } else if (ArrayBuffer.isView(body)) { + return body.buffer; + } else if (body instanceof ArrayBuffer) { + return body; + } else if (typeof body === "object") { + return textEncoder.encode(JSON.stringify(body)).buffer; + } + throw new TypeError("unsupported request body type"); +} +function getDefaultHeaders(method) { + const headers = {}; + if (method === "POST" || method === "PUT" || method === "PATCH") { + headers["Content-Type"] = "application/json"; + } + headers["Accept"] = "application/json"; + return headers; +} +function makeBasicAuthHeader(username, password) { + const auth = `${username}:${password}`; + const authEncoded = base64FromArrayBuffer(stringToBytes(auth)); + return `Basic ${authEncoded}`; +} + +// ../taler-util/lib/operation.js +async function opSuccessFromHttp(resp, codec) { + const body = await readSuccessResponseJsonOrThrow(resp, codec); + return { type: "ok", body }; +} +function opFixedSuccess(body) { + return { type: "ok", body }; +} +function opEmptySuccess(resp) { + return { type: "ok", body: void 0 }; +} +async function opKnownAlternativeFailure(resp, s5, codec) { + const body = await readSuccessResponseJsonOrThrow(resp, codec); + return { type: "fail", case: s5, body }; +} +async function opKnownHttpFailure(s5, resp) { + const detail = await readTalerErrorResponse(resp); + return { type: "fail", case: s5, detail }; +} +function opKnownTalerFailure(s5, detail) { + return { type: "fail", case: s5, detail }; +} +function opUnknownFailure(resp, error2) { + throw TalerError.fromDetail(TalerErrorCode.WALLET_UNEXPECTED_REQUEST_ERROR, { + requestUrl: resp.requestUrl, + requestMethod: resp.requestMethod, + httpStatusCode: resp.status, + errorResponse: error2 + }, `Unexpected HTTP status ${resp.status} in response`); +} + // ../taler-util/lib/taleruri.js -function parseWithdrawUri(s5) { - const pi = parseProtoInfo(s5, "withdraw"); - if (!pi) { - return void 0; +function codecForTalerUriString() { + return { + decode(x6, c4) { + if (typeof x6 !== "string") { + throw new DecodingError(`expected string at ${renderContext(c4)} but got ${typeof x6}`); + } + if (parseTalerUri(x6) === void 0) { + throw new DecodingError(`invalid taler URI at ${renderContext(c4)} but got "${x6}"`); + } + return x6; + } + }; +} +function parseWithdrawUriWithError(s5) { + const pi = parseProtoInfoWithError(s5, "withdraw"); + if (pi.type === "fail") { + return pi; } - const parts = pi.rest.split("/"); + const parts = pi.body.rest.split("/"); if (parts.length < 2) { - return void 0; + return opKnownTalerFailure(TalerErrorCode.WALLET_TALER_URI_MALFORMED, { + code: TalerErrorCode.WALLET_TALER_URI_MALFORMED + }); } const host = parts[0].toLowerCase(); const pathSegments = parts.slice(1, parts.length - 1); const withdrawId = parts[parts.length - 1]; const p4 = [host, ...pathSegments].join("/"); - return { + const result = { type: TalerUriAction.Withdraw, - bankIntegrationApiBaseUrl: canonicalizeBaseUrl(`${pi.innerProto}://${p4}/`), + bankIntegrationApiBaseUrl: canonicalizeBaseUrl(`${pi.body.innerProto}://${p4}/`), withdrawalOperationId: withdrawId }; + return opFixedSuccess(result); +} +function parseWithdrawUri(s5) { + const r3 = parseWithdrawUriWithError(s5); + if (r3.type === "fail") + return void 0; + return r3.body; +} +function parseAddExchangeUriWithError(s5) { + const pi = parseProtoInfoWithError(s5, "add-exchange"); + if (pi.type === "fail") { + return pi; + } + const parts = pi.body.rest.split("/"); + if (parts.length < 2) { + return opKnownTalerFailure(TalerErrorCode.WALLET_TALER_URI_MALFORMED, { + code: TalerErrorCode.WALLET_TALER_URI_MALFORMED + }); + } + const host = parts[0].toLowerCase(); + const pathSegments = parts.slice(1, parts.length - 1); + const p4 = [host, ...pathSegments].join("/"); + const result = { + type: TalerUriAction.AddExchange, + exchangeBaseUrl: canonicalizeBaseUrl(`${pi.body.innerProto}://${p4}/`) + }; + return opFixedSuccess(result); +} +function parseAddExchangeUri(s5) { + const r3 = parseAddExchangeUriWithError(s5); + if (r3.type === "fail") + return void 0; + return r3.body; } var TalerUriType; (function(TalerUriType2) { @@ -14249,6 +14657,7 @@ var TalerUriAction; TalerUriAction2["Restore"] = "restore"; TalerUriAction2["DevExperiment"] = "dev-experiment"; TalerUriAction2["WithdrawExchange"] = "withdraw-exchange"; + TalerUriAction2["AddExchange"] = "add-exchange"; })(TalerUriAction || (TalerUriAction = {})); function parseProtoInfo(s5, action) { const pfxPlain = `taler://${action}/`; @@ -14267,6 +14676,30 @@ function parseProtoInfo(s5, action) { return void 0; } } +function parseProtoInfoWithError(s5, action) { + if (!s5.toLowerCase().startsWith("taler://") && !s5.toLowerCase().startsWith("taler+http://")) { + return opKnownTalerFailure(TalerErrorCode.WALLET_TALER_URI_MALFORMED, { + code: TalerErrorCode.WALLET_TALER_URI_MALFORMED + }); + } + const pfxPlain = `taler://${action}/`; + const pfxHttp = `taler+http://${action}/`; + if (s5.toLowerCase().startsWith(pfxPlain)) { + return opFixedSuccess({ + innerProto: "https", + rest: s5.substring(pfxPlain.length) + }); + } else if (s5.toLowerCase().startsWith(pfxHttp)) { + return opFixedSuccess({ + innerProto: "http", + rest: s5.substring(pfxHttp.length) + }); + } else { + return opKnownTalerFailure(TalerErrorCode.WALLET_TALER_URI_MALFORMED, { + code: TalerErrorCode.WALLET_TALER_URI_MALFORMED + }); + } +} var parsers = { [TalerUriAction.Pay]: parsePayUri, [TalerUriAction.PayPull]: parsePayPullUri, @@ -14276,15 +14709,63 @@ var parsers = { [TalerUriAction.Refund]: parseRefundUri, [TalerUriAction.Withdraw]: parseWithdrawUri, [TalerUriAction.DevExperiment]: parseDevExperimentUri, - [TalerUriAction.WithdrawExchange]: parseWithdrawExchangeUri + [TalerUriAction.WithdrawExchange]: parseWithdrawExchangeUri, + [TalerUriAction.AddExchange]: parseAddExchangeUri }; +function parseTalerUri(string2) { + const https = string2.startsWith("taler://"); + const http = string2.startsWith("taler+http://"); + if (!https && !http) + return void 0; + const actionStart = https ? 8 : 13; + const actionEnd = string2.indexOf("/", actionStart + 1); + const action = string2.substring(actionStart, actionEnd); + const found = Object.values(TalerUriAction).find((x6) => x6 === action); + if (!found) + return void 0; + return parsers[found](string2); +} +function stringifyTalerUri(uri) { + switch (uri.type) { + case TalerUriAction.DevExperiment: { + return stringifyDevExperimentUri(uri); + } + case TalerUriAction.Pay: { + return stringifyPayUri(uri); + } + case TalerUriAction.PayPull: { + return stringifyPayPullUri(uri); + } + case TalerUriAction.PayPush: { + return stringifyPayPushUri(uri); + } + case TalerUriAction.PayTemplate: { + return stringifyPayTemplateUri(uri); + } + case TalerUriAction.Restore: { + return stringifyRestoreUri(uri); + } + case TalerUriAction.Refund: { + return stringifyRefundUri(uri); + } + case TalerUriAction.Withdraw: { + return stringifyWithdrawUri(uri); + } + case TalerUriAction.WithdrawExchange: { + return stringifyWithdrawExchange(uri); + } + case TalerUriAction.AddExchange: { + return stringifyAddExchange(uri); + } + } +} function parsePayUri(s5) { const pi = parseProtoInfo(s5, "pay"); if (!pi) { return void 0; } const c4 = pi?.rest.split("?"); - const q5 = new URLSearchParams(c4[1] ?? ""); + const q5 = new URLSearchParams2(c4[1] ?? ""); const claimToken = q5.get("c") ?? void 0; const noncePriv = q5.get("n") ?? void 0; const parts = c4[0].split("/"); @@ -14316,7 +14797,7 @@ function parsePayTemplateUri(uriString) { if (parts.length < 2) { return void 0; } - const q5 = new URLSearchParams(c4[1] ?? ""); + const q5 = new URLSearchParams2(c4[1] ?? ""); const params = {}; q5.forEach((v3, k5) => { params[k5] = v3; @@ -14390,7 +14871,7 @@ function parseWithdrawExchangeUri(s5) { const pathSegments = parts.slice(1, parts.length - 1); const hostAndSegments = [host, ...pathSegments].join("/"); const exchangeBaseUrl = canonicalizeBaseUrl(`${pi.innerProto}://${hostAndSegments}/`); - const q5 = new URLSearchParams(c4[1] ?? ""); + const q5 = new URLSearchParams2(c4[1] ?? ""); const amount = q5.get("a") ?? void 0; return { type: TalerUriAction.WithdrawExchange, @@ -14457,6 +14938,38 @@ function parseRestoreUri(uri) { providers }; } +function stringifyPayUri({ merchantBaseUrl, orderId, sessionId, claimToken, noncePriv }) { + const { proto, path, query } = getUrlInfo(merchantBaseUrl, { + c: claimToken, + n: noncePriv + }); + return `${proto}://pay/${path}${orderId}/${sessionId}${query}`; +} +function stringifyPayPullUri({ contractPriv, exchangeBaseUrl }) { + const { proto, path } = getUrlInfo(exchangeBaseUrl); + return `${proto}://pay-pull/${path}${contractPriv}`; +} +function stringifyPayPushUri({ contractPriv, exchangeBaseUrl }) { + const { proto, path } = getUrlInfo(exchangeBaseUrl); + return `${proto}://pay-push/${path}${contractPriv}`; +} +function stringifyRestoreUri({ providers, walletRootPriv }) { + const list = providers.map((url) => `${encodeURIComponent(new URL2(url).href)}`).join(","); + return `taler://restore/${walletRootPriv}/${list}`; +} +function stringifyWithdrawExchange({ exchangeBaseUrl, exchangePub, amount }) { + const { proto, path, query } = getUrlInfo(exchangeBaseUrl, { + a: amount + }); + return `${proto}://withdraw-exchange/${path}${exchangePub ?? ""}${query}`; +} +function stringifyAddExchange({ exchangeBaseUrl }) { + const { proto, path } = getUrlInfo(exchangeBaseUrl); + return `${proto}://add-exchange/${path}`; +} +function stringifyDevExperimentUri({ devExperimentId }) { + return `taler://dev-experiment/${devExperimentId}`; +} function stringifyPayTemplateUri({ merchantBaseUrl, templateId, templateParams }) { const { proto, path, query } = getUrlInfo(merchantBaseUrl, templateParams); return `${proto}://pay-template/${path}${templateId}${query}`; @@ -14465,6 +14978,10 @@ function stringifyRefundUri({ merchantBaseUrl, orderId }) { const { proto, path } = getUrlInfo(merchantBaseUrl); return `${proto}://refund/${path}${orderId}/`; } +function stringifyWithdrawUri({ bankIntegrationApiBaseUrl, withdrawalOperationId }) { + const { proto, path } = getUrlInfo(bankIntegrationApiBaseUrl); + return `${proto}://withdraw/${path}${withdrawalOperationId}`; +} function getUrlInfo(baseUrl, params = {}) { const url = new URL2(baseUrl); let proto; @@ -14485,7 +15002,7 @@ function getUrlInfo(baseUrl, params = {}) { if (!path.endsWith("/")) { path = path + "/"; } - const qp = new URLSearchParams(); + const qp = new URLSearchParams2(); let withParams = false; Object.entries(params).forEach(([name, value]) => { if (value !== void 0) { @@ -14498,6 +15015,78 @@ function getUrlInfo(baseUrl, params = {}) { } // ../taler-util/lib/http-client/types.js +var codecForAccessToken = codecForString; +var codecForTokenSuccessResponse = () => buildCodecForObject().property("access_token", codecForAccessToken()).property("expiration", codecForTimestamp).build("TalerAuthentication.TokenSuccessResponse"); +var codecForTokenSuccessResponseMerchant = () => buildCodecForObject().property("token", codecForAccessToken()).property("expiration", codecForTimestamp).build("TalerAuthentication.TokenSuccessResponseMerchant"); +var codecForCurrencySpecificiation = () => buildCodecForObject().property("name", codecForString()).property("num_fractional_input_digits", codecForNumber()).property("num_fractional_normal_digits", codecForNumber()).property("num_fractional_trailing_zero_digits", codecForNumber()).property("alt_unit_names", codecForMap(codecForString())).build("CurrencySpecification"); +var codecForExchangeConfigInfo = () => buildCodecForObject().property("base_url", codecForString()).property("currency", codecForString()).property("master_pub", codecForString()).build("TalerMerchantApi.ExchangeConfigInfo"); +var codecForMerchantConfig = () => buildCodecForObject().property("name", codecForConstString("taler-merchant")).property("currency", codecForString()).property("version", codecForString()).property("currencies", codecForMap(codecForCurrencySpecificiation())).property("exchanges", codecForList(codecForExchangeConfigInfo())).build("TalerMerchantApi.VersionResponse"); +var codecForClaimResponse = () => buildCodecForObject().property("contract_terms", codecForContractTerms()).property("sig", codecForString()).build("TalerMerchantApi.ClaimResponse"); +var codecForPaymentResponse = () => buildCodecForObject().property("pos_confirmation", codecOptional(codecForString())).property("sig", codecForString()).build("TalerMerchantApi.PaymentResponse"); +var codecForStatusPaid = () => buildCodecForObject().property("refund_amount", codecForAmountString()).property("refund_pending", codecForBoolean()).property("refund_taken", codecForAmountString()).property("refunded", codecForBoolean()).property("type", codecForConstString("paid")).build("TalerMerchantApi.StatusPaid"); +var codecForStatusGoto = () => buildCodecForObject().property("public_reorder_url", codecForURL()).property("type", codecForConstString("goto")).build("TalerMerchantApi.StatusGotoResponse"); +var codecForStatusStatusUnpaid = () => buildCodecForObject().property("type", codecForConstString("unpaid")).property("already_paid_order_id", codecOptional(codecForString())).property("fulfillment_url", codecOptional(codecForString())).property("taler_pay_uri", codecForTalerUriString()).build("TalerMerchantApi.PaymentResponse"); +var codecForPaidRefundStatusResponse = () => buildCodecForObject().property("pos_confirmation", codecOptional(codecForString())).property("refunded", codecForBoolean()).build("TalerMerchantApi.PaidRefundStatusResponse"); +var codecForMerchantAbortPayRefundSuccessStatus = () => buildCodecForObject().property("exchange_pub", codecForString()).property("exchange_sig", codecForString()).property("exchange_status", codecForConstNumber(200)).property("type", codecForConstString("success")).build("TalerMerchantApi.MerchantAbortPayRefundSuccessStatus"); +var codecForMerchantAbortPayRefundFailureStatus = () => buildCodecForObject().property("exchange_code", codecForNumber()).property("exchange_reply", codecForAny()).property("exchange_status", codecForNumber()).property("type", codecForConstString("failure")).build("TalerMerchantApi.MerchantAbortPayRefundFailureStatus"); +var codecForMerchantAbortPayRefundStatus = () => buildCodecForUnion().discriminateOn("type").alternative("success", codecForMerchantAbortPayRefundSuccessStatus()).alternative("failure", codecForMerchantAbortPayRefundFailureStatus()).build("TalerMerchantApi.MerchantAbortPayRefundStatus"); +var codecForAbortResponse = () => buildCodecForObject().property("refunds", codecForList(codecForMerchantAbortPayRefundStatus())).build("TalerMerchantApi.AbortResponse"); +var codecForWalletRefundResponse = () => buildCodecForObject().property("merchant_pub", codecForString()).property("refund_amount", codecForAmountString()).property("refunds", codecForList(codecForMerchantCoinRefundStatus())).build("TalerMerchantApi.AbortResponse"); +var codecForMerchantCoinRefundSuccessStatus = () => buildCodecForObject().property("type", codecForConstString("success")).property("coin_pub", codecForString()).property("exchange_status", codecForConstNumber(200)).property("exchange_sig", codecForString()).property("rtransaction_id", codecForNumber()).property("refund_amount", codecForAmountString()).property("exchange_pub", codecForString()).property("execution_time", codecForTimestamp).build("TalerMerchantApi.MerchantCoinRefundSuccessStatus"); +var codecForMerchantCoinRefundFailureStatus = () => buildCodecForObject().property("type", codecForConstString("failure")).property("coin_pub", codecForString()).property("exchange_status", codecForNumber()).property("rtransaction_id", codecForNumber()).property("refund_amount", codecForAmountString()).property("exchange_code", codecOptional(codecForNumber())).property("exchange_reply", codecOptional(codecForAny())).property("execution_time", codecForTimestamp).build("TalerMerchantApi.MerchantCoinRefundFailureStatus"); +var codecForMerchantCoinRefundStatus = () => buildCodecForUnion().discriminateOn("type").alternative("success", codecForMerchantCoinRefundSuccessStatus()).alternative("failure", codecForMerchantCoinRefundFailureStatus()).build("TalerMerchantApi.MerchantCoinRefundStatus"); +var codecForQueryInstancesResponse = () => buildCodecForObject().property("name", codecForString()).property("user_type", codecForString()).property("email", codecOptional(codecForString())).property("website", codecOptional(codecForString())).property("logo", codecOptional(codecForString())).property("merchant_pub", codecForString()).property("address", codecForLocation()).property("jurisdiction", codecForLocation()).property("use_stefan", codecForBoolean()).property("default_wire_transfer_delay", codecForDuration).property("default_pay_delay", codecForDuration).property("auth", buildCodecForObject().property("method", codecForEither(codecForConstString("token"), codecForConstString("external"))).build("TalerMerchantApi.QueryInstancesResponse.auth")).build("TalerMerchantApi.QueryInstancesResponse"); +var codecForAccountKycRedirects = () => buildCodecForObject().property("pending_kycs", codecForList(codecForMerchantAccountKycRedirect())).property("timeout_kycs", codecForList(codecForExchangeKycTimeout())).build("TalerMerchantApi.AccountKycRedirects"); +var codecForMerchantAccountKycRedirect = () => buildCodecForObject().property("kyc_url", codecForURL()).property("aml_status", codecForNumber()).property("exchange_url", codecForURL()).property("payto_uri", codecForPaytoString()).build("TalerMerchantApi.MerchantAccountKycRedirect"); +var codecForExchangeKycTimeout = () => buildCodecForObject().property("exchange_url", codecForURL()).property("exchange_code", codecForNumber()).property("exchange_http_status", codecForNumber()).build("TalerMerchantApi.ExchangeKycTimeout"); +var codecForAccountAddResponse = () => buildCodecForObject().property("h_wire", codecForString()).property("salt", codecForString()).build("TalerMerchantApi.AccountAddResponse"); +var codecForAccountsSummaryResponse = () => buildCodecForObject().property("accounts", codecForList(codecForBankAccountSummaryEntry())).build("TalerMerchantApi.AccountsSummaryResponse"); +var codecForBankAccountSummaryEntry = () => buildCodecForObject().property("payto_uri", codecForPaytoString()).property("h_wire", codecForString()).build("TalerMerchantApi.BankAccountSummaryEntry"); +var codecForBankAccountEntry = () => buildCodecForObject().property("payto_uri", codecForPaytoString()).property("h_wire", codecForString()).property("salt", codecForString()).property("credit_facade_url", codecOptional(codecForURL())).property("active", codecOptional(codecForBoolean())).build("TalerMerchantApi.BankAccountEntry"); +var codecForInventorySummaryResponse = () => buildCodecForObject().property("products", codecForList(codecForInventoryEntry())).build("TalerMerchantApi.InventorySummaryResponse"); +var codecForInventoryEntry = () => buildCodecForObject().property("product_id", codecForString()).property("product_serial", codecForNumber()).build("TalerMerchantApi.InventoryEntry"); +var codecForProductDetail = () => buildCodecForObject().property("description", codecForString()).property("description_i18n", codecForInternationalizedString()).property("unit", codecForString()).property("price", codecForAmountString()).property("image", codecForString()).property("taxes", codecForList(codecForTax())).property("address", codecForLocation()).property("next_restock", codecForTimestamp).property("total_stock", codecForNumber()).property("total_sold", codecForNumber()).property("total_lost", codecForNumber()).property("minimum_age", codecOptional(codecForNumber())).build("TalerMerchantApi.ProductDetail"); +var codecForTax = () => buildCodecForObject().property("name", codecForString()).property("tax", codecForAmountString()).build("TalerMerchantApi.Tax"); +var codecForPostOrderResponse = () => buildCodecForObject().property("order_id", codecForString()).property("token", codecOptional(codecForString())).build("TalerMerchantApi.PostOrderResponse"); +var codecForOutOfStockResponse = () => buildCodecForObject().property("product_id", codecForString()).property("available_quantity", codecForNumber()).property("requested_quantity", codecForNumber()).property("restock_expected", codecForTimestamp).build("TalerMerchantApi.OutOfStockResponse"); +var codecForOrderHistory = () => buildCodecForObject().property("orders", codecForList(codecForOrderHistoryEntry())).build("TalerMerchantApi.OrderHistory"); +var codecForOrderHistoryEntry = () => buildCodecForObject().property("order_id", codecForString()).property("row_id", codecForNumber()).property("timestamp", codecForTimestamp).property("amount", codecForAmountString()).property("summary", codecForString()).property("refundable", codecForBoolean()).property("paid", codecForBoolean()).build("TalerMerchantApi.OrderHistoryEntry"); +var codecForMerchant = () => buildCodecForObject().property("name", codecForString()).property("email", codecOptional(codecForString())).property("logo", codecOptional(codecForString())).property("website", codecOptional(codecForString())).property("address", codecOptional(codecForLocation())).property("jurisdiction", codecOptional(codecForLocation())).build("TalerMerchantApi.MerchantInfo"); +var codecForExchange = () => buildCodecForObject().property("master_pub", codecForString()).property("priority", codecForNumber()).property("url", codecForString()).build("TalerMerchantApi.Exchange"); +var codecForContractTerms = () => buildCodecForObject().property("order_id", codecForString()).property("fulfillment_url", codecOptional(codecForString())).property("fulfillment_message", codecOptional(codecForString())).property("fulfillment_message_i18n", codecOptional(codecForInternationalizedString())).property("merchant_base_url", codecForString()).property("h_wire", codecForString()).property("auto_refund", codecOptional(codecForDuration)).property("wire_method", codecForString()).property("summary", codecForString()).property("summary_i18n", codecOptional(codecForInternationalizedString())).property("nonce", codecForString()).property("amount", codecForAmountString()).property("pay_deadline", codecForTimestamp).property("refund_deadline", codecForTimestamp).property("wire_transfer_deadline", codecForTimestamp).property("timestamp", codecForTimestamp).property("delivery_location", codecOptional(codecForLocation())).property("delivery_date", codecOptional(codecForTimestamp)).property("max_fee", codecForAmountString()).property("merchant", codecForMerchant()).property("merchant_pub", codecForString()).property("exchanges", codecForList(codecForExchange())).property("products", codecForList(codecForProduct())).property("extra", codecForAny()).build("TalerMerchantApi.ContractTerms"); +var codecForProduct = () => buildCodecForObject().property("product_id", codecOptional(codecForString())).property("description", codecForString()).property("description_i18n", codecOptional(codecForInternationalizedString())).property("quantity", codecOptional(codecForNumber())).property("unit", codecOptional(codecForString())).property("price", codecOptional(codecForAmountString())).property("image", codecOptional(codecForString())).property("taxes", codecOptional(codecForList(codecForTax()))).property("delivery_date", codecOptional(codecForTimestamp)).build("TalerMerchantApi.Product"); +var codecForCheckPaymentPaidResponse = () => buildCodecForObject().property("order_status", codecForConstString("paid")).property("refunded", codecForBoolean()).property("refund_pending", codecForBoolean()).property("wired", codecForBoolean()).property("deposit_total", codecForAmountString()).property("exchange_code", codecForNumber()).property("exchange_http_status", codecForNumber()).property("refund_amount", codecForAmountString()).property("contract_terms", codecForContractTerms()).property("wire_reports", codecForList(codecForTransactionWireReport())).property("wire_details", codecForList(codecForTransactionWireTransfer())).property("refund_details", codecForList(codecForRefundDetails())).property("order_status_url", codecForURL()).build("TalerMerchantApi.CheckPaymentPaidResponse"); +var codecForCheckPaymentUnpaidResponse = () => buildCodecForObject().property("order_status", codecForConstString("unpaid")).property("taler_pay_uri", codecForTalerUriString()).property("creation_time", codecForTimestamp).property("summary", codecForString()).property("total_amount", codecForAmountString()).property("already_paid_order_id", codecOptional(codecForString())).property("already_paid_fulfillment_url", codecOptional(codecForString())).property("order_status_url", codecForString()).build("TalerMerchantApi.CheckPaymentPaidResponse"); +var codecForCheckPaymentClaimedResponse = () => buildCodecForObject().property("order_status", codecForConstString("claimed")).property("contract_terms", codecForContractTerms()).build("TalerMerchantApi.CheckPaymentClaimedResponse"); +var codecForMerchantOrderPrivateStatusResponse = () => buildCodecForUnion().discriminateOn("order_status").alternative("paid", codecForCheckPaymentPaidResponse()).alternative("unpaid", codecForCheckPaymentUnpaidResponse()).alternative("claimed", codecForCheckPaymentClaimedResponse()).build("TalerMerchantApi.MerchantOrderStatusResponse"); +var codecForRefundDetails = () => buildCodecForObject().property("reason", codecForString()).property("pending", codecForBoolean()).property("timestamp", codecForTimestamp).property("amount", codecForAmountString()).build("TalerMerchantApi.RefundDetails"); +var codecForTransactionWireTransfer = () => buildCodecForObject().property("exchange_url", codecForURL()).property("wtid", codecForString()).property("execution_time", codecForTimestamp).property("amount", codecForAmountString()).property("confirmed", codecForBoolean()).build("TalerMerchantApi.TransactionWireTransfer"); +var codecForTransactionWireReport = () => buildCodecForObject().property("code", codecForNumber()).property("hint", codecForString()).property("exchange_code", codecForNumber()).property("exchange_http_status", codecForNumber()).property("coin_pub", codecForString()).build("TalerMerchantApi.TransactionWireReport"); +var codecForMerchantRefundResponse = () => buildCodecForObject().property("taler_refund_uri", codecForTalerUriString()).property("h_contract", codecForString()).build("TalerMerchantApi.MerchantRefundResponse"); +var codecForTansferList = () => buildCodecForObject().property("transfers", codecForList(codecForTransferDetails())).build("TalerMerchantApi.TransferList"); +var codecForTransferDetails = () => buildCodecForObject().property("credit_amount", codecForAmountString()).property("wtid", codecForString()).property("payto_uri", codecForPaytoString()).property("exchange_url", codecForURL()).property("transfer_serial_id", codecForNumber()).property("execution_time", codecOptional(codecForTimestamp)).property("verified", codecOptional(codecForBoolean())).property("confirmed", codecOptional(codecForBoolean())).build("TalerMerchantApi.TransferDetails"); +var codecForOtpDeviceSummaryResponse = () => buildCodecForObject().property("otp_devices", codecForList(codecForOtpDeviceEntry())).build("TalerMerchantApi.OtpDeviceSummaryResponse"); +var codecForOtpDeviceEntry = () => buildCodecForObject().property("otp_device_id", codecForString()).property("device_description", codecForString()).build("TalerMerchantApi.OtpDeviceEntry"); +var codecForOtpDeviceDetails = () => buildCodecForObject().property("device_description", codecForString()).property("otp_algorithm", codecForNumber()).property("otp_ctr", codecOptional(codecForNumber())).property("otp_timestamp", codecForNumber()).property("otp_code", codecOptional(codecForString())).build("TalerMerchantApi.OtpDeviceDetails"); +var codecForTemplateSummaryResponse = () => buildCodecForObject().property("templates", codecForList(codecForTemplateEntry())).build("TalerMerchantApi.TemplateSummaryResponse"); +var codecForTemplateEntry = () => buildCodecForObject().property("template_id", codecForString()).property("template_description", codecForString()).build("TalerMerchantApi.TemplateEntry"); +var codecForTemplateDetails = () => buildCodecForObject().property("template_description", codecForString()).property("otp_id", codecOptional(codecForString())).property("template_contract", codecForTemplateContractDetails()).property("required_currency", codecOptional(codecForString())).property("editable_defaults", codecOptional(codecForTemplateContractDetailsDefaults())).build("TalerMerchantApi.TemplateDetails"); +var codecForTemplateContractDetails = () => buildCodecForObject().property("summary", codecOptional(codecForString())).property("currency", codecOptional(codecForString())).property("amount", codecOptional(codecForAmountString())).property("minimum_age", codecForNumber()).property("pay_duration", codecForDuration).build("TalerMerchantApi.TemplateContractDetails"); +var codecForTemplateContractDetailsDefaults = () => buildCodecForObject().property("summary", codecOptional(codecForString())).property("currency", codecOptional(codecForString())).property("amount", codecOptional(codecForAmountString())).property("minimum_age", codecOptional(codecForNumber())).property("pay_duration", codecOptional(codecForDuration)).build("TalerMerchantApi.TemplateContractDetailsDefaults"); +var codecForWalletTemplateDetails = () => buildCodecForObject().property("template_contract", codecForTemplateContractDetails()).property("required_currency", codecOptional(codecForString())).property("editable_defaults", codecOptional(codecForTemplateContractDetailsDefaults())).build("TalerMerchantApi.WalletTemplateDetails"); +var codecForWebhookSummaryResponse = () => buildCodecForObject().property("webhooks", codecForList(codecForWebhookEntry())).build("TalerMerchantApi.WebhookSummaryResponse"); +var codecForWebhookEntry = () => buildCodecForObject().property("webhook_id", codecForString()).property("event_type", codecForString()).build("TalerMerchantApi.WebhookEntry"); +var codecForWebhookDetails = () => buildCodecForObject().property("event_type", codecForString()).property("url", codecForString()).property("http_method", codecForString()).property("header_template", codecOptional(codecForString())).property("body_template", codecOptional(codecForString())).build("TalerMerchantApi.WebhookDetails"); +var codecForTokenFamilyKind = () => codecForEither(codecForConstString("discount"), codecForConstString("subscription")); +var codecForTokenFamilyDetails = () => buildCodecForObject().property("slug", codecForString()).property("name", codecForString()).property("description", codecForString()).property("description_i18n", codecForInternationalizedString()).property("valid_after", codecForTimestamp).property("valid_before", codecForTimestamp).property("duration", codecForDuration).property("kind", codecForTokenFamilyKind()).property("issued", codecForNumber()).property("redeemed", codecForNumber()).build("TalerMerchantApi.TokenFamilyDetails"); +var codecForTokenFamiliesList = () => buildCodecForObject().property("token_families", codecForList(codecForTokenFamilySummary())).build("TalerMerchantApi.TokenFamiliesList"); +var codecForTokenFamilySummary = () => buildCodecForObject().property("slug", codecForString()).property("name", codecForString()).property("valid_after", codecForTimestamp).property("valid_before", codecForTimestamp).property("kind", codecForTokenFamilyKind()).build("TalerMerchantApi.TokenFamilySummary"); +var codecForInstancesResponse = () => buildCodecForObject().property("instances", codecForList(codecForInstance())).build("TalerMerchantApi.InstancesResponse"); +var codecForInstance = () => buildCodecForObject().property("name", codecForString()).property("user_type", codecForString()).property("website", codecOptional(codecForString())).property("logo", codecOptional(codecForString())).property("id", codecForString()).property("merchant_pub", codecForString()).property("payment_targets", codecForList(codecForString())).property("deleted", codecForBoolean()).build("TalerMerchantApi.Instance"); +var codecForRevenueConfig = () => buildCodecForObject().property("name", codecForConstString("taler-revenue")).property("version", codecForString()).property("currency", codecForString()).property("implementation", codecOptional(codecForString())).build("TalerRevenueApi.RevenueConfig"); +var codecForRevenueIncomingHistory = () => buildCodecForObject().property("credit_account", codecForPaytoString()).property("incoming_transactions", codecForList(codecForRevenueIncomingBankTransaction())).build("TalerRevenueApi.MerchantIncomingHistory"); +var codecForRevenueIncomingBankTransaction = () => buildCodecForObject().property("amount", codecForAmountString()).property("date", codecForTimestamp).property("debit_account", codecForPaytoString()).property("row_id", codecForNumber()).property("subject", codecForString()).build("TalerRevenueApi.RevenueIncomingBankTransaction"); +var codecForURL = codecForString; var TalerCorebankApi; (function(TalerCorebankApi2) { let MonitorTimeframeParam; @@ -14523,6 +15112,14 @@ var TalerExchangeApi; AmlState2[AmlState2["frozen"] = 2] = "frozen"; })(AmlState = TalerExchangeApi2.AmlState || (TalerExchangeApi2.AmlState = {})); })(TalerExchangeApi || (TalerExchangeApi = {})); +var TalerMerchantApi; +(function(TalerMerchantApi37) { + let TokenFamilyKind; + (function(TokenFamilyKind2) { + TokenFamilyKind2["Discount"] = "discount"; + TokenFamilyKind2["Subscription"] = "subscription"; + })(TokenFamilyKind = TalerMerchantApi37.TokenFamilyKind || (TalerMerchantApi37.TokenFamilyKind = {})); +})(TalerMerchantApi || (TalerMerchantApi = {})); // ../taler-util/lib/http-status-codes.js var HttpStatusCode; @@ -14590,9 +15187,17 @@ var HttpStatusCode; HttpStatusCode2[HttpStatusCode2["NetworkAuthenticationRequired"] = 511] = "NetworkAuthenticationRequired"; })(HttpStatusCode || (HttpStatusCode = {})); -// ../taler-util/lib/http-common.js -var textEncoder = new TextEncoder(); -var logger3 = new Logger("http.ts"); +// ../taler-util/lib/http-impl.missing.js +var HttpLibImpl = class { + fetch(url, opt) { + throw new Error("Method not implemented."); + } +}; + +// ../taler-util/lib/http.js +function createPlatformHttpLib(args) { + return new HttpLibImpl(args); +} // ../taler-util/lib/libtool-version.js var LibtoolVersion; @@ -14635,6 +15240,97 @@ var logger4 = new Logger("MerchantApiClient.ts"); // ../taler-util/lib/RequestThrottler.js var logger5 = new Logger("RequestThrottler.ts"); +var MAX_PER_SECOND = 100; +var MAX_PER_MINUTE = 500; +var MAX_PER_HOUR = 2e3; +var OriginState = class { + constructor() { + this.tokensSecond = MAX_PER_SECOND; + this.tokensMinute = MAX_PER_MINUTE; + this.tokensHour = MAX_PER_HOUR; + this.lastUpdate = AbsoluteTime.now(); + } + refill() { + const now2 = AbsoluteTime.now(); + if (AbsoluteTime.cmp(now2, this.lastUpdate) < 0) { + this.lastUpdate = now2; + return; + } + const d5 = AbsoluteTime.difference(now2, this.lastUpdate); + if (d5.d_ms === "forever") { + throw Error("assertion failed"); + } + this.tokensSecond = Math.min(MAX_PER_SECOND, this.tokensSecond + d5.d_ms / 1e3); + this.tokensMinute = Math.min(MAX_PER_MINUTE, this.tokensMinute + d5.d_ms / 1e3 / 60); + this.tokensHour = Math.min(MAX_PER_HOUR, this.tokensHour + d5.d_ms / 1e3 / 60 / 60); + this.lastUpdate = now2; + } + /** + * Return true if the request for this origin should be throttled. + * Otherwise, take a token out of the respective buckets. + */ + applyThrottle() { + this.refill(); + if (this.tokensSecond < 1) { + logger5.warn("request throttled (per second limit exceeded)"); + return true; + } + if (this.tokensMinute < 1) { + logger5.warn("request throttled (per minute limit exceeded)"); + return true; + } + if (this.tokensHour < 1) { + logger5.warn("request throttled (per hour limit exceeded)"); + return true; + } + this.tokensSecond--; + this.tokensMinute--; + this.tokensHour--; + return false; + } +}; +var RequestThrottler = class { + constructor() { + this.perOriginInfo = {}; + } + /** + * Get the throttling state for an origin, or + * initialize if no state is associated with the + * origin yet. + */ + getState(origin) { + const s5 = this.perOriginInfo[origin]; + if (s5) { + return s5; + } + const ns = this.perOriginInfo[origin] = new OriginState(); + return ns; + } + /** + * Apply throttling to a request. + * + * @returns whether the request should be throttled. + */ + applyThrottle(requestUrl) { + const origin = new URL(requestUrl).origin; + return this.getState(origin).applyThrottle(); + } + /** + * Get the throttle statistics for a particular URL. + */ + getThrottleStats(requestUrl) { + const origin = new URL(requestUrl).origin; + const state = this.getState(origin); + return { + tokensHour: state.tokensHour, + tokensMinute: state.tokensMinute, + tokensSecond: state.tokensSecond, + maxTokensHour: MAX_PER_HOUR, + maxTokensMinute: MAX_PER_MINUTE, + maxTokensSecond: MAX_PER_SECOND + }; + } +}; // ../taler-util/lib/ReserveTransaction.js var ReserveTransactionType; @@ -14656,6 +15352,39 @@ var CreditDebitIndicator; CreditDebitIndicator2["Debit"] = "debit"; })(CreditDebitIndicator || (CreditDebitIndicator = {})); +// ../taler-util/lib/base64.js +function base64FromArrayBuffer(arrayBuffer) { + var base64 = ""; + var encodings2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + var bytes = new Uint8Array(arrayBuffer); + var byteLength = bytes.byteLength; + var byteRemainder = byteLength % 3; + var mainLength = byteLength - byteRemainder; + var a5, b4, c4, d5; + var chunk; + for (var i4 = 0; i4 < mainLength; i4 = i4 + 3) { + chunk = bytes[i4] << 16 | bytes[i4 + 1] << 8 | bytes[i4 + 2]; + a5 = (chunk & 16515072) >> 18; + b4 = (chunk & 258048) >> 12; + c4 = (chunk & 4032) >> 6; + d5 = chunk & 63; + base64 += encodings2[a5] + encodings2[b4] + encodings2[c4] + encodings2[d5]; + } + if (byteRemainder == 1) { + chunk = bytes[mainLength]; + a5 = (chunk & 252) >> 2; + b4 = (chunk & 3) << 4; + base64 += encodings2[a5] + encodings2[b4] + "=="; + } else if (byteRemainder == 2) { + chunk = bytes[mainLength] << 8 | bytes[mainLength + 1]; + a5 = (chunk & 64512) >> 10; + b4 = (chunk & 1008) >> 4; + c4 = (chunk & 15) << 2; + base64 += encodings2[a5] + encodings2[b4] + encodings2[c4] + "="; + } + return base64; +} + // ../taler-util/lib/contract-terms.js var logger8 = new Logger("contractTerms.ts"); var ContractTermsUtil; @@ -14824,6 +15553,72 @@ var ContractTermsUtil; })(ContractTermsUtil || (ContractTermsUtil = {})); // ../taler-util/lib/errors.js +function makeErrorDetail(code, detail, hint) { + if (!hint && !detail.hint) { + hint = getDefaultHint(code); + } + const when = AbsoluteTime.now(); + return { code, when, hint, ...detail }; +} +function getDefaultHint(code) { + const errName = TalerErrorCode[code]; + if (errName) { + return `Error (${errName})`; + } else { + return `Error (<unknown>)`; + } +} +var TalerError = class _TalerError extends Error { + constructor(d5, cause) { + super(d5.hint ?? `Error (code ${d5.code})`); + this.errorDetail = d5; + this.cause = cause; + Object.setPrototypeOf(this, _TalerError.prototype); + } + static fromDetail(code, detail, hint, cause) { + if (!hint) { + hint = getDefaultHint(code); + } + const when = AbsoluteTime.now(); + return new _TalerError({ code, when, hint, ...detail }, cause); + } + static fromUncheckedDetail(d5, c4) { + return new _TalerError({ ...d5 }, c4); + } + static fromException(e4) { + const errDetail = getErrorDetailFromException(e4); + return new _TalerError(errDetail, e4); + } + hasErrorCode(code) { + return this.errorDetail.code === code; + } + toString() { + return `TalerError: ${JSON.stringify(this.errorDetail)}`; + } +}; +function getErrorDetailFromException(e4) { + if (e4 instanceof TalerError) { + return e4.errorDetail; + } + if (e4 instanceof CancellationToken.CancellationError) { + const err2 = makeErrorDetail(TalerErrorCode.WALLET_CORE_REQUEST_CANCELLED, {}); + return err2; + } + if (e4 instanceof Error) { + const err2 = makeErrorDetail(TalerErrorCode.WALLET_UNEXPECTED_EXCEPTION, { + stack: e4.stack + }, `unexpected exception (message: ${e4.message})`); + return err2; + } + let excString; + try { + excString = e4.toString(); + } catch (e5) { + excString = "can't stringify exception"; + } + const err = makeErrorDetail(TalerErrorCode.WALLET_UNEXPECTED_EXCEPTION, {}, `unexpected exception (not an exception, ${excString})`); + return err; +} function assertUnreachable(x6) { throw new Error("Didn't expect to get here"); } @@ -14927,12 +15722,19 @@ var TransactionType; TransactionType2["PeerPullDebit"] = "peer-pull-debit"; TransactionType2["PeerPullCredit"] = "peer-pull-credit"; TransactionType2["Recoup"] = "recoup"; + TransactionType2["DenomLoss"] = "denom-loss"; })(TransactionType || (TransactionType = {})); var WithdrawalType; (function(WithdrawalType2) { WithdrawalType2["TalerBankIntegrationApi"] = "taler-bank-integration-api"; WithdrawalType2["ManualTransfer"] = "manual-transfer"; })(WithdrawalType || (WithdrawalType = {})); +var DenomLossEventType; +(function(DenomLossEventType2) { + DenomLossEventType2["DenomExpired"] = "denom-expired"; + DenomLossEventType2["DenomVanished"] = "denom-vanished"; + DenomLossEventType2["DenomUnoffered"] = "denom-unoffered"; +})(DenomLossEventType || (DenomLossEventType = {})); var PaymentStatus; (function(PaymentStatus2) { PaymentStatus2["Aborted"] = "aborted"; @@ -14973,6 +15775,7 @@ var ScopeType; var CoinStatus; (function(CoinStatus2) { CoinStatus2["Fresh"] = "fresh"; + CoinStatus2["DenomLoss"] = "denom-loss"; CoinStatus2["FreshSuspended"] = "fresh-suspended"; CoinStatus2["Dormant"] = "dormant"; })(CoinStatus || (CoinStatus = {})); @@ -15077,6 +15880,2006 @@ var ProviderPaymentType; ProviderPaymentType2["TermsChanged"] = "terms-changed"; })(ProviderPaymentType || (ProviderPaymentType = {})); +// ../taler-util/lib/http-client/utils.js +function makeBearerTokenAuthHeader(token) { + return `Bearer secret-token:${token}`; +} +function addPaginationParams(url, pagination) { + if (!pagination) + return; + if (pagination.offset) { + url.searchParams.set("start", pagination.offset); + } + const order = !pagination || pagination.order === "asc" ? 1 : -1; + const limit = !pagination || !pagination.limit || pagination.limit === 0 ? 5 : Math.abs(pagination.limit); + url.searchParams.set("delta", String(order * limit)); +} +function addMerchantPaginationParams(url, pagination) { + if (!pagination) + return; + if (pagination.offset) { + url.searchParams.set("offset", pagination.offset); + } + const order = !pagination || pagination.order === "asc" ? 1 : -1; + const limit = !pagination || !pagination.limit || pagination.limit === 0 ? 5 : Math.abs(pagination.limit); + url.searchParams.set("limit", String(order * limit)); +} +function addLongPollingParam(url, param) { + if (!param) + return; + if (param.timeoutMs) { + url.searchParams.set("long_poll_ms", String(param.timeoutMs)); + } +} +var nullEvictor = { + notifySuccess: () => Promise.resolve() +}; + +// ../taler-util/lib/http-client/bank-conversion.js +var TalerBankConversionCacheEviction; +(function(TalerBankConversionCacheEviction2) { + TalerBankConversionCacheEviction2[TalerBankConversionCacheEviction2["UPDATE_RATE"] = 0] = "UPDATE_RATE"; +})(TalerBankConversionCacheEviction || (TalerBankConversionCacheEviction = {})); + +// ../taler-util/lib/http-client/authentication.js +var TalerAuthenticationHttpClient = class { + constructor(baseUrl, httpClient) { + this.baseUrl = baseUrl; + this.PROTOCOL_VERSION = "0:0:0"; + this.httpLib = httpClient ?? createPlatformHttpLib(); + } + isCompatible(version) { + const compare2 = LibtoolVersion.compare(this.PROTOCOL_VERSION, version); + return compare2?.compatible ?? false; + } + /** + * https://docs.taler.net/core/api-corebank.html#post--accounts-$USERNAME-token + * + * @returns + */ + async createAccessTokenBasic(username, password, body) { + const url = new URL(`token`, this.baseUrl); + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + headers: { + Authorization: makeBasicAuthHeader(username, password) + }, + body + }); + switch (resp.status) { + case HttpStatusCode.Ok: + return opSuccessFromHttp(resp, codecForTokenSuccessResponse()); + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * + * @returns + */ + async createAccessTokenBearer(token, body) { + const url = new URL(`token`, this.baseUrl); + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + headers: { + Authorization: makeBearerTokenAuthHeader(token) + }, + body + }); + switch (resp.status) { + case HttpStatusCode.Ok: + return opSuccessFromHttp(resp, codecForTokenSuccessResponseMerchant()); + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + async deleteAccessToken(token) { + const url = new URL(`token`, this.baseUrl); + const resp = await this.httpLib.fetch(url.href, { + method: "DELETE", + headers: { + Authorization: makeBearerTokenAuthHeader(token) + } + }); + switch (resp.status) { + case HttpStatusCode.Ok: + return opEmptySuccess(resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } +}; + +// ../taler-util/lib/http-client/bank-core.js +var TalerCoreBankCacheEviction; +(function(TalerCoreBankCacheEviction2) { + TalerCoreBankCacheEviction2[TalerCoreBankCacheEviction2["DELETE_ACCOUNT"] = 0] = "DELETE_ACCOUNT"; + TalerCoreBankCacheEviction2[TalerCoreBankCacheEviction2["CREATE_ACCOUNT"] = 1] = "CREATE_ACCOUNT"; + TalerCoreBankCacheEviction2[TalerCoreBankCacheEviction2["UPDATE_ACCOUNT"] = 2] = "UPDATE_ACCOUNT"; + TalerCoreBankCacheEviction2[TalerCoreBankCacheEviction2["UPDATE_PASSWORD"] = 3] = "UPDATE_PASSWORD"; + TalerCoreBankCacheEviction2[TalerCoreBankCacheEviction2["CREATE_TRANSACTION"] = 4] = "CREATE_TRANSACTION"; + TalerCoreBankCacheEviction2[TalerCoreBankCacheEviction2["CONFIRM_WITHDRAWAL"] = 5] = "CONFIRM_WITHDRAWAL"; + TalerCoreBankCacheEviction2[TalerCoreBankCacheEviction2["ABORT_WITHDRAWAL"] = 6] = "ABORT_WITHDRAWAL"; + TalerCoreBankCacheEviction2[TalerCoreBankCacheEviction2["CREATE_WITHDRAWAL"] = 7] = "CREATE_WITHDRAWAL"; + TalerCoreBankCacheEviction2[TalerCoreBankCacheEviction2["CREATE_CASHOUT"] = 8] = "CREATE_CASHOUT"; +})(TalerCoreBankCacheEviction || (TalerCoreBankCacheEviction = {})); + +// ../taler-util/lib/http-client/merchant.js +var TalerMerchantInstanceCacheEviction; +(function(TalerMerchantInstanceCacheEviction2) { + TalerMerchantInstanceCacheEviction2[TalerMerchantInstanceCacheEviction2["CREATE_ORDER"] = 0] = "CREATE_ORDER"; + TalerMerchantInstanceCacheEviction2[TalerMerchantInstanceCacheEviction2["UPDATE_ORDER"] = 1] = "UPDATE_ORDER"; + TalerMerchantInstanceCacheEviction2[TalerMerchantInstanceCacheEviction2["DELETE_ORDER"] = 2] = "DELETE_ORDER"; + TalerMerchantInstanceCacheEviction2[TalerMerchantInstanceCacheEviction2["UPDATE_CURRENT_INSTANCE"] = 3] = "UPDATE_CURRENT_INSTANCE"; + TalerMerchantInstanceCacheEviction2[TalerMerchantInstanceCacheEviction2["DELETE_CURRENT_INSTANCE"] = 4] = "DELETE_CURRENT_INSTANCE"; + TalerMerchantInstanceCacheEviction2[TalerMerchantInstanceCacheEviction2["CREATE_BANK_ACCOUNT"] = 5] = "CREATE_BANK_ACCOUNT"; + TalerMerchantInstanceCacheEviction2[TalerMerchantInstanceCacheEviction2["UPDATE_BANK_ACCOUNT"] = 6] = "UPDATE_BANK_ACCOUNT"; + TalerMerchantInstanceCacheEviction2[TalerMerchantInstanceCacheEviction2["DELETE_BANK_ACCOUNT"] = 7] = "DELETE_BANK_ACCOUNT"; + TalerMerchantInstanceCacheEviction2[TalerMerchantInstanceCacheEviction2["CREATE_PRODUCT"] = 8] = "CREATE_PRODUCT"; + TalerMerchantInstanceCacheEviction2[TalerMerchantInstanceCacheEviction2["UPDATE_PRODUCT"] = 9] = "UPDATE_PRODUCT"; + TalerMerchantInstanceCacheEviction2[TalerMerchantInstanceCacheEviction2["DELETE_PRODUCT"] = 10] = "DELETE_PRODUCT"; + TalerMerchantInstanceCacheEviction2[TalerMerchantInstanceCacheEviction2["CREATE_TRANSFER"] = 11] = "CREATE_TRANSFER"; + TalerMerchantInstanceCacheEviction2[TalerMerchantInstanceCacheEviction2["DELETE_TRANSFER"] = 12] = "DELETE_TRANSFER"; + TalerMerchantInstanceCacheEviction2[TalerMerchantInstanceCacheEviction2["CREATE_DEVICE"] = 13] = "CREATE_DEVICE"; + TalerMerchantInstanceCacheEviction2[TalerMerchantInstanceCacheEviction2["UPDATE_DEVICE"] = 14] = "UPDATE_DEVICE"; + TalerMerchantInstanceCacheEviction2[TalerMerchantInstanceCacheEviction2["DELETE_DEVICE"] = 15] = "DELETE_DEVICE"; + TalerMerchantInstanceCacheEviction2[TalerMerchantInstanceCacheEviction2["CREATE_TEMPLATE"] = 16] = "CREATE_TEMPLATE"; + TalerMerchantInstanceCacheEviction2[TalerMerchantInstanceCacheEviction2["UPDATE_TEMPLATE"] = 17] = "UPDATE_TEMPLATE"; + TalerMerchantInstanceCacheEviction2[TalerMerchantInstanceCacheEviction2["DELETE_TEMPLATE"] = 18] = "DELETE_TEMPLATE"; + TalerMerchantInstanceCacheEviction2[TalerMerchantInstanceCacheEviction2["CREATE_WEBHOOK"] = 19] = "CREATE_WEBHOOK"; + TalerMerchantInstanceCacheEviction2[TalerMerchantInstanceCacheEviction2["UPDATE_WEBHOOK"] = 20] = "UPDATE_WEBHOOK"; + TalerMerchantInstanceCacheEviction2[TalerMerchantInstanceCacheEviction2["DELETE_WEBHOOK"] = 21] = "DELETE_WEBHOOK"; + TalerMerchantInstanceCacheEviction2[TalerMerchantInstanceCacheEviction2["CREATE_TOKENFAMILY"] = 22] = "CREATE_TOKENFAMILY"; + TalerMerchantInstanceCacheEviction2[TalerMerchantInstanceCacheEviction2["UPDATE_TOKENFAMILY"] = 23] = "UPDATE_TOKENFAMILY"; + TalerMerchantInstanceCacheEviction2[TalerMerchantInstanceCacheEviction2["DELETE_TOKENFAMILY"] = 24] = "DELETE_TOKENFAMILY"; + TalerMerchantInstanceCacheEviction2[TalerMerchantInstanceCacheEviction2["LAST"] = 25] = "LAST"; +})(TalerMerchantInstanceCacheEviction || (TalerMerchantInstanceCacheEviction = {})); +var TalerMerchantManagementCacheEviction; +(function(TalerMerchantManagementCacheEviction2) { + TalerMerchantManagementCacheEviction2[TalerMerchantManagementCacheEviction2["CREATE_INSTANCE"] = 26] = "CREATE_INSTANCE"; + TalerMerchantManagementCacheEviction2[TalerMerchantManagementCacheEviction2["UPDATE_INSTANCE"] = 27] = "UPDATE_INSTANCE"; + TalerMerchantManagementCacheEviction2[TalerMerchantManagementCacheEviction2["DELETE_INSTANCE"] = 28] = "DELETE_INSTANCE"; +})(TalerMerchantManagementCacheEviction || (TalerMerchantManagementCacheEviction = {})); +var TalerMerchantInstanceHttpClient = class { + constructor(baseUrl, httpClient, cacheEvictor) { + this.baseUrl = baseUrl; + this.PROTOCOL_VERSION = "10:0:6"; + this.httpLib = httpClient ?? createPlatformHttpLib(); + this.cacheEvictor = cacheEvictor ?? nullEvictor; + } + isCompatible(version) { + const compare2 = LibtoolVersion.compare(this.PROTOCOL_VERSION, version); + return compare2?.compatible ?? false; + } + /** + * https://docs.taler.net/core/api-merchant.html#get--config + * + */ + async getConfig() { + const url = new URL(`config`, this.baseUrl); + const resp = await this.httpLib.fetch(url.href, { + method: "GET" + }); + switch (resp.status) { + case HttpStatusCode.Ok: + return opSuccessFromHttp(resp, codecForMerchantConfig()); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + // + // Wallet API + // + /** + * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-orders-$ORDER_ID-claim + */ + async claimOrder(orderId, body) { + const url = new URL(`orders/${orderId}/claim`, this.baseUrl); + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body + }); + switch (resp.status) { + case HttpStatusCode.Ok: { + this.cacheEvictor.notifySuccess(TalerMerchantInstanceCacheEviction.UPDATE_ORDER); + return opSuccessFromHttp(resp, codecForClaimResponse()); + } + case HttpStatusCode.Conflict: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-orders-$ORDER_ID-pay + */ + async makePayment(orderId, body) { + const url = new URL(`orders/${orderId}/pay`, this.baseUrl); + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body + }); + switch (resp.status) { + case HttpStatusCode.Ok: { + this.cacheEvictor.notifySuccess(TalerMerchantInstanceCacheEviction.UPDATE_ORDER); + return opSuccessFromHttp(resp, codecForPaymentResponse()); + } + case HttpStatusCode.BadRequest: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.PaymentRequired: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Forbidden: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.RequestTimeout: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Conflict: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Gone: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.PreconditionFailed: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.BadGateway: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.GatewayTimeout: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-orders-$ORDER_ID + */ + async getPaymentStatus(orderId, params = {}) { + const url = new URL(`orders/${orderId}`, this.baseUrl); + if (params.allowRefundedForRepurchase !== void 0) { + url.searchParams.set("allow_refunded_for_repurchase", params.allowRefundedForRepurchase ? "YES" : "NO"); + } + if (params.awaitRefundObtained !== void 0) { + url.searchParams.set("await_refund_obtained", params.allowRefundedForRepurchase ? "YES" : "NO"); + } + if (params.claimToken !== void 0) { + url.searchParams.set("token", params.claimToken); + } + if (params.contractTermHash !== void 0) { + url.searchParams.set("h_contract", params.contractTermHash); + } + if (params.refund !== void 0) { + url.searchParams.set("refund", params.refund); + } + if (params.sessionId !== void 0) { + url.searchParams.set("session_id", params.sessionId); + } + if (params.timeout !== void 0) { + url.searchParams.set("timeout_ms", String(params.timeout)); + } + const resp = await this.httpLib.fetch(url.href, { + method: "GET" + // body, + }); + switch (resp.status) { + case HttpStatusCode.Ok: + return opSuccessFromHttp(resp, codecForStatusPaid()); + case HttpStatusCode.Accepted: + return opSuccessFromHttp(resp, codecForStatusGoto()); + case HttpStatusCode.PaymentRequired: + return opSuccessFromHttp(resp, codecForStatusStatusUnpaid()); + case HttpStatusCode.Forbidden: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotAcceptable: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#demonstrating-payment + */ + async demostratePayment(orderId, body) { + const url = new URL(`orders/${orderId}/paid`, this.baseUrl); + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body + }); + switch (resp.status) { + case HttpStatusCode.Ok: { + this.cacheEvictor.notifySuccess(TalerMerchantInstanceCacheEviction.UPDATE_ORDER); + return opSuccessFromHttp(resp, codecForPaidRefundStatusResponse()); + } + case HttpStatusCode.BadRequest: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Forbidden: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#aborting-incomplete-payments + */ + async abortIncompletePayment(orderId, body) { + const url = new URL(`orders/${orderId}/abort`, this.baseUrl); + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body + }); + switch (resp.status) { + case HttpStatusCode.Ok: { + this.cacheEvictor.notifySuccess(TalerMerchantInstanceCacheEviction.UPDATE_ORDER); + return opSuccessFromHttp(resp, codecForAbortResponse()); + } + case HttpStatusCode.BadRequest: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Forbidden: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#obtaining-refunds + */ + async obtainRefund(orderId, body) { + const url = new URL(`orders/${orderId}/refund`, this.baseUrl); + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body + }); + switch (resp.status) { + case HttpStatusCode.Ok: { + this.cacheEvictor.notifySuccess(TalerMerchantInstanceCacheEviction.UPDATE_ORDER); + return opSuccessFromHttp(resp, codecForWalletRefundResponse()); + } + case HttpStatusCode.BadRequest: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Forbidden: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + // + // Management + // + /** + * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-auth + */ + async updateCurrentInstanceAuthentication(token, body) { + const url = new URL(`private/auth`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body, + headers + }); + switch (resp.status) { + case HttpStatusCode.Ok: + return opEmptySuccess(resp); + case HttpStatusCode.NoContent: + return opEmptySuccess(resp); + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#patch-[-instances-$INSTANCE]-private + */ + async updateCurrentInstance(token, body) { + const url = new URL(`private`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "PATCH", + body, + headers + }); + switch (resp.status) { + case HttpStatusCode.NoContent: { + this.cacheEvictor.notifySuccess(TalerMerchantInstanceCacheEviction.UPDATE_CURRENT_INSTANCE); + return opEmptySuccess(resp); + } + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private + * + */ + async getCurrentInstanceDetails(token) { + const url = new URL(`private`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + headers + }); + switch (resp.status) { + case HttpStatusCode.Ok: + return opSuccessFromHttp(resp, codecForQueryInstancesResponse()); + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#delete-[-instances-$INSTANCE]-private + */ + async deleteCurrentInstance(token, params = {}) { + const url = new URL(`private`, this.baseUrl); + if (params.purge !== void 0) { + url.searchParams.set("purge", params.purge ? "YES" : "NO"); + } + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "DELETE", + headers + }); + switch (resp.status) { + case HttpStatusCode.NoContent: { + this.cacheEvictor.notifySuccess(TalerMerchantInstanceCacheEviction.DELETE_CURRENT_INSTANCE); + return opEmptySuccess(resp); + } + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Conflict: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#get--instances-$INSTANCE-private-kyc + */ + async getCurrentIntanceKycStatus(token, params = {}) { + const url = new URL(`private/kyc`, this.baseUrl); + if (params.wireHash) { + url.searchParams.set("h_wire", params.wireHash); + } + if (params.exchangeURL) { + url.searchParams.set("exchange_url", params.exchangeURL); + } + if (params.timeout) { + url.searchParams.set("timeout_ms", String(params.timeout)); + } + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + headers + }); + switch (resp.status) { + case HttpStatusCode.Accepted: + return opSuccessFromHttp(resp, codecForAccountKycRedirects()); + case HttpStatusCode.NoContent: + return opEmptySuccess(resp); + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.BadGateway: + return opKnownAlternativeFailure(resp, resp.status, codecForAccountKycRedirects()); + case HttpStatusCode.ServiceUnavailable: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.GatewayTimeout: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + // + // Bank Accounts + // + /** + * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-accounts + */ + async addBankAccount(token, body) { + const url = new URL(`private/accounts`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body, + headers + }); + switch (resp.status) { + case HttpStatusCode.Ok: { + this.cacheEvictor.notifySuccess(TalerMerchantInstanceCacheEviction.CREATE_BANK_ACCOUNT); + return opSuccessFromHttp(resp, codecForAccountAddResponse()); + } + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Conflict: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#patch-[-instances-$INSTANCE]-private-accounts-$H_WIRE + */ + async updateBankAccount(token, wireAccount, body) { + const url = new URL(`private/accounts/${wireAccount}`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "PATCH", + body, + headers + }); + switch (resp.status) { + case HttpStatusCode.NoContent: { + this.cacheEvictor.notifySuccess(TalerMerchantInstanceCacheEviction.UPDATE_BANK_ACCOUNT); + return opEmptySuccess(resp); + } + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private-accounts + */ + async listBankAccounts(token, params) { + const url = new URL(`private/accounts`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + headers + }); + switch (resp.status) { + case HttpStatusCode.Ok: + return opSuccessFromHttp(resp, codecForAccountsSummaryResponse()); + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private-accounts-$H_WIRE + */ + async getBankAccountDetails(token, wireAccount) { + const url = new URL(`private/accounts/${wireAccount}`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + headers + }); + switch (resp.status) { + case HttpStatusCode.Ok: + return opSuccessFromHttp(resp, codecForBankAccountEntry()); + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#delete-[-instances-$INSTANCE]-private-accounts-$H_WIRE + */ + async deleteBankAccount(token, wireAccount) { + const url = new URL(`private/accounts/${wireAccount}`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "DELETE", + headers + }); + switch (resp.status) { + case HttpStatusCode.NoContent: { + this.cacheEvictor.notifySuccess(TalerMerchantInstanceCacheEviction.DELETE_BANK_ACCOUNT); + return opEmptySuccess(resp); + } + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + // + // Inventory Management + // + /** + * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-products + */ + async addProduct(token, body) { + const url = new URL(`private/products`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body, + headers + }); + switch (resp.status) { + case HttpStatusCode.NoContent: { + this.cacheEvictor.notifySuccess(TalerMerchantInstanceCacheEviction.CREATE_PRODUCT); + return opEmptySuccess(resp); + } + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Conflict: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#patch-[-instances-$INSTANCE]-private-products-$PRODUCT_ID + */ + async updateProduct(token, productId, body) { + const url = new URL(`private/products/${productId}`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "PATCH", + body, + headers + }); + switch (resp.status) { + case HttpStatusCode.NoContent: { + this.cacheEvictor.notifySuccess(TalerMerchantInstanceCacheEviction.UPDATE_PRODUCT); + return opEmptySuccess(resp); + } + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Conflict: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private-products + */ + async listProducts(token, params) { + const url = new URL(`private/products`, this.baseUrl); + addMerchantPaginationParams(url, params); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + headers + }); + switch (resp.status) { + case HttpStatusCode.Ok: + return opSuccessFromHttp(resp, codecForInventorySummaryResponse()); + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private-products-$PRODUCT_ID + */ + async getProductDetails(token, productId) { + const url = new URL(`private/products/${productId}`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + headers + }); + switch (resp.status) { + case HttpStatusCode.Ok: + return opSuccessFromHttp(resp, codecForProductDetail()); + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#reserving-inventory + */ + async lockProduct(token, productId, body) { + const url = new URL(`private/products/${productId}/lock`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body, + headers + }); + switch (resp.status) { + case HttpStatusCode.NoContent: { + this.cacheEvictor.notifySuccess(TalerMerchantInstanceCacheEviction.UPDATE_PRODUCT); + return opEmptySuccess(resp); + } + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Gone: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#removing-products-from-inventory + */ + async deleteProduct(token, productId) { + const url = new URL(`private/products/${productId}`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "DELETE", + headers + }); + switch (resp.status) { + case HttpStatusCode.NoContent: { + this.cacheEvictor.notifySuccess(TalerMerchantInstanceCacheEviction.DELETE_PRODUCT); + return opEmptySuccess(resp); + } + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Conflict: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + // + // Payment processing + // + /** + * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-orders + */ + async createOrder(token, body) { + const url = new URL(`private/orders`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body, + headers + }); + return this.procesOrderCreationResponse(resp); + } + async procesOrderCreationResponse(resp) { + switch (resp.status) { + case HttpStatusCode.Ok: { + this.cacheEvictor.notifySuccess(TalerMerchantInstanceCacheEviction.CREATE_ORDER); + return opSuccessFromHttp(resp, codecForPostOrderResponse()); + } + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Conflict: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Gone: + return opKnownAlternativeFailure(resp, resp.status, codecForOutOfStockResponse()); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#inspecting-orders + */ + async listOrders(token, params = {}) { + const url = new URL(`private/orders`, this.baseUrl); + if (params.date) { + url.searchParams.set("date_s", String(params.date)); + } + if (params.fulfillmentUrl) { + url.searchParams.set("fulfillment_url", params.fulfillmentUrl); + } + if (params.paid !== void 0) { + url.searchParams.set("paid", params.paid ? "YES" : "NO"); + } + if (params.refunded !== void 0) { + url.searchParams.set("refunded", params.refunded ? "YES" : "NO"); + } + if (params.sessionId) { + url.searchParams.set("session_id", params.sessionId); + } + if (params.timeout) { + url.searchParams.set("timeout", String(params.timeout)); + } + if (params.wired !== void 0) { + url.searchParams.set("wired", params.wired ? "YES" : "NO"); + } + addMerchantPaginationParams(url, params); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + headers + }); + switch (resp.status) { + case HttpStatusCode.Ok: + return opSuccessFromHttp(resp, codecForOrderHistory()); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private-orders-$ORDER_ID + */ + async getOrderDetails(token, orderId, params = {}) { + const url = new URL(`private/orders/${orderId}`, this.baseUrl); + if (params.allowRefundedForRepurchase !== void 0) { + url.searchParams.set("allow_refunded_for_repurchase", params.allowRefundedForRepurchase ? "YES" : "NO"); + } + if (params.sessionId) { + url.searchParams.set("session_id", params.sessionId); + } + if (params.timeout) { + url.searchParams.set("timeout_ms", String(params.timeout)); + } + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + headers + }); + switch (resp.status) { + case HttpStatusCode.Ok: + return opSuccessFromHttp(resp, codecForMerchantOrderPrivateStatusResponse()); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.BadGateway: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.GatewayTimeout: + return opKnownAlternativeFailure(resp, resp.status, codecForOutOfStockResponse()); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#private-order-data-cleanup + */ + async forgetOrder(token, orderId, body) { + const url = new URL(`private/orders/${orderId}/forget`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "PATCH", + body, + headers + }); + switch (resp.status) { + case HttpStatusCode.Ok: { + this.cacheEvictor.notifySuccess(TalerMerchantInstanceCacheEviction.UPDATE_ORDER); + return opEmptySuccess(resp); + } + case HttpStatusCode.NoContent: + return opEmptySuccess(resp); + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.BadRequest: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Conflict: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#delete-[-instances-$INSTANCE]-private-orders-$ORDER_ID + */ + async deleteOrder(token, orderId) { + const url = new URL(`private/orders/${orderId}`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "DELETE", + headers + }); + switch (resp.status) { + case HttpStatusCode.NoContent: { + this.cacheEvictor.notifySuccess(TalerMerchantInstanceCacheEviction.DELETE_ORDER); + return opEmptySuccess(resp); + } + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Conflict: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + // + // Refunds + // + /** + * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-orders-$ORDER_ID-refund + */ + async addRefund(token, orderId, body) { + const url = new URL(`private/orders/${orderId}/refund`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body, + headers + }); + switch (resp.status) { + case HttpStatusCode.Ok: { + this.cacheEvictor.notifySuccess(TalerMerchantInstanceCacheEviction.UPDATE_ORDER); + return opSuccessFromHttp(resp, codecForMerchantRefundResponse()); + } + case HttpStatusCode.Forbidden: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Gone: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Conflict: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + // + // Wire Transfer + // + /** + * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-transfers + */ + async informWireTransfer(token, body) { + const url = new URL(`private/transfers`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body, + headers + }); + switch (resp.status) { + case HttpStatusCode.NoContent: { + this.cacheEvictor.notifySuccess(TalerMerchantInstanceCacheEviction.CREATE_TRANSFER); + return opEmptySuccess(resp); + } + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Conflict: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private-transfers + */ + async listWireTransfers(token, params = {}) { + const url = new URL(`private/transfers`, this.baseUrl); + if (params.after) { + url.searchParams.set("after", String(params.after)); + } + if (params.before) { + url.searchParams.set("before", String(params.before)); + } + if (params.paytoURI) { + url.searchParams.set("payto_uri", params.paytoURI); + } + if (params.verified !== void 0) { + url.searchParams.set("verified", params.verified ? "YES" : "NO"); + } + addMerchantPaginationParams(url, params); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + headers + }); + switch (resp.status) { + case HttpStatusCode.Ok: + return opSuccessFromHttp(resp, codecForTansferList()); + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#delete-[-instances-$INSTANCE]-private-transfers-$TID + */ + async deleteWireTransfer(token, transferId) { + const url = new URL(`private/transfers/${transferId}`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "DELETE", + headers + }); + switch (resp.status) { + case HttpStatusCode.NoContent: { + this.cacheEvictor.notifySuccess(TalerMerchantInstanceCacheEviction.DELETE_TRANSFER); + return opEmptySuccess(resp); + } + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Conflict: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + // + // OTP Devices + // + /** + * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-otp-devices + */ + async addOtpDevice(token, body) { + const url = new URL(`private/otp-devices`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body, + headers + }); + switch (resp.status) { + case HttpStatusCode.NoContent: { + this.cacheEvictor.notifySuccess(TalerMerchantInstanceCacheEviction.CREATE_DEVICE); + return opEmptySuccess(resp); + } + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#patch-[-instances-$INSTANCE]-private-otp-devices-$DEVICE_ID + */ + async updateOtpDevice(token, deviceId, body) { + const url = new URL(`private/otp-devices/${deviceId}`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "PATCH", + body, + headers + }); + switch (resp.status) { + case HttpStatusCode.NoContent: { + this.cacheEvictor.notifySuccess(TalerMerchantInstanceCacheEviction.UPDATE_DEVICE); + return opEmptySuccess(resp); + } + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Conflict: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private-otp-devices + */ + async listOtpDevices(token, params) { + const url = new URL(`private/otp-devices`, this.baseUrl); + addMerchantPaginationParams(url, params); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + headers + }); + switch (resp.status) { + case HttpStatusCode.Ok: + return opSuccessFromHttp(resp, codecForOtpDeviceSummaryResponse()); + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private-otp-devices-$DEVICE_ID + */ + async getOtpDeviceDetails(token, deviceId, params = {}) { + const url = new URL(`private/otp-devices/${deviceId}`, this.baseUrl); + if (params.faketime) { + url.searchParams.set("faketime", String(params.faketime)); + } + if (params.price) { + url.searchParams.set("price", params.price); + } + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + headers + }); + switch (resp.status) { + case HttpStatusCode.Ok: + return opSuccessFromHttp(resp, codecForOtpDeviceDetails()); + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#delete-[-instances-$INSTANCE]-private-otp-devices-$DEVICE_ID + */ + async deleteOtpDevice(token, deviceId) { + const url = new URL(`private/otp-devices/${deviceId}`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "DELETE", + headers + }); + switch (resp.status) { + case HttpStatusCode.NoContent: { + this.cacheEvictor.notifySuccess(TalerMerchantInstanceCacheEviction.DELETE_DEVICE); + return opEmptySuccess(resp); + } + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + // + // Templates + // + /** + * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-templates + */ + async addTemplate(token, body) { + const url = new URL(`private/templates`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body, + headers + }); + switch (resp.status) { + case HttpStatusCode.NoContent: { + this.cacheEvictor.notifySuccess(TalerMerchantInstanceCacheEviction.CREATE_TEMPLATE); + return opEmptySuccess(resp); + } + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#patch-[-instances-$INSTANCE]-private-templates-$TEMPLATE_ID + */ + async updateTemplate(token, templateId, body) { + const url = new URL(`private/templates/${templateId}`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "PATCH", + body, + headers + }); + switch (resp.status) { + case HttpStatusCode.NoContent: { + this.cacheEvictor.notifySuccess(TalerMerchantInstanceCacheEviction.UPDATE_TEMPLATE); + return opEmptySuccess(resp); + } + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Conflict: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#inspecting-template + */ + async listTemplates(token, params) { + const url = new URL(`private/templates`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + headers + }); + switch (resp.status) { + case HttpStatusCode.Ok: + return opSuccessFromHttp(resp, codecForTemplateSummaryResponse()); + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-private-templates-$TEMPLATE_ID + */ + async getTemplateDetails(token, templateId) { + const url = new URL(`private/templates/${templateId}`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + headers + }); + switch (resp.status) { + case HttpStatusCode.Ok: + return opSuccessFromHttp(resp, codecForTemplateDetails()); + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#delete-[-instances-$INSTANCE]-private-templates-$TEMPLATE_ID + */ + async deleteTemplate(token, templateId) { + const url = new URL(`private/templates/${templateId}`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "DELETE", + headers + }); + switch (resp.status) { + case HttpStatusCode.NoContent: { + this.cacheEvictor.notifySuccess(TalerMerchantInstanceCacheEviction.DELETE_TEMPLATE); + return opEmptySuccess(resp); + } + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCE]-templates-$TEMPLATE_ID + */ + async useTemplateGetInfo(templateId) { + const url = new URL(`templates/${templateId}`, this.baseUrl); + const resp = await this.httpLib.fetch(url.href, { + method: "GET" + }); + switch (resp.status) { + case HttpStatusCode.Ok: + return opSuccessFromHttp(resp, codecForWalletTemplateDetails()); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCES]-templates-$TEMPLATE_ID + */ + async useTemplateCreateOrder(templateId, body) { + const url = new URL(`templates/${templateId}`, this.baseUrl); + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body + }); + return this.procesOrderCreationResponse(resp); + } + // + // Webhooks + // + /** + * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCES]-private-webhooks + */ + async addWebhook(token, body) { + const url = new URL(`private/webhooks`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body, + headers + }); + switch (resp.status) { + case HttpStatusCode.NoContent: { + this.cacheEvictor.notifySuccess(TalerMerchantInstanceCacheEviction.CREATE_WEBHOOK); + return opEmptySuccess(resp); + } + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#patch-[-instances-$INSTANCES]-private-webhooks-$WEBHOOK_ID + */ + async updateWebhook(token, webhookId, body) { + const url = new URL(`private/webhooks/${webhookId}`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "PATCH", + body, + headers + }); + switch (resp.status) { + case HttpStatusCode.NoContent: { + this.cacheEvictor.notifySuccess(TalerMerchantInstanceCacheEviction.UPDATE_WEBHOOK); + return opEmptySuccess(resp); + } + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Conflict: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCES]-private-webhooks + */ + async listWebhooks(token, params) { + const url = new URL(`private/webhooks`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + headers + }); + switch (resp.status) { + case HttpStatusCode.Ok: + return opSuccessFromHttp(resp, codecForWebhookSummaryResponse()); + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCES]-private-webhooks-$WEBHOOK_ID + */ + async getWebhookDetails(token, webhookId) { + const url = new URL(`private/webhooks/${webhookId}`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + headers + }); + switch (resp.status) { + case HttpStatusCode.NoContent: + return opSuccessFromHttp(resp, codecForWebhookDetails()); + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#delete-[-instances-$INSTANCES]-private-webhooks-$WEBHOOK_ID + */ + async deleteWebhook(token, webhookId) { + const url = new URL(`private/webhooks/${webhookId}`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "DELETE", + headers + }); + switch (resp.status) { + case HttpStatusCode.NoContent: { + this.cacheEvictor.notifySuccess(TalerMerchantInstanceCacheEviction.DELETE_WEBHOOK); + return opEmptySuccess(resp); + } + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + // + // token families + // + /** + * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCES]-private-tokenfamilies + */ + async createTokenFamily(token, body) { + const url = new URL(`private/tokenfamilies`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body, + headers + }); + switch (resp.status) { + case HttpStatusCode.NoContent: { + this.cacheEvictor.notifySuccess(TalerMerchantInstanceCacheEviction.CREATE_TOKENFAMILY); + return opEmptySuccess(resp); + } + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#patch-[-instances-$INSTANCES]-private-tokenfamilies-$TOKEN_FAMILY_SLUG + */ + async updateTokenFamily(token, tokenSlug, body) { + const url = new URL(`private/tokenfamilies/${tokenSlug}`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body, + headers + }); + switch (resp.status) { + case HttpStatusCode.Ok: { + this.cacheEvictor.notifySuccess(TalerMerchantInstanceCacheEviction.UPDATE_TOKENFAMILY); + return opSuccessFromHttp(resp, codecForTokenFamilyDetails()); + } + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCES]-private-tokenfamilies + */ + async listTokenFamilies(token, params) { + const url = new URL(`private/tokenfamilies`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + headers + }); + switch (resp.status) { + case HttpStatusCode.Ok: + return opSuccessFromHttp(resp, codecForTokenFamiliesList()); + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#get-[-instances-$INSTANCES]-private-tokenfamilies-$TOKEN_FAMILY_SLUG + */ + async getTokenFamilyDetails(token, tokenSlug) { + const url = new URL(`private/tokenfamilies/${tokenSlug}`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + headers + }); + switch (resp.status) { + case HttpStatusCode.Ok: + return opSuccessFromHttp(resp, codecForTokenFamilyDetails()); + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#delete-[-instances-$INSTANCES]-private-tokenfamilies-$TOKEN_FAMILY_SLUG + */ + async deleteTokenFamily(token, tokenSlug) { + const url = new URL(`private/tokenfamilies/${tokenSlug}`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "DELETE", + headers + }); + switch (resp.status) { + case HttpStatusCode.NoContent: { + this.cacheEvictor.notifySuccess(TalerMerchantInstanceCacheEviction.DELETE_TOKENFAMILY); + return opEmptySuccess(resp); + } + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * Get the auth api against the current instance + * + * https://docs.taler.net/core/api-merchant.html#post-[-instances-$INSTANCE]-private-token + * https://docs.taler.net/core/api-merchant.html#delete-[-instances-$INSTANCE]-private-token + */ + getAuthenticationAPI() { + return new URL(`private/`, this.baseUrl); + } +}; +var TalerMerchantManagementHttpClient = class extends TalerMerchantInstanceHttpClient { + constructor(baseUrl, httpClient, cacheEvictor) { + super(baseUrl, httpClient, cacheEvictor); + this.baseUrl = baseUrl; + this.cacheManagementEvictor = cacheEvictor ?? nullEvictor; + } + getSubInstanceAPI(instanceId) { + return new URL(`instances/${instanceId}/`, this.baseUrl); + } + // + // Instance Management + // + /** + * https://docs.taler.net/core/api-merchant.html#post--management-instances + */ + async createInstance(token, body) { + const url = new URL(`management/instances`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body, + headers + }); + switch (resp.status) { + case HttpStatusCode.NoContent: { + this.cacheManagementEvictor.notifySuccess(TalerMerchantManagementCacheEviction.CREATE_INSTANCE); + return opEmptySuccess(resp); + } + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Conflict: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#post--management-instances-$INSTANCE-auth + */ + async updateInstanceAuthentication(token, instanceId, body) { + const url = new URL(`management/instances/${instanceId}/auth`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "POST", + body, + headers + }); + switch (resp.status) { + case HttpStatusCode.NoContent: + return opEmptySuccess(resp); + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#patch--management-instances-$INSTANCE + */ + async updateInstance(token, instanceId, body) { + const url = new URL(`management/instances/${instanceId}`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "PATCH", + body, + headers + }); + switch (resp.status) { + case HttpStatusCode.NoContent: { + this.cacheManagementEvictor.notifySuccess(TalerMerchantManagementCacheEviction.UPDATE_INSTANCE); + return opEmptySuccess(resp); + } + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#get--management-instances + */ + async listInstances(token, params) { + const url = new URL(`management/instances`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + headers + }); + switch (resp.status) { + case HttpStatusCode.Ok: + return opSuccessFromHttp(resp, codecForInstancesResponse()); + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#get--management-instances-$INSTANCE + * + */ + async getInstanceDetails(token, instanceId) { + const url = new URL(`management/instances/${instanceId}`, this.baseUrl); + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + headers + }); + switch (resp.status) { + case HttpStatusCode.Ok: + return opSuccessFromHttp(resp, codecForQueryInstancesResponse()); + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#delete--management-instances-$INSTANCE + */ + async deleteInstance(token, instanceId, params = {}) { + const url = new URL(`management/instances/${instanceId}`, this.baseUrl); + if (params.purge !== void 0) { + url.searchParams.set("purge", params.purge ? "YES" : "NO"); + } + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "DELETE", + headers + }); + switch (resp.status) { + case HttpStatusCode.NoContent: { + this.cacheManagementEvictor.notifySuccess(TalerMerchantManagementCacheEviction.DELETE_INSTANCE); + return opEmptySuccess(resp); + } + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Conflict: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-merchant.html#get--management-instances-$INSTANCE-kyc + */ + async getIntanceKycStatus(token, instanceId, params) { + const url = new URL(`management/instances/${instanceId}/kyc`, this.baseUrl); + if (params.wireHash) { + url.searchParams.set("h_wire", params.wireHash); + } + if (params.exchangeURL) { + url.searchParams.set("exchange_url", params.exchangeURL); + } + if (params.timeout) { + url.searchParams.set("timeout_ms", String(params.timeout)); + } + const headers = {}; + if (token) { + headers.Authorization = makeBearerTokenAuthHeader(token); + } + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + headers + }); + switch (resp.status) { + case HttpStatusCode.Accepted: + return opSuccessFromHttp(resp, codecForAccountKycRedirects()); + case HttpStatusCode.NoContent: + return opEmptySuccess(resp); + case HttpStatusCode.NotFound: + return opEmptySuccess(resp); + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.BadGateway: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.ServiceUnavailable: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Conflict: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } +}; + +// ../taler-util/lib/http-client/bank-revenue.js +var TalerRevenueHttpClient = class { + constructor(baseUrl, httpClient) { + this.baseUrl = baseUrl; + this.PROTOCOL_VERSION = "0:0:0"; + this.httpLib = httpClient ?? createPlatformHttpLib(); + } + isCompatible(version) { + const compare2 = LibtoolVersion.compare(this.PROTOCOL_VERSION, version); + return compare2?.compatible ?? false; + } + /** + * https://docs.taler.net/core/api-bank-revenue.html#get--config + * + */ + async getConfig(auth) { + const url = new URL(`config`, this.baseUrl); + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + headers: { + Authorization: auth ? makeBasicAuthHeader(auth.username, auth.password) : void 0 + } + }); + switch (resp.status) { + case HttpStatusCode.Ok: + return opSuccessFromHttp(resp, codecForRevenueConfig()); + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } + /** + * https://docs.taler.net/core/api-bank-revenue.html#get--history + * + * @returns + */ + async getHistory(auth, params) { + const url = new URL(`history`, this.baseUrl); + addPaginationParams(url, params); + addLongPollingParam(url, params); + const resp = await this.httpLib.fetch(url.href, { + method: "GET", + headers: { + Authorization: auth ? makeBasicAuthHeader(auth.username, auth.password) : void 0 + } + }); + switch (resp.status) { + case HttpStatusCode.Ok: + return opSuccessFromHttp(resp, codecForRevenueIncomingHistory()); + case HttpStatusCode.BadRequest: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.Unauthorized: + return opKnownHttpFailure(resp.status, resp); + case HttpStatusCode.NotFound: + return opKnownHttpFailure(resp.status, resp); + default: + return opUnknownFailure(resp, await readTalerErrorResponse(resp)); + } + } +}; + // ../taler-util/lib/i18n.js var jedLib = __toESM(require_jed(), 1); var logger9 = new Logger("i18n/index.ts"); @@ -15199,8 +18002,64 @@ var ObservabilityEventType; ObservabilityEventType2["CryptoStart"] = "crypto-start"; ObservabilityEventType2["CryptoFinishSuccess"] = "crypto-finish-success"; ObservabilityEventType2["CryptoFinishError"] = "crypto-finish-error"; + ObservabilityEventType2["Message"] = "message"; })(ObservabilityEventType || (ObservabilityEventType = {})); +// ../taler-util/lib/observability.js +var seqId = 1e3; +var ObservableHttpClientLibrary = class { + constructor(impl, oc) { + this.impl = impl; + this.oc = oc; + this.cancelatorById = /* @__PURE__ */ new Map(); + } + cancelRequest(id) { + const cancelator = this.cancelatorById.get(id); + if (!cancelator) + return; + cancelator.cancel(); + } + async fetch(url, opt) { + const id = `req-${seqId}`; + seqId = seqId + 1; + const cancelator = CancellationToken.create(); + if (opt?.cancellationToken) { + opt.cancellationToken.onCancelled(cancelator.cancel); + } + this.cancelatorById.set(id, cancelator); + this.oc.observe({ + id, + when: AbsoluteTime.now(), + type: ObservabilityEventType.HttpFetchStart, + url + }); + const optsWithCancel = opt ?? {}; + optsWithCancel.cancellationToken = cancelator.token; + try { + const res = await this.impl.fetch(url, optsWithCancel); + this.oc.observe({ + id, + when: AbsoluteTime.now(), + type: ObservabilityEventType.HttpFetchFinishSuccess, + url, + status: res.status + }); + return res; + } catch (e4) { + this.oc.observe({ + id, + when: AbsoluteTime.now(), + type: ObservabilityEventType.HttpFetchFinishError, + url, + error: getErrorDetailFromException(e4) + }); + throw e4; + } finally { + this.cancelatorById.delete(id); + } + } +}; + // ../taler-util/lib/rfc3548.js var encTable2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; function encodeRfc3548Base32(data) { @@ -15398,6 +18257,14 @@ init_hooks_module(); init_preact_module(); init_hooks_module(); init_preact_module(); +init_hooks_module(); +init_preact_module(); +init_hooks_module(); +init_preact_module(); +init_hooks_module(); +init_preact_module(); +init_hooks_module(); +init_preact_module(); init_preact_module(); init_preact_module(); init_hooks_module(); @@ -15778,8 +18645,8 @@ function getBrowserLang(completeness) { return void 0; } var langPreferenceKey = buildStorageKey("lang-preference"); -function useLang(initial2, completeness) { - const defaultValue = (getBrowserLang(completeness) || initial2 || "en").substring(0, 2); +function useLang(initial22, completeness) { + const defaultValue = (getBrowserLang(completeness) || initial22 || "en").substring(0, 2); return useLocalStorage(langPreferenceKey, defaultValue); } var storage2 = memoryMap(); @@ -15870,18 +18737,10 @@ function strToUTF8Arr(sDOMStr) { } return aBytes; } -var ErrorType = /* @__PURE__ */ ((ErrorType2) => { - ErrorType2[ErrorType2["CLIENT"] = 0] = "CLIENT"; - ErrorType2[ErrorType2["SERVER"] = 1] = "SERVER"; - ErrorType2[ErrorType2["UNREADABLE"] = 2] = "UNREADABLE"; - ErrorType2[ErrorType2["TIMEOUT"] = 3] = "TIMEOUT"; - ErrorType2[ErrorType2["UNEXPECTED"] = 4] = "UNEXPECTED"; - return ErrorType2; -})(ErrorType || {}); async function defaultRequestHandler(baseUrl, endpoint, options = {}) { const requestHeaders = {}; if (options.token) { - requestHeaders.Authorization = `Bearer ${options.token}`; + requestHeaders.Authorization = `Bearer secret-token:${options.token}`; } else if (options.basicAuth) { requestHeaders.Authorization = `Basic ${base64encode( `${options.basicAuth.username}:${options.basicAuth.password}` @@ -16100,8 +18959,166 @@ function validateURL(baseUrl, endpoint) { } } var logger11 = new Logger("browserHttpLib"); +var BrowserFetchHttpLib = class { + constructor(args) { + this.throttle = new RequestThrottler(); + this.throttlingEnabled = true; + this.requireTls = false; + this.throttlingEnabled = args?.enableThrottling ?? true; + this.requireTls = args?.requireTls ?? false; + } + async fetch(requestUrl, options) { + const requestMethod = options?.method ?? "GET"; + const requestBody = options?.body; + const requestHeader = options?.headers; + const requestTimeout = options?.timeout ?? Duration.fromMilliseconds(DEFAULT_REQUEST_TIMEOUT_MS); + const requestCancel = options?.cancellationToken; + const parsedUrl = new URL(requestUrl); + if (this.throttlingEnabled && this.throttle.applyThrottle(requestUrl)) { + throw TalerError.fromDetail( + TalerErrorCode.WALLET_HTTP_REQUEST_THROTTLED, + { + requestMethod, + requestUrl, + throttleStats: this.throttle.getThrottleStats(requestUrl) + }, + `request to origin ${parsedUrl.origin} was throttled` + ); + } + if (this.requireTls && parsedUrl.protocol !== "https:") { + throw TalerError.fromDetail( + TalerErrorCode.WALLET_NETWORK_ERROR, + { + requestMethod, + requestUrl + }, + `request to ${parsedUrl.origin} is not possible with protocol ${parsedUrl.protocol}` + ); + } + const myBody = requestMethod === "POST" || requestMethod === "PUT" || requestMethod === "PATCH" ? encodeBody(requestBody) : void 0; + const requestHeadersMap = getDefaultHeaders(requestMethod); + if (requestHeader) { + Object.entries(requestHeader).forEach(([key, value]) => { + if (value === void 0) + return; + requestHeadersMap[key] = value; + }); + } + const controller = new AbortController(); + let timeoutId; + if (requestTimeout.d_ms !== "forever") { + timeoutId = setTimeout(() => { + controller.abort(TalerErrorCode.GENERIC_TIMEOUT); + }, requestTimeout.d_ms); + } + if (requestCancel) { + requestCancel.onCancelled(() => { + controller.abort(TalerErrorCode.GENERIC_CLIENT_INTERNAL_ERROR); + }); + } + try { + const response = await fetch(requestUrl, { + headers: requestHeadersMap, + body: myBody, + method: requestMethod, + signal: controller.signal + }); + if (timeoutId) { + clearTimeout(timeoutId); + } + const headerMap = new Headers2(); + response.headers.forEach((value, key) => { + headerMap.set(key, value); + }); + return { + headers: headerMap, + status: response.status, + requestMethod, + requestUrl, + json: makeJsonHandler(response, requestUrl, requestMethod), + text: makeTextHandler(response, requestUrl, requestMethod), + bytes: async () => (await response.blob()).arrayBuffer() + }; + } catch (e22) { + if (controller.signal) { + throw TalerError.fromDetail( + controller.signal.reason, + { + requestUrl, + requestMethod, + timeoutMs: requestTimeout.d_ms === "forever" ? 0 : requestTimeout.d_ms + }, + `HTTP request failed.` + ); + } + throw e22; + } + } +}; +function makeTextHandler(response, requestUrl, requestMethod) { + return async function getTextFromResponse() { + let respText; + try { + respText = await response.text(); + } catch (e22) { + throw TalerError.fromDetail( + TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE, + { + requestUrl, + requestMethod, + httpStatusCode: response.status + }, + "Invalid text from HTTP response" + ); + } + return respText; + }; +} +function makeJsonHandler(response, requestUrl, requestMethod) { + let responseJson = void 0; + return async function getJsonFromResponse() { + if (responseJson === void 0) { + try { + responseJson = await response.json(); + } catch (e22) { + const message = e22 instanceof Error ? `Invalid JSON from HTTP response: ${e22.message}` : "Invalid JSON from HTTP response"; + throw TalerError.fromDetail( + TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE, + { + requestUrl, + requestMethod, + httpStatusCode: response.status + }, + message + ); + } + } + if (responseJson === null || typeof responseJson !== "object") { + throw TalerError.fromDetail( + TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE, + { + requestUrl, + requestMethod, + httpStatusCode: response.status + }, + "Invalid JSON from HTTP response: null or not object" + ); + } + return responseJson; + }; +} +function urlPattern(pattern, reverse) { + const url = reverse; + return { + pattern: new RegExp(pattern), + url + }; +} +var nullRountDef = { + pattern: new RegExp(/.*/), + url: () => "" +}; var Context = B({ request: defaultRequestHandler }); -var useApiContext = () => q2(Context); function buildFormatLongFn(args) { return function() { var options = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {}; @@ -23215,7 +26232,7 @@ var initial = { }; var Context2 = B(initial); var TranslationProvider = ({ - initial: initial2, + initial: initial22, children, forceLang, source, @@ -23229,7 +26246,7 @@ var TranslationProvider = ({ it: !completenessProp || !completenessProp["it"] ? 0 : completenessProp["it"], sv: !completenessProp || !completenessProp["sv"] ? 0 : completenessProp["sv"] }; - const { value: lang, update: changeLanguage } = useLang(initial2, completeness); + const { value: lang, update: changeLanguage } = useLang(initial22, completeness); h2(() => { if (forceLang) { changeLanguage(forceLang); @@ -23250,6 +26267,205 @@ var TranslationProvider = ({ }); }; var useTranslationContext = () => q2(Context2); +var ActiviyTracker = class { + constructor() { + this.observers = new Array(); + this.notify = this.notify.bind(this); + this.subscribe = this.subscribe.bind(this); + } + notify(data) { + this.observers.forEach((observer) => observer(data)); + } + subscribe(func) { + this.observers.push(func); + return () => { + this.observers.forEach((observer, index) => { + if (observer === func) { + this.observers.splice(index, 1); + } + }); + }; + } +}; +var BankContext = B(void 0); +var MerchantContext = B(void 0); +var useMerchantApiContext = () => q2(MerchantContext); +var CONFIG_FAIL_TRY_AGAIN_MS2 = 5e3; +var MerchantApiProvider = ({ + baseUrl, + children, + evictors = {}, + frameOnError +}) => { + const [checked, setChecked] = p3(); + const [merchantEndpoint, changeMerchantEndpoint] = p3(baseUrl); + const { getRemoteConfig, VERSION: VERSION2, lib, cancelRequest, onActivity } = buildMerchantApiClient(merchantEndpoint, evictors); + h2(() => { + let keepRetrying = true; + async function testConfig() { + try { + const config = await getRemoteConfig(); + if (LibtoolVersion.compare(VERSION2, config.version)) { + setChecked({ type: "ok", config, hints: [] }); + } else { + setChecked({ + type: "incompatible", + result: config, + supported: VERSION2 + }); + } + } catch (error2) { + if (error2 instanceof TalerError) { + if (keepRetrying) { + setTimeout(() => { + testConfig(); + }, CONFIG_FAIL_TRY_AGAIN_MS2); + } + setChecked({ type: "error", error: error2 }); + } else { + setChecked({ type: "error", error: TalerError.fromException(error2) }); + } + } + } + testConfig(); + return () => { + keepRetrying = false; + }; + }, []); + if (!checked || checked.type !== "ok") { + return h(frameOnError, { state: checked }, []); + } + const value = { + url: merchantEndpoint, + config: checked.config, + onActivity, + lib, + cancelRequest, + changeBackend: changeMerchantEndpoint, + hints: checked.hints + }; + return h(MerchantContext.Provider, { + value, + children + }); +}; +function buildMerchantApiClient(url, evictors) { + const httpFetch = new BrowserFetchHttpLib({ + enableThrottling: true, + requireTls: false + }); + const tracker = new ActiviyTracker(); + const httpLib = new ObservableHttpClientLibrary(httpFetch, { + observe(ev) { + tracker.notify(ev); + } + }); + const instance = new TalerMerchantManagementHttpClient( + url.href, + httpLib, + evictors.management + ); + const authenticate = new TalerAuthenticationHttpClient( + instance.getAuthenticationAPI().href, + httpLib + ); + const rootUrl = url; + function getSubInstanceAPI(instanceId) { + const newURL = new URL(`instance/${instanceId}/`, rootUrl); + const api = buildMerchantApiClient(newURL, evictors); + return api.lib; + } + async function getRemoteConfig() { + const resp = await instance.getConfig(); + if (resp.type === "fail") { + throw TalerError.fromUncheckedDetail(resp.detail); + } + return resp.body; + } + return { + getRemoteConfig, + VERSION: instance.PROTOCOL_VERSION, + lib: { + instance, + authenticate, + subInstanceApi: getSubInstanceAPI + }, + onActivity: tracker.subscribe, + cancelRequest: httpLib.cancelRequest + }; +} +var Context3 = B(void 0); +var useNavigationContext = () => q2(Context3); +function getPathAndParamsFromWindow() { + const path = typeof window !== "undefined" ? window.location.hash.substring(1) : "/"; + const params = {}; + if (typeof window !== "undefined") { + for (const [key, value] of new URLSearchParams(window.location.search)) { + params[key] = value; + } + } + return { path, params }; +} +var { path: initialPath, params: initialParams } = getPathAndParamsFromWindow(); +var PopStateEventType = "popstate"; +var BrowserHashNavigationProvider = ({ + children +}) => { + const [{ path, params }, setState] = p3({ + path: initialPath, + params: initialParams + }); + if (typeof window === "undefined") { + throw Error( + "Can't use BrowserHashNavigationProvider if there is no window object" + ); + } + function navigateTo(path2) { + const { params: params2 } = getPathAndParamsFromWindow(); + setState({ path: path2, params: params2 }); + window.location.href = path2; + } + h2(() => { + function eventListener() { + setState(getPathAndParamsFromWindow()); + } + window.addEventListener(PopStateEventType, eventListener); + return () => { + window.removeEventListener(PopStateEventType, eventListener); + }; + }, []); + return h(Context3.Provider, { + value: { path, params, navigateTo }, + children + }); +}; +function createHeadMetaTag(uri, onNotFound) { + const meta = document.createElement("meta"); + meta.setAttribute("name", "taler-uri"); + meta.setAttribute("content", stringifyTalerUri(uri)); + document.head.appendChild(meta); + let walletFound = false; + window.addEventListener("beforeunload", () => { + walletFound = true; + }); + setTimeout(() => { + if (!walletFound && onNotFound) { + onNotFound(); + } + }, 10); +} +var Context4 = B(void 0); +var TalerWalletIntegrationBrowserProvider = ({ + children +}) => { + const value = { + publishTalerAction: createHeadMetaTag + }; + return h(Context4.Provider, { + value, + children + }); +}; var utils_exports = {}; __export2(utils_exports, { compose: () => compose, @@ -23271,8 +26487,8 @@ function compose(hook, viewMap) { return ComposedComponent; } return (p4) => { - const h37 = withHook(() => hook(p4)); - return h37(); + const h41 = withHook(() => hook(p4)); + return h41(); }; } function recursive(hook) { @@ -23288,8 +26504,8 @@ function recursive(hook) { return ComposedComponent; } return (p4) => { - const h37 = withHook(() => hook(p4)); - return h37(); + const h41 = withHook(() => hook(p4)); + return h41(); }; } function saveVNodeForInspection(obj) { @@ -23339,6 +26555,930 @@ var FormContext = B({}); init_preact_module(); init_hooks_module(); +// ../../node_modules/.pnpm/swr@2.2.2_react@18.2.0/node_modules/swr/core/dist/index.mjs +init_compat_module(); +var import_shim = __toESM(require_shim(), 1); + +// ../../node_modules/.pnpm/swr@2.2.2_react@18.2.0/node_modules/swr/_internal/dist/index.mjs +init_compat_module(); +var noop = () => { +}; +var UNDEFINED = ( + /*#__NOINLINE__*/ + noop() +); +var OBJECT = Object; +var isUndefined = (v3) => v3 === UNDEFINED; +var isFunction = (v3) => typeof v3 == "function"; +var mergeObjects = (a5, b4) => ({ + ...a5, + ...b4 +}); +var isPromiseLike = (x6) => isFunction(x6.then); +var table = /* @__PURE__ */ new WeakMap(); +var counter = 0; +var stableHash = (arg) => { + const type = typeof arg; + const constructor = arg && arg.constructor; + const isDate3 = constructor == Date; + let result; + let index; + if (OBJECT(arg) === arg && !isDate3 && constructor != RegExp) { + result = table.get(arg); + if (result) + return result; + result = ++counter + "~"; + table.set(arg, result); + if (constructor == Array) { + result = "@"; + for (index = 0; index < arg.length; index++) { + result += stableHash(arg[index]) + ","; + } + table.set(arg, result); + } + if (constructor == OBJECT) { + result = "#"; + const keys = OBJECT.keys(arg).sort(); + while (!isUndefined(index = keys.pop())) { + if (!isUndefined(arg[index])) { + result += index + ":" + stableHash(arg[index]) + ","; + } + } + table.set(arg, result); + } + } else { + result = isDate3 ? arg.toJSON() : type == "symbol" ? arg.toString() : type == "string" ? JSON.stringify(arg) : "" + arg; + } + return result; +}; +var SWRGlobalState = /* @__PURE__ */ new WeakMap(); +var EMPTY_CACHE = {}; +var INITIAL_CACHE = {}; +var STR_UNDEFINED = "undefined"; +var isWindowDefined = typeof window != STR_UNDEFINED; +var isDocumentDefined = typeof document != STR_UNDEFINED; +var hasRequestAnimationFrame = () => isWindowDefined && typeof window["requestAnimationFrame"] != STR_UNDEFINED; +var createCacheHelper = (cache2, key) => { + const state = SWRGlobalState.get(cache2); + return [ + // Getter + () => !isUndefined(key) && cache2.get(key) || EMPTY_CACHE, + // Setter + (info) => { + if (!isUndefined(key)) { + const prev = cache2.get(key); + if (!(key in INITIAL_CACHE)) { + INITIAL_CACHE[key] = prev; + } + state[5](key, mergeObjects(prev, info), prev || EMPTY_CACHE); + } + }, + // Subscriber + state[6], + // Get server cache snapshot + () => { + if (!isUndefined(key)) { + if (key in INITIAL_CACHE) + return INITIAL_CACHE[key]; + } + return !isUndefined(key) && cache2.get(key) || EMPTY_CACHE; + } + ]; +}; +var online = true; +var isOnline = () => online; +var [onWindowEvent, offWindowEvent] = isWindowDefined && window.addEventListener ? [ + window.addEventListener.bind(window), + window.removeEventListener.bind(window) +] : [ + noop, + noop +]; +var isVisible = () => { + const visibilityState = isDocumentDefined && document.visibilityState; + return isUndefined(visibilityState) || visibilityState !== "hidden"; +}; +var initFocus = (callback) => { + if (isDocumentDefined) { + document.addEventListener("visibilitychange", callback); + } + onWindowEvent("focus", callback); + return () => { + if (isDocumentDefined) { + document.removeEventListener("visibilitychange", callback); + } + offWindowEvent("focus", callback); + }; +}; +var initReconnect = (callback) => { + const onOnline = () => { + online = true; + callback(); + }; + const onOffline = () => { + online = false; + }; + onWindowEvent("online", onOnline); + onWindowEvent("offline", onOffline); + return () => { + offWindowEvent("online", onOnline); + offWindowEvent("offline", onOffline); + }; +}; +var preset = { + isOnline, + isVisible +}; +var defaultConfigOptions = { + initFocus, + initReconnect +}; +var IS_REACT_LEGACY = !bn.useId; +var IS_SERVER = !isWindowDefined || "Deno" in window; +var rAF = (f3) => hasRequestAnimationFrame() ? window["requestAnimationFrame"](f3) : setTimeout(f3, 1); +var useIsomorphicLayoutEffect = IS_SERVER ? h2 : s2; +var navigatorConnection = typeof navigator !== "undefined" && navigator.connection; +var slowConnection = !IS_SERVER && navigatorConnection && ([ + "slow-2g", + "2g" +].includes(navigatorConnection.effectiveType) || navigatorConnection.saveData); +var serialize = (key) => { + if (isFunction(key)) { + try { + key = key(); + } catch (err) { + key = ""; + } + } + const args = key; + key = typeof key == "string" ? key : (Array.isArray(key) ? key.length : key) ? stableHash(key) : ""; + return [ + key, + args + ]; +}; +var __timestamp = 0; +var getTimestamp = () => ++__timestamp; +var FOCUS_EVENT = 0; +var RECONNECT_EVENT = 1; +var MUTATE_EVENT = 2; +var ERROR_REVALIDATE_EVENT = 3; +var events = { + __proto__: null, + ERROR_REVALIDATE_EVENT, + FOCUS_EVENT, + MUTATE_EVENT, + RECONNECT_EVENT +}; +async function internalMutate(...args) { + const [cache2, _key, _data, _opts] = args; + const options = mergeObjects({ + populateCache: true, + throwOnError: true + }, typeof _opts === "boolean" ? { + revalidate: _opts + } : _opts || {}); + let populateCache = options.populateCache; + const rollbackOnErrorOption = options.rollbackOnError; + let optimisticData = options.optimisticData; + const revalidate = options.revalidate !== false; + const rollbackOnError = (error2) => { + return typeof rollbackOnErrorOption === "function" ? rollbackOnErrorOption(error2) : rollbackOnErrorOption !== false; + }; + const throwOnError = options.throwOnError; + if (isFunction(_key)) { + const keyFilter = _key; + const matchedKeys = []; + const it = cache2.keys(); + for (const key of it) { + if ( + // Skip the special useSWRInfinite and useSWRSubscription keys. + !/^\$(inf|sub)\$/.test(key) && keyFilter(cache2.get(key)._k) + ) { + matchedKeys.push(key); + } + } + return Promise.all(matchedKeys.map(mutateByKey)); + } + return mutateByKey(_key); + async function mutateByKey(_k) { + const [key] = serialize(_k); + if (!key) + return; + const [get, set2] = createCacheHelper(cache2, key); + const [EVENT_REVALIDATORS, MUTATION, FETCH, PRELOAD] = SWRGlobalState.get(cache2); + const startRevalidate = () => { + const revalidators = EVENT_REVALIDATORS[key]; + if (revalidate) { + delete FETCH[key]; + delete PRELOAD[key]; + if (revalidators && revalidators[0]) { + return revalidators[0](MUTATE_EVENT).then(() => get().data); + } + } + return get().data; + }; + if (args.length < 3) { + return startRevalidate(); + } + let data = _data; + let error2; + const beforeMutationTs = getTimestamp(); + MUTATION[key] = [ + beforeMutationTs, + 0 + ]; + const hasOptimisticData = !isUndefined(optimisticData); + const state = get(); + const displayedData = state.data; + const currentData = state._c; + const committedData = isUndefined(currentData) ? displayedData : currentData; + if (hasOptimisticData) { + optimisticData = isFunction(optimisticData) ? optimisticData(committedData, displayedData) : optimisticData; + set2({ + data: optimisticData, + _c: committedData + }); + } + if (isFunction(data)) { + try { + data = data(committedData); + } catch (err) { + error2 = err; + } + } + if (data && isPromiseLike(data)) { + data = await data.catch((err) => { + error2 = err; + }); + if (beforeMutationTs !== MUTATION[key][0]) { + if (error2) + throw error2; + return data; + } else if (error2 && hasOptimisticData && rollbackOnError(error2)) { + populateCache = true; + set2({ + data: committedData, + _c: UNDEFINED + }); + } + } + if (populateCache) { + if (!error2) { + if (isFunction(populateCache)) { + const populateCachedData = populateCache(data, committedData); + set2({ + data: populateCachedData, + error: UNDEFINED, + _c: UNDEFINED + }); + } else { + set2({ + data, + error: UNDEFINED, + _c: UNDEFINED + }); + } + } + } + MUTATION[key][1] = getTimestamp(); + Promise.resolve(startRevalidate()).then(() => { + set2({ + _c: UNDEFINED + }); + }); + if (error2) { + if (throwOnError) + throw error2; + return; + } + return data; + } +} +var revalidateAllKeys = (revalidators, type) => { + for (const key in revalidators) { + if (revalidators[key][0]) + revalidators[key][0](type); + } +}; +var initCache = (provider, options) => { + if (!SWRGlobalState.has(provider)) { + const opts = mergeObjects(defaultConfigOptions, options); + const EVENT_REVALIDATORS = {}; + const mutate2 = internalMutate.bind(UNDEFINED, provider); + let unmount = noop; + const subscriptions = {}; + const subscribe = (key, callback) => { + const subs = subscriptions[key] || []; + subscriptions[key] = subs; + subs.push(callback); + return () => subs.splice(subs.indexOf(callback), 1); + }; + const setter = (key, value, prev) => { + provider.set(key, value); + const subs = subscriptions[key]; + if (subs) { + for (const fn2 of subs) { + fn2(value, prev); + } + } + }; + const initProvider = () => { + if (!SWRGlobalState.has(provider)) { + SWRGlobalState.set(provider, [ + EVENT_REVALIDATORS, + {}, + {}, + {}, + mutate2, + setter, + subscribe + ]); + if (!IS_SERVER) { + const releaseFocus = opts.initFocus(setTimeout.bind(UNDEFINED, revalidateAllKeys.bind(UNDEFINED, EVENT_REVALIDATORS, FOCUS_EVENT))); + const releaseReconnect = opts.initReconnect(setTimeout.bind(UNDEFINED, revalidateAllKeys.bind(UNDEFINED, EVENT_REVALIDATORS, RECONNECT_EVENT))); + unmount = () => { + releaseFocus && releaseFocus(); + releaseReconnect && releaseReconnect(); + SWRGlobalState.delete(provider); + }; + } + } + }; + initProvider(); + return [ + provider, + mutate2, + initProvider, + unmount + ]; + } + return [ + provider, + SWRGlobalState.get(provider)[4] + ]; +}; +var onErrorRetry = (_3, __, config, revalidate, opts) => { + const maxRetryCount = config.errorRetryCount; + const currentRetryCount = opts.retryCount; + const timeout = ~~((Math.random() + 0.5) * (1 << (currentRetryCount < 8 ? currentRetryCount : 8))) * config.errorRetryInterval; + if (!isUndefined(maxRetryCount) && currentRetryCount > maxRetryCount) { + return; + } + setTimeout(revalidate, timeout, opts); +}; +var compare = (currentData, newData) => stableHash(currentData) == stableHash(newData); +var [cache, mutate] = initCache(/* @__PURE__ */ new Map()); +var defaultConfig = mergeObjects( + { + // events + onLoadingSlow: noop, + onSuccess: noop, + onError: noop, + onErrorRetry, + onDiscarded: noop, + // switches + revalidateOnFocus: true, + revalidateOnReconnect: true, + revalidateIfStale: true, + shouldRetryOnError: true, + // timeouts + errorRetryInterval: slowConnection ? 1e4 : 5e3, + focusThrottleInterval: 5 * 1e3, + dedupingInterval: 2 * 1e3, + loadingTimeout: slowConnection ? 5e3 : 3e3, + // providers + compare, + isPaused: () => false, + cache, + mutate, + fallback: {} + }, + // use web preset by default + preset +); +var mergeConfigs = (a5, b4) => { + const v3 = mergeObjects(a5, b4); + if (b4) { + const { use: u1, fallback: f1 } = a5; + const { use: u22, fallback: f22 } = b4; + if (u1 && u22) { + v3.use = u1.concat(u22); + } + if (f1 && f22) { + v3.fallback = mergeObjects(f1, f22); + } + } + return v3; +}; +var SWRConfigContext = B({}); +var SWRConfig = (props) => { + const { value } = props; + const parentConfig = q2(SWRConfigContext); + const isFunctionalConfig = isFunction(value); + const config = F(() => isFunctionalConfig ? value(parentConfig) : value, [ + isFunctionalConfig, + parentConfig, + value + ]); + const extendedConfig = F(() => isFunctionalConfig ? config : mergeConfigs(parentConfig, config), [ + isFunctionalConfig, + parentConfig, + config + ]); + const provider = config && config.provider; + const cacheContextRef = _2(UNDEFINED); + if (provider && !cacheContextRef.current) { + cacheContextRef.current = initCache(provider(extendedConfig.cache || cache), config); + } + const cacheContext = cacheContextRef.current; + if (cacheContext) { + extendedConfig.cache = cacheContext[0]; + extendedConfig.mutate = cacheContext[1]; + } + useIsomorphicLayoutEffect(() => { + if (cacheContext) { + cacheContext[2] && cacheContext[2](); + return cacheContext[3]; + } + }, []); + return h(SWRConfigContext.Provider, mergeObjects(props, { + value: extendedConfig + })); +}; +var INFINITE_PREFIX = "$inf$"; +var enableDevtools = isWindowDefined && window.__SWR_DEVTOOLS_USE__; +var use = enableDevtools ? window.__SWR_DEVTOOLS_USE__ : []; +var setupDevTools = () => { + if (enableDevtools) { + window.__SWR_DEVTOOLS_REACT__ = bn; + } +}; +var normalize = (args) => { + return isFunction(args[1]) ? [ + args[0], + args[1], + args[2] || {} + ] : [ + args[0], + null, + (args[1] === null ? args[2] : args[1]) || {} + ]; +}; +var useSWRConfig = () => { + return mergeObjects(defaultConfig, q2(SWRConfigContext)); +}; +var middleware = (useSWRNext) => (key_, fetcher_, config) => { + const fetcher = fetcher_ && ((...args) => { + const [key] = serialize(key_); + const [, , , PRELOAD] = SWRGlobalState.get(cache); + if (key.startsWith(INFINITE_PREFIX)) { + return fetcher_(...args); + } + const req = PRELOAD[key]; + if (isUndefined(req)) + return fetcher_(...args); + delete PRELOAD[key]; + return req; + }); + return useSWRNext(key_, fetcher, config); +}; +var BUILT_IN_MIDDLEWARE = use.concat(middleware); +var withArgs = (hook) => { + return function useSWRArgs(...args) { + const fallbackConfig = useSWRConfig(); + const [key, fn2, _config] = normalize(args); + const config = mergeConfigs(fallbackConfig, _config); + let next = hook; + const { use: use3 } = config; + const middleware2 = (use3 || []).concat(BUILT_IN_MIDDLEWARE); + for (let i4 = middleware2.length; i4--; ) { + next = middleware2[i4](next); + } + return next(key, fn2 || config.fetcher || null, config); + }; +}; +var subscribeCallback = (key, callbacks, callback) => { + const keyedRevalidators = callbacks[key] || (callbacks[key] = []); + keyedRevalidators.push(callback); + return () => { + const index = keyedRevalidators.indexOf(callback); + if (index >= 0) { + keyedRevalidators[index] = keyedRevalidators[keyedRevalidators.length - 1]; + keyedRevalidators.pop(); + } + }; +}; +setupDevTools(); + +// ../../node_modules/.pnpm/swr@2.2.2_react@18.2.0/node_modules/swr/core/dist/index.mjs +var use2 = bn.use || ((promise) => { + if (promise.status === "pending") { + throw promise; + } else if (promise.status === "fulfilled") { + return promise.value; + } else if (promise.status === "rejected") { + throw promise.reason; + } else { + promise.status = "pending"; + promise.then((v3) => { + promise.status = "fulfilled"; + promise.value = v3; + }, (e4) => { + promise.status = "rejected"; + promise.reason = e4; + }); + throw promise; + } +}); +var WITH_DEDUPE = { + dedupe: true +}; +var useSWRHandler = (_key, fetcher, config) => { + const { cache: cache2, compare: compare2, suspense, fallbackData, revalidateOnMount, revalidateIfStale, refreshInterval, refreshWhenHidden, refreshWhenOffline, keepPreviousData } = config; + const [EVENT_REVALIDATORS, MUTATION, FETCH, PRELOAD] = SWRGlobalState.get(cache2); + const [key, fnArg] = serialize(_key); + const initialMountedRef = _2(false); + const unmountedRef = _2(false); + const keyRef = _2(key); + const fetcherRef = _2(fetcher); + const configRef = _2(config); + const getConfig = () => configRef.current; + const isActive = () => getConfig().isVisible() && getConfig().isOnline(); + const [getCache, setCache, subscribeCache, getInitialCache] = createCacheHelper(cache2, key); + const stateDependencies = _2({}).current; + const fallback = isUndefined(fallbackData) ? config.fallback[key] : fallbackData; + const isEqual = (prev, current) => { + for (const _3 in stateDependencies) { + const t4 = _3; + if (t4 === "data") { + if (!compare2(prev[t4], current[t4])) { + if (!isUndefined(prev[t4])) { + return false; + } + if (!compare2(returnedData, current[t4])) { + return false; + } + } + } else { + if (current[t4] !== prev[t4]) { + return false; + } + } + } + return true; + }; + const getSnapshot = F(() => { + const shouldStartRequest = (() => { + if (!key) + return false; + if (!fetcher) + return false; + if (!isUndefined(revalidateOnMount)) + return revalidateOnMount; + if (getConfig().isPaused()) + return false; + if (suspense) + return false; + if (!isUndefined(revalidateIfStale)) + return revalidateIfStale; + return true; + })(); + const getSelectedCache = (state) => { + const snapshot = mergeObjects(state); + delete snapshot._k; + if (!shouldStartRequest) { + return snapshot; + } + return { + isValidating: true, + isLoading: true, + ...snapshot + }; + }; + const cachedData2 = getCache(); + const initialData = getInitialCache(); + const clientSnapshot = getSelectedCache(cachedData2); + const serverSnapshot = cachedData2 === initialData ? clientSnapshot : getSelectedCache(initialData); + let memorizedSnapshot = clientSnapshot; + return [ + () => { + const newSnapshot = getSelectedCache(getCache()); + const compareResult = isEqual(newSnapshot, memorizedSnapshot); + if (compareResult) { + memorizedSnapshot.data = newSnapshot.data; + memorizedSnapshot.isLoading = newSnapshot.isLoading; + memorizedSnapshot.isValidating = newSnapshot.isValidating; + memorizedSnapshot.error = newSnapshot.error; + return memorizedSnapshot; + } else { + memorizedSnapshot = newSnapshot; + return newSnapshot; + } + }, + () => serverSnapshot + ]; + }, [ + cache2, + key + ]); + const cached = (0, import_shim.useSyncExternalStore)(T2( + (callback) => subscribeCache(key, (current, prev) => { + if (!isEqual(prev, current)) + callback(); + }), + // eslint-disable-next-line react-hooks/exhaustive-deps + [ + cache2, + key + ] + ), getSnapshot[0], getSnapshot[1]); + const isInitialMount = !initialMountedRef.current; + const hasRevalidator = EVENT_REVALIDATORS[key] && EVENT_REVALIDATORS[key].length > 0; + const cachedData = cached.data; + const data = isUndefined(cachedData) ? fallback : cachedData; + const error2 = cached.error; + const laggyDataRef = _2(data); + const returnedData = keepPreviousData ? isUndefined(cachedData) ? laggyDataRef.current : cachedData : data; + const shouldDoInitialRevalidation = (() => { + if (hasRevalidator && !isUndefined(error2)) + return false; + if (isInitialMount && !isUndefined(revalidateOnMount)) + return revalidateOnMount; + if (getConfig().isPaused()) + return false; + if (suspense) + return isUndefined(data) ? false : revalidateIfStale; + return isUndefined(data) || revalidateIfStale; + })(); + const defaultValidatingState = !!(key && fetcher && isInitialMount && shouldDoInitialRevalidation); + const isValidating = isUndefined(cached.isValidating) ? defaultValidatingState : cached.isValidating; + const isLoading = isUndefined(cached.isLoading) ? defaultValidatingState : cached.isLoading; + const revalidate = T2( + async (revalidateOpts) => { + const currentFetcher = fetcherRef.current; + if (!key || !currentFetcher || unmountedRef.current || getConfig().isPaused()) { + return false; + } + let newData; + let startAt; + let loading = true; + const opts = revalidateOpts || {}; + const shouldStartNewRequest = !FETCH[key] || !opts.dedupe; + const callbackSafeguard = () => { + if (IS_REACT_LEGACY) { + return !unmountedRef.current && key === keyRef.current && initialMountedRef.current; + } + return key === keyRef.current; + }; + const finalState = { + isValidating: false, + isLoading: false + }; + const finishRequestAndUpdateState = () => { + setCache(finalState); + }; + const cleanupState = () => { + const requestInfo = FETCH[key]; + if (requestInfo && requestInfo[1] === startAt) { + delete FETCH[key]; + } + }; + const initialState = { + isValidating: true + }; + if (isUndefined(getCache().data)) { + initialState.isLoading = true; + } + try { + if (shouldStartNewRequest) { + setCache(initialState); + if (config.loadingTimeout && isUndefined(getCache().data)) { + setTimeout(() => { + if (loading && callbackSafeguard()) { + getConfig().onLoadingSlow(key, config); + } + }, config.loadingTimeout); + } + FETCH[key] = [ + currentFetcher(fnArg), + getTimestamp() + ]; + } + [newData, startAt] = FETCH[key]; + newData = await newData; + if (shouldStartNewRequest) { + setTimeout(cleanupState, config.dedupingInterval); + } + if (!FETCH[key] || FETCH[key][1] !== startAt) { + if (shouldStartNewRequest) { + if (callbackSafeguard()) { + getConfig().onDiscarded(key); + } + } + return false; + } + finalState.error = UNDEFINED; + const mutationInfo = MUTATION[key]; + if (!isUndefined(mutationInfo) && // case 1 + (startAt <= mutationInfo[0] || // case 2 + startAt <= mutationInfo[1] || // case 3 + mutationInfo[1] === 0)) { + finishRequestAndUpdateState(); + if (shouldStartNewRequest) { + if (callbackSafeguard()) { + getConfig().onDiscarded(key); + } + } + return false; + } + const cacheData = getCache().data; + finalState.data = compare2(cacheData, newData) ? cacheData : newData; + if (shouldStartNewRequest) { + if (callbackSafeguard()) { + getConfig().onSuccess(newData, key, config); + } + } + } catch (err) { + cleanupState(); + const currentConfig = getConfig(); + const { shouldRetryOnError } = currentConfig; + if (!currentConfig.isPaused()) { + finalState.error = err; + if (shouldStartNewRequest && callbackSafeguard()) { + currentConfig.onError(err, key, currentConfig); + if (shouldRetryOnError === true || isFunction(shouldRetryOnError) && shouldRetryOnError(err)) { + if (isActive()) { + currentConfig.onErrorRetry(err, key, currentConfig, (_opts) => { + const revalidators = EVENT_REVALIDATORS[key]; + if (revalidators && revalidators[0]) { + revalidators[0](events.ERROR_REVALIDATE_EVENT, _opts); + } + }, { + retryCount: (opts.retryCount || 0) + 1, + dedupe: true + }); + } + } + } + } + } + loading = false; + finishRequestAndUpdateState(); + return true; + }, + // `setState` is immutable, and `eventsCallback`, `fnArg`, and + // `keyValidating` are depending on `key`, so we can exclude them from + // the deps array. + // + // FIXME: + // `fn` and `config` might be changed during the lifecycle, + // but they might be changed every render like this. + // `useSWR('key', () => fetch('/api/'), { suspense: true })` + // So we omit the values from the deps array + // even though it might cause unexpected behaviors. + // eslint-disable-next-line react-hooks/exhaustive-deps + [ + key, + cache2 + ] + ); + const boundMutate = T2( + // Use callback to make sure `keyRef.current` returns latest result every time + (...args) => { + return internalMutate(cache2, keyRef.current, ...args); + }, + // eslint-disable-next-line react-hooks/exhaustive-deps + [] + ); + useIsomorphicLayoutEffect(() => { + fetcherRef.current = fetcher; + configRef.current = config; + if (!isUndefined(cachedData)) { + laggyDataRef.current = cachedData; + } + }); + useIsomorphicLayoutEffect(() => { + if (!key) + return; + const softRevalidate = revalidate.bind(UNDEFINED, WITH_DEDUPE); + let nextFocusRevalidatedAt = 0; + const onRevalidate = (type, opts = {}) => { + if (type == events.FOCUS_EVENT) { + const now2 = Date.now(); + if (getConfig().revalidateOnFocus && now2 > nextFocusRevalidatedAt && isActive()) { + nextFocusRevalidatedAt = now2 + getConfig().focusThrottleInterval; + softRevalidate(); + } + } else if (type == events.RECONNECT_EVENT) { + if (getConfig().revalidateOnReconnect && isActive()) { + softRevalidate(); + } + } else if (type == events.MUTATE_EVENT) { + return revalidate(); + } else if (type == events.ERROR_REVALIDATE_EVENT) { + return revalidate(opts); + } + return; + }; + const unsubEvents = subscribeCallback(key, EVENT_REVALIDATORS, onRevalidate); + unmountedRef.current = false; + keyRef.current = key; + initialMountedRef.current = true; + setCache({ + _k: fnArg + }); + if (shouldDoInitialRevalidation) { + if (isUndefined(data) || IS_SERVER) { + softRevalidate(); + } else { + rAF(softRevalidate); + } + } + return () => { + unmountedRef.current = true; + unsubEvents(); + }; + }, [ + key + ]); + useIsomorphicLayoutEffect(() => { + let timer2; + function next() { + const interval = isFunction(refreshInterval) ? refreshInterval(getCache().data) : refreshInterval; + if (interval && timer2 !== -1) { + timer2 = setTimeout(execute, interval); + } + } + function execute() { + if (!getCache().error && (refreshWhenHidden || getConfig().isVisible()) && (refreshWhenOffline || getConfig().isOnline())) { + revalidate(WITH_DEDUPE).then(next); + } else { + next(); + } + } + next(); + return () => { + if (timer2) { + clearTimeout(timer2); + timer2 = -1; + } + }; + }, [ + refreshInterval, + refreshWhenHidden, + refreshWhenOffline, + key + ]); + x3(returnedData); + if (suspense && isUndefined(data) && key) { + if (!IS_REACT_LEGACY && IS_SERVER) { + throw new Error("Fallback data is required when using suspense in SSR."); + } + fetcherRef.current = fetcher; + configRef.current = config; + unmountedRef.current = false; + const req = PRELOAD[key]; + if (!isUndefined(req)) { + const promise = boundMutate(req); + use2(promise); + } + if (isUndefined(error2)) { + const promise = revalidate(WITH_DEDUPE); + if (!isUndefined(returnedData)) { + promise.status = "fulfilled"; + promise.value = true; + } + use2(promise); + } else { + throw error2; + } + } + return { + mutate: boundMutate, + get data() { + stateDependencies.data = true; + return returnedData; + }, + get error() { + stateDependencies.error = true; + return error2; + }, + get isValidating() { + stateDependencies.isValidating = true; + return isValidating; + }, + get isLoading() { + stateDependencies.isLoading = true; + return isLoading; + } + }; +}; +var SWRConfig2 = OBJECT.defineProperty(SWRConfig, "defaultValue", { + value: defaultConfig +}); +var useSWR = withArgs(useSWRHandler); + // ../../node_modules/.pnpm/@babel+runtime@7.19.4/node_modules/@babel/runtime/helpers/esm/extends.js function _extends() { _extends = Object.assign ? Object.assign.bind() : function(target) { @@ -23638,9 +27778,9 @@ function createHashHistory(props) { } var transitionManager = createTransitionManager(); function setState(nextState) { - _extends(history2, nextState); - history2.length = globalHistory.length; - transitionManager.notifyListeners(history2.location, history2.action); + _extends(history3, nextState); + history3.length = globalHistory.length; + transitionManager.notifyListeners(history3.location, history3.action); } var forceNextPop = false; var ignorePath = null; @@ -23654,7 +27794,7 @@ function createHashHistory(props) { replaceHashPath(encodedPath2); } else { var location2 = getDOMLocation(); - var prevLocation = history2.location; + var prevLocation = history3.location; if (!forceNextPop && locationsAreEqual$$1(prevLocation, location2)) return; if (ignorePath === createPath(location2)) @@ -23682,7 +27822,7 @@ function createHashHistory(props) { } } function revertPop(fromLocation) { - var toLocation = history2.location; + var toLocation = history3.location; var toIndex = allPaths.lastIndexOf(createPath(toLocation)); if (toIndex === -1) toIndex = 0; @@ -23712,7 +27852,7 @@ function createHashHistory(props) { function push(path2, state) { false ? tiny_warning_esm_default(state === void 0, "Hash history cannot push state; it is ignored") : void 0; var action = "PUSH"; - var location2 = createLocation(path2, void 0, void 0, history2.location); + var location2 = createLocation(path2, void 0, void 0, history3.location); transitionManager.confirmTransitionTo(location2, action, getUserConfirmation, function(ok) { if (!ok) return; @@ -23722,7 +27862,7 @@ function createHashHistory(props) { if (hashChanged) { ignorePath = path3; pushHashPath(encodedPath2); - var prevIndex = allPaths.lastIndexOf(createPath(history2.location)); + var prevIndex = allPaths.lastIndexOf(createPath(history3.location)); var nextPaths = allPaths.slice(0, prevIndex + 1); nextPaths.push(path3); allPaths = nextPaths; @@ -23739,7 +27879,7 @@ function createHashHistory(props) { function replace(path2, state) { false ? tiny_warning_esm_default(state === void 0, "Hash history cannot replace state; it is ignored") : void 0; var action = "REPLACE"; - var location2 = createLocation(path2, void 0, void 0, history2.location); + var location2 = createLocation(path2, void 0, void 0, history3.location); transitionManager.confirmTransitionTo(location2, action, getUserConfirmation, function(ok) { if (!ok) return; @@ -23750,7 +27890,7 @@ function createHashHistory(props) { ignorePath = path3; replaceHashPath(encodedPath2); } - var prevIndex = allPaths.indexOf(createPath(history2.location)); + var prevIndex = allPaths.indexOf(createPath(history3.location)); if (prevIndex !== -1) allPaths[prevIndex] = path3; setState({ @@ -23804,7 +27944,7 @@ function createHashHistory(props) { unlisten(); }; } - var history2 = { + var history3 = { length: globalHistory.length, action: "POP", location: initialLocation, @@ -23817,10 +27957,10 @@ function createHashHistory(props) { block, listen }; - return history2; + return history3; } -// src/ApplicationReadyRoutes.tsx +// src/Routing.tsx init_preact_module(); // ../../node_modules/.pnpm/preact-router@3.2.1_preact@10.11.3/node_modules/preact-router/dist/preact-router.es.js @@ -24112,9 +28252,667 @@ Router.Route = Route; Router.Link = Link; Router.exec = exec; -// src/ApplicationReadyRoutes.tsx +// src/Routing.tsx +init_hooks_module(); + +// src/components/exception/loading.tsx +init_preact_module(); +function Loading() { + return /* @__PURE__ */ h( + "div", + { + class: "columns is-centered is-vcentered", + style: { + height: "calc(100% - 3rem)", + position: "absolute", + width: "100%" + } + }, + /* @__PURE__ */ h(Spinner, null) + ); +} +function Spinner() { + return /* @__PURE__ */ h("div", { class: "lds-ring" }, /* @__PURE__ */ h("div", null), /* @__PURE__ */ h("div", null), /* @__PURE__ */ h("div", null), /* @__PURE__ */ h("div", null)); +} + +// src/components/menu/index.tsx +init_preact_module(); init_hooks_module(); +// src/AdminRoutes.tsx +init_preact_module(); + +// src/paths/admin/create/index.tsx +init_preact_module(); +init_hooks_module(); + +// src/context/session.ts +var codecForSessionStateLoggedIn = () => buildCodecForObject().property("status", codecForConstString("loggedIn")).property("instance", codecForString()).property("impersonate", codecOptional(codecForImpresonate())).property("token", codecOptional(codecForString())).property("isAdmin", codecForBoolean()).build("SessionState.LoggedIn"); +var codecForSessionStateExpired = () => buildCodecForObject().property("status", codecForConstString("expired")).property("instance", codecForString()).property("impersonate", codecOptional(codecForImpresonate())).property("isAdmin", codecForBoolean()).build("SessionState.Expired"); +var codecForSessionStateLoggedOut = () => buildCodecForObject().property("status", codecForConstString("loggedOut")).property("instance", codecForString()).property("isAdmin", codecForBoolean()).build("SessionState.LoggedOut"); +var codecForImpresonate = () => buildCodecForObject().property("originalInstance", codecForString()).property( + "originalToken", + codecOptional(codecForString()) +).property("originalBackendUrl", codecForString()).build("SessionState.Impersonate"); +var codecForSessionState = () => buildCodecForUnion().discriminateOn("status").alternative("loggedIn", codecForSessionStateLoggedIn()).alternative("loggedOut", codecForSessionStateLoggedOut()).alternative("expired", codecForSessionStateExpired()).build("SessionState"); +function inferInstanceName(url) { + const match6 = INSTANCE_ID_LOOKUP.exec(url.href); + return !match6 || !match6[1] ? DEFAULT_ADMIN_USERNAME : match6[1]; +} +var defaultState = (url) => { + const instance = inferInstanceName(url); + return { + status: "loggedIn", + instance, + isAdmin: instance === DEFAULT_ADMIN_USERNAME, + token: void 0, + impersonate: void 0 + }; +}; +var SESSION_STATE_KEY = buildStorageKey( + "merchant-session", + codecForSessionState() +); +var DEFAULT_ADMIN_USERNAME = "default"; +var INSTANCE_ID_LOOKUP = /\/instances\/([^/]*)\/?$/; +function useSessionContext() { + const { url: merchantUrl, changeBackend } = useMerchantApiContext(); + const { value: state, update } = useLocalStorage( + SESSION_STATE_KEY, + defaultState(merchantUrl) + ); + return { + state, + logOut() { + const instance = inferInstanceName(merchantUrl); + const nextState = { + status: "loggedOut", + instance, + isAdmin: instance === DEFAULT_ADMIN_USERNAME + }; + update(nextState); + }, + deImpersonate() { + if (state.status === "loggedOut" || state.status === "expired") { + return; + } + if (state.impersonate === void 0) { + return; + } + const newURL = new URL(`./`, state.impersonate.originalBackendUrl); + changeBackend(newURL); + const nextState = { + status: "loggedIn", + isAdmin: state.impersonate.originalInstance === DEFAULT_ADMIN_USERNAME, + instance: state.impersonate.originalInstance, + token: state.impersonate.originalToken, + impersonate: void 0 + }; + update(nextState); + }, + impersonate(info) { + if (state.status === "loggedOut" || state.status === "expired") { + return; + } + changeBackend(info.baseUrl); + const nextState = { + status: "loggedIn", + isAdmin: info.instance === DEFAULT_ADMIN_USERNAME, + instance: info.instance, + // FIXME: bank and merchant should have consistent behavior + token: info.token?.substring("secret-token:".length), + impersonate: { + originalBackendUrl: merchantUrl.href, + originalToken: state.token, + originalInstance: state.instance + } + }; + update(nextState); + }, + expired() { + if (state.status === "loggedOut") + return; + const nextState = { + ...state, + status: "expired", + token: void 0 + }; + update(nextState); + }, + logIn(info) { + const nextState = { + impersonate: void 0, + ...state, + status: "loggedIn", + // FIXME: bank and merchant should have consistent behavior + token: info.token?.substring("secret-token:".length) + // token: info.token, + }; + update(nextState); + cleanAllCache(); + } + }; +} +function cleanAllCache() { + mutate(() => true, void 0, { revalidate: false }); +} + +// src/paths/admin/create/CreatePage.tsx +init_preact_module(); +init_hooks_module(); + +// src/components/exception/AsyncButton.tsx +init_preact_module(); + +// src/components/modal/index.tsx +init_preact_module(); +init_hooks_module(); + +// src/utils/constants.ts +var PAYTO_REGEX = /^payto:\/\/[a-zA-Z][a-zA-Z0-9-.]+(\/[a-zA-Z0-9\-\.\~\(\)@_%:!$&'*+,;=]*)*\??((amount|receiver-name|sender-name|instruction|message)=[a-zA-Z0-9\-\.\~\(\)@_%:!$'*+,;=]*&?)*$/; +var CROCKFORD_BASE32_REGEX = /^[0123456789ABCDEFGHJKMNPQRSTVWXYZ]+[*~$=U]*$/; +var URL_REGEX = /^((https?:)(\/\/\/?)([\w]*(?::[\w]*)?@)?([\d\w\.-]+)(?::(\d+))?)\/$/; +var PAGINATED_LIST_SIZE = 5; +var PAGINATED_LIST_REQUEST = PAGINATED_LIST_SIZE + 1; +var DEFAULT_REQUEST_TIMEOUT = 10; +var MAX_IMAGE_SIZE = 1024 * 1024; +var INSTANCE_ID_REGEX = /^[a-zA-Z0-9][a-zA-Z0-9_.@-]+$/; +var COUNTRY_TABLE = { + AE: "U.A.E.", + AF: "Afghanistan", + AL: "Albania", + AM: "Armenia", + AN: "Netherlands Antilles", + AR: "Argentina", + AT: "Austria", + AU: "Australia", + AZ: "Azerbaijan", + BA: "Bosnia and Herzegovina", + BD: "Bangladesh", + BE: "Belgium", + BG: "Bulgaria", + BH: "Bahrain", + BN: "Brunei Darussalam", + BO: "Bolivia", + BR: "Brazil", + BT: "Bhutan", + BY: "Belarus", + BZ: "Belize", + CA: "Canada", + CG: "Congo", + CH: "Switzerland", + CI: "Cote d'Ivoire", + CL: "Chile", + CM: "Cameroon", + CN: "People's Republic of China", + CO: "Colombia", + CR: "Costa Rica", + CS: "Serbia and Montenegro", + CZ: "Czech Republic", + DE: "Germany", + DK: "Denmark", + DO: "Dominican Republic", + DZ: "Algeria", + EC: "Ecuador", + EE: "Estonia", + EG: "Egypt", + ER: "Eritrea", + ES: "Spain", + ET: "Ethiopia", + FI: "Finland", + FO: "Faroe Islands", + FR: "France", + GB: "United Kingdom", + GD: "Caribbean", + GE: "Georgia", + GL: "Greenland", + GR: "Greece", + GT: "Guatemala", + HK: "Hong Kong", + // HK: "Hong Kong S.A.R.", + HN: "Honduras", + HR: "Croatia", + HT: "Haiti", + HU: "Hungary", + ID: "Indonesia", + IE: "Ireland", + IL: "Israel", + IN: "India", + IQ: "Iraq", + IR: "Iran", + IS: "Iceland", + IT: "Italy", + JM: "Jamaica", + JO: "Jordan", + JP: "Japan", + KE: "Kenya", + KG: "Kyrgyzstan", + KH: "Cambodia", + KR: "South Korea", + KW: "Kuwait", + KZ: "Kazakhstan", + LA: "Laos", + LB: "Lebanon", + LI: "Liechtenstein", + LK: "Sri Lanka", + LT: "Lithuania", + LU: "Luxembourg", + LV: "Latvia", + LY: "Libya", + MA: "Morocco", + MC: "Principality of Monaco", + MD: "Moldava", + // MD: "Moldova", + ME: "Montenegro", + MK: "Former Yugoslav Republic of Macedonia", + ML: "Mali", + MM: "Myanmar", + MN: "Mongolia", + MO: "Macau S.A.R.", + MT: "Malta", + MV: "Maldives", + MX: "Mexico", + MY: "Malaysia", + NG: "Nigeria", + NI: "Nicaragua", + NL: "Netherlands", + NO: "Norway", + NP: "Nepal", + NZ: "New Zealand", + OM: "Oman", + PA: "Panama", + PE: "Peru", + PH: "Philippines", + PK: "Islamic Republic of Pakistan", + PL: "Poland", + PR: "Puerto Rico", + PT: "Portugal", + PY: "Paraguay", + QA: "Qatar", + RE: "Reunion", + RO: "Romania", + RS: "Serbia", + RU: "Russia", + RW: "Rwanda", + SA: "Saudi Arabia", + SE: "Sweden", + SG: "Singapore", + SI: "Slovenia", + SK: "Slovak", + SN: "Senegal", + SO: "Somalia", + SR: "Suriname", + SV: "El Salvador", + SY: "Syria", + TH: "Thailand", + TJ: "Tajikistan", + TM: "Turkmenistan", + TN: "Tunisia", + TR: "Turkey", + TT: "Trinidad and Tobago", + TW: "Taiwan", + TZ: "Tanzania", + UA: "Ukraine", + US: "United States", + UY: "Uruguay", + VA: "Vatican", + VE: "Venezuela", + VN: "Viet Nam", + YE: "Yemen", + ZA: "South Africa", + ZW: "Zimbabwe" +}; + +// src/components/form/FormProvider.tsx +init_preact_module(); +init_hooks_module(); +var noUpdater = () => (s5) => s5; +function FormProvider({ + object: object2 = {}, + errors: errors2 = {}, + name = "", + valueHandler, + children +}) { + const initialObject = F(() => object2, []); + const value = F( + () => ({ + errors: errors2, + object: object2, + initialObject, + valueHandler: valueHandler ? valueHandler : noUpdater, + name, + toStr: {}, + fromStr: {} + }), + [errors2, object2, valueHandler] + ); + return /* @__PURE__ */ h(FormContext2.Provider, { value }, /* @__PURE__ */ h( + "form", + { + class: "field", + onSubmit: (e4) => { + e4.preventDefault(); + } + }, + children + )); +} +var FormContext2 = B(null); +function useFormContext() { + return q2(FormContext2); +} + +// src/components/form/Input.tsx +init_preact_module(); + +// src/components/form/useField.tsx +init_hooks_module(); +function useField(name) { + const { errors: errors2, object: object2, initialObject, toStr, fromStr, valueHandler } = useFormContext(); + const [isDirty, setDirty] = p3(false); + const updateField = (field) => (value2) => { + setDirty(true); + return valueHandler((prev) => { + return setValueDeeper(prev, String(field).split("."), value2); + }); + }; + const defaultToString4 = (f3) => String(!f3 ? "" : f3); + const defaultFromString4 = (v3) => v3; + const value = readField(object2, String(name)); + const initial3 = readField(initialObject, String(name)); + const hasError = readField(errors2, String(name)); + return { + error: isDirty ? hasError : void 0, + required: !isDirty && hasError, + value, + initial: initial3, + onChange: updateField(name), + toStr: toStr[name] ? toStr[name] : defaultToString4, + fromStr: fromStr[name] ? fromStr[name] : defaultFromString4 + }; +} +var readField = (object2, name) => { + return name.split(".").reduce((prev, current) => prev && prev[current], object2); +}; +var setValueDeeper = (object2, names2, value) => { + if (names2.length === 0) + return value; + const [head, ...rest] = names2; + return { ...object2, [head]: setValueDeeper(object2[head] || {}, rest, value) }; +}; + +// src/components/form/Input.tsx +var defaultToString = (f3) => f3 || ""; +var defaultFromString = (v3) => v3; +var TextInput = ({ inputType, error: error2, ...rest }) => inputType === "multiline" ? /* @__PURE__ */ h( + "textarea", + { + ...rest, + class: error2 ? "textarea is-danger" : "textarea", + rows: "3" + } +) : /* @__PURE__ */ h( + "input", + { + ...rest, + class: error2 ? "input is-danger" : "input", + type: inputType + } +); +function Input({ + name, + readonly, + placeholder, + tooltip, + label, + expand, + help, + children, + inputType, + inputExtra, + side, + fromStr = defaultFromString, + toStr = defaultToString +}) { + const { error: error2, value, onChange, required } = useField(name); + return /* @__PURE__ */ h("div", { class: "field is-horizontal" }, /* @__PURE__ */ h("div", { class: "field-label is-normal" }, /* @__PURE__ */ h("label", { class: "label" }, label, tooltip && /* @__PURE__ */ h("span", { class: "icon has-tooltip-right", "data-tooltip": tooltip }, /* @__PURE__ */ h("i", { class: "mdi mdi-information" })))), /* @__PURE__ */ h("div", { class: "field-body is-flex-grow-3" }, /* @__PURE__ */ h("div", { class: "field" }, /* @__PURE__ */ h( + "p", + { + class: expand ? "control is-expanded has-icons-right" : "control has-icons-right" + }, + /* @__PURE__ */ h( + TextInput, + { + error: error2, + ...inputExtra, + inputType, + placeholder, + readonly, + disabled: readonly, + name: String(name), + value: toStr(value), + onChange: (e4) => onChange(fromStr(e4.currentTarget.value)) + } + ), + help, + children, + required && /* @__PURE__ */ h("span", { class: "icon has-text-danger is-right" }, /* @__PURE__ */ h("i", { class: "mdi mdi-alert" })) + ), error2 && /* @__PURE__ */ h("p", { class: "help is-danger" }, error2)), side)); +} + +// src/components/modal/index.tsx +function ConfirmModal({ + active, + description, + onCancel, + onConfirm, + children, + danger, + disabled, + label = "Confirm" +}) { + const { i18n: i18n2 } = useTranslationContext(); + return /* @__PURE__ */ h("div", { class: active ? "modal is-active" : "modal" }, /* @__PURE__ */ h("div", { class: "modal-background ", onClick: onCancel }), /* @__PURE__ */ h("div", { class: "modal-card", style: { maxWidth: 700 } }, /* @__PURE__ */ h("header", { class: "modal-card-head" }, !description ? null : /* @__PURE__ */ h("p", { class: "modal-card-title" }, /* @__PURE__ */ h("b", null, description)), /* @__PURE__ */ h("button", { class: "delete ", "aria-label": "close", onClick: onCancel })), /* @__PURE__ */ h("section", { class: "modal-card-body" }, children), /* @__PURE__ */ h("footer", { class: "modal-card-foot" }, /* @__PURE__ */ h("div", { class: "buttons is-right", style: { width: "100%" } }, onConfirm ? /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h("button", { class: "button ", onClick: onCancel }, /* @__PURE__ */ h(i18n2.Translate, null, "Cancel")), /* @__PURE__ */ h( + "button", + { + class: danger ? "button is-danger " : "button is-info ", + disabled, + onClick: onConfirm + }, + /* @__PURE__ */ h(i18n2.Translate, null, label) + )) : /* @__PURE__ */ h("button", { class: "button ", onClick: onCancel }, /* @__PURE__ */ h(i18n2.Translate, null, "Close"))))), /* @__PURE__ */ h( + "button", + { + class: "modal-close is-large ", + "aria-label": "close", + onClick: onCancel + } + )); +} +function SimpleModal({ onCancel, children }) { + return /* @__PURE__ */ h("div", { class: "modal is-active" }, /* @__PURE__ */ h("div", { class: "modal-background ", onClick: onCancel }), /* @__PURE__ */ h("div", { class: "modal-card" }, /* @__PURE__ */ h("section", { class: "modal-card-body is-main-section" }, children)), /* @__PURE__ */ h( + "button", + { + class: "modal-close is-large ", + "aria-label": "close", + onClick: onCancel + } + )); +} +function DeleteModal({ + element, + onCancel, + onConfirm +}) { + return /* @__PURE__ */ h( + ConfirmModal, + { + label: `Delete instance`, + description: `Delete the instance "${element.name}"`, + danger: true, + active: true, + onCancel, + onConfirm: () => onConfirm(element.id) + }, + /* @__PURE__ */ h("p", null, "If you delete the instance named ", /* @__PURE__ */ h("b", null, '"', element.name, '"'), " (ID:", " ", /* @__PURE__ */ h("b", null, element.id), "), the merchant will no longer be able to process orders or refunds"), + /* @__PURE__ */ h("p", null, "This action deletes the instance private key, but preserves all transaction data. You can still access that data after deleting the instance."), + /* @__PURE__ */ h("p", { class: "warning" }, "Deleting an instance ", /* @__PURE__ */ h("b", null, "cannot be undone"), ".") + ); +} +function PurgeModal({ + element, + onCancel, + onConfirm +}) { + return /* @__PURE__ */ h( + ConfirmModal, + { + label: `Purge the instance`, + description: `Purge the instance "${element.name}"`, + danger: true, + active: true, + onCancel, + onConfirm: () => onConfirm(element.id) + }, + /* @__PURE__ */ h("p", null, "If you purge the instance named ", /* @__PURE__ */ h("b", null, '"', element.name, '"'), " (ID:", " ", /* @__PURE__ */ h("b", null, element.id), "), you will also delete all it's transaction data."), + /* @__PURE__ */ h("p", null, "The instance will disappear from your list, and you will no longer be able to access it's data."), + /* @__PURE__ */ h("p", { class: "warning" }, "Purging an instance ", /* @__PURE__ */ h("b", null, "cannot be undone"), ".") + ); +} +function SetTokenNewInstanceModal({ + onCancel, + onClear, + onConfirm +}) { + const [form, setValue] = p3({ + new_token: "", + repeat_token: "" + }); + const { i18n: i18n2 } = useTranslationContext(); + const errors2 = { + new_token: !form.new_token ? i18n2.str`cannot be empty` : form.new_token === form.old_token ? i18n2.str`cannot be the same as the old access token` : void 0, + repeat_token: form.new_token !== form.repeat_token ? i18n2.str`is not the same` : void 0 + }; + const hasErrors = Object.keys(errors2).some( + (k5) => errors2[k5] !== void 0 + ); + return /* @__PURE__ */ h("div", { class: "modal is-active" }, /* @__PURE__ */ h("div", { class: "modal-background ", onClick: onCancel }), /* @__PURE__ */ h("div", { class: "modal-card" }, /* @__PURE__ */ h("header", { class: "modal-card-head" }, /* @__PURE__ */ h("p", { class: "modal-card-title" }, i18n2.str`You are setting the access token for the new instance`), /* @__PURE__ */ h("button", { class: "delete ", "aria-label": "close", onClick: onCancel })), /* @__PURE__ */ h("section", { class: "modal-card-body is-main-section" }, /* @__PURE__ */ h("div", { class: "columns" }, /* @__PURE__ */ h("div", { class: "column" }), /* @__PURE__ */ h("div", { class: "column is-four-fifths" }, /* @__PURE__ */ h( + FormProvider, + { + errors: errors2, + object: form, + valueHandler: setValue + }, + /* @__PURE__ */ h( + Input, + { + name: "new_token", + label: i18n2.str`New access token`, + tooltip: i18n2.str`next access token to be used`, + inputType: "password" + } + ), + /* @__PURE__ */ h( + Input, + { + name: "repeat_token", + label: i18n2.str`Repeat access token`, + tooltip: i18n2.str`confirm the same access token`, + inputType: "password" + } + ) + ), /* @__PURE__ */ h("p", null, /* @__PURE__ */ h(i18n2.Translate, null, "With external authorization method no check will be done by the merchant backend"))), /* @__PURE__ */ h("div", { class: "column" }))), /* @__PURE__ */ h("footer", { class: "modal-card-foot" }, onClear && /* @__PURE__ */ h( + "button", + { + class: "button is-danger", + onClick: onClear, + disabled: onClear === void 0 + }, + /* @__PURE__ */ h(i18n2.Translate, null, "Set external authorization") + ), /* @__PURE__ */ h("div", { class: "buttons is-right", style: { width: "100%" } }, /* @__PURE__ */ h("button", { class: "button ", onClick: onCancel }, /* @__PURE__ */ h(i18n2.Translate, null, "Cancel")), /* @__PURE__ */ h( + "button", + { + class: "button is-info", + onClick: () => onConfirm(form.new_token), + disabled: hasErrors + }, + /* @__PURE__ */ h(i18n2.Translate, null, "Set access token") + )))), /* @__PURE__ */ h( + "button", + { + class: "modal-close is-large ", + "aria-label": "close", + onClick: onCancel + } + )); +} +function LoadingModal({ onCancel }) { + const { i18n: i18n2 } = useTranslationContext(); + return /* @__PURE__ */ h("div", { class: "modal is-active" }, /* @__PURE__ */ h("div", { class: "modal-background ", onClick: onCancel }), /* @__PURE__ */ h("div", { class: "modal-card" }, /* @__PURE__ */ h("header", { class: "modal-card-head" }, /* @__PURE__ */ h("p", { class: "modal-card-title" }, /* @__PURE__ */ h(i18n2.Translate, null, "Operation in progress..."))), /* @__PURE__ */ h("section", { class: "modal-card-body" }, /* @__PURE__ */ h("div", { class: "columns" }, /* @__PURE__ */ h("div", { class: "column" }), /* @__PURE__ */ h(Spinner, null), /* @__PURE__ */ h("div", { class: "column" })), /* @__PURE__ */ h("p", null, i18n2.str`The operation will be automatically canceled after ${DEFAULT_REQUEST_TIMEOUT} seconds`)), /* @__PURE__ */ h("footer", { class: "modal-card-foot" }, /* @__PURE__ */ h("div", { class: "buttons is-right", style: { width: "100%" } }, /* @__PURE__ */ h("button", { class: "button ", onClick: onCancel }, /* @__PURE__ */ h(i18n2.Translate, null, "Cancel"))))), /* @__PURE__ */ h( + "button", + { + class: "modal-close is-large ", + "aria-label": "close", + onClick: onCancel + } + )); +} + +// src/hooks/async.ts +init_hooks_module(); +function useAsync(fn2, { slowTolerance: tooLong } = { slowTolerance: 1e3 }) { + const [data, setData] = p3(void 0); + const [isLoading, setLoading] = p3(false); + const [error2, setError] = p3(void 0); + const [isSlow, setSlow] = p3(false); + const request = async (...args) => { + if (!fn2) + return; + setLoading(true); + const handler = setTimeout(() => { + setSlow(true); + }, tooLong); + try { + const result = await fn2(...args); + setData(result); + } catch (error3) { + setError(error3); + } + setLoading(false); + setSlow(false); + clearTimeout(handler); + }; + function cancel() { + setLoading(false); + setSlow(false); + } + return { + request, + cancel, + data, + isSlow, + isLoading, + error: error2 + }; +} + +// src/components/exception/AsyncButton.tsx +function AsyncButton({ onClick, disabled, children, ...rest }) { + const { isSlow, isLoading, request, cancel } = useAsync(onClick); + const { i18n: i18n2 } = useTranslationContext(); + if (isSlow) { + return /* @__PURE__ */ h(LoadingModal, { onCancel: cancel }); + } + if (isLoading) { + return /* @__PURE__ */ h("button", { class: "button" }, /* @__PURE__ */ h(i18n2.Translate, null, "Loading...")); + } + return /* @__PURE__ */ h("span", { ...rest }, /* @__PURE__ */ h("button", { class: "button is-success", onClick: request, disabled }, children)); +} + +// src/components/instance/DefaultInstanceFormFields.tsx +init_preact_module(); + // ../../node_modules/.pnpm/date-fns@2.29.3/node_modules/date-fns/esm/_lib/toInteger/index.js function toInteger2(dirtyNumber) { if (dirtyNumber === null || dirtyNumber === true || dirtyNumber === false) { @@ -26172,2054 +30970,6 @@ function isFuture(dirtyDate) { return toDate2(dirtyDate).getTime() > Date.now(); } -// src/InstanceRoutes.tsx -init_preact_module(); -init_hooks_module(); - -// src/components/exception/loading.tsx -init_preact_module(); -function Loading() { - return /* @__PURE__ */ h( - "div", - { - class: "columns is-centered is-vcentered", - style: { - height: "calc(100% - 3rem)", - position: "absolute", - width: "100%" - } - }, - /* @__PURE__ */ h(Spinner, null) - ); -} -function Spinner() { - return /* @__PURE__ */ h("div", { class: "lds-ring" }, /* @__PURE__ */ h("div", null), /* @__PURE__ */ h("div", null), /* @__PURE__ */ h("div", null), /* @__PURE__ */ h("div", null)); -} - -// src/components/menu/index.tsx -init_preact_module(); -init_hooks_module(); - -// src/AdminRoutes.tsx -init_preact_module(); - -// src/paths/admin/create/index.tsx -init_preact_module(); -init_hooks_module(); - -// src/context/backend.ts -init_preact_module(); -init_hooks_module(); - -// src/hooks/index.ts -init_hooks_module(); -var calculateRootPath = () => { - const rootPath = typeof window !== void 0 ? window.location.origin + window.location.pathname : "/"; - return rootPath.replace("/webui/", ""); -}; -var loginTokenCodec = buildCodecForObject().property("token", codecForString()).property("expiration", codecForTimestamp).build("loginToken"); -var TOKENS_KEY = buildStorageKey("merchant-token", codecForMap(loginTokenCodec)); -function useBackendURL(url) { - const [value, setter] = useSimpleLocalStorage( - "merchant-base-url", - url || calculateRootPath() - ); - const checkedSetter = (v3) => { - return setter((p4) => (v3 instanceof Function ? v3(p4 ?? "") : v3).replace(/\/$/, "")); - }; - return [value, checkedSetter]; -} -function useBackendDefaultToken() { - const { update: setToken, value: tokenMap, reset } = useLocalStorage(TOKENS_KEY, {}); - function updateToken(value) { - if (value === void 0) { - reset(); - } else { - const res = { ...tokenMap, "default": value }; - setToken(res); - } - } - return [tokenMap["default"], updateToken]; -} -function useBackendInstanceToken(id) { - const { update: setToken, value: tokenMap, reset } = useLocalStorage(TOKENS_KEY, {}); - const [defaultToken, defaultSetToken] = useBackendDefaultToken(); - if (id === "default") { - return [defaultToken, defaultSetToken]; - } - function updateToken(value) { - if (value === void 0) { - reset(); - } else { - const res = { ...tokenMap, [id]: value }; - setToken(res); - } - } - return [tokenMap[id], updateToken]; -} -function useSimpleLocalStorage(key, initialValue) { - const [storedValue, setStoredValue] = p3( - () => { - return typeof window !== "undefined" ? window.localStorage.getItem(key) || initialValue : initialValue; - } - ); - const setValue = (value) => { - setStoredValue((p4) => { - const toStore = value instanceof Function ? value(p4) : value; - if (typeof window !== "undefined") { - if (!toStore) { - window.localStorage.removeItem(key); - } else { - window.localStorage.setItem(key, toStore); - } - } - return toStore; - }); - }; - return [storedValue, setValue]; -} - -// src/context/backend.ts -var BackendContext = B({ - url: "", - alreadyTriedLogin: false, - token: void 0, - updateToken: () => null -}); -function useBackendContextState(defaultUrl) { - const [url] = useBackendURL(defaultUrl); - const [token, updateToken] = useBackendDefaultToken(); - return { - url, - token, - alreadyTriedLogin: token !== void 0, - updateToken - }; -} -var BackendContextProvider = ({ - children, - defaultUrl -}) => { - const value = useBackendContextState(defaultUrl); - return h(BackendContext.Provider, { value, children }); -}; -var useBackendContext = () => q2(BackendContext); - -// src/hooks/backend.ts -init_hooks_module(); - -// ../../node_modules/.pnpm/swr@2.2.2_react@18.2.0/node_modules/swr/core/dist/index.mjs -init_compat_module(); -var import_shim = __toESM(require_shim(), 1); - -// ../../node_modules/.pnpm/swr@2.2.2_react@18.2.0/node_modules/swr/_internal/dist/index.mjs -init_compat_module(); -var noop = () => { -}; -var UNDEFINED = ( - /*#__NOINLINE__*/ - noop() -); -var OBJECT = Object; -var isUndefined = (v3) => v3 === UNDEFINED; -var isFunction = (v3) => typeof v3 == "function"; -var mergeObjects = (a5, b4) => ({ - ...a5, - ...b4 -}); -var isPromiseLike = (x6) => isFunction(x6.then); -var table = /* @__PURE__ */ new WeakMap(); -var counter = 0; -var stableHash = (arg) => { - const type = typeof arg; - const constructor = arg && arg.constructor; - const isDate3 = constructor == Date; - let result; - let index; - if (OBJECT(arg) === arg && !isDate3 && constructor != RegExp) { - result = table.get(arg); - if (result) - return result; - result = ++counter + "~"; - table.set(arg, result); - if (constructor == Array) { - result = "@"; - for (index = 0; index < arg.length; index++) { - result += stableHash(arg[index]) + ","; - } - table.set(arg, result); - } - if (constructor == OBJECT) { - result = "#"; - const keys = OBJECT.keys(arg).sort(); - while (!isUndefined(index = keys.pop())) { - if (!isUndefined(arg[index])) { - result += index + ":" + stableHash(arg[index]) + ","; - } - } - table.set(arg, result); - } - } else { - result = isDate3 ? arg.toJSON() : type == "symbol" ? arg.toString() : type == "string" ? JSON.stringify(arg) : "" + arg; - } - return result; -}; -var SWRGlobalState = /* @__PURE__ */ new WeakMap(); -var EMPTY_CACHE = {}; -var INITIAL_CACHE = {}; -var STR_UNDEFINED = "undefined"; -var isWindowDefined = typeof window != STR_UNDEFINED; -var isDocumentDefined = typeof document != STR_UNDEFINED; -var hasRequestAnimationFrame = () => isWindowDefined && typeof window["requestAnimationFrame"] != STR_UNDEFINED; -var createCacheHelper = (cache2, key) => { - const state = SWRGlobalState.get(cache2); - return [ - // Getter - () => !isUndefined(key) && cache2.get(key) || EMPTY_CACHE, - // Setter - (info) => { - if (!isUndefined(key)) { - const prev = cache2.get(key); - if (!(key in INITIAL_CACHE)) { - INITIAL_CACHE[key] = prev; - } - state[5](key, mergeObjects(prev, info), prev || EMPTY_CACHE); - } - }, - // Subscriber - state[6], - // Get server cache snapshot - () => { - if (!isUndefined(key)) { - if (key in INITIAL_CACHE) - return INITIAL_CACHE[key]; - } - return !isUndefined(key) && cache2.get(key) || EMPTY_CACHE; - } - ]; -}; -var online = true; -var isOnline = () => online; -var [onWindowEvent, offWindowEvent] = isWindowDefined && window.addEventListener ? [ - window.addEventListener.bind(window), - window.removeEventListener.bind(window) -] : [ - noop, - noop -]; -var isVisible = () => { - const visibilityState = isDocumentDefined && document.visibilityState; - return isUndefined(visibilityState) || visibilityState !== "hidden"; -}; -var initFocus = (callback) => { - if (isDocumentDefined) { - document.addEventListener("visibilitychange", callback); - } - onWindowEvent("focus", callback); - return () => { - if (isDocumentDefined) { - document.removeEventListener("visibilitychange", callback); - } - offWindowEvent("focus", callback); - }; -}; -var initReconnect = (callback) => { - const onOnline = () => { - online = true; - callback(); - }; - const onOffline = () => { - online = false; - }; - onWindowEvent("online", onOnline); - onWindowEvent("offline", onOffline); - return () => { - offWindowEvent("online", onOnline); - offWindowEvent("offline", onOffline); - }; -}; -var preset = { - isOnline, - isVisible -}; -var defaultConfigOptions = { - initFocus, - initReconnect -}; -var IS_REACT_LEGACY = !bn.useId; -var IS_SERVER = !isWindowDefined || "Deno" in window; -var rAF = (f3) => hasRequestAnimationFrame() ? window["requestAnimationFrame"](f3) : setTimeout(f3, 1); -var useIsomorphicLayoutEffect = IS_SERVER ? h2 : s2; -var navigatorConnection = typeof navigator !== "undefined" && navigator.connection; -var slowConnection = !IS_SERVER && navigatorConnection && ([ - "slow-2g", - "2g" -].includes(navigatorConnection.effectiveType) || navigatorConnection.saveData); -var serialize = (key) => { - if (isFunction(key)) { - try { - key = key(); - } catch (err) { - key = ""; - } - } - const args = key; - key = typeof key == "string" ? key : (Array.isArray(key) ? key.length : key) ? stableHash(key) : ""; - return [ - key, - args - ]; -}; -var __timestamp = 0; -var getTimestamp = () => ++__timestamp; -var FOCUS_EVENT = 0; -var RECONNECT_EVENT = 1; -var MUTATE_EVENT = 2; -var ERROR_REVALIDATE_EVENT = 3; -var events = { - __proto__: null, - ERROR_REVALIDATE_EVENT, - FOCUS_EVENT, - MUTATE_EVENT, - RECONNECT_EVENT -}; -async function internalMutate(...args) { - const [cache2, _key, _data, _opts] = args; - const options = mergeObjects({ - populateCache: true, - throwOnError: true - }, typeof _opts === "boolean" ? { - revalidate: _opts - } : _opts || {}); - let populateCache = options.populateCache; - const rollbackOnErrorOption = options.rollbackOnError; - let optimisticData = options.optimisticData; - const revalidate = options.revalidate !== false; - const rollbackOnError = (error2) => { - return typeof rollbackOnErrorOption === "function" ? rollbackOnErrorOption(error2) : rollbackOnErrorOption !== false; - }; - const throwOnError = options.throwOnError; - if (isFunction(_key)) { - const keyFilter = _key; - const matchedKeys = []; - const it = cache2.keys(); - for (const key of it) { - if ( - // Skip the special useSWRInfinite and useSWRSubscription keys. - !/^\$(inf|sub)\$/.test(key) && keyFilter(cache2.get(key)._k) - ) { - matchedKeys.push(key); - } - } - return Promise.all(matchedKeys.map(mutateByKey)); - } - return mutateByKey(_key); - async function mutateByKey(_k) { - const [key] = serialize(_k); - if (!key) - return; - const [get, set2] = createCacheHelper(cache2, key); - const [EVENT_REVALIDATORS, MUTATION, FETCH, PRELOAD] = SWRGlobalState.get(cache2); - const startRevalidate = () => { - const revalidators = EVENT_REVALIDATORS[key]; - if (revalidate) { - delete FETCH[key]; - delete PRELOAD[key]; - if (revalidators && revalidators[0]) { - return revalidators[0](MUTATE_EVENT).then(() => get().data); - } - } - return get().data; - }; - if (args.length < 3) { - return startRevalidate(); - } - let data = _data; - let error2; - const beforeMutationTs = getTimestamp(); - MUTATION[key] = [ - beforeMutationTs, - 0 - ]; - const hasOptimisticData = !isUndefined(optimisticData); - const state = get(); - const displayedData = state.data; - const currentData = state._c; - const committedData = isUndefined(currentData) ? displayedData : currentData; - if (hasOptimisticData) { - optimisticData = isFunction(optimisticData) ? optimisticData(committedData, displayedData) : optimisticData; - set2({ - data: optimisticData, - _c: committedData - }); - } - if (isFunction(data)) { - try { - data = data(committedData); - } catch (err) { - error2 = err; - } - } - if (data && isPromiseLike(data)) { - data = await data.catch((err) => { - error2 = err; - }); - if (beforeMutationTs !== MUTATION[key][0]) { - if (error2) - throw error2; - return data; - } else if (error2 && hasOptimisticData && rollbackOnError(error2)) { - populateCache = true; - set2({ - data: committedData, - _c: UNDEFINED - }); - } - } - if (populateCache) { - if (!error2) { - if (isFunction(populateCache)) { - const populateCachedData = populateCache(data, committedData); - set2({ - data: populateCachedData, - error: UNDEFINED, - _c: UNDEFINED - }); - } else { - set2({ - data, - error: UNDEFINED, - _c: UNDEFINED - }); - } - } - } - MUTATION[key][1] = getTimestamp(); - Promise.resolve(startRevalidate()).then(() => { - set2({ - _c: UNDEFINED - }); - }); - if (error2) { - if (throwOnError) - throw error2; - return; - } - return data; - } -} -var revalidateAllKeys = (revalidators, type) => { - for (const key in revalidators) { - if (revalidators[key][0]) - revalidators[key][0](type); - } -}; -var initCache = (provider, options) => { - if (!SWRGlobalState.has(provider)) { - const opts = mergeObjects(defaultConfigOptions, options); - const EVENT_REVALIDATORS = {}; - const mutate2 = internalMutate.bind(UNDEFINED, provider); - let unmount = noop; - const subscriptions = {}; - const subscribe = (key, callback) => { - const subs = subscriptions[key] || []; - subscriptions[key] = subs; - subs.push(callback); - return () => subs.splice(subs.indexOf(callback), 1); - }; - const setter = (key, value, prev) => { - provider.set(key, value); - const subs = subscriptions[key]; - if (subs) { - for (const fn2 of subs) { - fn2(value, prev); - } - } - }; - const initProvider = () => { - if (!SWRGlobalState.has(provider)) { - SWRGlobalState.set(provider, [ - EVENT_REVALIDATORS, - {}, - {}, - {}, - mutate2, - setter, - subscribe - ]); - if (!IS_SERVER) { - const releaseFocus = opts.initFocus(setTimeout.bind(UNDEFINED, revalidateAllKeys.bind(UNDEFINED, EVENT_REVALIDATORS, FOCUS_EVENT))); - const releaseReconnect = opts.initReconnect(setTimeout.bind(UNDEFINED, revalidateAllKeys.bind(UNDEFINED, EVENT_REVALIDATORS, RECONNECT_EVENT))); - unmount = () => { - releaseFocus && releaseFocus(); - releaseReconnect && releaseReconnect(); - SWRGlobalState.delete(provider); - }; - } - } - }; - initProvider(); - return [ - provider, - mutate2, - initProvider, - unmount - ]; - } - return [ - provider, - SWRGlobalState.get(provider)[4] - ]; -}; -var onErrorRetry = (_3, __, config, revalidate, opts) => { - const maxRetryCount = config.errorRetryCount; - const currentRetryCount = opts.retryCount; - const timeout = ~~((Math.random() + 0.5) * (1 << (currentRetryCount < 8 ? currentRetryCount : 8))) * config.errorRetryInterval; - if (!isUndefined(maxRetryCount) && currentRetryCount > maxRetryCount) { - return; - } - setTimeout(revalidate, timeout, opts); -}; -var compare = (currentData, newData) => stableHash(currentData) == stableHash(newData); -var [cache, mutate] = initCache(/* @__PURE__ */ new Map()); -var defaultConfig = mergeObjects( - { - // events - onLoadingSlow: noop, - onSuccess: noop, - onError: noop, - onErrorRetry, - onDiscarded: noop, - // switches - revalidateOnFocus: true, - revalidateOnReconnect: true, - revalidateIfStale: true, - shouldRetryOnError: true, - // timeouts - errorRetryInterval: slowConnection ? 1e4 : 5e3, - focusThrottleInterval: 5 * 1e3, - dedupingInterval: 2 * 1e3, - loadingTimeout: slowConnection ? 5e3 : 3e3, - // providers - compare, - isPaused: () => false, - cache, - mutate, - fallback: {} - }, - // use web preset by default - preset -); -var mergeConfigs = (a5, b4) => { - const v3 = mergeObjects(a5, b4); - if (b4) { - const { use: u1, fallback: f1 } = a5; - const { use: u22, fallback: f22 } = b4; - if (u1 && u22) { - v3.use = u1.concat(u22); - } - if (f1 && f22) { - v3.fallback = mergeObjects(f1, f22); - } - } - return v3; -}; -var SWRConfigContext = B({}); -var SWRConfig = (props) => { - const { value } = props; - const parentConfig = q2(SWRConfigContext); - const isFunctionalConfig = isFunction(value); - const config = F(() => isFunctionalConfig ? value(parentConfig) : value, [ - isFunctionalConfig, - parentConfig, - value - ]); - const extendedConfig = F(() => isFunctionalConfig ? config : mergeConfigs(parentConfig, config), [ - isFunctionalConfig, - parentConfig, - config - ]); - const provider = config && config.provider; - const cacheContextRef = _2(UNDEFINED); - if (provider && !cacheContextRef.current) { - cacheContextRef.current = initCache(provider(extendedConfig.cache || cache), config); - } - const cacheContext = cacheContextRef.current; - if (cacheContext) { - extendedConfig.cache = cacheContext[0]; - extendedConfig.mutate = cacheContext[1]; - } - useIsomorphicLayoutEffect(() => { - if (cacheContext) { - cacheContext[2] && cacheContext[2](); - return cacheContext[3]; - } - }, []); - return h(SWRConfigContext.Provider, mergeObjects(props, { - value: extendedConfig - })); -}; -var INFINITE_PREFIX = "$inf$"; -var enableDevtools = isWindowDefined && window.__SWR_DEVTOOLS_USE__; -var use = enableDevtools ? window.__SWR_DEVTOOLS_USE__ : []; -var setupDevTools = () => { - if (enableDevtools) { - window.__SWR_DEVTOOLS_REACT__ = bn; - } -}; -var normalize = (args) => { - return isFunction(args[1]) ? [ - args[0], - args[1], - args[2] || {} - ] : [ - args[0], - null, - (args[1] === null ? args[2] : args[1]) || {} - ]; -}; -var useSWRConfig = () => { - return mergeObjects(defaultConfig, q2(SWRConfigContext)); -}; -var middleware = (useSWRNext) => (key_, fetcher_, config) => { - const fetcher = fetcher_ && ((...args) => { - const [key] = serialize(key_); - const [, , , PRELOAD] = SWRGlobalState.get(cache); - if (key.startsWith(INFINITE_PREFIX)) { - return fetcher_(...args); - } - const req = PRELOAD[key]; - if (isUndefined(req)) - return fetcher_(...args); - delete PRELOAD[key]; - return req; - }); - return useSWRNext(key_, fetcher, config); -}; -var BUILT_IN_MIDDLEWARE = use.concat(middleware); -var withArgs = (hook) => { - return function useSWRArgs(...args) { - const fallbackConfig = useSWRConfig(); - const [key, fn2, _config] = normalize(args); - const config = mergeConfigs(fallbackConfig, _config); - let next = hook; - const { use: use3 } = config; - const middleware2 = (use3 || []).concat(BUILT_IN_MIDDLEWARE); - for (let i4 = middleware2.length; i4--; ) { - next = middleware2[i4](next); - } - return next(key, fn2 || config.fetcher || null, config); - }; -}; -var subscribeCallback = (key, callbacks, callback) => { - const keyedRevalidators = callbacks[key] || (callbacks[key] = []); - keyedRevalidators.push(callback); - return () => { - const index = keyedRevalidators.indexOf(callback); - if (index >= 0) { - keyedRevalidators[index] = keyedRevalidators[keyedRevalidators.length - 1]; - keyedRevalidators.pop(); - } - }; -}; -setupDevTools(); - -// ../../node_modules/.pnpm/swr@2.2.2_react@18.2.0/node_modules/swr/core/dist/index.mjs -var use2 = bn.use || ((promise) => { - if (promise.status === "pending") { - throw promise; - } else if (promise.status === "fulfilled") { - return promise.value; - } else if (promise.status === "rejected") { - throw promise.reason; - } else { - promise.status = "pending"; - promise.then((v3) => { - promise.status = "fulfilled"; - promise.value = v3; - }, (e4) => { - promise.status = "rejected"; - promise.reason = e4; - }); - throw promise; - } -}); -var WITH_DEDUPE = { - dedupe: true -}; -var useSWRHandler = (_key, fetcher, config) => { - const { cache: cache2, compare: compare2, suspense, fallbackData, revalidateOnMount, revalidateIfStale, refreshInterval, refreshWhenHidden, refreshWhenOffline, keepPreviousData } = config; - const [EVENT_REVALIDATORS, MUTATION, FETCH, PRELOAD] = SWRGlobalState.get(cache2); - const [key, fnArg] = serialize(_key); - const initialMountedRef = _2(false); - const unmountedRef = _2(false); - const keyRef = _2(key); - const fetcherRef = _2(fetcher); - const configRef = _2(config); - const getConfig = () => configRef.current; - const isActive = () => getConfig().isVisible() && getConfig().isOnline(); - const [getCache, setCache, subscribeCache, getInitialCache] = createCacheHelper(cache2, key); - const stateDependencies = _2({}).current; - const fallback = isUndefined(fallbackData) ? config.fallback[key] : fallbackData; - const isEqual = (prev, current) => { - for (const _3 in stateDependencies) { - const t4 = _3; - if (t4 === "data") { - if (!compare2(prev[t4], current[t4])) { - if (!isUndefined(prev[t4])) { - return false; - } - if (!compare2(returnedData, current[t4])) { - return false; - } - } - } else { - if (current[t4] !== prev[t4]) { - return false; - } - } - } - return true; - }; - const getSnapshot = F(() => { - const shouldStartRequest = (() => { - if (!key) - return false; - if (!fetcher) - return false; - if (!isUndefined(revalidateOnMount)) - return revalidateOnMount; - if (getConfig().isPaused()) - return false; - if (suspense) - return false; - if (!isUndefined(revalidateIfStale)) - return revalidateIfStale; - return true; - })(); - const getSelectedCache = (state) => { - const snapshot = mergeObjects(state); - delete snapshot._k; - if (!shouldStartRequest) { - return snapshot; - } - return { - isValidating: true, - isLoading: true, - ...snapshot - }; - }; - const cachedData2 = getCache(); - const initialData = getInitialCache(); - const clientSnapshot = getSelectedCache(cachedData2); - const serverSnapshot = cachedData2 === initialData ? clientSnapshot : getSelectedCache(initialData); - let memorizedSnapshot = clientSnapshot; - return [ - () => { - const newSnapshot = getSelectedCache(getCache()); - const compareResult = isEqual(newSnapshot, memorizedSnapshot); - if (compareResult) { - memorizedSnapshot.data = newSnapshot.data; - memorizedSnapshot.isLoading = newSnapshot.isLoading; - memorizedSnapshot.isValidating = newSnapshot.isValidating; - memorizedSnapshot.error = newSnapshot.error; - return memorizedSnapshot; - } else { - memorizedSnapshot = newSnapshot; - return newSnapshot; - } - }, - () => serverSnapshot - ]; - }, [ - cache2, - key - ]); - const cached = (0, import_shim.useSyncExternalStore)(T2( - (callback) => subscribeCache(key, (current, prev) => { - if (!isEqual(prev, current)) - callback(); - }), - // eslint-disable-next-line react-hooks/exhaustive-deps - [ - cache2, - key - ] - ), getSnapshot[0], getSnapshot[1]); - const isInitialMount = !initialMountedRef.current; - const hasRevalidator = EVENT_REVALIDATORS[key] && EVENT_REVALIDATORS[key].length > 0; - const cachedData = cached.data; - const data = isUndefined(cachedData) ? fallback : cachedData; - const error2 = cached.error; - const laggyDataRef = _2(data); - const returnedData = keepPreviousData ? isUndefined(cachedData) ? laggyDataRef.current : cachedData : data; - const shouldDoInitialRevalidation = (() => { - if (hasRevalidator && !isUndefined(error2)) - return false; - if (isInitialMount && !isUndefined(revalidateOnMount)) - return revalidateOnMount; - if (getConfig().isPaused()) - return false; - if (suspense) - return isUndefined(data) ? false : revalidateIfStale; - return isUndefined(data) || revalidateIfStale; - })(); - const defaultValidatingState = !!(key && fetcher && isInitialMount && shouldDoInitialRevalidation); - const isValidating = isUndefined(cached.isValidating) ? defaultValidatingState : cached.isValidating; - const isLoading = isUndefined(cached.isLoading) ? defaultValidatingState : cached.isLoading; - const revalidate = T2( - async (revalidateOpts) => { - const currentFetcher = fetcherRef.current; - if (!key || !currentFetcher || unmountedRef.current || getConfig().isPaused()) { - return false; - } - let newData; - let startAt; - let loading = true; - const opts = revalidateOpts || {}; - const shouldStartNewRequest = !FETCH[key] || !opts.dedupe; - const callbackSafeguard = () => { - if (IS_REACT_LEGACY) { - return !unmountedRef.current && key === keyRef.current && initialMountedRef.current; - } - return key === keyRef.current; - }; - const finalState = { - isValidating: false, - isLoading: false - }; - const finishRequestAndUpdateState = () => { - setCache(finalState); - }; - const cleanupState = () => { - const requestInfo = FETCH[key]; - if (requestInfo && requestInfo[1] === startAt) { - delete FETCH[key]; - } - }; - const initialState = { - isValidating: true - }; - if (isUndefined(getCache().data)) { - initialState.isLoading = true; - } - try { - if (shouldStartNewRequest) { - setCache(initialState); - if (config.loadingTimeout && isUndefined(getCache().data)) { - setTimeout(() => { - if (loading && callbackSafeguard()) { - getConfig().onLoadingSlow(key, config); - } - }, config.loadingTimeout); - } - FETCH[key] = [ - currentFetcher(fnArg), - getTimestamp() - ]; - } - [newData, startAt] = FETCH[key]; - newData = await newData; - if (shouldStartNewRequest) { - setTimeout(cleanupState, config.dedupingInterval); - } - if (!FETCH[key] || FETCH[key][1] !== startAt) { - if (shouldStartNewRequest) { - if (callbackSafeguard()) { - getConfig().onDiscarded(key); - } - } - return false; - } - finalState.error = UNDEFINED; - const mutationInfo = MUTATION[key]; - if (!isUndefined(mutationInfo) && // case 1 - (startAt <= mutationInfo[0] || // case 2 - startAt <= mutationInfo[1] || // case 3 - mutationInfo[1] === 0)) { - finishRequestAndUpdateState(); - if (shouldStartNewRequest) { - if (callbackSafeguard()) { - getConfig().onDiscarded(key); - } - } - return false; - } - const cacheData = getCache().data; - finalState.data = compare2(cacheData, newData) ? cacheData : newData; - if (shouldStartNewRequest) { - if (callbackSafeguard()) { - getConfig().onSuccess(newData, key, config); - } - } - } catch (err) { - cleanupState(); - const currentConfig = getConfig(); - const { shouldRetryOnError } = currentConfig; - if (!currentConfig.isPaused()) { - finalState.error = err; - if (shouldStartNewRequest && callbackSafeguard()) { - currentConfig.onError(err, key, currentConfig); - if (shouldRetryOnError === true || isFunction(shouldRetryOnError) && shouldRetryOnError(err)) { - if (isActive()) { - currentConfig.onErrorRetry(err, key, currentConfig, (_opts) => { - const revalidators = EVENT_REVALIDATORS[key]; - if (revalidators && revalidators[0]) { - revalidators[0](events.ERROR_REVALIDATE_EVENT, _opts); - } - }, { - retryCount: (opts.retryCount || 0) + 1, - dedupe: true - }); - } - } - } - } - } - loading = false; - finishRequestAndUpdateState(); - return true; - }, - // `setState` is immutable, and `eventsCallback`, `fnArg`, and - // `keyValidating` are depending on `key`, so we can exclude them from - // the deps array. - // - // FIXME: - // `fn` and `config` might be changed during the lifecycle, - // but they might be changed every render like this. - // `useSWR('key', () => fetch('/api/'), { suspense: true })` - // So we omit the values from the deps array - // even though it might cause unexpected behaviors. - // eslint-disable-next-line react-hooks/exhaustive-deps - [ - key, - cache2 - ] - ); - const boundMutate = T2( - // Use callback to make sure `keyRef.current` returns latest result every time - (...args) => { - return internalMutate(cache2, keyRef.current, ...args); - }, - // eslint-disable-next-line react-hooks/exhaustive-deps - [] - ); - useIsomorphicLayoutEffect(() => { - fetcherRef.current = fetcher; - configRef.current = config; - if (!isUndefined(cachedData)) { - laggyDataRef.current = cachedData; - } - }); - useIsomorphicLayoutEffect(() => { - if (!key) - return; - const softRevalidate = revalidate.bind(UNDEFINED, WITH_DEDUPE); - let nextFocusRevalidatedAt = 0; - const onRevalidate = (type, opts = {}) => { - if (type == events.FOCUS_EVENT) { - const now2 = Date.now(); - if (getConfig().revalidateOnFocus && now2 > nextFocusRevalidatedAt && isActive()) { - nextFocusRevalidatedAt = now2 + getConfig().focusThrottleInterval; - softRevalidate(); - } - } else if (type == events.RECONNECT_EVENT) { - if (getConfig().revalidateOnReconnect && isActive()) { - softRevalidate(); - } - } else if (type == events.MUTATE_EVENT) { - return revalidate(); - } else if (type == events.ERROR_REVALIDATE_EVENT) { - return revalidate(opts); - } - return; - }; - const unsubEvents = subscribeCallback(key, EVENT_REVALIDATORS, onRevalidate); - unmountedRef.current = false; - keyRef.current = key; - initialMountedRef.current = true; - setCache({ - _k: fnArg - }); - if (shouldDoInitialRevalidation) { - if (isUndefined(data) || IS_SERVER) { - softRevalidate(); - } else { - rAF(softRevalidate); - } - } - return () => { - unmountedRef.current = true; - unsubEvents(); - }; - }, [ - key - ]); - useIsomorphicLayoutEffect(() => { - let timer2; - function next() { - const interval = isFunction(refreshInterval) ? refreshInterval(getCache().data) : refreshInterval; - if (interval && timer2 !== -1) { - timer2 = setTimeout(execute, interval); - } - } - function execute() { - if (!getCache().error && (refreshWhenHidden || getConfig().isVisible()) && (refreshWhenOffline || getConfig().isOnline())) { - revalidate(WITH_DEDUPE).then(next); - } else { - next(); - } - } - next(); - return () => { - if (timer2) { - clearTimeout(timer2); - timer2 = -1; - } - }; - }, [ - refreshInterval, - refreshWhenHidden, - refreshWhenOffline, - key - ]); - x3(returnedData); - if (suspense && isUndefined(data) && key) { - if (!IS_REACT_LEGACY && IS_SERVER) { - throw new Error("Fallback data is required when using suspense in SSR."); - } - fetcherRef.current = fetcher; - configRef.current = config; - unmountedRef.current = false; - const req = PRELOAD[key]; - if (!isUndefined(req)) { - const promise = boundMutate(req); - use2(promise); - } - if (isUndefined(error2)) { - const promise = revalidate(WITH_DEDUPE); - if (!isUndefined(returnedData)) { - promise.status = "fulfilled"; - promise.value = true; - } - use2(promise); - } else { - throw error2; - } - } - return { - mutate: boundMutate, - get data() { - stateDependencies.data = true; - return returnedData; - }, - get error() { - stateDependencies.error = true; - return error2; - }, - get isValidating() { - stateDependencies.isValidating = true; - return isValidating; - }, - get isLoading() { - stateDependencies.isLoading = true; - return isLoading; - } - }; -}; -var SWRConfig2 = OBJECT.defineProperty(SWRConfig, "defaultValue", { - value: defaultConfig -}); -var useSWR = withArgs(useSWRHandler); - -// src/context/instance.ts -init_preact_module(); -init_hooks_module(); -var Context3 = B({}); -var InstanceContextProvider = Context3.Provider; -var useInstanceContext = () => q2(Context3); - -// src/hooks/backend.ts -function useMatchMutate() { - const { cache: cache2, mutate: mutate2 } = useSWRConfig(); - if (!(cache2 instanceof Map)) { - throw new Error( - "matchMutate requires the cache provider to be a Map instance" - ); - } - return function matchRegexMutate(re) { - return mutate2((key) => { - if (!key || !re) - return true; - if (typeof key === "string" && re.test(key)) - return true; - if (typeof key === "object" && re.test(key[0])) - return true; - return false; - }, void 0, { - revalidate: true - }); - }; -} -function useBackendInstancesTestForAdmin() { - const { request } = useBackendBaseRequest(); - const [result, setResult] = p3({ loading: true }); - h2(() => { - request(`/management/instances`).then((data) => setResult(data)).catch( - (error2) => setResult(error2.cause) - ); - }, [request]); - return result; -} -var CHECK_CONFIG_INTERVAL_OK = 5 * 60 * 1e3; -var CHECK_CONFIG_INTERVAL_FAIL = 2 * 1e3; -function useBackendConfig() { - const { request } = useBackendBaseRequest(); - const [result, setResult] = p3({ data: { loading: true }, timer: 0 }); - h2(() => { - if (result.timer) { - clearTimeout(result.timer); - } - function tryConfig() { - request(`/config`).then((data) => { - const timer2 = setTimeout(() => { - tryConfig(); - }, CHECK_CONFIG_INTERVAL_OK); - setResult({ data, timer: timer2 }); - }).catch((error2) => { - const timer2 = setTimeout(() => { - tryConfig(); - }, CHECK_CONFIG_INTERVAL_FAIL); - const data = error2.cause; - setResult({ data, timer: timer2 }); - }); - } - tryConfig(); - }, [request]); - return result.data; -} -function useCredentialsChecker() { - const { request } = useApiContext(); - async function requestNewLoginToken(baseUrl, token) { - const data = { - scope: "write", - duration: { - d_us: "forever" - }, - refreshable: true - }; - try { - const response = await request(baseUrl, `/private/token`, { - method: "POST", - token, - data - }); - return { valid: true, token: response.data.token, expiration: response.data.expiration }; - } catch (error2) { - if (error2 instanceof RequestError) { - return { valid: false, cause: error2.cause }; - } - return { - valid: false, - cause: { - type: ErrorType.UNEXPECTED, - loading: false, - info: { - hasToken: true, - status: 0, - options: {}, - url: `/private/token`, - payload: {} - }, - exception: error2, - message: error2 instanceof Error ? error2.message : "unpexepected error" - } - }; - } - } - ; - async function refreshLoginToken(baseUrl, token) { - if (AbsoluteTime.isExpired(AbsoluteTime.fromProtocolTimestamp(token.expiration))) { - return { - valid: false, - cause: { - type: ErrorType.CLIENT, - status: HttpStatusCode.Unauthorized, - message: "login token expired, login again.", - info: { - hasToken: true, - status: 401, - options: {}, - url: `/private/token`, - payload: {} - }, - payload: {} - } - }; - } - return requestNewLoginToken(baseUrl, token.token); - } - return { requestNewLoginToken, refreshLoginToken }; -} -function useBackendBaseRequest() { - const { url: backend, token: loginToken } = useBackendContext(); - const { request: requestHandler } = useApiContext(); - const token = loginToken?.token; - const request = T2( - function requestImpl(endpoint, options = {}) { - return requestHandler(backend, endpoint, { ...options, token }).then((res) => { - return res; - }).catch((err) => { - throw err; - }); - }, - [backend, token] - ); - return { request }; -} -function useBackendInstanceRequest() { - const { url: rootBackendUrl, token: rootToken } = useBackendContext(); - const { token: instanceToken, id, admin } = useInstanceContext(); - const { request: requestHandler } = useApiContext(); - const { baseUrl, token: loginToken } = !admin ? { baseUrl: rootBackendUrl, token: rootToken } : { baseUrl: rootBackendUrl, token: instanceToken }; - const token = loginToken?.token; - const request = T2( - function requestImpl(endpoint, options = {}) { - return requestHandler(baseUrl, endpoint, { token, ...options }); - }, - [baseUrl, token] - ); - const multiFetcher = T2( - function multiFetcherImpl(args) { - const [endpoints] = args; - return Promise.all( - endpoints.map( - (endpoint) => requestHandler(baseUrl, endpoint, { token }) - ) - ); - }, - [baseUrl, token] - ); - const fetcher = T2( - function fetcherImpl(endpoint) { - return requestHandler(baseUrl, endpoint, { token }); - }, - [baseUrl, token] - ); - const orderFetcher = T2( - function orderFetcherImpl(args) { - const [endpoint, paid, refunded, wired, searchDate, delta] = args; - const date_s = delta && delta < 0 && searchDate ? Math.floor(searchDate.getTime() / 1e3) + 1 : searchDate !== void 0 ? Math.floor(searchDate.getTime() / 1e3) : void 0; - const params = {}; - if (paid !== void 0) - params.paid = paid; - if (delta !== void 0) - params.delta = delta; - if (refunded !== void 0) - params.refunded = refunded; - if (wired !== void 0) - params.wired = wired; - if (date_s !== void 0) - params.date_s = date_s; - if (delta === 0) { - return Promise.resolve({ - ok: true, - data: { orders: [] } - }); - } - return requestHandler(baseUrl, endpoint, { params, token }); - }, - [baseUrl, token] - ); - const transferFetcher = T2( - function transferFetcherImpl(args) { - const [endpoint, payto_uri, verified, position, delta] = args; - const params = {}; - if (payto_uri !== void 0) - params.payto_uri = payto_uri; - if (verified !== void 0) - params.verified = verified; - if (delta === 0) { - return Promise.resolve({ - ok: true, - data: { transfers: [] } - }); - } - if (delta !== void 0) { - params.limit = delta; - } - if (position !== void 0) - params.offset = position; - return requestHandler(baseUrl, endpoint, { params, token }); - }, - [baseUrl, token] - ); - const templateFetcher = T2( - function templateFetcherImpl(args) { - const [endpoint, position, delta] = args; - const params = {}; - if (delta === 0) { - return Promise.resolve({ - ok: true, - data: { templates: [] } - }); - } - if (delta !== void 0) { - params.limit = delta; - } - if (position !== void 0) - params.offset = position; - return requestHandler(baseUrl, endpoint, { params, token }); - }, - [baseUrl, token] - ); - const webhookFetcher = T2( - function webhookFetcherImpl(args) { - const [endpoint, position, delta] = args; - const params = {}; - if (delta === 0) { - return Promise.resolve({ - ok: true, - data: { webhooks: [] } - }); - } - if (delta !== void 0) { - params.limit = delta; - } - if (position !== void 0) - params.offset = position; - return requestHandler(baseUrl, endpoint, { params, token }); - }, - [baseUrl, token] - ); - return { - request, - fetcher, - multiFetcher, - orderFetcher, - transferFetcher, - templateFetcher, - webhookFetcher - }; -} - -// src/hooks/instance.ts -var useSWR2 = useSWR; -function useAdminAPI() { - const { request } = useBackendBaseRequest(); - const mutateAll = useMatchMutate(); - const createInstance = async (instance) => { - await request(`/management/instances`, { - method: "POST", - data: instance - }); - mutateAll(/\/management\/instances/); - }; - const deleteInstance = async (id) => { - await request(`/management/instances/${id}`, { - method: "DELETE" - }); - mutateAll(/\/management\/instances/); - }; - const purgeInstance = async (id) => { - await request(`/management/instances/${id}`, { - method: "DELETE", - params: { - purge: "YES" - } - }); - mutateAll(/\/management\/instances/); - }; - return { createInstance, deleteInstance, purgeInstance }; -} -function useManagementAPI(instanceId) { - const mutateAll = useMatchMutate(); - const { url: backendURL } = useBackendContext(); - const { updateToken } = useBackendContext(); - const { request } = useBackendBaseRequest(); - const { requestNewLoginToken } = useCredentialsChecker(); - const updateInstance = async (instance) => { - await request(`/management/instances/${instanceId}`, { - method: "PATCH", - data: instance - }); - mutateAll(/\/management\/instances/); - }; - const deleteInstance = async () => { - await request(`/management/instances/${instanceId}`, { - method: "DELETE" - }); - mutateAll(/\/management\/instances/); - }; - const clearAccessToken = async (currentToken) => { - await request(`/management/instances/${instanceId}/auth`, { - method: "POST", - token: currentToken, - data: { method: "external" } - }); - mutateAll(/\/management\/instances/); - }; - const setNewAccessToken = async (currentToken, newToken) => { - await request(`/management/instances/${instanceId}/auth`, { - method: "POST", - token: currentToken, - data: { method: "token", token: newToken } - }); - const resp = await requestNewLoginToken(backendURL, newToken); - if (resp.valid) { - const { token, expiration } = resp; - updateToken({ token, expiration }); - } else { - updateToken(void 0); - } - mutateAll(/\/management\/instances/); - }; - return { updateInstance, deleteInstance, setNewAccessToken, clearAccessToken }; -} -function useInstanceAPI() { - const { mutate: mutate2 } = useSWRConfig(); - const { url: backendURL, updateToken } = useBackendContext(); - const { - token: adminToken - } = useBackendContext(); - const { request } = useBackendInstanceRequest(); - const { requestNewLoginToken } = useCredentialsChecker(); - const updateInstance = async (instance) => { - await request(`/private/`, { - method: "PATCH", - data: instance - }); - if (adminToken) - mutate2(["/private/instances", adminToken, backendURL], null); - mutate2([`/private/`], null); - }; - const deleteInstance = async () => { - await request(`/private/`, { - method: "DELETE" - // token: adminToken, - }); - if (adminToken) - mutate2(["/private/instances", adminToken, backendURL], null); - mutate2([`/private/`], null); - }; - const clearAccessToken = async (currentToken) => { - await request(`/private/auth`, { - method: "POST", - token: currentToken, - data: { method: "external" } - }); - mutate2([`/private/`], null); - }; - const setNewAccessToken = async (currentToken, newToken) => { - await request(`/private/auth`, { - method: "POST", - token: currentToken, - data: { method: "token", token: newToken } - }); - const resp = await requestNewLoginToken(backendURL, newToken); - if (resp.valid) { - const { token, expiration } = resp; - updateToken({ token, expiration }); - } else { - updateToken(void 0); - } - mutate2([`/private/`], null); - }; - return { updateInstance, deleteInstance, setNewAccessToken, clearAccessToken }; -} -function useInstanceDetails() { - const { fetcher } = useBackendInstanceRequest(); - const { data, error: error2, isValidating } = useSWR2([`/private/`], fetcher, { - refreshInterval: 0, - refreshWhenHidden: false, - revalidateOnFocus: false, - revalidateOnReconnect: false, - refreshWhenOffline: false, - revalidateIfStale: false, - errorRetryCount: 0, - errorRetryInterval: 1, - shouldRetryOnError: false - }); - if (isValidating) - return { loading: true, data: data?.data }; - if (data) - return data; - if (error2) - return error2.cause; - return { loading: true }; -} -function useInstanceKYCDetails() { - const { fetcher } = useBackendInstanceRequest(); - const { data, error: error2 } = useSWR2([`/private/kyc`], fetcher, { - refreshInterval: 60 * 1e3, - refreshWhenHidden: false, - revalidateOnFocus: false, - revalidateIfStale: false, - revalidateOnMount: false, - revalidateOnReconnect: false, - refreshWhenOffline: false, - errorRetryCount: 0, - errorRetryInterval: 1, - shouldRetryOnError: false - }); - if (data) { - if (data.info?.status === 202) - return { ok: true, data: { type: "redirect", status: data.data } }; - return { ok: true, data: { type: "ok" } }; - } - if (error2) - return error2.cause; - return { loading: true }; -} -function useManagedInstanceDetails(instanceId) { - const { request } = useBackendBaseRequest(); - const { data, error: error2, isValidating } = useSWR2([`/management/instances/${instanceId}`], request, { - refreshInterval: 0, - refreshWhenHidden: false, - revalidateOnFocus: false, - revalidateOnReconnect: false, - refreshWhenOffline: false, - errorRetryCount: 0, - errorRetryInterval: 1, - shouldRetryOnError: false - }); - if (isValidating) - return { loading: true, data: data?.data }; - if (data) - return data; - if (error2) - return error2.cause; - return { loading: true }; -} -function useBackendInstances() { - const { request } = useBackendBaseRequest(); - const { data, error: error2, isValidating } = useSWR2(["/management/instances"], request); - if (isValidating) - return { loading: true, data: data?.data }; - if (data) - return data; - if (error2) - return error2.cause; - return { loading: true }; -} - -// src/paths/admin/create/CreatePage.tsx -init_preact_module(); -init_hooks_module(); - -// src/components/exception/AsyncButton.tsx -init_preact_module(); - -// src/components/modal/index.tsx -init_preact_module(); -init_hooks_module(); - -// src/utils/constants.ts -var PAYTO_REGEX = /^payto:\/\/[a-zA-Z][a-zA-Z0-9-.]+(\/[a-zA-Z0-9\-\.\~\(\)@_%:!$&'*+,;=]*)*\??((amount|receiver-name|sender-name|instruction|message)=[a-zA-Z0-9\-\.\~\(\)@_%:!$'*+,;=]*&?)*$/; -var INSTANCE_ID_LOOKUP = /\/instances\/([^/]*)\/?$/; -var CROCKFORD_BASE32_REGEX = /^[0123456789ABCDEFGHJKMNPQRSTVWXYZ]+[*~$=U]*$/; -var URL_REGEX = /^((https?:)(\/\/\/?)([\w]*(?::[\w]*)?@)?([\d\w\.-]+)(?::(\d+))?)\/$/; -var PAGE_SIZE = 20; -var MAX_RESULT_SIZE = PAGE_SIZE * 2 - 1; -var DEFAULT_REQUEST_TIMEOUT = 10; -var MAX_IMAGE_SIZE = 1024 * 1024; -var INSTANCE_ID_REGEX = /^[a-zA-Z0-9][a-zA-Z0-9_.@-]+$/; -var COUNTRY_TABLE = { - AE: "U.A.E.", - AF: "Afghanistan", - AL: "Albania", - AM: "Armenia", - AN: "Netherlands Antilles", - AR: "Argentina", - AT: "Austria", - AU: "Australia", - AZ: "Azerbaijan", - BA: "Bosnia and Herzegovina", - BD: "Bangladesh", - BE: "Belgium", - BG: "Bulgaria", - BH: "Bahrain", - BN: "Brunei Darussalam", - BO: "Bolivia", - BR: "Brazil", - BT: "Bhutan", - BY: "Belarus", - BZ: "Belize", - CA: "Canada", - CG: "Congo", - CH: "Switzerland", - CI: "Cote d'Ivoire", - CL: "Chile", - CM: "Cameroon", - CN: "People's Republic of China", - CO: "Colombia", - CR: "Costa Rica", - CS: "Serbia and Montenegro", - CZ: "Czech Republic", - DE: "Germany", - DK: "Denmark", - DO: "Dominican Republic", - DZ: "Algeria", - EC: "Ecuador", - EE: "Estonia", - EG: "Egypt", - ER: "Eritrea", - ES: "Spain", - ET: "Ethiopia", - FI: "Finland", - FO: "Faroe Islands", - FR: "France", - GB: "United Kingdom", - GD: "Caribbean", - GE: "Georgia", - GL: "Greenland", - GR: "Greece", - GT: "Guatemala", - HK: "Hong Kong", - // HK: "Hong Kong S.A.R.", - HN: "Honduras", - HR: "Croatia", - HT: "Haiti", - HU: "Hungary", - ID: "Indonesia", - IE: "Ireland", - IL: "Israel", - IN: "India", - IQ: "Iraq", - IR: "Iran", - IS: "Iceland", - IT: "Italy", - JM: "Jamaica", - JO: "Jordan", - JP: "Japan", - KE: "Kenya", - KG: "Kyrgyzstan", - KH: "Cambodia", - KR: "South Korea", - KW: "Kuwait", - KZ: "Kazakhstan", - LA: "Laos", - LB: "Lebanon", - LI: "Liechtenstein", - LK: "Sri Lanka", - LT: "Lithuania", - LU: "Luxembourg", - LV: "Latvia", - LY: "Libya", - MA: "Morocco", - MC: "Principality of Monaco", - MD: "Moldava", - // MD: "Moldova", - ME: "Montenegro", - MK: "Former Yugoslav Republic of Macedonia", - ML: "Mali", - MM: "Myanmar", - MN: "Mongolia", - MO: "Macau S.A.R.", - MT: "Malta", - MV: "Maldives", - MX: "Mexico", - MY: "Malaysia", - NG: "Nigeria", - NI: "Nicaragua", - NL: "Netherlands", - NO: "Norway", - NP: "Nepal", - NZ: "New Zealand", - OM: "Oman", - PA: "Panama", - PE: "Peru", - PH: "Philippines", - PK: "Islamic Republic of Pakistan", - PL: "Poland", - PR: "Puerto Rico", - PT: "Portugal", - PY: "Paraguay", - QA: "Qatar", - RE: "Reunion", - RO: "Romania", - RS: "Serbia", - RU: "Russia", - RW: "Rwanda", - SA: "Saudi Arabia", - SE: "Sweden", - SG: "Singapore", - SI: "Slovenia", - SK: "Slovak", - SN: "Senegal", - SO: "Somalia", - SR: "Suriname", - SV: "El Salvador", - SY: "Syria", - TH: "Thailand", - TJ: "Tajikistan", - TM: "Turkmenistan", - TN: "Tunisia", - TR: "Turkey", - TT: "Trinidad and Tobago", - TW: "Taiwan", - TZ: "Tanzania", - UA: "Ukraine", - US: "United States", - UY: "Uruguay", - VA: "Vatican", - VE: "Venezuela", - VN: "Viet Nam", - YE: "Yemen", - ZA: "South Africa", - ZW: "Zimbabwe" -}; - -// src/components/form/FormProvider.tsx -init_preact_module(); -init_hooks_module(); -var noUpdater = () => (s5) => s5; -function FormProvider({ - object: object2 = {}, - errors: errors2 = {}, - name = "", - valueHandler, - children -}) { - const initialObject = F(() => object2, []); - const value = F( - () => ({ - errors: errors2, - object: object2, - initialObject, - valueHandler: valueHandler ? valueHandler : noUpdater, - name, - toStr: {}, - fromStr: {} - }), - [errors2, object2, valueHandler] - ); - return /* @__PURE__ */ h(FormContext2.Provider, { value }, /* @__PURE__ */ h( - "form", - { - class: "field", - onSubmit: (e4) => { - e4.preventDefault(); - } - }, - children - )); -} -var FormContext2 = B(null); -function useFormContext() { - return q2(FormContext2); -} - -// src/components/form/Input.tsx -init_preact_module(); - -// src/components/form/useField.tsx -init_hooks_module(); -function useField(name) { - const { errors: errors2, object: object2, initialObject, toStr, fromStr, valueHandler } = useFormContext(); - const [isDirty, setDirty] = p3(false); - const updateField = (field) => (value2) => { - setDirty(true); - return valueHandler((prev) => { - return setValueDeeper(prev, String(field).split("."), value2); - }); - }; - const defaultToString5 = (f3) => String(!f3 ? "" : f3); - const defaultFromString5 = (v3) => v3; - const value = readField(object2, String(name)); - const initial2 = readField(initialObject, String(name)); - const hasError = readField(errors2, String(name)); - return { - error: isDirty ? hasError : void 0, - required: !isDirty && hasError, - value, - initial: initial2, - onChange: updateField(name), - toStr: toStr[name] ? toStr[name] : defaultToString5, - fromStr: fromStr[name] ? fromStr[name] : defaultFromString5 - }; -} -var readField = (object2, name) => { - return name.split(".").reduce((prev, current) => prev && prev[current], object2); -}; -var setValueDeeper = (object2, names2, value) => { - if (names2.length === 0) - return value; - const [head, ...rest] = names2; - return { ...object2, [head]: setValueDeeper(object2[head] || {}, rest, value) }; -}; - -// src/components/form/Input.tsx -var defaultToString = (f3) => f3 || ""; -var defaultFromString = (v3) => v3; -var TextInput = ({ inputType, error: error2, ...rest }) => inputType === "multiline" ? /* @__PURE__ */ h( - "textarea", - { - ...rest, - class: error2 ? "textarea is-danger" : "textarea", - rows: "3" - } -) : /* @__PURE__ */ h( - "input", - { - ...rest, - class: error2 ? "input is-danger" : "input", - type: inputType - } -); -function Input({ - name, - readonly, - placeholder, - tooltip, - label, - expand, - help, - children, - inputType, - inputExtra, - side, - fromStr = defaultFromString, - toStr = defaultToString -}) { - const { error: error2, value, onChange, required } = useField(name); - return /* @__PURE__ */ h("div", { class: "field is-horizontal" }, /* @__PURE__ */ h("div", { class: "field-label is-normal" }, /* @__PURE__ */ h("label", { class: "label" }, label, tooltip && /* @__PURE__ */ h("span", { class: "icon has-tooltip-right", "data-tooltip": tooltip }, /* @__PURE__ */ h("i", { class: "mdi mdi-information" })))), /* @__PURE__ */ h("div", { class: "field-body is-flex-grow-3" }, /* @__PURE__ */ h("div", { class: "field" }, /* @__PURE__ */ h( - "p", - { - class: expand ? "control is-expanded has-icons-right" : "control has-icons-right" - }, - /* @__PURE__ */ h( - TextInput, - { - error: error2, - ...inputExtra, - inputType, - placeholder, - readonly, - disabled: readonly, - name: String(name), - value: toStr(value), - onChange: (e4) => onChange(fromStr(e4.currentTarget.value)) - } - ), - help, - children, - required && /* @__PURE__ */ h("span", { class: "icon has-text-danger is-right" }, /* @__PURE__ */ h("i", { class: "mdi mdi-alert" })) - ), error2 && /* @__PURE__ */ h("p", { class: "help is-danger" }, error2)), side)); -} - -// src/components/modal/index.tsx -function ConfirmModal({ - active, - description, - onCancel, - onConfirm, - children, - danger, - disabled, - label = "Confirm" -}) { - const { i18n: i18n2 } = useTranslationContext(); - return /* @__PURE__ */ h("div", { class: active ? "modal is-active" : "modal" }, /* @__PURE__ */ h("div", { class: "modal-background ", onClick: onCancel }), /* @__PURE__ */ h("div", { class: "modal-card", style: { maxWidth: 700 } }, /* @__PURE__ */ h("header", { class: "modal-card-head" }, !description ? null : /* @__PURE__ */ h("p", { class: "modal-card-title" }, /* @__PURE__ */ h("b", null, description)), /* @__PURE__ */ h("button", { class: "delete ", "aria-label": "close", onClick: onCancel })), /* @__PURE__ */ h("section", { class: "modal-card-body" }, children), /* @__PURE__ */ h("footer", { class: "modal-card-foot" }, /* @__PURE__ */ h("div", { class: "buttons is-right", style: { width: "100%" } }, onConfirm ? /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h("button", { class: "button ", onClick: onCancel }, /* @__PURE__ */ h(i18n2.Translate, null, "Cancel")), /* @__PURE__ */ h( - "button", - { - class: danger ? "button is-danger " : "button is-info ", - disabled, - onClick: onConfirm - }, - /* @__PURE__ */ h(i18n2.Translate, null, label) - )) : /* @__PURE__ */ h("button", { class: "button ", onClick: onCancel }, /* @__PURE__ */ h(i18n2.Translate, null, "Close"))))), /* @__PURE__ */ h( - "button", - { - class: "modal-close is-large ", - "aria-label": "close", - onClick: onCancel - } - )); -} -function SimpleModal({ onCancel, children }) { - return /* @__PURE__ */ h("div", { class: "modal is-active" }, /* @__PURE__ */ h("div", { class: "modal-background ", onClick: onCancel }), /* @__PURE__ */ h("div", { class: "modal-card" }, /* @__PURE__ */ h("section", { class: "modal-card-body is-main-section" }, children)), /* @__PURE__ */ h( - "button", - { - class: "modal-close is-large ", - "aria-label": "close", - onClick: onCancel - } - )); -} -function DeleteModal({ - element, - onCancel, - onConfirm -}) { - return /* @__PURE__ */ h( - ConfirmModal, - { - label: `Delete instance`, - description: `Delete the instance "${element.name}"`, - danger: true, - active: true, - onCancel, - onConfirm: () => onConfirm(element.id) - }, - /* @__PURE__ */ h("p", null, "If you delete the instance named ", /* @__PURE__ */ h("b", null, '"', element.name, '"'), " (ID:", " ", /* @__PURE__ */ h("b", null, element.id), "), the merchant will no longer be able to process orders or refunds"), - /* @__PURE__ */ h("p", null, "This action deletes the instance private key, but preserves all transaction data. You can still access that data after deleting the instance."), - /* @__PURE__ */ h("p", { class: "warning" }, "Deleting an instance ", /* @__PURE__ */ h("b", null, "cannot be undone"), ".") - ); -} -function PurgeModal({ - element, - onCancel, - onConfirm -}) { - return /* @__PURE__ */ h( - ConfirmModal, - { - label: `Purge the instance`, - description: `Purge the instance "${element.name}"`, - danger: true, - active: true, - onCancel, - onConfirm: () => onConfirm(element.id) - }, - /* @__PURE__ */ h("p", null, "If you purge the instance named ", /* @__PURE__ */ h("b", null, '"', element.name, '"'), " (ID:", " ", /* @__PURE__ */ h("b", null, element.id), "), you will also delete all it's transaction data."), - /* @__PURE__ */ h("p", null, "The instance will disappear from your list, and you will no longer be able to access it's data."), - /* @__PURE__ */ h("p", { class: "warning" }, "Purging an instance ", /* @__PURE__ */ h("b", null, "cannot be undone"), ".") - ); -} -function SetTokenNewInstanceModal({ - onCancel, - onClear, - onConfirm -}) { - const [form, setValue] = p3({ - new_token: "", - repeat_token: "" - }); - const { i18n: i18n2 } = useTranslationContext(); - const errors2 = { - new_token: !form.new_token ? i18n2.str`cannot be empty` : form.new_token === form.old_token ? i18n2.str`cannot be the same as the old access token` : void 0, - repeat_token: form.new_token !== form.repeat_token ? i18n2.str`is not the same` : void 0 - }; - const hasErrors = Object.keys(errors2).some( - (k5) => errors2[k5] !== void 0 - ); - return /* @__PURE__ */ h("div", { class: "modal is-active" }, /* @__PURE__ */ h("div", { class: "modal-background ", onClick: onCancel }), /* @__PURE__ */ h("div", { class: "modal-card" }, /* @__PURE__ */ h("header", { class: "modal-card-head" }, /* @__PURE__ */ h("p", { class: "modal-card-title" }, i18n2.str`You are setting the access token for the new instance`), /* @__PURE__ */ h("button", { class: "delete ", "aria-label": "close", onClick: onCancel })), /* @__PURE__ */ h("section", { class: "modal-card-body is-main-section" }, /* @__PURE__ */ h("div", { class: "columns" }, /* @__PURE__ */ h("div", { class: "column" }), /* @__PURE__ */ h("div", { class: "column is-four-fifths" }, /* @__PURE__ */ h( - FormProvider, - { - errors: errors2, - object: form, - valueHandler: setValue - }, - /* @__PURE__ */ h( - Input, - { - name: "new_token", - label: i18n2.str`New access token`, - tooltip: i18n2.str`next access token to be used`, - inputType: "password" - } - ), - /* @__PURE__ */ h( - Input, - { - name: "repeat_token", - label: i18n2.str`Repeat access token`, - tooltip: i18n2.str`confirm the same access token`, - inputType: "password" - } - ) - ), /* @__PURE__ */ h("p", null, /* @__PURE__ */ h(i18n2.Translate, null, "With external authorization method no check will be done by the merchant backend"))), /* @__PURE__ */ h("div", { class: "column" }))), /* @__PURE__ */ h("footer", { class: "modal-card-foot" }, onClear && /* @__PURE__ */ h( - "button", - { - class: "button is-danger", - onClick: onClear, - disabled: onClear === void 0 - }, - /* @__PURE__ */ h(i18n2.Translate, null, "Set external authorization") - ), /* @__PURE__ */ h("div", { class: "buttons is-right", style: { width: "100%" } }, /* @__PURE__ */ h("button", { class: "button ", onClick: onCancel }, /* @__PURE__ */ h(i18n2.Translate, null, "Cancel")), /* @__PURE__ */ h( - "button", - { - class: "button is-info", - onClick: () => onConfirm(form.new_token), - disabled: hasErrors - }, - /* @__PURE__ */ h(i18n2.Translate, null, "Set access token") - )))), /* @__PURE__ */ h( - "button", - { - class: "modal-close is-large ", - "aria-label": "close", - onClick: onCancel - } - )); -} -function LoadingModal({ onCancel }) { - const { i18n: i18n2 } = useTranslationContext(); - return /* @__PURE__ */ h("div", { class: "modal is-active" }, /* @__PURE__ */ h("div", { class: "modal-background ", onClick: onCancel }), /* @__PURE__ */ h("div", { class: "modal-card" }, /* @__PURE__ */ h("header", { class: "modal-card-head" }, /* @__PURE__ */ h("p", { class: "modal-card-title" }, /* @__PURE__ */ h(i18n2.Translate, null, "Operation in progress..."))), /* @__PURE__ */ h("section", { class: "modal-card-body" }, /* @__PURE__ */ h("div", { class: "columns" }, /* @__PURE__ */ h("div", { class: "column" }), /* @__PURE__ */ h(Spinner, null), /* @__PURE__ */ h("div", { class: "column" })), /* @__PURE__ */ h("p", null, i18n2.str`The operation will be automatically canceled after ${DEFAULT_REQUEST_TIMEOUT} seconds`)), /* @__PURE__ */ h("footer", { class: "modal-card-foot" }, /* @__PURE__ */ h("div", { class: "buttons is-right", style: { width: "100%" } }, /* @__PURE__ */ h("button", { class: "button ", onClick: onCancel }, /* @__PURE__ */ h(i18n2.Translate, null, "Cancel"))))), /* @__PURE__ */ h( - "button", - { - class: "modal-close is-large ", - "aria-label": "close", - onClick: onCancel - } - )); -} - -// src/hooks/async.ts -init_hooks_module(); -function useAsync(fn2, { slowTolerance: tooLong } = { slowTolerance: 1e3 }) { - const [data, setData] = p3(void 0); - const [isLoading, setLoading] = p3(false); - const [error2, setError] = p3(void 0); - const [isSlow, setSlow] = p3(false); - const request = async (...args) => { - if (!fn2) - return; - setLoading(true); - const handler = setTimeout(() => { - setSlow(true); - }, tooLong); - try { - const result = await fn2(...args); - setData(result); - } catch (error3) { - setError(error3); - } - setLoading(false); - setSlow(false); - clearTimeout(handler); - }; - function cancel() { - setLoading(false); - setSlow(false); - } - return { - request, - cancel, - data, - isSlow, - isLoading, - error: error2 - }; -} - -// src/components/exception/AsyncButton.tsx -function AsyncButton({ onClick, disabled, children, ...rest }) { - const { isSlow, isLoading, request, cancel } = useAsync(onClick); - const { i18n: i18n2 } = useTranslationContext(); - if (isSlow) { - return /* @__PURE__ */ h(LoadingModal, { onCancel: cancel }); - } - if (isLoading) { - return /* @__PURE__ */ h("button", { class: "button" }, /* @__PURE__ */ h(i18n2.Translate, null, "Loading...")); - } - return /* @__PURE__ */ h("span", { ...rest }, /* @__PURE__ */ h("button", { class: "button is-success", onClick: request, disabled }, children)); -} - -// src/components/instance/DefaultInstanceFormFields.tsx -init_preact_module(); - // src/components/form/InputDuration.tsx init_preact_module(); init_hooks_module(); @@ -28285,11 +31035,11 @@ function DurationPicker({ )); } function InputNumber({ - initial: initial2, + initial: initial3, onChange }) { const [value, handler] = p3({ - v: toTwoDigitString(initial2) + v: toTwoDigitString(initial3) }); return /* @__PURE__ */ h( "input", @@ -28300,7 +31050,7 @@ function InputNumber({ e4.preventDefault(); const n2 = Number.parseInt(e4.currentTarget.value, 10); if (isNaN(n2)) - return handler({ v: toTwoDigitString(initial2) }); + return handler({ v: toTwoDigitString(initial3) }); return handler({ v: toTwoDigitString(n2) }); }, style: { @@ -28655,7 +31405,7 @@ function InputToggle({ disabled: readonly, onChange: onCheckboxClick } - ), /* @__PURE__ */ h("div", { class: "toggle-switch" })), help), error2 && /* @__PURE__ */ h("p", { class: "help is-danger" }, error2)))); + ), /* @__PURE__ */ h("div", { class: `toggle-switch ${readonly ? "disabled" : ""}`, style: { cursor: readonly ? "default" : void 0 } })), help), error2 && /* @__PURE__ */ h("p", { class: "help is-danger" }, error2)))); } // src/components/form/InputWithAddon.tsx @@ -28711,12 +31461,12 @@ function DefaultInstanceFormFields({ showId }) { const { i18n: i18n2 } = useTranslationContext(); - const { url: backendURL } = useBackendContext(); + const { url: backendUrl } = useMerchantApiContext(); return /* @__PURE__ */ h(p2, null, showId && /* @__PURE__ */ h( InputWithAddon, { name: "id", - addonBefore: `${backendURL}/instances/`, + addonBefore: new URL("instances/", backendUrl.href).href, readonly: readonlyId, label: i18n2.str`Identifier`, tooltip: i18n2.str`Name of the instance in URLs. The 'default' instance is special in that it is used to administer other instances.` @@ -28917,26 +31667,34 @@ function CreatePage({ onCreate, onBack, forceId }) { // src/paths/admin/create/index.tsx function Create({ onBack, onConfirm, forceId }) { - const { createInstance } = useAdminAPI(); const [notif, setNotif] = p3(void 0); const { i18n: i18n2 } = useTranslationContext(); - const { requestNewLoginToken } = useCredentialsChecker(); - const { url: backendURL, updateToken } = useBackendContext(); + const { lib } = useMerchantApiContext(); + const { state, logIn } = useSessionContext(); return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(NotificationCard, { notification: notif }), /* @__PURE__ */ h( CreatePage, { onBack, forceId, onCreate: async (d5) => { + if (state.status !== "loggedIn") + return; try { - await createInstance(d5); + await lib.instance.createInstance(state.token, d5); if (d5.auth.token) { - const resp = await requestNewLoginToken(backendURL, d5.auth.token); - if (resp.valid) { - const { token, expiration } = resp; - updateToken({ token, expiration }); - } else { - updateToken(void 0); + const result = await lib.authenticate.createAccessTokenBearer( + d5.auth.token, + { + scope: "write", + duration: { + d_us: "forever" + }, + refreshable: true + } + ); + if (result.type === "ok") { + const { token } = result.body; + logIn({ token }); } } onConfirm(); @@ -28960,6 +31718,222 @@ function Create({ onBack, onConfirm, forceId }) { init_preact_module(); init_hooks_module(); +// src/components/ErrorLoadingMerchant.tsx +init_preact_module(); +function ErrorLoadingMerchant({ error: error2, showDetail }) { + const { i18n: i18n2 } = useTranslationContext(); + switch (error2.errorDetail.code) { + case TalerErrorCode.GENERIC_TIMEOUT: { + if (error2.hasErrorCode(TalerErrorCode.GENERIC_TIMEOUT)) { + const { requestMethod, requestUrl, timeoutMs } = error2.errorDetail; + return /* @__PURE__ */ h( + NotificationCard, + { + notification: { + type: "ERROR", + message: i18n2.str`The request reached a timeout, check your connection.`, + description: error2.message, + details: JSON.stringify({ requestMethod, requestUrl, timeoutMs }, void 0, 2) + } + } + ); + } + assertUnreachable(1); + } + case TalerErrorCode.GENERIC_CLIENT_INTERNAL_ERROR: { + if (error2.hasErrorCode(TalerErrorCode.GENERIC_CLIENT_INTERNAL_ERROR)) { + const { requestMethod, requestUrl, timeoutMs } = error2.errorDetail; + return /* @__PURE__ */ h( + NotificationCard, + { + notification: { + type: "ERROR", + message: i18n2.str`The request was cancelled.`, + description: error2.message, + details: JSON.stringify({ requestMethod, requestUrl, timeoutMs }, void 0, 2) + } + } + ); + } + assertUnreachable(1); + } + case TalerErrorCode.WALLET_HTTP_REQUEST_GENERIC_TIMEOUT: { + if (error2.hasErrorCode(TalerErrorCode.WALLET_HTTP_REQUEST_GENERIC_TIMEOUT)) { + const { requestMethod, requestUrl, timeoutMs } = error2.errorDetail; + return /* @__PURE__ */ h( + NotificationCard, + { + notification: { + type: "ERROR", + message: i18n2.str`The request reached a timeout, check your connection.`, + description: error2.message, + details: JSON.stringify({ requestMethod, requestUrl, timeoutMs }, void 0, 2) + } + } + ); + } + assertUnreachable(1); + } + case TalerErrorCode.WALLET_HTTP_REQUEST_THROTTLED: { + if (error2.hasErrorCode(TalerErrorCode.WALLET_HTTP_REQUEST_THROTTLED)) { + const { requestMethod, requestUrl, throttleStats } = error2.errorDetail; + return /* @__PURE__ */ h( + NotificationCard, + { + notification: { + type: "ERROR", + message: i18n2.str`A lot of request were made to the same server and this action was throttled.`, + description: error2.message, + details: JSON.stringify({ requestMethod, requestUrl, throttleStats }, void 0, 2) + } + } + ); + } + assertUnreachable(1); + } + case TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE: { + if (error2.hasErrorCode(TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE)) { + const { requestMethod, requestUrl, httpStatusCode, validationError } = error2.errorDetail; + return /* @__PURE__ */ h( + NotificationCard, + { + notification: { + type: "ERROR", + message: i18n2.str`The response of the request is malformed.`, + description: error2.message, + details: JSON.stringify({ requestMethod, requestUrl, httpStatusCode, validationError }, void 0, 2) + } + } + ); + } + assertUnreachable(1); + } + case TalerErrorCode.WALLET_NETWORK_ERROR: { + if (error2.hasErrorCode(TalerErrorCode.WALLET_NETWORK_ERROR)) { + const { requestMethod, requestUrl } = error2.errorDetail; + return /* @__PURE__ */ h( + NotificationCard, + { + notification: { + type: "ERROR", + message: i18n2.str`Could not complete the request due to a network problem.`, + description: error2.message, + details: JSON.stringify({ requestMethod, requestUrl }, void 0, 2) + } + } + ); + } + assertUnreachable(1); + } + case TalerErrorCode.WALLET_UNEXPECTED_REQUEST_ERROR: { + if (error2.hasErrorCode(TalerErrorCode.WALLET_UNEXPECTED_REQUEST_ERROR)) { + const { requestMethod, requestUrl, httpStatusCode, errorResponse } = error2.errorDetail; + return /* @__PURE__ */ h( + NotificationCard, + { + notification: { + type: "ERROR", + message: i18n2.str`Unexpected request error.`, + description: error2.message, + details: JSON.stringify({ requestMethod, requestUrl, httpStatusCode, errorResponse }, void 0, 2) + } + } + ); + } + assertUnreachable(1); + } + default: { + return /* @__PURE__ */ h( + NotificationCard, + { + notification: { + type: "ERROR", + message: i18n2.str`Unexpected error.`, + description: error2.message, + details: JSON.stringify(error2.errorDetail, void 0, 2) + } + } + ); + } + } +} + +// src/hooks/instance.ts +var useSWR2 = useSWR; +function revalidateInstanceDetails() { + return mutate( + (key) => Array.isArray(key) && key[key.length - 1] === "getCurrentInstanceDetails", + void 0, + { revalidate: true } + ); +} +function useInstanceDetails() { + const { state: session } = useSessionContext(); + const { lib: { instance } } = useMerchantApiContext(); + async function fetcher([token]) { + return await instance.getCurrentInstanceDetails(token); + } + const { data, error: error2 } = useSWR2([session.token, "getCurrentInstanceDetails"], fetcher); + if (data) + return data; + if (error2) + return error2; + return void 0; +} +function useInstanceKYCDetails() { + const { state: session } = useSessionContext(); + const { lib: { instance } } = useMerchantApiContext(); + async function fetcher([token]) { + return await instance.getCurrentIntanceKycStatus(token, {}); + } + const { data, error: error2 } = useSWR2([session.token, "getCurrentIntanceKycStatus"], fetcher); + if (data) + return data; + if (error2) + return error2; + return void 0; +} +function revalidateManagedInstanceDetails() { + return mutate( + (key) => Array.isArray(key) && key[key.length - 1] === "getInstanceDetails", + void 0, + { revalidate: true } + ); +} +function useManagedInstanceDetails(instanceId) { + const { state: session } = useSessionContext(); + const { lib: { instance } } = useMerchantApiContext(); + async function fetcher([token, instanceId2]) { + return await instance.getInstanceDetails(token, instanceId2); + } + const { data, error: error2 } = useSWR2([session.token, instanceId, "getInstanceDetails"], fetcher); + if (data) + return data; + if (error2) + return error2; + return void 0; +} +function revalidateBackendInstances() { + return mutate( + (key) => Array.isArray(key) && key[key.length - 1] === "listInstances", + void 0, + { revalidate: true } + ); +} +function useBackendInstances() { + const { state: session } = useSessionContext(); + const { lib: { instance } } = useMerchantApiContext(); + async function fetcher([token]) { + return await instance.listInstances(token); + } + const { data, error: error2 } = useSWR2([session.token, "listInstances"], fetcher); + if (data) + return data; + if (error2) + return error2; + return void 0; +} + // src/paths/admin/list/View.tsx init_preact_module(); init_hooks_module(); @@ -28972,7 +31946,6 @@ function CardTable({ onCreate, onUpdate, onPurge, - setInstanceName, onDelete, selected }) { @@ -29014,7 +31987,6 @@ function CardTable({ instances, onPurge, onUpdate, - setInstanceName, onDelete, rowSelection, rowSelectionHandler @@ -29027,7 +31999,6 @@ function toggleSelected(id) { function Table({ rowSelection, rowSelectionHandler, - setInstanceName, instances, onUpdate, onDelete, @@ -29051,16 +32022,7 @@ function Table({ checked: rowSelection.indexOf(i4.id) != -1, onClick: () => rowSelectionHandler(toggleSelected(i4.id)) } - ), /* @__PURE__ */ h("span", { class: "check" }))), /* @__PURE__ */ h("td", null, /* @__PURE__ */ h( - "a", - { - href: `#/orders?instance=${i4.id}`, - onClick: (e4) => { - setInstanceName(i4.id); - } - }, - i4.id - )), /* @__PURE__ */ h("td", null, i4.name), /* @__PURE__ */ h("td", { class: "is-actions-cell right-sticky" }, /* @__PURE__ */ h("div", { class: "buttons is-right" }, /* @__PURE__ */ h( + ), /* @__PURE__ */ h("span", { class: "check" }))), /* @__PURE__ */ h("td", null, i4.id), /* @__PURE__ */ h("td", null, i4.name), /* @__PURE__ */ h("td", { class: "is-actions-cell right-sticky" }, /* @__PURE__ */ h("div", { class: "buttons is-right" }, /* @__PURE__ */ h( "button", { class: "button is-small is-success jb-modal", @@ -29089,7 +32051,7 @@ function Table({ } function EmptyTable() { const { i18n: i18n2 } = useTranslationContext(); - return /* @__PURE__ */ h("div", { class: "content has-text-grey has-text-centered" }, /* @__PURE__ */ h("p", null, /* @__PURE__ */ h("span", { class: "icon is-large" }, /* @__PURE__ */ h("i", { class: "mdi mdi-emoticon-sad mdi-48px" }))), /* @__PURE__ */ h("p", null, /* @__PURE__ */ h(i18n2.Translate, null, "There is no instances yet, add more pressing the + sign"))); + return /* @__PURE__ */ h("div", { class: "content has-text-grey has-text-centered" }, /* @__PURE__ */ h("p", null, /* @__PURE__ */ h("span", { class: "icon is-large" }, /* @__PURE__ */ h("i", { class: "mdi mdi-magnify mdi-48px" }))), /* @__PURE__ */ h("p", null, /* @__PURE__ */ h(i18n2.Translate, null, "There is no instances yet, add more pressing the + sign"))); } function notEmpty(value) { return value !== null && value !== void 0; @@ -29105,7 +32067,6 @@ function View({ onDelete, onPurge, onUpdate, - setInstanceName, selected }) { const [show, setShow] = p3("active"); @@ -29141,7 +32102,6 @@ function View({ instances: showingInstances, onDelete, onPurge, - setInstanceName, onUpdate, selected, onCreate @@ -29149,39 +32109,228 @@ function View({ )); } +// src/paths/login/index.tsx +init_preact_module(); +init_hooks_module(); +var tokenRequest = { + scope: "write", + duration: { + d_us: "forever" + }, + refreshable: true +}; +function LoginPage(_p) { + const [token, setToken] = p3(""); + const [notif, setNotif] = p3(void 0); + const { state, logIn, impersonate } = useSessionContext(); + const { lib } = useMerchantApiContext(); + const { i18n: i18n2 } = useTranslationContext(); + async function doImpersonateImpl(instanceId) { + const newInstanceApi = lib.subInstanceApi(instanceId); + const cfg = await newInstanceApi.instance.getConfig(); + if (cfg.type !== "ok") { + setNotif({ + message: "Could not load the configuration of this instance.", + description: newInstanceApi.instance.baseUrl, + type: "ERROR" + }); + return; + } + const result = await newInstanceApi.authenticate.createAccessTokenBearer( + token, + tokenRequest + ); + if (result.type === "ok") { + const { token: token2 } = result.body; + impersonate({ instance: instanceId, baseUrl: new URL(newInstanceApi.instance.baseUrl), token: token2 }); + return; + } else { + switch (result.case) { + case HttpStatusCode.Unauthorized: { + setNotif({ + message: "Your password is incorrect", + type: "ERROR" + }); + return; + } + case HttpStatusCode.NotFound: { + setNotif({ + message: "Your instance not found", + type: "ERROR" + }); + return; + } + } + } + } + async function doLoginImpl() { + const result = await lib.authenticate.createAccessTokenBearer( + token, + tokenRequest + ); + if (result.type === "ok") { + const { token: token2 } = result.body; + logIn({ token: token2 }); + return; + } else { + switch (result.case) { + case HttpStatusCode.Unauthorized: { + setNotif({ + message: "Your password is incorrect", + type: "ERROR" + }); + return; + } + case HttpStatusCode.NotFound: { + setNotif({ + message: "Your instance not found", + type: "ERROR" + }); + return; + } + } + } + } + if (state.status === "loggedIn" && state.impersonate !== void 0) { + return /* @__PURE__ */ h("div", { class: "columns is-centered", style: { margin: "auto" } }, /* @__PURE__ */ h("div", { class: "column is-two-thirds " }, /* @__PURE__ */ h("div", { class: "modal-card", style: { width: "100%", margin: 0 } }, /* @__PURE__ */ h( + "header", + { + class: "modal-card-head", + style: { border: "1px solid", borderBottom: 0 } + }, + /* @__PURE__ */ h("p", { class: "modal-card-title" }, i18n2.str`Login required`) + ), /* @__PURE__ */ h( + "section", + { + class: "modal-card-body", + style: { border: "1px solid", borderTop: 0, borderBottom: 0 } + }, + /* @__PURE__ */ h("p", null, /* @__PURE__ */ h(i18n2.Translate, null, "Need the access token for the instance", " ", /* @__PURE__ */ h("b", null, '"', state.instance, '"'))), + /* @__PURE__ */ h("div", { class: "field is-horizontal" }, /* @__PURE__ */ h("div", { class: "field-label is-normal" }, /* @__PURE__ */ h("label", { class: "label" }, /* @__PURE__ */ h(i18n2.Translate, null, "Access Token"))), /* @__PURE__ */ h("div", { class: "field-body" }, /* @__PURE__ */ h("div", { class: "field" }, /* @__PURE__ */ h("p", { class: "control is-expanded" }, /* @__PURE__ */ h( + "input", + { + class: "input", + type: "password", + placeholder: "current access token", + name: "token", + onKeyPress: (e4) => e4.keyCode === 13 ? doImpersonateImpl(state.instance) : null, + value: token, + onInput: (e4) => setToken(e4?.currentTarget.value) + } + ))))) + ), /* @__PURE__ */ h( + "footer", + { + class: "modal-card-foot ", + style: { + justifyContent: "flex-end", + border: "1px solid", + borderTop: 0 + } + }, + /* @__PURE__ */ h(AsyncButton2, { onClick: () => doImpersonateImpl(state.instance) }, /* @__PURE__ */ h(i18n2.Translate, null, "Confirm")) + )))); + } + return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(NotificationCard, { notification: notif }), /* @__PURE__ */ h("div", { class: "columns is-centered", style: { margin: "auto" } }, /* @__PURE__ */ h("div", { class: "column is-two-thirds " }, /* @__PURE__ */ h("div", { class: "modal-card", style: { width: "100%", margin: 0 } }, /* @__PURE__ */ h( + "header", + { + class: "modal-card-head", + style: { border: "1px solid", borderBottom: 0 } + }, + /* @__PURE__ */ h("p", { class: "modal-card-title" }, i18n2.str`Login required`) + ), /* @__PURE__ */ h( + "section", + { + class: "modal-card-body", + style: { border: "1px solid", borderTop: 0, borderBottom: 0 } + }, + /* @__PURE__ */ h(i18n2.Translate, null, "Please enter your access token for ", /* @__PURE__ */ h("b", null, '"', state.instance, '"'), "."), + /* @__PURE__ */ h("div", { class: "field is-horizontal" }, /* @__PURE__ */ h("div", { class: "field-label is-normal" }, /* @__PURE__ */ h("label", { class: "label" }, /* @__PURE__ */ h(i18n2.Translate, null, "Access Token"))), /* @__PURE__ */ h("div", { class: "field-body" }, /* @__PURE__ */ h("div", { class: "field" }, /* @__PURE__ */ h("p", { class: "control is-expanded" }, /* @__PURE__ */ h( + "input", + { + class: "input", + type: "password", + placeholder: "current access token", + name: "token", + onKeyPress: (e4) => e4.keyCode === 13 ? doLoginImpl() : null, + value: token, + onInput: (e4) => setToken(e4?.currentTarget.value) + } + ))))) + ), /* @__PURE__ */ h( + "footer", + { + class: "modal-card-foot ", + style: { + justifyContent: "space-between", + border: "1px solid", + borderTop: 0 + } + }, + /* @__PURE__ */ h("div", null), + /* @__PURE__ */ h(AsyncButton2, { type: "is-info", onClick: doLoginImpl }, /* @__PURE__ */ h(i18n2.Translate, null, "Confirm")) + ))))); +} +function AsyncButton2({ + onClick, + disabled, + type = "", + children +}) { + const [running, setRunning] = p3(false); + return /* @__PURE__ */ h( + "button", + { + class: "button " + type, + disabled: disabled || running, + onClick: () => { + setRunning(true); + onClick().then(() => { + setRunning(false); + }).catch(() => { + setRunning(false); + }); + } + }, + children + ); +} + // src/paths/admin/list/index.tsx function Instances({ - onUnauthorized, - onLoadError, - onNotFound, onCreate, - onUpdate, - setInstanceName + onUpdate }) { const result = useBackendInstances(); const [deleting, setDeleting] = p3(null); const [purging, setPurging] = p3(null); - const { deleteInstance, purgeInstance } = useAdminAPI(); const [notif, setNotif] = p3(void 0); const { i18n: i18n2 } = useTranslationContext(); - if (result.loading) + const { lib } = useMerchantApiContext(); + const { state } = useSessionContext(); + if (!result) return /* @__PURE__ */ h(Loading, null); - if (!result.ok) { - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.Unauthorized) - return onUnauthorized(); - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.NotFound) - return onNotFound(); - return onLoadError(result); + if (result instanceof TalerError) { + return /* @__PURE__ */ h(ErrorLoadingMerchant, { error: result }); + } + if (result.type === "fail") { + switch (result.case) { + case HttpStatusCode.Unauthorized: { + return /* @__PURE__ */ h(LoginPage, null); + } + default: { + assertUnreachable(result.case); + } + } } return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(NotificationCard, { notification: notif }), /* @__PURE__ */ h( View, { - instances: result.data.instances, + instances: result.body.instances, onDelete: setDeleting, onCreate, onPurge: setPurging, onUpdate, - setInstanceName, selected: !!deleting } ), deleting && /* @__PURE__ */ h( @@ -29190,8 +32339,11 @@ function Instances({ element: deleting, onCancel: () => setDeleting(null), onConfirm: async () => { + if (state.status !== "loggedIn") { + return; + } try { - await deleteInstance(deleting.id); + await lib.instance.deleteInstance(state.token, deleting.id); setNotif({ message: i18n2.str`Instance "${deleting.name}" (ID: ${deleting.id}) has been deleted`, type: "SUCCESS" @@ -29212,8 +32364,11 @@ function Instances({ element: purging, onCancel: () => setPurging(null), onConfirm: async () => { + if (state.status !== "loggedIn") { + return; + } try { - await purgeInstance(purging.id); + await lib.instance.deleteInstance(state.token, purging.id, { purge: true }); setNotif({ message: i18n2.str`Instance '${purging.name}' (ID: ${purging.id}) has been disabled`, type: "SUCCESS" @@ -29276,13 +32431,6 @@ function NavigationBar({ onMobileMenu, title }) { // src/components/menu/SideBar.tsx init_preact_module(); -// src/context/config.ts -init_preact_module(); -init_hooks_module(); -var Context4 = B(null); -var ConfigContextProvider = Context4.Provider; -var useConfigContext = () => q2(Context4); - // src/components/menu/LangSelector.tsx init_preact_module(); init_hooks_module(); @@ -38969,56 +42117,62 @@ function LangSelector() { // src/components/menu/SideBar.tsx var VERSION = true ? "0.9.3-dev.27" : void 0; -function Sidebar({ - mobile, - instance, - onShowSettings, - onLogout, - admin, - mimic, - isPasswordOk -}) { - const config = useConfigContext(); - const { url: backendURL } = useBackendContext(); +function Sidebar({ mobile }) { const { i18n: i18n2 } = useTranslationContext(); const kycStatus = useInstanceKYCDetails(); - const needKYC = kycStatus.ok && kycStatus.data.type === "redirect"; - return /* @__PURE__ */ h("aside", { class: "aside is-placed-left is-expanded", style: { overflowY: "scroll" } }, mobile && /* @__PURE__ */ h( - "div", - { - class: "footer", - onClick: (e4) => { - return e4.stopImmediatePropagation(); - } - }, - /* @__PURE__ */ h(LangSelector, null) - ), /* @__PURE__ */ h("div", { class: "aside-tools" }, /* @__PURE__ */ h("div", { class: "aside-tools-label" }, /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("b", null, "Taler"), " Backoffice"), /* @__PURE__ */ h( - "div", - { - class: "is-size-7 has-text-right", - style: { lineHeight: 0, marginTop: -10 } - }, - VERSION, - " (", - config.version, - ")" - ))), /* @__PURE__ */ h("div", { class: "menu is-menu-main" }, instance ? /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h("ul", { class: "menu-list" }, /* @__PURE__ */ h("li", null, /* @__PURE__ */ h("a", { href: "/orders", class: "has-icon" }, /* @__PURE__ */ h("span", { class: "icon" }, /* @__PURE__ */ h("i", { class: "mdi mdi-cash-register" })), /* @__PURE__ */ h("span", { class: "menu-item-label" }, /* @__PURE__ */ h(i18n2.Translate, null, "Orders")))), /* @__PURE__ */ h("li", null, /* @__PURE__ */ h("a", { href: "/inventory", class: "has-icon" }, /* @__PURE__ */ h("span", { class: "icon" }, /* @__PURE__ */ h("i", { class: "mdi mdi-shopping" })), /* @__PURE__ */ h("span", { class: "menu-item-label" }, /* @__PURE__ */ h(i18n2.Translate, null, "Inventory")))), /* @__PURE__ */ h("li", null, /* @__PURE__ */ h("a", { href: "/transfers", class: "has-icon" }, /* @__PURE__ */ h("span", { class: "icon" }, /* @__PURE__ */ h("i", { class: "mdi mdi-arrow-left-right" })), /* @__PURE__ */ h("span", { class: "menu-item-label" }, /* @__PURE__ */ h(i18n2.Translate, null, "Transfers")))), /* @__PURE__ */ h("li", null, /* @__PURE__ */ h("a", { href: "/templates", class: "has-icon" }, /* @__PURE__ */ h("span", { class: "icon" }, /* @__PURE__ */ h("i", { class: "mdi mdi-newspaper" })), /* @__PURE__ */ h("span", { class: "menu-item-label" }, /* @__PURE__ */ h(i18n2.Translate, null, "Templates")))), needKYC && /* @__PURE__ */ h("li", null, /* @__PURE__ */ h("a", { href: "/kyc", class: "has-icon" }, /* @__PURE__ */ h("span", { class: "icon" }, /* @__PURE__ */ h("i", { class: "mdi mdi-account-check" })), /* @__PURE__ */ h("span", { class: "menu-item-label" }, "KYC Status")))), /* @__PURE__ */ h("p", { class: "menu-label" }, /* @__PURE__ */ h(i18n2.Translate, null, "Configuration")), /* @__PURE__ */ h("ul", { class: "menu-list" }, /* @__PURE__ */ h("li", null, /* @__PURE__ */ h("a", { href: "/bank", class: "has-icon" }, /* @__PURE__ */ h("span", { class: "icon" }, /* @__PURE__ */ h("i", { class: "mdi mdi-bank" })), /* @__PURE__ */ h("span", { class: "menu-item-label" }, /* @__PURE__ */ h(i18n2.Translate, null, "Bank account")))), /* @__PURE__ */ h("li", null, /* @__PURE__ */ h("a", { href: "/otp-devices", class: "has-icon" }, /* @__PURE__ */ h("span", { class: "icon" }, /* @__PURE__ */ h("i", { class: "mdi mdi-lock" })), /* @__PURE__ */ h("span", { class: "menu-item-label" }, /* @__PURE__ */ h(i18n2.Translate, null, "OTP Devices")))), /* @__PURE__ */ h("li", null, /* @__PURE__ */ h("a", { href: "/webhooks", class: "has-icon" }, /* @__PURE__ */ h("span", { class: "icon" }, /* @__PURE__ */ h("i", { class: "mdi mdi-newspaper" })), /* @__PURE__ */ h("span", { class: "menu-item-label" }, /* @__PURE__ */ h(i18n2.Translate, null, "Webhooks")))), /* @__PURE__ */ h("li", null, /* @__PURE__ */ h("a", { href: "/settings", class: "has-icon" }, /* @__PURE__ */ h("span", { class: "icon" }, /* @__PURE__ */ h("i", { class: "mdi mdi-square-edit-outline" })), /* @__PURE__ */ h("span", { class: "menu-item-label" }, /* @__PURE__ */ h(i18n2.Translate, null, "Settings")))), /* @__PURE__ */ h("li", null, /* @__PURE__ */ h("a", { href: "/token", class: "has-icon" }, /* @__PURE__ */ h("span", { class: "icon" }, /* @__PURE__ */ h("i", { class: "mdi mdi-security" })), /* @__PURE__ */ h("span", { class: "menu-item-label" }, /* @__PURE__ */ h(i18n2.Translate, null, "Access token")))))) : void 0, /* @__PURE__ */ h("p", { class: "menu-label" }, /* @__PURE__ */ h(i18n2.Translate, null, "Connection")), /* @__PURE__ */ h("ul", { class: "menu-list" }, /* @__PURE__ */ h("li", null, /* @__PURE__ */ h( - "a", - { - class: "has-icon is-state-info is-hoverable", - onClick: () => onShowSettings() - }, - /* @__PURE__ */ h("span", { class: "icon" }, /* @__PURE__ */ h("i", { class: "mdi mdi-newspaper" })), - /* @__PURE__ */ h("span", { class: "menu-item-label" }, /* @__PURE__ */ h(i18n2.Translate, null, "Interface")) - )), /* @__PURE__ */ h("li", null, /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("span", { style: { width: "3rem" }, class: "icon" }, /* @__PURE__ */ h("i", { class: "mdi mdi-web" })), /* @__PURE__ */ h("span", { class: "menu-item-label" }, new URL(backendURL).hostname))), /* @__PURE__ */ h("li", null, /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("span", { style: { width: "3rem" }, class: "icon" }, "ID"), /* @__PURE__ */ h("span", { class: "menu-item-label" }, !instance ? "default" : instance))), admin && !mimic && /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h("p", { class: "menu-label" }, /* @__PURE__ */ h(i18n2.Translate, null, "Instances")), /* @__PURE__ */ h("li", null, /* @__PURE__ */ h("a", { href: "/instance/new", class: "has-icon" }, /* @__PURE__ */ h("span", { class: "icon" }, /* @__PURE__ */ h("i", { class: "mdi mdi-plus" })), /* @__PURE__ */ h("span", { class: "menu-item-label" }, /* @__PURE__ */ h(i18n2.Translate, null, "New")))), /* @__PURE__ */ h("li", null, /* @__PURE__ */ h("a", { href: "/instances", class: "has-icon" }, /* @__PURE__ */ h("span", { class: "icon" }, /* @__PURE__ */ h("i", { class: "mdi mdi-format-list-bulleted" })), /* @__PURE__ */ h("span", { class: "menu-item-label" }, /* @__PURE__ */ h(i18n2.Translate, null, "List"))))), isPasswordOk ? /* @__PURE__ */ h("li", null, /* @__PURE__ */ h( - "a", + const needKYC = kycStatus !== void 0 && !(kycStatus instanceof TalerError) && kycStatus.type === "ok" && !!kycStatus.body; + const { state, logOut } = useSessionContext(); + const isLoggedIn = state.status === "loggedIn"; + const hasToken = isLoggedIn && state.token !== void 0; + const { config, url: backendURL } = useMerchantApiContext(); + return /* @__PURE__ */ h( + "aside", { - class: "has-icon is-state-info is-hoverable", - onClick: () => onLogout() + class: "aside is-placed-left is-expanded", + style: { overflowY: "scroll" } }, - /* @__PURE__ */ h("span", { class: "icon" }, /* @__PURE__ */ h("i", { class: "mdi mdi-logout default" })), - /* @__PURE__ */ h("span", { class: "menu-item-label" }, /* @__PURE__ */ h(i18n2.Translate, null, "Log out")) - )) : void 0))); + mobile && /* @__PURE__ */ h( + "div", + { + class: "footer", + onClick: (e4) => { + return e4.stopImmediatePropagation(); + } + }, + /* @__PURE__ */ h(LangSelector, null) + ), + /* @__PURE__ */ h("div", { class: "aside-tools" }, /* @__PURE__ */ h("div", { class: "aside-tools-label" }, /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("b", null, "Taler"), " Backoffice"), /* @__PURE__ */ h( + "div", + { + class: "is-size-7 has-text-right", + style: { lineHeight: 0, marginTop: -10 } + }, + VERSION, + " (", + config.version, + ")" + ))), + /* @__PURE__ */ h("div", { class: "menu is-menu-main" }, isLoggedIn ? /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h("ul", { class: "menu-list" }, /* @__PURE__ */ h("li", null, /* @__PURE__ */ h("a", { href: "/orders", class: "has-icon" }, /* @__PURE__ */ h("span", { class: "icon" }, /* @__PURE__ */ h("i", { class: "mdi mdi-cash-register" })), /* @__PURE__ */ h("span", { class: "menu-item-label" }, /* @__PURE__ */ h(i18n2.Translate, null, "Orders")))), /* @__PURE__ */ h("li", null, /* @__PURE__ */ h("a", { href: "/inventory", class: "has-icon" }, /* @__PURE__ */ h("span", { class: "icon" }, /* @__PURE__ */ h("i", { class: "mdi mdi-shopping" })), /* @__PURE__ */ h("span", { class: "menu-item-label" }, /* @__PURE__ */ h(i18n2.Translate, null, "Inventory")))), /* @__PURE__ */ h("li", null, /* @__PURE__ */ h("a", { href: "/transfers", class: "has-icon" }, /* @__PURE__ */ h("span", { class: "icon" }, /* @__PURE__ */ h("i", { class: "mdi mdi-arrow-left-right" })), /* @__PURE__ */ h("span", { class: "menu-item-label" }, /* @__PURE__ */ h(i18n2.Translate, null, "Transfers")))), /* @__PURE__ */ h("li", null, /* @__PURE__ */ h("a", { href: "/templates", class: "has-icon" }, /* @__PURE__ */ h("span", { class: "icon" }, /* @__PURE__ */ h("i", { class: "mdi mdi-newspaper" })), /* @__PURE__ */ h("span", { class: "menu-item-label" }, /* @__PURE__ */ h(i18n2.Translate, null, "Templates")))), needKYC && /* @__PURE__ */ h("li", null, /* @__PURE__ */ h("a", { href: "/kyc", class: "has-icon" }, /* @__PURE__ */ h("span", { class: "icon" }, /* @__PURE__ */ h("i", { class: "mdi mdi-account-check" })), /* @__PURE__ */ h("span", { class: "menu-item-label" }, "KYC Status")))), /* @__PURE__ */ h("p", { class: "menu-label" }, /* @__PURE__ */ h(i18n2.Translate, null, "Configuration")), /* @__PURE__ */ h("ul", { class: "menu-list" }, /* @__PURE__ */ h("li", null, /* @__PURE__ */ h("a", { href: "/bank", class: "has-icon" }, /* @__PURE__ */ h("span", { class: "icon" }, /* @__PURE__ */ h("i", { class: "mdi mdi-bank" })), /* @__PURE__ */ h("span", { class: "menu-item-label" }, /* @__PURE__ */ h(i18n2.Translate, null, "Bank account")))), /* @__PURE__ */ h("li", null, /* @__PURE__ */ h("a", { href: "/otp-devices", class: "has-icon" }, /* @__PURE__ */ h("span", { class: "icon" }, /* @__PURE__ */ h("i", { class: "mdi mdi-lock" })), /* @__PURE__ */ h("span", { class: "menu-item-label" }, /* @__PURE__ */ h(i18n2.Translate, null, "OTP Devices")))), /* @__PURE__ */ h("li", null, /* @__PURE__ */ h("a", { href: "/webhooks", class: "has-icon" }, /* @__PURE__ */ h("span", { class: "icon" }, /* @__PURE__ */ h("i", { class: "mdi mdi-newspaper" })), /* @__PURE__ */ h("span", { class: "menu-item-label" }, /* @__PURE__ */ h(i18n2.Translate, null, "Webhooks")))), /* @__PURE__ */ h("li", null, /* @__PURE__ */ h("a", { href: "/settings", class: "has-icon" }, /* @__PURE__ */ h("span", { class: "icon" }, /* @__PURE__ */ h("i", { class: "mdi mdi-square-edit-outline" })), /* @__PURE__ */ h("span", { class: "menu-item-label" }, /* @__PURE__ */ h(i18n2.Translate, null, "Settings")))), /* @__PURE__ */ h("li", null, /* @__PURE__ */ h("a", { href: "/token", class: "has-icon" }, /* @__PURE__ */ h("span", { class: "icon" }, /* @__PURE__ */ h("i", { class: "mdi mdi-security" })), /* @__PURE__ */ h("span", { class: "menu-item-label" }, /* @__PURE__ */ h(i18n2.Translate, null, "Access token")))))) : void 0, /* @__PURE__ */ h("p", { class: "menu-label" }, /* @__PURE__ */ h(i18n2.Translate, null, "Connection")), /* @__PURE__ */ h("ul", { class: "menu-list" }, /* @__PURE__ */ h("li", null, /* @__PURE__ */ h( + "a", + { + class: "has-icon is-state-info is-hoverable", + href: "/interface" + }, + /* @__PURE__ */ h("span", { class: "icon" }, /* @__PURE__ */ h("i", { class: "mdi mdi-newspaper" })), + /* @__PURE__ */ h("span", { class: "menu-item-label" }, /* @__PURE__ */ h(i18n2.Translate, null, "Interface")) + )), /* @__PURE__ */ h("li", null, /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("span", { style: { width: "3rem" }, class: "icon" }, /* @__PURE__ */ h("i", { class: "mdi mdi-web" })), /* @__PURE__ */ h("span", { class: "menu-item-label" }, backendURL.hostname))), /* @__PURE__ */ h("li", null, /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("span", { style: { width: "3rem" }, class: "icon" }, "ID"), /* @__PURE__ */ h("span", { class: "menu-item-label" }, state.instance))), state.isAdmin && /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h("p", { class: "menu-label" }, /* @__PURE__ */ h(i18n2.Translate, null, "Instances")), /* @__PURE__ */ h("li", null, /* @__PURE__ */ h("a", { href: "/instance/new", class: "has-icon" }, /* @__PURE__ */ h("span", { class: "icon" }, /* @__PURE__ */ h("i", { class: "mdi mdi-plus" })), /* @__PURE__ */ h("span", { class: "menu-item-label" }, /* @__PURE__ */ h(i18n2.Translate, null, "New")))), /* @__PURE__ */ h("li", null, /* @__PURE__ */ h("a", { href: "/instances", class: "has-icon" }, /* @__PURE__ */ h("span", { class: "icon" }, /* @__PURE__ */ h("i", { class: "mdi mdi-format-list-bulleted" })), /* @__PURE__ */ h("span", { class: "menu-item-label" }, /* @__PURE__ */ h(i18n2.Translate, null, "List"))))), hasToken ? /* @__PURE__ */ h("li", null, /* @__PURE__ */ h( + "a", + { + class: "has-icon is-state-info is-hoverable", + onClick: (e4) => { + logOut(); + e4.preventDefault(); + } + }, + /* @__PURE__ */ h("span", { class: "icon" }, /* @__PURE__ */ h("i", { class: "mdi mdi-logout default" })), + /* @__PURE__ */ h("span", { class: "menu-item-label" }, /* @__PURE__ */ h(i18n2.Translate, null, "Log out")) + )) : void 0)) + ); } // src/components/menu/index.tsx @@ -39086,20 +42240,12 @@ function WithTitle({ }, [title]); return /* @__PURE__ */ h(p2, null, children); } -function Menu({ - onLogout, - onShowSettings, - title, - instance, - path, - admin, - setInstanceName, - isPasswordOk -}) { +function Menu(_p) { const [mobileOpen, setMobileOpen] = p3(false); - const titleWithSubtitle = title ? title : !admin ? getInstanceTitle(path, instance) : getAdminTitle(path, instance); - const adminInstance = instance === "default"; - const mimic = admin && !adminInstance; + const { state, deImpersonate } = useSessionContext(); + const { path } = useNavigationContext(); + const titleWithSubtitle = !state.isAdmin ? getInstanceTitle(path, state.instance) : getAdminTitle(path, state.instance); + const isLoggedIn = state.status === "loggedIn"; return /* @__PURE__ */ h(WithTitle, { title: titleWithSubtitle }, /* @__PURE__ */ h( "div", { @@ -39113,33 +42259,30 @@ function Menu({ title: titleWithSubtitle } ), - onLogout && /* @__PURE__ */ h( - Sidebar, - { - onShowSettings, - onLogout, - admin, - mimic, - instance, - mobile: mobileOpen, - isPasswordOk - } - ), - mimic && /* @__PURE__ */ h("nav", { class: "level", style: { - zIndex: 100, - position: "fixed", - width: "50%", - marginLeft: "20%" - } }, /* @__PURE__ */ h("div", { class: "level-item has-text-centered has-background-warning" }, /* @__PURE__ */ h("p", { class: "is-size-5" }, "You are viewing the instance ", /* @__PURE__ */ h("b", null, '"', instance, '"'), ".", " ", /* @__PURE__ */ h( - "a", + isLoggedIn && /* @__PURE__ */ h(Sidebar, { mobile: mobileOpen }), + state.status !== "loggedOut" && state.impersonate !== void 0 && /* @__PURE__ */ h( + "nav", { - href: "#/instances", - onClick: (e4) => { - setInstanceName("default"); + class: "level", + style: { + zIndex: 100, + position: "fixed", + width: "50%", + marginLeft: "20%" } }, - "go back" - )))) + /* @__PURE__ */ h("div", { class: "level-item has-text-centered has-background-warning" }, /* @__PURE__ */ h("p", { class: "is-size-5" }, "You are viewing the instance ", /* @__PURE__ */ h("b", null, '"', state.instance, '"'), ".", " ", /* @__PURE__ */ h( + "a", + { + href: "#/instances", + onClick: (e4) => { + deImpersonate(); + e4.preventDefault(); + } + }, + "go back" + ))) + ) )); } function NotificationCard({ @@ -39178,150 +42321,82 @@ function NotConnectedAppMenu({ ) ); } -function NotYetReadyAppMenu({ - onLogout, - onShowSettings, - title, - isPasswordOk -}) { - const [mobileOpen, setMobileOpen] = p3(false); - h2(() => { - document.title = `Taler Backoffice: ${title}`; - }, [title]); - return /* @__PURE__ */ h( - "div", - { - class: mobileOpen ? "has-aside-mobile-expanded" : "", - onClick: () => setMobileOpen(false) - }, - /* @__PURE__ */ h( - NavigationBar, - { - onMobileMenu: () => setMobileOpen(!mobileOpen), - title - } - ), - onLogout && /* @__PURE__ */ h(Sidebar, { onShowSettings, onLogout, instance: "", mobile: mobileOpen, isPasswordOk }) - ); -} // src/hooks/bank.ts -init_hooks_module(); var useSWR3 = useSWR; -function useBankAccountAPI() { - const mutateAll = useMatchMutate(); - const { request } = useBackendInstanceRequest(); - const createBankAccount = async (data) => { - const res = await request(`/private/accounts`, { - method: "POST", - data - }); - await mutateAll(/.*private\/accounts.*/); - return res; - }; - const updateBankAccount = async (h_wire, data) => { - const res = await request(`/private/accounts/${h_wire}`, { - method: "PATCH", - data - }); - await mutateAll(/.*private\/accounts.*/); - return res; - }; - const deleteBankAccount = async (h_wire) => { - const res = await request(`/private/accounts/${h_wire}`, { - method: "DELETE" - }); - await mutateAll(/.*private\/accounts.*/); - return res; - }; - return { - createBankAccount, - updateBankAccount, - deleteBankAccount - }; +function revalidateInstanceBankAccounts() { + return mutate( + (key) => Array.isArray(key) && key[key.length - 1] === "listBankAccounts", + void 0, + { revalidate: true } + ); } -function useInstanceBankAccounts(args, updatePosition) { - const { fetcher } = useBackendInstanceRequest(); - const [pageAfter, setPageAfter] = p3(1); - const totalAfter = pageAfter * PAGE_SIZE; - const { - data: afterData, - error: afterError, - isValidating: loadingAfter - } = useSWR3([`/private/accounts`], fetcher); - const [lastAfter, setLastAfter] = p3({ loading: true }); - h2(() => { - if (afterData) - setLastAfter(afterData); - }, [ - afterData - /*, beforeData*/ - ]); - if (afterError) - return afterError.cause; - const isReachingEnd = afterData && afterData.data.accounts.length < totalAfter; - const isReachingStart = false; - const pagination = { - isReachingEnd, - isReachingStart, - loadMore: () => { - if (!afterData || isReachingEnd) - return; - if (afterData.data.accounts.length < MAX_RESULT_SIZE) { - setPageAfter(pageAfter + 1); - } else { - const from = `${afterData.data.accounts[afterData.data.accounts.length - 1].h_wire}`; - if (from && updatePosition) - updatePosition(from); - } - }, - loadMorePrev: () => { - } - }; - const accounts = !afterData ? [] : (afterData || lastAfter).data.accounts; - if (loadingAfter) - return { loading: true, data: { accounts } }; - if ( - /*beforeData &&*/ - afterData - ) { - return { ok: true, data: { accounts }, ...pagination }; +function useInstanceBankAccounts() { + const { state: session } = useSessionContext(); + const { lib: { instance } } = useMerchantApiContext(); + async function fetcher([token, bid]) { + return await instance.listBankAccounts(token, { + // limit: PAGINATED_LIST_REQUEST, + // offset: bid, + // order: "dec", + }); } - return { loading: true }; + const { data, error: error2 } = useSWR3([session.token, "offset", "listBankAccounts"], fetcher); + if (error2) + return error2; + if (data === void 0) + return void 0; + if (data.type !== "ok") + return data; + return data; +} +function revalidateBankAccountDetails() { + return mutate( + (key) => Array.isArray(key) && key[key.length - 1] === "getBankAccountDetails", + void 0, + { revalidate: true } + ); } function useBankAccountDetails(h_wire) { - const { fetcher } = useBackendInstanceRequest(); - const { data, error: error2, isValidating } = useSWR3([`/private/accounts/${h_wire}`], fetcher, { - refreshInterval: 0, - refreshWhenHidden: false, - revalidateOnFocus: false, - revalidateOnReconnect: false, - refreshWhenOffline: false - }); - if (isValidating) - return { loading: true, data: data?.data }; - if (data) { - return data; + const { state: session } = useSessionContext(); + const { lib: { instance } } = useMerchantApiContext(); + async function fetcher([token, wireId]) { + return await instance.getBankAccountDetails(token, wireId); } + const { data, error: error2 } = useSWR3([session.token, h_wire, "getBankAccountDetails"], fetcher); + if (data) + return data; if (error2) - return error2.cause; - return { loading: true }; + return error2; + return void 0; } -// src/hooks/useSettings.ts +// src/hooks/preference.ts var defaultSettings = { advanceOrderMode: false, + hideKycUntil: AbsoluteTime.never(), + hideMissingAccountUntil: AbsoluteTime.never(), dateFormat: "ymd" }; -var codecForSettings = () => buildCodecForObject().property("advanceOrderMode", codecForBoolean()).property("dateFormat", codecForEither( - codecForConstString("ymd"), - codecForConstString("dmy"), - codecForConstString("mdy") -)).build("Settings"); -var SETTINGS_KEY = buildStorageKey("merchant-settings", codecForSettings()); -function useSettings() { - const { value, update } = useLocalStorage(SETTINGS_KEY, defaultSettings); - return [value, update]; +var codecForPreferences = () => buildCodecForObject().property("advanceOrderMode", codecForBoolean()).property("hideKycUntil", codecForAbsoluteTime).property("hideMissingAccountUntil", codecForAbsoluteTime).property( + "dateFormat", + codecForEither( + codecForConstString("ymd"), + codecForConstString("dmy"), + codecForConstString("mdy") + ) +).build("Preferences"); +var PREFERENCES_KEY = buildStorageKey( + "merchant-preferences", + codecForPreferences() +); +function usePreference() { + const { value, update } = useLocalStorage(PREFERENCES_KEY, defaultSettings); + function updateField(k5, v3) { + const newValue = { ...value, [k5]: v3 }; + update(newValue); + } + return [value, updateField, update]; } function dateFormatForSettings(s5) { switch (s5.dateFormat) { @@ -39436,13 +42511,13 @@ function InputPaytoForm({ const paths = !initialPayto ? [] : initialPayto.targetPath.split("/"); const initialPath1 = paths.length >= 1 ? paths[0] : void 0; const initialPath2 = paths.length >= 2 ? paths[1] : void 0; - const initial2 = initialPayto === void 0 ? defaultTarget : { + const initial3 = initialPayto === void 0 ? defaultTarget : { target: initialPayto.targetType, params: initialPayto.params, path1: initialPath1, path2: initialPath2 }; - const [value, setValue] = p3(initial2); + const [value, setValue] = p3(initial3); const { i18n: i18n2 } = useTranslationContext(); const errors2 = { target: value.target === noTargetValue ? i18n2.str`required` : void 0, @@ -39586,26 +42661,138 @@ function InputPaytoForm({ )); } -// src/paths/instance/accounts/create/CreatePage.tsx -var accountAuthType = ["none", "basic"]; -function isValidURL(s5) { +// src/paths/instance/accounts/update/UpdatePage.tsx +init_preact_module(); +init_hooks_module(); +var accountAuthType = ["unedit", "none", "basic"]; +function UpdatePage({ account, onUpdate, onBack }) { + const { i18n: i18n2 } = useTranslationContext(); + const [state, setState] = p3(account); + if (state.credit_facade_credentials?.type === "unedit") { + state.credit_facade_credentials = void 0; + } + const facadeURL = safeConvertURL(state.credit_facade_url); + const errors2 = { + credit_facade_url: !state.credit_facade_url ? void 0 : !facadeURL ? i18n2.str`Invalid url` : !facadeURL.href.endsWith("/") ? i18n2.str`URL should end with a '/'` : facadeURL.searchParams.size > 0 ? i18n2.str`URL should not contain params` : facadeURL.hash ? i18n2.str`URL should not hash param` : void 0, + credit_facade_credentials: undefinedIfEmpty({ + username: state.credit_facade_credentials?.type !== "basic" ? void 0 : !state.credit_facade_credentials.username ? i18n2.str`required` : void 0, + password: state.credit_facade_credentials?.type !== "basic" ? void 0 : !state.credit_facade_credentials.password ? i18n2.str`required` : void 0, + repeatPassword: state.credit_facade_credentials?.type !== "basic" ? void 0 : !state.credit_facade_credentials.repeatPassword ? i18n2.str`required` : state.credit_facade_credentials.repeatPassword !== state.credit_facade_credentials.password ? i18n2.str`doesn't match` : void 0 + }) + }; + const hasErrors = Object.keys(errors2).some( + (k5) => errors2[k5] !== void 0 + ); + const submitForm = () => { + if (hasErrors) + return Promise.reject(); + const credit_facade_url = !state.credit_facade_url ? void 0 : facadeURL?.href; + const credit_facade_credentials = credit_facade_url == void 0 || state.credit_facade_credentials === void 0 ? void 0 : state.credit_facade_credentials.type === "basic" ? { + type: "basic", + password: state.credit_facade_credentials.password, + username: state.credit_facade_credentials.username + } : { + type: "none" + }; + return onUpdate({ credit_facade_credentials, credit_facade_url }); + }; + return /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("section", { class: "section" }, /* @__PURE__ */ h("section", { class: "hero is-hero-bar" }, /* @__PURE__ */ h("div", { class: "hero-body" }, /* @__PURE__ */ h("div", { class: "level" }, /* @__PURE__ */ h("div", { class: "level-left" }, /* @__PURE__ */ h("div", { class: "level-item" }, /* @__PURE__ */ h("span", { class: "is-size-4" }, "Account: ", /* @__PURE__ */ h("b", null, account.id.substring(0, 8), "..."))))))), /* @__PURE__ */ h("hr", null), /* @__PURE__ */ h("section", { class: "section is-main-section" }, /* @__PURE__ */ h("div", { class: "columns" }, /* @__PURE__ */ h("div", { class: "column is-four-fifths" }, /* @__PURE__ */ h( + FormProvider, + { + object: state, + valueHandler: setState, + errors: errors2 + }, + /* @__PURE__ */ h( + InputPaytoForm, + { + name: "payto_uri", + label: i18n2.str`Account`, + readonly: true + } + ), + /* @__PURE__ */ h( + Input, + { + name: "credit_facade_url", + label: i18n2.str`Account info URL`, + help: "https://bank.com", + expand: true, + tooltip: i18n2.str`From where the merchant can download information about incoming wire transfers to this account` + } + ), + /* @__PURE__ */ h( + InputSelector, + { + name: "credit_facade_credentials.type", + label: i18n2.str`Auth type`, + tooltip: i18n2.str`Choose the authentication type for the account info URL`, + values: accountAuthType, + toStr: (str) => { + if (str === "none") + return "Without authentication"; + if (str === "basic") + return "With authentication"; + return "Do not change"; + } + } + ), + state.credit_facade_credentials?.type === "basic" ? /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h( + Input, + { + name: "credit_facade_credentials.username", + label: i18n2.str`Username`, + tooltip: i18n2.str`Username to access the account information.` + } + ), /* @__PURE__ */ h( + Input, + { + name: "credit_facade_credentials.password", + inputType: "password", + label: i18n2.str`Password`, + tooltip: i18n2.str`Password to access the account information.` + } + ), /* @__PURE__ */ h( + Input, + { + name: "credit_facade_credentials.repeatPassword", + inputType: "password", + label: i18n2.str`Repeat password` + } + )) : void 0 + ), /* @__PURE__ */ h("div", { class: "buttons is-right mt-5" }, onBack && /* @__PURE__ */ h("button", { class: "button", onClick: onBack }, /* @__PURE__ */ h(i18n2.Translate, null, "Cancel")), /* @__PURE__ */ h( + AsyncButton, + { + disabled: hasErrors, + "data-tooltip": hasErrors ? i18n2.str`Need to complete marked fields` : "confirm operation", + onClick: submitForm + }, + /* @__PURE__ */ h(i18n2.Translate, null, "Confirm") + ))))))); +} +function safeConvertURL(s5) { + if (!s5) + return void 0; try { - const u4 = new URL("/", s5); - return true; + return new URL(s5); } catch (e4) { - return false; + return void 0; } } + +// src/paths/instance/accounts/create/CreatePage.tsx +var accountAuthType2 = ["none", "basic"]; function CreatePage2({ onCreate, onBack }) { const { i18n: i18n2 } = useTranslationContext(); const [state, setState] = p3({}); + const facadeURL = safeConvertURL(state.credit_facade_url); const errors2 = { payto_uri: !state.payto_uri ? i18n2.str`required` : void 0, credit_facade_credentials: !state.credit_facade_credentials ? void 0 : undefinedIfEmpty({ username: state.credit_facade_credentials.type === "basic" && !state.credit_facade_credentials.username ? i18n2.str`required` : void 0, password: state.credit_facade_credentials.type === "basic" && !state.credit_facade_credentials.password ? i18n2.str`required` : void 0 }), - credit_facade_url: !state.credit_facade_url ? void 0 : !isValidURL(state.credit_facade_url) ? i18n2.str`not valid url` : void 0, + credit_facade_url: !state.credit_facade_url ? void 0 : !facadeURL ? i18n2.str`Invalid url` : !facadeURL.href.endsWith("/") ? i18n2.str`URL should end with a '/'` : facadeURL.searchParams.size > 0 ? i18n2.str`URL should not contain params` : facadeURL.hash ? i18n2.str`URL should not hash param` : void 0, repeatPassword: !state.credit_facade_credentials ? void 0 : state.credit_facade_credentials.type === "basic" && (!state.credit_facade_credentials.password || state.credit_facade_credentials.password !== state.repeatPassword) ? i18n2.str`is not the same` : void 0 }; const hasErrors = Object.keys(errors2).some( @@ -39614,7 +42801,7 @@ function CreatePage2({ onCreate, onBack }) { const submitForm = () => { if (hasErrors) return Promise.reject(); - const credit_facade_url = !state.credit_facade_url ? void 0 : new URL("/", state.credit_facade_url).href; + const credit_facade_url = !state.credit_facade_url ? void 0 : facadeURL?.href; const credit_facade_credentials = credit_facade_url == void 0 ? void 0 : state.credit_facade_credentials?.type === "basic" ? { type: "basic", password: state.credit_facade_credentials.password, @@ -39658,7 +42845,7 @@ function CreatePage2({ onCreate, onBack }) { name: "credit_facade_credentials.type", label: i18n2.str`Auth type`, tooltip: i18n2.str`Choose the authentication type for the account info URL`, - values: accountAuthType, + values: accountAuthType2, toStr: (str) => { if (str === "none") return "Without authentication"; @@ -39702,15 +42889,70 @@ function CreatePage2({ onCreate, onBack }) { // src/paths/instance/accounts/create/index.tsx function CreateValidator({ onConfirm, onBack }) { - const { createBankAccount } = useBankAccountAPI(); + const { lib: api } = useMerchantApiContext(); + const { state } = useSessionContext(); const [notif, setNotif] = p3(void 0); const { i18n: i18n2 } = useTranslationContext(); return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(NotificationCard, { notification: notif }), /* @__PURE__ */ h( CreatePage2, { onBack, - onCreate: (request) => { - return createBankAccount(request).then((d5) => { + onCreate: async (request) => { + const revenueAPI = !request.credit_facade_url ? void 0 : new URL("./", request.credit_facade_url); + if (revenueAPI) { + const resp = await testRevenueAPI( + revenueAPI, + request.credit_facade_credentials + ); + if (resp.type === "fail") { + switch (resp.case) { + case 0 /* NO_CONFIG */: { + setNotif({ + message: i18n2.str`Could not create account`, + type: "ERROR", + description: i18n2.str`The endpoint doesn't seems to be a Taler Revenue API` + }); + return; + } + case 1 /* CLIENT_BAD_REQUEST */: { + setNotif({ + message: i18n2.str`Could not create account`, + type: "ERROR", + description: i18n2.str`Server replied with "bad request".` + }); + return; + } + case 2 /* UNAUTHORIZED */: { + setNotif({ + message: i18n2.str`Could not create account`, + type: "ERROR", + description: i18n2.str`Unauthorized, try with another credentials.` + }); + return; + } + case 3 /* NOT_FOUND */: { + setNotif({ + message: i18n2.str`Could not create account`, + type: "ERROR", + description: i18n2.str`Check facade URL, server replied with "not found".` + }); + return; + } + case 4 /* GENERIC_ERROR */: { + setNotif({ + message: i18n2.str`Could not create account`, + type: "ERROR", + description: resp.detail.hint + }); + return; + } + default: { + assertUnreachable(resp.case); + } + } + } + } + return api.instance.addBankAccount(state.token, request).then(() => { onConfirm(); }).catch((error2) => { setNotif({ @@ -39723,11 +42965,118 @@ function CreateValidator({ onConfirm, onBack }) { } )); } +async function testRevenueAPI(revenueAPI, creds) { + const api = new TalerRevenueHttpClient( + revenueAPI.href, + new BrowserFetchHttpLib() + ); + const auth = creds === void 0 ? void 0 : creds.type === "none" ? void 0 : creds.type === "basic" ? { + username: creds.username, + password: creds.password + } : void 0; + try { + const config = await api.getConfig(auth); + if (config.type === "fail") { + switch (config.case) { + case HttpStatusCode.Unauthorized: { + return { + type: "fail", + case: 2 /* UNAUTHORIZED */, + detail: { + code: 1 + } + }; + } + case HttpStatusCode.NotFound: { + return { + type: "fail", + case: 0 /* NO_CONFIG */, + detail: { + code: 1 + } + }; + } + } + } + const history3 = await api.getHistory(auth); + if (history3.type === "fail") { + switch (history3.case) { + case HttpStatusCode.BadRequest: { + return { + type: "fail", + case: 1 /* CLIENT_BAD_REQUEST */, + detail: { + code: 1 + } + }; + } + case HttpStatusCode.Unauthorized: { + return { + type: "fail", + case: 2 /* UNAUTHORIZED */, + detail: { + code: 1 + } + }; + } + case HttpStatusCode.NotFound: { + return { + type: "fail", + case: 3 /* NOT_FOUND */, + detail: { + code: 1 + } + }; + } + } + } + } catch (err) { + if (err instanceof TalerError) { + return { + type: "fail", + case: 4 /* GENERIC_ERROR */, + detail: err.errorDetail + }; + } + } + return opFixedSuccess(void 0); +} // src/paths/instance/accounts/list/index.tsx init_preact_module(); init_hooks_module(); +// src/paths/notfound/index.tsx +init_preact_module(); +function NotFoundPage() { + return /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("p", null, "That page doesn't exist."), /* @__PURE__ */ h(Link, { href: "/" }, /* @__PURE__ */ h("h4", null, "Back to Home"))); +} +function NotFoundPageOrAdminCreate() { + const { state } = useSessionContext(); + const { i18n: i18n2 } = useTranslationContext(); + if (state.isAdmin && state.instance === DEFAULT_ADMIN_USERNAME) { + return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h( + NotificationCard, + { + notification: { + message: i18n2.str`No 'default' instance configured yet.`, + description: i18n2.str`Create a 'default' instance to begin using the merchant backoffice.`, + type: "INFO" + } + } + ), /* @__PURE__ */ h( + Create, + { + forceId: DEFAULT_ADMIN_USERNAME, + onConfirm: () => { + route("/bank" /* bank_list */); + } + } + )); + } + return /* @__PURE__ */ h(NotFoundPage, null); +} + // src/paths/instance/accounts/list/ListPage.tsx init_preact_module(); @@ -39738,11 +43087,7 @@ function CardTable2({ accounts, onCreate, onDelete, - onSelect, - onLoadMoreAfter, - onLoadMoreBefore, - hasMoreAfter, - hasMoreBefore + onSelect }) { const [rowSelection, rowSelectionHandler] = p3([]); const { i18n: i18n2 } = useTranslationContext(); @@ -39760,22 +43105,14 @@ function CardTable2({ onDelete, onSelect, rowSelection, - rowSelectionHandler, - onLoadMoreAfter, - onLoadMoreBefore, - hasMoreAfter, - hasMoreBefore + rowSelectionHandler } ) : /* @__PURE__ */ h(EmptyTable2, null))))); } function Table2({ accounts, - onLoadMoreAfter, onDelete, - onSelect, - onLoadMoreBefore, - hasMoreAfter, - hasMoreBefore + onSelect }) { const { i18n: i18n2 } = useTranslationContext(); const emptyList = { "bitcoin": [], "x-taler-bank": [], "iban": [], "unknown": [] }; @@ -39912,7 +43249,7 @@ function Table2({ } function EmptyTable2() { const { i18n: i18n2 } = useTranslationContext(); - return /* @__PURE__ */ h("div", { class: "content has-text-grey has-text-centered" }, /* @__PURE__ */ h("p", null, /* @__PURE__ */ h("span", { class: "icon is-large" }, /* @__PURE__ */ h("i", { class: "mdi mdi-emoticon-sad mdi-48px" }))), /* @__PURE__ */ h("p", null, /* @__PURE__ */ h(i18n2.Translate, null, "There is no accounts yet, add more pressing the + sign"))); + return /* @__PURE__ */ h("div", { class: "content has-text-grey has-text-centered" }, /* @__PURE__ */ h("p", null, /* @__PURE__ */ h("span", { class: "icon is-large" }, /* @__PURE__ */ h("i", { class: "mdi mdi-magnify mdi-48px" }))), /* @__PURE__ */ h("p", null, /* @__PURE__ */ h(i18n2.Translate, null, "There is no accounts yet, add more pressing the + sign"))); } // src/paths/instance/accounts/list/ListPage.tsx @@ -39920,12 +43257,10 @@ function ListPage({ devices, onCreate, onDelete, - onSelect, - onLoadMoreBefore, - onLoadMoreAfter + onSelect + // onLoadMoreBefore, + // onLoadMoreAfter, }) { - const form = { payto_uri: "" }; - const { i18n: i18n2 } = useTranslationContext(); return /* @__PURE__ */ h("section", { class: "section is-main-section" }, /* @__PURE__ */ h( CardTable2, { @@ -39935,63 +43270,65 @@ function ListPage({ })), onCreate, onDelete, - onSelect, - onLoadMoreBefore, - hasMoreBefore: !onLoadMoreBefore, - onLoadMoreAfter, - hasMoreAfter: !onLoadMoreAfter + onSelect } )); } // src/paths/instance/accounts/list/index.tsx function ListOtpDevices({ - onUnauthorized, - onLoadError, onCreate, - onSelect, - onNotFound + onSelect }) { - const [position, setPosition] = p3(void 0); const { i18n: i18n2 } = useTranslationContext(); const [notif, setNotif] = p3(void 0); - const { deleteBankAccount } = useBankAccountAPI(); - const result = useInstanceBankAccounts({ position }, (id) => setPosition(id)); - if (result.loading) + const { lib: api } = useMerchantApiContext(); + const { state } = useSessionContext(); + const result = useInstanceBankAccounts(); + if (!result) return /* @__PURE__ */ h(Loading, null); - if (!result.ok) { - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.Unauthorized) - return onUnauthorized(); - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.NotFound) - return onNotFound(); - return onLoadError(result); - } - return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(NotificationCard, { notification: notif }), result.data.accounts.length < 1 && /* @__PURE__ */ h(NotificationCard, { notification: { + if (result instanceof TalerError) { + return /* @__PURE__ */ h(ErrorLoadingMerchant, { error: result }); + } + if (result.type === "fail") { + switch (result.case) { + case HttpStatusCode.NotFound: { + return /* @__PURE__ */ h(NotFoundPageOrAdminCreate, null); + } + case HttpStatusCode.Unauthorized: { + return /* @__PURE__ */ h(LoginPage, null); + } + default: { + assertUnreachable(result); + } + } + } + return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(NotificationCard, { notification: notif }), result.body.accounts.length < 1 && /* @__PURE__ */ h(NotificationCard, { notification: { type: "WARN", message: i18n2.str`You need to associate a bank account to receive revenue.`, description: i18n2.str`Without this the merchant backend will refuse to create new orders.` } }), /* @__PURE__ */ h( ListPage, { - devices: result.data.accounts, - onLoadMoreBefore: result.isReachingStart ? result.loadMorePrev : void 0, - onLoadMoreAfter: result.isReachingEnd ? result.loadMore : void 0, + devices: result.body.accounts, onCreate, onSelect: (e4) => { onSelect(e4.h_wire); }, - onDelete: (e4) => deleteBankAccount(e4.h_wire).then( - () => setNotif({ - message: i18n2.str`bank account delete successfully`, - type: "SUCCESS" - }) - ).catch( - (error2) => setNotif({ - message: i18n2.str`could not delete the bank account`, - type: "ERROR", - description: error2.message - }) - ) + onDelete: (e4) => { + return api.instance.deleteBankAccount(state.token, e4.h_wire).then( + () => setNotif({ + message: i18n2.str`bank account delete successfully`, + type: "SUCCESS" + }) + ).catch( + (error2) => setNotif({ + message: i18n2.str`could not delete the bank account`, + type: "ERROR", + description: error2.message + }) + ); + } } )); } @@ -39999,153 +43336,95 @@ function ListOtpDevices({ // src/paths/instance/accounts/update/index.tsx init_preact_module(); init_hooks_module(); - -// src/paths/instance/accounts/update/UpdatePage.tsx -init_preact_module(); -init_hooks_module(); -var accountAuthType2 = ["unedit", "none", "basic"]; -function UpdatePage({ account, onUpdate, onBack }) { - const { i18n: i18n2 } = useTranslationContext(); - const [state, setState] = p3(account); - if (state.credit_facade_credentials?.type === "unedit") { - state.credit_facade_credentials = void 0; - } - const errors2 = { - credit_facade_url: !state.credit_facade_url ? void 0 : !isValidURL2(state.credit_facade_url) ? i18n2.str`invalid url` : void 0, - credit_facade_credentials: undefinedIfEmpty({ - username: state.credit_facade_credentials?.type !== "basic" ? void 0 : !state.credit_facade_credentials.username ? i18n2.str`required` : void 0, - password: state.credit_facade_credentials?.type !== "basic" ? void 0 : !state.credit_facade_credentials.password ? i18n2.str`required` : void 0, - repeatPassword: state.credit_facade_credentials?.type !== "basic" ? void 0 : !state.credit_facade_credentials.repeatPassword ? i18n2.str`required` : state.credit_facade_credentials.repeatPassword !== state.credit_facade_credentials.password ? i18n2.str`doesn't match` : void 0 - }) - }; - const hasErrors = Object.keys(errors2).some( - (k5) => errors2[k5] !== void 0 - ); - const submitForm = () => { - if (hasErrors) - return Promise.reject(); - const credit_facade_url = !state.credit_facade_url ? void 0 : new URL("/", state.credit_facade_url).href; - const credit_facade_credentials = credit_facade_url == void 0 || state.credit_facade_credentials === void 0 ? void 0 : state.credit_facade_credentials.type === "basic" ? { - type: "basic", - password: state.credit_facade_credentials.password, - username: state.credit_facade_credentials.username - } : { - type: "none" - }; - return onUpdate({ credit_facade_credentials, credit_facade_url }); - }; - return /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("section", { class: "section" }, /* @__PURE__ */ h("section", { class: "hero is-hero-bar" }, /* @__PURE__ */ h("div", { class: "hero-body" }, /* @__PURE__ */ h("div", { class: "level" }, /* @__PURE__ */ h("div", { class: "level-left" }, /* @__PURE__ */ h("div", { class: "level-item" }, /* @__PURE__ */ h("span", { class: "is-size-4" }, "Account: ", /* @__PURE__ */ h("b", null, account.id.substring(0, 8), "..."))))))), /* @__PURE__ */ h("hr", null), /* @__PURE__ */ h("section", { class: "section is-main-section" }, /* @__PURE__ */ h("div", { class: "columns" }, /* @__PURE__ */ h("div", { class: "column is-four-fifths" }, /* @__PURE__ */ h( - FormProvider, - { - object: state, - valueHandler: setState, - errors: errors2 - }, - /* @__PURE__ */ h( - InputPaytoForm, - { - name: "payto_uri", - label: i18n2.str`Account`, - readonly: true - } - ), - /* @__PURE__ */ h( - Input, - { - name: "credit_facade_url", - label: i18n2.str`Account info URL`, - help: "https://bank.com", - expand: true, - tooltip: i18n2.str`From where the merchant can download information about incoming wire transfers to this account` - } - ), - /* @__PURE__ */ h( - InputSelector, - { - name: "credit_facade_credentials.type", - label: i18n2.str`Auth type`, - tooltip: i18n2.str`Choose the authentication type for the account info URL`, - values: accountAuthType2, - toStr: (str) => { - if (str === "none") - return "Without authentication"; - if (str === "basic") - return "With authentication"; - return "Do not change"; - } - } - ), - state.credit_facade_credentials?.type === "basic" ? /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h( - Input, - { - name: "credit_facade_credentials.username", - label: i18n2.str`Username`, - tooltip: i18n2.str`Username to access the account information.` - } - ), /* @__PURE__ */ h( - Input, - { - name: "credit_facade_credentials.password", - inputType: "password", - label: i18n2.str`Password`, - tooltip: i18n2.str`Password to access the account information.` - } - ), /* @__PURE__ */ h( - Input, - { - name: "credit_facade_credentials.repeatPassword", - inputType: "password", - label: i18n2.str`Repeat password` - } - )) : void 0 - ), /* @__PURE__ */ h("div", { class: "buttons is-right mt-5" }, onBack && /* @__PURE__ */ h("button", { class: "button", onClick: onBack }, /* @__PURE__ */ h(i18n2.Translate, null, "Cancel")), /* @__PURE__ */ h( - AsyncButton, - { - disabled: hasErrors, - "data-tooltip": hasErrors ? i18n2.str`Need to complete marked fields` : "confirm operation", - onClick: submitForm - }, - /* @__PURE__ */ h(i18n2.Translate, null, "Confirm") - ))))))); -} -function isValidURL2(s5) { - try { - const u4 = new URL("/", s5); - return true; - } catch (e4) { - return false; - } -} - -// src/paths/instance/accounts/update/index.tsx function UpdateValidator({ bid, onConfirm, - onBack, - onUnauthorized, - onNotFound, - onLoadError + onBack }) { - const { updateBankAccount } = useBankAccountAPI(); + const { lib: api } = useMerchantApiContext(); + const { state } = useSessionContext(); const result = useBankAccountDetails(bid); const [notif, setNotif] = p3(void 0); const { i18n: i18n2 } = useTranslationContext(); - if (result.loading) + if (!result) return /* @__PURE__ */ h(Loading, null); - if (!result.ok) { - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.Unauthorized) - return onUnauthorized(); - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.NotFound) - return onNotFound(); - return onLoadError(result); + if (result instanceof TalerError) { + return /* @__PURE__ */ h(ErrorLoadingMerchant, { error: result }); + } + if (result.type === "fail") { + switch (result.case) { + case HttpStatusCode.NotFound: { + return /* @__PURE__ */ h(NotFoundPageOrAdminCreate, null); + } + case HttpStatusCode.Unauthorized: { + return /* @__PURE__ */ h(LoginPage, null); + } + default: { + assertUnreachable(result); + } + } } return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(NotificationCard, { notification: notif }), /* @__PURE__ */ h( UpdatePage, { - account: { ...result.data, id: bid }, + account: { ...result.body, id: bid }, onBack, - onUpdate: (data) => { - return updateBankAccount(bid, data).then(onConfirm).catch((error2) => { + onUpdate: async (request) => { + const revenueAPI = !request.credit_facade_url ? void 0 : new URL("./", request.credit_facade_url); + if (revenueAPI) { + const resp = await testRevenueAPI( + revenueAPI, + request.credit_facade_credentials + ); + if (resp.type === "fail") { + switch (resp.case) { + case 0 /* NO_CONFIG */: { + setNotif({ + message: i18n2.str`Could not create account`, + type: "ERROR", + description: i18n2.str`The endpoint doesn't seems to be a Taler Revenue API` + }); + return; + } + case 1 /* CLIENT_BAD_REQUEST */: { + setNotif({ + message: i18n2.str`Could not create account`, + type: "ERROR", + description: i18n2.str`Server replied with "bad request".` + }); + return; + } + case 2 /* UNAUTHORIZED */: { + setNotif({ + message: i18n2.str`Could not create account`, + type: "ERROR", + description: i18n2.str`Unauthorized, try with another credentials.` + }); + return; + } + case 3 /* NOT_FOUND */: { + setNotif({ + message: i18n2.str`Could not create account`, + type: "ERROR", + description: i18n2.str`Check facade URL, server replied with "not found".` + }); + return; + } + case 4 /* GENERIC_ERROR */: { + setNotif({ + message: i18n2.str`Could not create account`, + type: "ERROR", + description: resp.detail.hint + }); + return; + } + default: { + assertUnreachable(resp.case); + } + } + } + } + return api.instance.updateBankAccount(state.token, bid, request).then(onConfirm).catch((error2) => { setNotif({ message: i18n2.str`could not update account`, type: "ERROR", @@ -40188,22 +43467,40 @@ function EmptyTable3() { } // src/paths/instance/kyc/list/index.tsx -function ListKYC({ - onUnauthorized, - onLoadError, - onNotFound -}) { +function ListKYC(_p) { const result = useInstanceKYCDetails(); - if (result.loading) + if (!result) return /* @__PURE__ */ h(Loading, null); - if (!result.ok) { - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.Unauthorized) - return onUnauthorized(); - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.NotFound) - return onNotFound(); - return onLoadError(result); - } - const status = result.data.type === "ok" ? void 0 : result.data.status; + if (result instanceof TalerError) { + return /* @__PURE__ */ h(ErrorLoadingMerchant, { error: result }); + } + if (result.type === "fail") { + switch (result.case) { + case HttpStatusCode.GatewayTimeout: { + return /* @__PURE__ */ h("div", null); + } + case HttpStatusCode.BadGateway: { + const status2 = result.body; + if (!status2) { + return /* @__PURE__ */ h("div", null, "no kyc required"); + } + return /* @__PURE__ */ h(ListPage2, { status: status2 }); + } + case HttpStatusCode.ServiceUnavailable: { + return /* @__PURE__ */ h("div", null); + } + case HttpStatusCode.Unauthorized: { + return /* @__PURE__ */ h("div", null); + } + case HttpStatusCode.NotFound: { + return /* @__PURE__ */ h("div", null); + } + default: { + assertUnreachable(result); + } + } + } + const status = result.body; if (!status) { return /* @__PURE__ */ h("div", null, "no kyc required"); } @@ -40214,260 +43511,146 @@ function ListKYC({ init_preact_module(); init_hooks_module(); -// src/hooks/order.ts +// src/hooks/product.ts init_hooks_module(); + +// src/hooks/webhooks.ts var useSWR4 = useSWR; -function useOrderAPI() { - const mutateAll = useMatchMutate(); - const { request } = useBackendInstanceRequest(); - const createOrder = async (data) => { - const res = await request( - `/private/orders`, - { - method: "POST", - data - } - ); - await mutateAll(/.*private\/orders.*/); - return res; - }; - const refundOrder = async (orderId, data) => { - mutateAll(/@"\/private\/orders"@/); - const res = request( - `/private/orders/${orderId}/refund`, - { - method: "POST", - data - } - ); - await mutateAll(/.*private\/orders.*/); - return res; - }; - const forgetOrder = async (orderId, data) => { - mutateAll(/@"\/private\/orders"@/); - const res = request(`/private/orders/${orderId}/forget`, { - method: "PATCH", - data - }); - await mutateAll(/.*private\/orders.*/); - return res; - }; - const deleteOrder = async (orderId) => { - mutateAll(/@"\/private\/orders"@/); - const res = request(`/private/orders/${orderId}`, { - method: "DELETE" - }); - await mutateAll(/.*private\/orders.*/); - return res; - }; - const getPaymentURL = async (orderId) => { - return request( - `/private/orders/${orderId}`, - { - method: "GET" - } - ).then((res) => { - const url = res.data.order_status === "unpaid" ? res.data.taler_pay_uri : res.data.contract_terms.fulfillment_url; - const response = res; - response.data = url || ""; - return response; - }); - }; - return { createOrder, forgetOrder, deleteOrder, refundOrder, getPaymentURL }; +function revalidateInstanceWebhooks() { + return mutate( + (key) => Array.isArray(key) && key[key.length - 1] === "listWebhooks", + void 0, + { revalidate: true } + ); } -function useOrderDetails(oderId) { - const { fetcher } = useBackendInstanceRequest(); - const { data, error: error2, isValidating } = useSWR4([`/private/orders/${oderId}`], fetcher, { - refreshInterval: 0, - refreshWhenHidden: false, - revalidateOnFocus: false, - revalidateOnReconnect: false, - refreshWhenOffline: false - }); - if (isValidating) - return { loading: true, data: data?.data }; - if (data) - return data; +function useInstanceWebhooks() { + const { state: session } = useSessionContext(); + const { lib: { instance } } = useMerchantApiContext(); + async function fetcher([token, bid]) { + return await instance.listWebhooks(token, { + // limit: PAGINATED_LIST_REQUEST, + // offset: bid, + // order: "dec", + }); + } + const { data, error: error2 } = useSWR4([session.token, "offset", "listWebhooks"], fetcher); if (error2) - return error2.cause; - return { loading: true }; -} -function useInstanceOrders(args, updateFilter) { - const { orderFetcher } = useBackendInstanceRequest(); - const [pageBefore, setPageBefore] = p3(1); - const [pageAfter, setPageAfter] = p3(1); - const totalAfter = pageAfter * PAGE_SIZE; - const totalBefore = args?.date ? pageBefore * PAGE_SIZE : 0; - const { - data: beforeData, - error: beforeError, - isValidating: loadingBefore - } = useSWR4( - [ - `/private/orders`, - args?.paid, - args?.refunded, - args?.wired, - args?.date, - totalBefore - ], - orderFetcher - ); - const { - data: afterData, - error: afterError, - isValidating: loadingAfter - } = useSWR4( - [ - `/private/orders`, - args?.paid, - args?.refunded, - args?.wired, - args?.date, - -totalAfter - ], - orderFetcher - ); - const [lastBefore, setLastBefore] = p3({ loading: true }); - const [lastAfter, setLastAfter] = p3({ loading: true }); - h2(() => { - if (afterData) - setLastAfter(afterData); - if (beforeData) - setLastBefore(beforeData); - }, [afterData, beforeData]); - if (beforeError) - return beforeError.cause; - if (afterError) - return afterError.cause; - const isReachingEnd = afterData && afterData.data.orders.length < totalAfter; - const isReachingStart = args?.date === void 0 || beforeData && beforeData.data.orders.length < totalBefore; - const pagination = { - isReachingEnd, - isReachingStart, - loadMore: () => { - if (!afterData || isReachingEnd) + return error2; + if (data === void 0) + return void 0; + if (data.type !== "ok") + return data; + return data; +} +function buildPaginatedResult(data, offset, setOffset, getId) { + const isLastPage = data.length < PAGINATED_LIST_REQUEST; + const isFirstPage = offset === void 0; + const result = structuredClone(data); + if (result.length == PAGINATED_LIST_REQUEST) { + result.pop(); + } + return { + type: "ok", + body: result, + isLastPage, + isFirstPage, + loadNext: () => { + if (!result.length) return; - if (afterData.data.orders.length < MAX_RESULT_SIZE) { - setPageAfter(pageAfter + 1); - } else { - const from = afterData.data.orders[afterData.data.orders.length - 1].timestamp.t_s; - if (from && from !== "never" && updateFilter) - updateFilter(new Date(from * 1e3)); - } + const id = getId(result[result.length - 1]); + setOffset(id); }, - loadMorePrev: () => { - if (!beforeData || isReachingStart) - return; - if (beforeData.data.orders.length < MAX_RESULT_SIZE) { - setPageBefore(pageBefore + 1); - } else if (beforeData) { - const from = beforeData.data.orders[beforeData.data.orders.length - 1].timestamp.t_s; - if (from && from !== "never" && updateFilter) - updateFilter(new Date(from * 1e3)); - } + loadFirst: () => { + setOffset(void 0); } }; - const orders = !beforeData || !afterData ? [] : (beforeData || lastBefore).data.orders.slice().reverse().concat((afterData || lastAfter).data.orders); - if (loadingAfter || loadingBefore) - return { loading: true, data: { orders } }; - if (beforeData && afterData) { - return { ok: true, data: { orders }, ...pagination }; +} +function revalidateWebhookDetails() { + return mutate( + (key) => Array.isArray(key) && key[key.length - 1] === "getWebhookDetails", + void 0, + { revalidate: true } + ); +} +function useWebhookDetails(webhookId) { + const { state: session } = useSessionContext(); + const { lib: { instance } } = useMerchantApiContext(); + async function fetcher([hookId, token]) { + return await instance.getWebhookDetails(token, hookId); } - return { loading: true }; + const { data, error: error2 } = useSWR4([webhookId, session.token, "getWebhookDetails"], fetcher); + if (data) + return data; + if (error2) + return error2; + return void 0; } // src/hooks/product.ts var useSWR5 = useSWR; -function useProductAPI() { - const mutateAll = useMatchMutate(); - const { mutate: mutate2 } = useSWRConfig(); - const { request } = useBackendInstanceRequest(); - const createProduct = async (data) => { - const res = await request(`/private/products`, { - method: "POST", - data - }); - return await mutateAll(/.*\/private\/products.*/); - }; - const updateProduct = async (productId, data) => { - const r3 = await request(`/private/products/${productId}`, { - method: "PATCH", - data - }); - return await mutateAll(/.*\/private\/products.*/); - }; - const deleteProduct = async (productId) => { - await request(`/private/products/${productId}`, { - method: "DELETE" - }); - await mutate2([`/private/products`]); - }; - const lockProduct = async (productId, data) => { - await request(`/private/products/${productId}/lock`, { - method: "POST", - data - }); - return await mutateAll(/.*"\/private\/products.*/); - }; - const getProduct = async (productId) => { - await request(`/private/products/${productId}`, { - method: "GET" - }); - return; - }; - return { createProduct, updateProduct, deleteProduct, lockProduct, getProduct }; +function notUndefined(c4) { + return c4 !== void 0; +} +function revalidateInstanceProducts() { + return mutate( + (key) => Array.isArray(key) && key[key.length - 1] === "listProductsWithId", + void 0, + { revalidate: true } + ); } function useInstanceProducts() { - const { fetcher, multiFetcher } = useBackendInstanceRequest(); - const { data: list, error: listError } = useSWR5([`/private/products`], fetcher, { - refreshInterval: 0, - refreshWhenHidden: false, - revalidateOnFocus: false, - revalidateOnReconnect: false, - refreshWhenOffline: false - }); - const paths = (list?.data.products || []).map( - (p4) => `/private/products/${p4.product_id}` - ); - const { data: products, error: productError } = useSWR5([paths], multiFetcher, { - refreshInterval: 0, - refreshWhenHidden: false, - revalidateOnFocus: false, - revalidateOnReconnect: false, - refreshWhenOffline: false - }); - if (listError) - return listError.cause; - if (productError) - return productError.cause; - if (products) { - const dataWithId = products.map((d5) => { - return { - ...d5.data, - id: d5.info?.url.replace(/.*\/private\/products\//, "") || "" - }; + const { state: session } = useSessionContext(); + const { lib: { instance } } = useMerchantApiContext(); + const [offset, setOffset] = p3(); + async function fetcher([token, bid]) { + const list = await instance.listProducts(token, { + limit: PAGINATED_LIST_REQUEST, + offset: bid === void 0 ? void 0 : String(bid), + order: "dec" }); - return { ok: true, data: dataWithId }; + if (list.type !== "ok") { + return list; + } + const all = await Promise.all( + list.body.products.map(async (c4) => { + const r3 = await instance.getProductDetails(token, c4.product_id); + if (r3.type === "fail") { + return void 0; + } + return { ...r3.body, id: c4.product_id, serial: c4.product_serial }; + }) + ); + const products = all.filter(notUndefined); + return opFixedSuccess({ products }); } - return { loading: true }; + const { data, error: error2 } = useSWR5([session.token, offset, "listProductsWithId"], fetcher); + if (error2) + return error2; + if (data === void 0) + return void 0; + if (data.type !== "ok") + return data; + return buildPaginatedResult(data.body.products, offset, setOffset, (d5) => d5.serial); +} +function revalidateProductDetails() { + return mutate( + (key) => Array.isArray(key) && key[key.length - 1] === "getProductDetails", + void 0, + { revalidate: true } + ); } function useProductDetails(productId) { - const { fetcher } = useBackendInstanceRequest(); - const { data, error: error2, isValidating } = useSWR5([`/private/products/${productId}`], fetcher, { - refreshInterval: 0, - refreshWhenHidden: false, - revalidateOnFocus: false, - revalidateOnReconnect: false, - refreshWhenOffline: false - }); - if (isValidating) - return { loading: true, data: data?.data }; + const { state: session } = useSessionContext(); + const { lib: { instance } } = useMerchantApiContext(); + async function fetcher([pid, token]) { + return await instance.getProductDetails(token, pid); + } + const { data, error: error2 } = useSWR5([productId, session.token, "getProductDetails"], fetcher); if (data) return data; if (error2) - return error2.cause; - return { loading: true }; + return error2; + return void 0; } // src/paths/instance/orders/create/CreatePage.tsx @@ -40488,7 +43671,7 @@ function InputCurrency({ children, side }) { - const config = useConfigContext(); + const { config } = useMerchantApiContext(); return /* @__PURE__ */ h( InputWithAddon, { @@ -40540,7 +43723,6 @@ var DatePicker = class extends d { */ getDaysByMonth(month, year) { const calendar = []; - const date2 = new Date(year, month, 1); const firstDay = new Date(year, month, 1).getDay(); const lastDate = new Date(year, month + 1, 0).getDate(); let day = 0; @@ -40767,7 +43949,7 @@ function InputDate({ }) { const [opened, setOpened] = p3(false); const { i18n: i18n2 } = useTranslationContext(); - const [settings] = useSettings(); + const [settings] = usePreference(); const { error: error2, required, value, onChange } = useField(name); let strValue = ""; if (!value) { @@ -43481,10 +46663,10 @@ function NonInventoryProductFrom({ } ))); } -function ProductForm({ onSubscribe, initial: initial2 }) { +function ProductForm({ onSubscribe, initial: initial3 }) { const [value, valueHandler] = p3({ taxes: [], - ...initial2 + ...initial3 }); let errors2 = {}; try { @@ -43570,7 +46752,7 @@ function ProductList({ list, actions = [] }) { const totalPrice = !entry.price ? "0" : Amounts.stringify( Amounts.mult( Amounts.parseOrThrow(entry.price), - entry.quantity + entry.quantity ?? 0 ).amount ); return /* @__PURE__ */ h("tr", { key: index }, /* @__PURE__ */ h("td", null, /* @__PURE__ */ h( @@ -43627,9 +46809,13 @@ function toFloat(amount) { } // src/paths/instance/orders/create/CreatePage.tsx -function with_defaults2(config, currency) { - const defaultPayDeadline = Duration.fromTalerProtocolDuration(config.default_pay_delay); - const defaultWireDeadline = Duration.fromTalerProtocolDuration(config.default_wire_transfer_delay); +function with_defaults2(config, _currency) { + const defaultPayDeadline = Duration.fromTalerProtocolDuration( + config.default_pay_delay + ); + const defaultWireDeadline = Duration.fromTalerProtocolDuration( + config.default_wire_transfer_delay + ); return { inventoryProducts: {}, products: [], @@ -43651,11 +46837,11 @@ function CreatePage3({ instanceConfig, instanceInventory }) { - const config = useConfigContext(); + const { config } = useMerchantApiContext(); const instance_default = with_defaults2(instanceConfig, config.currency); const [value, valueHandler] = p3(instance_default); const zero = Amounts.zeroOfCurrency(config.currency); - const [settings, updateSettings] = useSettings(); + const [settings, updateSettings] = usePreference(); const inventoryList = Object.values(value.inventoryProducts || {}); const productList = Object.values(value.products || {}); const { i18n: i18n2 } = useTranslationContext(); @@ -43666,7 +46852,10 @@ function CreatePage3({ order_price: !value.pricing?.order_price ? i18n2.str`required` : !parsedPrice ? i18n2.str`not valid` : Amounts.isZero(parsedPrice) ? i18n2.str`must be greater than 0` : void 0 }), payments: undefinedIfEmpty({ - refund_deadline: !value.payments?.refund_deadline ? void 0 : value.payments.pay_deadline && Duration.cmp(value.payments.refund_deadline, value.payments.pay_deadline) === -1 ? i18n2.str`refund deadline cannot be before pay deadline` : value.payments.wire_transfer_deadline && Duration.cmp( + refund_deadline: !value.payments?.refund_deadline ? void 0 : value.payments.pay_deadline && Duration.cmp( + value.payments.refund_deadline, + value.payments.pay_deadline + ) === -1 ? i18n2.str`refund deadline cannot be before pay deadline` : value.payments.wire_transfer_deadline && Duration.cmp( value.payments.wire_transfer_deadline, value.payments.refund_deadline ) === -1 ? i18n2.str`wire transfer deadline cannot be before refund deadline` : void 0, @@ -43699,11 +46888,27 @@ function CreatePage3({ summary: order.pricing.summary, products: productList, extra: undefinedIfEmpty(value.extra), - pay_deadline: !value.payments.pay_deadline ? i18n2.str`required` : AbsoluteTime.toProtocolTimestamp(AbsoluteTime.addDuration(AbsoluteTime.now(), value.payments.pay_deadline)), - // : undefined, - wire_transfer_deadline: value.payments.wire_transfer_deadline ? AbsoluteTime.toProtocolTimestamp(AbsoluteTime.addDuration(AbsoluteTime.now(), value.payments.wire_transfer_deadline)) : void 0, - refund_deadline: value.payments.refund_deadline ? AbsoluteTime.toProtocolTimestamp(AbsoluteTime.addDuration(AbsoluteTime.now(), value.payments.refund_deadline)) : void 0, - auto_refund: value.payments.auto_refund_deadline ? Duration.toTalerProtocolDuration(value.payments.auto_refund_deadline) : void 0, + pay_deadline: AbsoluteTime.toProtocolTimestamp( + AbsoluteTime.addDuration( + AbsoluteTime.now(), + value.payments.pay_deadline + ) + ), + wire_transfer_deadline: AbsoluteTime.toProtocolTimestamp( + AbsoluteTime.addDuration( + AbsoluteTime.now(), + value.payments.wire_transfer_deadline + ) + ), + refund_deadline: AbsoluteTime.toProtocolTimestamp( + AbsoluteTime.addDuration( + AbsoluteTime.now(), + value.payments.refund_deadline + ) + ), + auto_refund: value.payments.auto_refund_deadline ? Duration.toTalerProtocolDuration( + value.payments.auto_refund_deadline + ) : void 0, max_fee: value.payments.max_fee, delivery_date: value.shipping.delivery_date ? { t_s: value.shipping.delivery_date.getTime() / 1e3 } : void 0, delivery_location: value.shipping.delivery_location, @@ -43754,7 +46959,7 @@ function CreatePage3({ if (!cur.price) return zero; const p4 = Amounts.parseOrThrow(cur.price); - return Amounts.add(prev, Amounts.mult(p4, cur.quantity).amount).amount; + return Amounts.add(prev, Amounts.mult(p4, cur.quantity ?? 0).amount).amount; }, zero); const hasProducts = inventoryList.length > 0 || productList.length > 0; const totalPrice = Amounts.add(totalPriceInventory, totalPriceProducts); @@ -43777,24 +46982,32 @@ function CreatePage3({ parsedPrice ?? Amounts.zeroOfCurrency(config.currency), totalPrice.amount ); - const minAgeByProducts = allProducts.reduce( - (cur, prev) => !prev.minimum_age || cur > prev.minimum_age ? cur : prev.minimum_age, + const minAgeByProducts = inventoryList.reduce( + (cur, prev) => !prev.product.minimum_age || cur > prev.product.minimum_age ? cur : prev.product.minimum_age, 0 ); const noDefault_payDeadline = !instance_default.payments || !instance_default.payments.pay_deadline; const noDefault_wireDeadline = !instance_default.payments || !instance_default.payments.wire_transfer_deadline; const requiresSomeTalerOptions = noDefault_payDeadline || noDefault_wireDeadline; - return /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("section", { class: "section is-main-section" }, /* @__PURE__ */ h("div", { class: "tabs is-toggle is-fullwidth is-small" }, /* @__PURE__ */ h("ul", null, /* @__PURE__ */ h("li", { class: !settings.advanceOrderMode ? "is-active" : "", onClick: () => { - updateSettings({ - ...settings, - advanceOrderMode: false - }); - } }, /* @__PURE__ */ h("a", null, /* @__PURE__ */ h("span", null, /* @__PURE__ */ h(i18n2.Translate, null, "Simple")))), /* @__PURE__ */ h("li", { class: settings.advanceOrderMode ? "is-active" : "", onClick: () => { - updateSettings({ - ...settings, - advanceOrderMode: true - }); - } }, /* @__PURE__ */ h("a", null, /* @__PURE__ */ h("span", null, /* @__PURE__ */ h(i18n2.Translate, null, "Advanced")))))), /* @__PURE__ */ h("div", { class: "columns" }, /* @__PURE__ */ h("div", { class: "column" }), /* @__PURE__ */ h("div", { class: "column is-four-fifths" }, /* @__PURE__ */ h( + return /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("section", { class: "section is-main-section" }, /* @__PURE__ */ h("div", { class: "tabs is-toggle is-fullwidth is-small" }, /* @__PURE__ */ h("ul", null, /* @__PURE__ */ h( + "li", + { + class: !settings.advanceOrderMode ? "is-active" : "", + onClick: () => { + updateSettings("advanceOrderMode", false); + } + }, + /* @__PURE__ */ h("a", null, /* @__PURE__ */ h("span", null, /* @__PURE__ */ h(i18n2.Translate, null, "Simple"))) + ), /* @__PURE__ */ h( + "li", + { + class: settings.advanceOrderMode ? "is-active" : "", + onClick: () => { + updateSettings("advanceOrderMode", true); + } + }, + /* @__PURE__ */ h("a", null, /* @__PURE__ */ h("span", null, /* @__PURE__ */ h(i18n2.Translate, null, "Advanced"))) + ))), /* @__PURE__ */ h("div", { class: "columns" }, /* @__PURE__ */ h("div", { class: "column" }), /* @__PURE__ */ h("div", { class: "column is-four-fifths" }, /* @__PURE__ */ h( InputGroup, { name: "inventory_products", @@ -43931,16 +47144,23 @@ function CreatePage3({ withForever: true, withoutClear: true, tooltip: i18n2.str`Time for the customer to pay for the offer before it expires. Inventory products will be reserved until this deadline. Time start to run after the order is created.`, - side: /* @__PURE__ */ h("span", null, /* @__PURE__ */ h("button", { class: "button", onClick: () => { - const c4 = { - ...value, - payments: { - ...value.payments ?? {}, - pay_deadline: instance_default.payments?.pay_deadline + side: /* @__PURE__ */ h("span", null, /* @__PURE__ */ h( + "button", + { + class: "button", + onClick: () => { + const c4 = { + ...value, + payments: { + ...value.payments ?? {}, + pay_deadline: instance_default.payments?.pay_deadline + } + }; + valueHandler(c4); } - }; - valueHandler(c4); - } }, /* @__PURE__ */ h(i18n2.Translate, null, "default"))) + }, + /* @__PURE__ */ h(i18n2.Translate, null, "default") + )) } ), settings.advanceOrderMode && /* @__PURE__ */ h( @@ -43948,19 +47168,31 @@ function CreatePage3({ { name: "payments.refund_deadline", label: i18n2.str`Refund time`, - help: /* @__PURE__ */ h(DeadlineHelp, { duration: value.payments?.refund_deadline }), + help: /* @__PURE__ */ h( + DeadlineHelp, + { + duration: value.payments?.refund_deadline + } + ), withForever: true, withoutClear: true, tooltip: i18n2.str`Time while the order can be refunded by the merchant. Time starts after the order is created.`, - side: /* @__PURE__ */ h("span", null, /* @__PURE__ */ h("button", { class: "button", onClick: () => { - valueHandler({ - ...value, - payments: { - ...value.payments ?? {}, - refund_deadline: instance_default.payments?.refund_deadline + side: /* @__PURE__ */ h("span", null, /* @__PURE__ */ h( + "button", + { + class: "button", + onClick: () => { + valueHandler({ + ...value, + payments: { + ...value.payments ?? {}, + refund_deadline: instance_default.payments?.refund_deadline + } + }); } - }); - } }, /* @__PURE__ */ h(i18n2.Translate, null, "default"))) + }, + /* @__PURE__ */ h(i18n2.Translate, null, "default") + )) } ), (settings.advanceOrderMode || noDefault_wireDeadline) && /* @__PURE__ */ h( @@ -43968,19 +47200,31 @@ function CreatePage3({ { name: "payments.wire_transfer_deadline", label: i18n2.str`Wire transfer time`, - help: /* @__PURE__ */ h(DeadlineHelp, { duration: value.payments?.wire_transfer_deadline }), + help: /* @__PURE__ */ h( + DeadlineHelp, + { + duration: value.payments?.wire_transfer_deadline + } + ), withoutClear: true, withForever: true, tooltip: i18n2.str`Time for the exchange to make the wire transfer. Time starts after the order is created.`, - side: /* @__PURE__ */ h("span", null, /* @__PURE__ */ h("button", { class: "button", onClick: () => { - valueHandler({ - ...value, - payments: { - ...value.payments ?? {}, - wire_transfer_deadline: instance_default.payments?.wire_transfer_deadline + side: /* @__PURE__ */ h("span", null, /* @__PURE__ */ h( + "button", + { + class: "button", + onClick: () => { + valueHandler({ + ...value, + payments: { + ...value.payments ?? {}, + wire_transfer_deadline: instance_default.payments?.wire_transfer_deadline + } + }); } - }); - } }, /* @__PURE__ */ h(i18n2.Translate, null, "default"))) + }, + /* @__PURE__ */ h(i18n2.Translate, null, "default") + )) } ), settings.advanceOrderMode && /* @__PURE__ */ h( @@ -43988,7 +47232,12 @@ function CreatePage3({ { name: "payments.auto_refund_deadline", label: i18n2.str`Auto-refund time`, - help: /* @__PURE__ */ h(DeadlineHelp, { duration: value.payments?.auto_refund_deadline }), + help: /* @__PURE__ */ h( + DeadlineHelp, + { + duration: value.payments?.auto_refund_deadline + } + ), tooltip: i18n2.str`Time until which the wallet will automatically check for refunds without user interaction.`, withForever: true } @@ -44026,36 +47275,67 @@ function CreatePage3({ label: i18n2.str`Additional information`, tooltip: i18n2.str`Custom information to be included in the contract for this order.` }, - Object.keys(value.extra ?? {}).map((key) => { + Object.keys(value.extra ?? {}).map((key, idx) => { return /* @__PURE__ */ h( Input, { name: `extra.${key}`, + key: String(idx), inputType: "multiline", label: key, tooltip: i18n2.str`You must enter a value in JavaScript Object Notation (JSON).`, - side: /* @__PURE__ */ h("button", { class: "button", onClick: (e4) => { - if (value.extra && value.extra[key] !== void 0) { - console.log(value.extra); - delete value.extra[key]; - } - valueHandler({ - ...value - }); - } }, "remove") + side: /* @__PURE__ */ h( + "button", + { + class: "button", + onClick: (e4) => { + if (value.extra && value.extra[key] !== void 0) { + console.log(value.extra); + delete value.extra[key]; + } + valueHandler({ + ...value + }); + e4.preventDefault(); + } + }, + "remove" + ) } ); }), - /* @__PURE__ */ h("div", { class: "field is-horizontal" }, /* @__PURE__ */ h("div", { class: "field-label is-normal" }, /* @__PURE__ */ h("label", { class: "label" }, /* @__PURE__ */ h(i18n2.Translate, null, "Custom field name"), /* @__PURE__ */ h("span", { class: "icon has-tooltip-right", "data-tooltip": "new extra field" }, /* @__PURE__ */ h("i", { class: "mdi mdi-information" })))), /* @__PURE__ */ h("div", { class: "field-body is-flex-grow-3" }, /* @__PURE__ */ h("div", { class: "field" }, /* @__PURE__ */ h("p", { class: "control" }, /* @__PURE__ */ h("input", { class: "input ", value: newField, onChange: (e4) => setNewField(e4.currentTarget.value) })))), /* @__PURE__ */ h("button", { class: "button", onClick: (e4) => { - setNewField(""); - valueHandler({ - ...value, - extra: { - ...value.extra ?? {}, - [newField]: "" + /* @__PURE__ */ h("div", { class: "field is-horizontal" }, /* @__PURE__ */ h("div", { class: "field-label is-normal" }, /* @__PURE__ */ h("label", { class: "label" }, /* @__PURE__ */ h(i18n2.Translate, null, "Custom field name"), /* @__PURE__ */ h( + "span", + { + class: "icon has-tooltip-right", + "data-tooltip": "new extra field" + }, + /* @__PURE__ */ h("i", { class: "mdi mdi-information" }) + ))), /* @__PURE__ */ h("div", { class: "field-body is-flex-grow-3" }, /* @__PURE__ */ h("div", { class: "field" }, /* @__PURE__ */ h("p", { class: "control" }, /* @__PURE__ */ h( + "input", + { + class: "input ", + value: newField, + onChange: (e4) => setNewField(e4.currentTarget.value) + } + )))), /* @__PURE__ */ h( + "button", + { + class: "button", + onClick: (e4) => { + setNewField(""); + valueHandler({ + ...value, + extra: { + ...value.extra ?? {}, + [newField]: "" + } + }); + e4.preventDefault(); } - }); - } }, "add")) + }, + "add" + )) ) ), /* @__PURE__ */ h("div", { class: "buttons is-right mt-5" }, onBack && /* @__PURE__ */ h("button", { class: "button", onClick: onBack }, /* @__PURE__ */ h(i18n2.Translate, null, "Cancel")), /* @__PURE__ */ h( "button", @@ -44075,8 +47355,7 @@ function asProduct(p4) { unit: p4.product.unit, quantity: p4.quantity, description: p4.product.description, - taxes: p4.product.taxes, - minimum_age: p4.product.minimum_age + taxes: p4.product.taxes }; } function DeadlineHelp({ duration }) { @@ -44101,40 +47380,63 @@ function DeadlineHelp({ duration }) { // src/paths/instance/orders/create/index.tsx function OrderCreate({ onConfirm, - onBack, - onLoadError, - onNotFound, - onUnauthorized + onBack }) { - const { createOrder } = useOrderAPI(); + const { lib } = useMerchantApiContext(); const [notif, setNotif] = p3(void 0); + const { state } = useSessionContext(); const detailsResult = useInstanceDetails(); const inventoryResult = useInstanceProducts(); - if (detailsResult.loading) + if (!detailsResult) return /* @__PURE__ */ h(Loading, null); - if (inventoryResult.loading) + if (detailsResult instanceof TalerError) { + return /* @__PURE__ */ h(ErrorLoadingMerchant, { error: detailsResult }); + } + if (detailsResult.type === "fail") { + switch (detailsResult.case) { + case HttpStatusCode.Unauthorized: { + return /* @__PURE__ */ h(LoginPage, null); + } + case HttpStatusCode.NotFound: { + return /* @__PURE__ */ h(NotFoundPageOrAdminCreate, null); + } + default: { + assertUnreachable(detailsResult); + } + } + } + if (!inventoryResult) return /* @__PURE__ */ h(Loading, null); - if (!detailsResult.ok) { - if (detailsResult.type === ErrorType.CLIENT && detailsResult.status === HttpStatusCode.Unauthorized) - return onUnauthorized(); - if (detailsResult.type === ErrorType.CLIENT && detailsResult.status === HttpStatusCode.NotFound) - return onNotFound(); - return onLoadError(detailsResult); - } - if (!inventoryResult.ok) { - if (inventoryResult.type === ErrorType.CLIENT && inventoryResult.status === HttpStatusCode.Unauthorized) - return onUnauthorized(); - if (inventoryResult.type === ErrorType.CLIENT && inventoryResult.status === HttpStatusCode.NotFound) - return onNotFound(); - return onLoadError(inventoryResult); + if (inventoryResult instanceof TalerError) { + return /* @__PURE__ */ h(ErrorLoadingMerchant, { error: inventoryResult }); + } + if (inventoryResult.type === "fail") { + switch (inventoryResult.case) { + case HttpStatusCode.NotFound: { + return /* @__PURE__ */ h(NotFoundPageOrAdminCreate, null); + } + case HttpStatusCode.Unauthorized: { + return /* @__PURE__ */ h(LoginPage, null); + } + default: { + assertUnreachable(inventoryResult); + } + } } return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(NotificationCard, { notification: notif }), /* @__PURE__ */ h( CreatePage3, { onBack, onCreate: (request) => { - createOrder(request).then((r3) => { - return onConfirm(r3.data.order_id); + lib.instance.createOrder(state.token, request).then((r3) => { + if (r3.type === "ok") { + return onConfirm(r3.body.order_id); + } else { + setNotif({ + message: "could not create order", + type: "ERROR" + }); + } }).catch((error2) => { setNotif({ message: "could not create order", @@ -44143,8 +47445,8 @@ function OrderCreate({ }); }); }, - instanceConfig: detailsResult.data, - instanceInventory: inventoryResult.data + instanceConfig: detailsResult.body, + instanceInventory: inventoryResult.body } )); } @@ -44153,6 +47455,60 @@ function OrderCreate({ init_preact_module(); init_hooks_module(); +// src/hooks/order.ts +var useSWR6 = useSWR; +function revalidateOrderDetails() { + return mutate( + (key) => Array.isArray(key) && key[key.length - 1] === "getOrderDetails", + void 0, + { revalidate: true } + ); +} +function useOrderDetails(oderId) { + const { state: session } = useSessionContext(); + const { lib: { instance } } = useMerchantApiContext(); + async function fetcher([dId, token]) { + return await instance.getOrderDetails(token, dId); + } + const { data, error: error2 } = useSWR6([oderId, session.token, "getOrderDetails"], fetcher); + if (data) + return data; + if (error2) + return error2; + return void 0; +} +function revalidateInstanceOrders() { + return mutate( + (key) => Array.isArray(key) && key[key.length - 1] === "listOrders", + void 0, + { revalidate: true } + ); +} +function useInstanceOrders(args, updatePosition = () => { +}) { + const { state: session } = useSessionContext(); + const { lib: { instance } } = useMerchantApiContext(); + async function fetcher([token, o3, p4, r3, w5, d5]) { + return await instance.listOrders(token, { + limit: PAGINATED_LIST_REQUEST, + offset: o3, + order: "dec", + paid: p4, + refunded: r3, + wired: w5, + date: d5 + }); + } + const { data, error: error2 } = useSWR6([session.token, args?.position, args?.paid, args?.refunded, args?.wired, args?.date, "listOrders"], fetcher); + if (error2) + return error2; + if (data === void 0) + return void 0; + if (data.type !== "ok") + return data; + return buildPaginatedResult(data.body.orders, args?.position, updatePosition, (d5) => String(d5.row_id)); +} + // src/paths/instance/orders/details/DetailPage.tsx init_preact_module(); init_hooks_module(); @@ -44189,9 +47545,7 @@ function CardTable3({ onCopyURL, onSelect, onLoadMoreAfter, - onLoadMoreBefore, - hasMoreAfter, - hasMoreBefore + onLoadMoreBefore }) { const [rowSelection, rowSelectionHandler] = p3([]); const { i18n: i18n2 } = useTranslationContext(); @@ -44205,9 +47559,7 @@ function CardTable3({ rowSelection, rowSelectionHandler, onLoadMoreAfter, - onLoadMoreBefore, - hasMoreAfter, - hasMoreBefore + onLoadMoreBefore } ) : /* @__PURE__ */ h(EmptyTable4, null))))); } @@ -44217,20 +47569,11 @@ function Table3({ onRefund, onCopyURL, onLoadMoreAfter, - onLoadMoreBefore, - hasMoreAfter, - hasMoreBefore + onLoadMoreBefore }) { const { i18n: i18n2 } = useTranslationContext(); - const [settings] = useSettings(); - return /* @__PURE__ */ h("div", { class: "table-container" }, hasMoreBefore && /* @__PURE__ */ h( - "button", - { - class: "button is-fullwidth", - onClick: onLoadMoreBefore - }, - /* @__PURE__ */ h(i18n2.Translate, null, "load newer orders") - ), /* @__PURE__ */ h("table", { class: "table is-striped is-hoverable is-fullwidth" }, /* @__PURE__ */ h("thead", null, /* @__PURE__ */ h("tr", null, /* @__PURE__ */ h("th", { style: { minWidth: 100 } }, /* @__PURE__ */ h(i18n2.Translate, null, "Date")), /* @__PURE__ */ h("th", { style: { minWidth: 100 } }, /* @__PURE__ */ h(i18n2.Translate, null, "Amount")), /* @__PURE__ */ h("th", { style: { minWidth: 400 } }, /* @__PURE__ */ h(i18n2.Translate, null, "Summary")), /* @__PURE__ */ h("th", { style: { minWidth: 50 } }))), /* @__PURE__ */ h("tbody", null, instances.map((i4) => { + const [settings] = usePreference(); + return /* @__PURE__ */ h("div", { class: "table-container" }, onLoadMoreBefore && /* @__PURE__ */ h("button", { class: "button is-fullwidth", onClick: onLoadMoreBefore }, /* @__PURE__ */ h(i18n2.Translate, null, "load first page")), /* @__PURE__ */ h("table", { class: "table is-striped is-hoverable is-fullwidth" }, /* @__PURE__ */ h("thead", null, /* @__PURE__ */ h("tr", null, /* @__PURE__ */ h("th", { style: { minWidth: 100 } }, /* @__PURE__ */ h(i18n2.Translate, null, "Date")), /* @__PURE__ */ h("th", { style: { minWidth: 100 } }, /* @__PURE__ */ h(i18n2.Translate, null, "Amount")), /* @__PURE__ */ h("th", { style: { minWidth: 400 } }, /* @__PURE__ */ h(i18n2.Translate, null, "Summary")), /* @__PURE__ */ h("th", { style: { minWidth: 50 } }))), /* @__PURE__ */ h("tbody", null, instances.map((i4) => { return /* @__PURE__ */ h("tr", { key: i4.id }, /* @__PURE__ */ h( "td", { @@ -44272,18 +47615,19 @@ function Table3({ }, /* @__PURE__ */ h(i18n2.Translate, null, "copy url") )))); - }))), hasMoreAfter && /* @__PURE__ */ h( + }))), onLoadMoreAfter && /* @__PURE__ */ h( "button", { class: "button is-fullwidth", + "data-tooltip": i18n2.str`load more orders after the last one`, onClick: onLoadMoreAfter }, - /* @__PURE__ */ h(i18n2.Translate, null, "load older orders") + /* @__PURE__ */ h(i18n2.Translate, null, "load next page") )); } function EmptyTable4() { const { i18n: i18n2 } = useTranslationContext(); - return /* @__PURE__ */ h("div", { class: "content has-text-grey has-text-centered" }, /* @__PURE__ */ h("p", null, /* @__PURE__ */ h("span", { class: "icon is-large" }, /* @__PURE__ */ h("i", { class: "mdi mdi-emoticon-sad mdi-48px" }))), /* @__PURE__ */ h("p", null, /* @__PURE__ */ h(i18n2.Translate, null, "No orders have been found matching your query!"))); + return /* @__PURE__ */ h("div", { class: "content has-text-grey has-text-centered" }, /* @__PURE__ */ h("p", null, /* @__PURE__ */ h("span", { class: "icon is-large" }, /* @__PURE__ */ h("i", { class: "mdi mdi-magnify mdi-48px" }))), /* @__PURE__ */ h("p", null, /* @__PURE__ */ h(i18n2.Translate, null, "No orders have been found matching your query!"))); } function RefundModal({ order, @@ -44291,10 +47635,10 @@ function RefundModal({ onConfirm }) { const [form, setValue] = p3({}); - const [settings] = useSettings(); + const [settings] = usePreference(); const { i18n: i18n2 } = useTranslationContext(); const refunds = (order.order_status === "paid" ? order.refund_details : []).reduce(mergeRefunds, []); - const config = useConfigContext(); + const { config } = useMerchantApiContext(); const totalRefunded = refunds.map((r3) => r3.amount).reduce( (p4, c4) => Amounts.add(p4, Amounts.parseOrThrow(c4)).amount, Amounts.zeroOfCurrency(config.currency) @@ -44403,7 +47747,7 @@ function Timeline({ events: e4 }) { type: "now" }); events2.sort((a5, b4) => a5.when.getTime() - b4.when.getTime()); - const [settings] = useSettings(); + const [settings] = usePreference(); const [state, setState] = p3(events2); h2(() => { const handle = setTimeout(() => { @@ -44548,6 +47892,8 @@ function ClaimedPage({ id, order }) { + const now2 = /* @__PURE__ */ new Date(); + const refundable = order.contract_terms.refund_deadline.t_s !== "never" && now2.getTime() < order.contract_terms.refund_deadline.t_s * 1e3; const events2 = []; if (order.contract_terms.timestamp.t_s !== "never") { events2.push({ @@ -44563,20 +47909,13 @@ function ClaimedPage({ type: "deadline" }); } - if (order.contract_terms.refund_deadline.t_s !== "never") { + if (order.contract_terms.refund_deadline.t_s !== "never" && refundable) { events2.push({ when: new Date(order.contract_terms.refund_deadline.t_s * 1e3), description: "refund deadline", type: "deadline" }); } - if (order.contract_terms.wire_transfer_deadline.t_s !== "never") { - events2.push({ - when: new Date(order.contract_terms.wire_transfer_deadline.t_s * 1e3), - description: "wire deadline", - type: "deadline" - }); - } if (order.contract_terms.delivery_date && order.contract_terms.delivery_date.t_s !== "never") { events2.push({ when: new Date(order.contract_terms.delivery_date?.t_s * 1e3), @@ -44586,7 +47925,7 @@ function ClaimedPage({ } const [value, valueHandler] = p3(order); const { i18n: i18n2 } = useTranslationContext(); - const [settings] = useSettings(); + const [settings] = usePreference(); return /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("section", { class: "section" }, /* @__PURE__ */ h("div", { class: "columns" }, /* @__PURE__ */ h("div", { class: "column" }), /* @__PURE__ */ h("div", { class: "column is-10" }, /* @__PURE__ */ h("section", { class: "hero is-hero-bar" }, /* @__PURE__ */ h("div", { class: "hero-body" }, /* @__PURE__ */ h("div", { class: "level" }, /* @__PURE__ */ h("div", { class: "level-left" }, /* @__PURE__ */ h("div", { class: "level-item" }, /* @__PURE__ */ h(i18n2.Translate, null, "Order"), " #", id, /* @__PURE__ */ h("div", { class: "tag is-info ml-4" }, /* @__PURE__ */ h(i18n2.Translate, null, "claimed"))))), /* @__PURE__ */ h("div", { class: "level" }, /* @__PURE__ */ h("div", { class: "level-left" }, /* @__PURE__ */ h("div", { class: "level-item" }, /* @__PURE__ */ h("h1", { class: "title" }, order.contract_terms.amount)))), /* @__PURE__ */ h("div", { class: "level" }, /* @__PURE__ */ h("div", { class: "level-left", style: { maxWidth: "100%" } }, /* @__PURE__ */ h("div", { class: "level-item", style: { maxWidth: "100%" } }, /* @__PURE__ */ h( "div", { @@ -44597,8 +47936,10 @@ function ClaimedPage({ textOverflow: "ellipsis" } }, - /* @__PURE__ */ h("p", null, /* @__PURE__ */ h("b", null, /* @__PURE__ */ h(i18n2.Translate, null, "claimed at"), ":"), " ", format( - new Date(order.contract_terms.timestamp.t_s * 1e3), + /* @__PURE__ */ h("p", null, /* @__PURE__ */ h("b", null, /* @__PURE__ */ h(i18n2.Translate, null, "claimed at"), ":"), " ", order.contract_terms.timestamp.t_s === "never" ? "never" : format( + new Date( + order.contract_terms.timestamp.t_s * 1e3 + ), datetimeFormatForSettings(settings) )) )))))), /* @__PURE__ */ h("section", { class: "section" }, /* @__PURE__ */ h("div", { class: "columns" }, /* @__PURE__ */ h("div", { class: "column is-4" }, /* @__PURE__ */ h("div", { class: "title" }, /* @__PURE__ */ h(i18n2.Translate, null, "Timeline")), /* @__PURE__ */ h(Timeline, { events: events2 })), /* @__PURE__ */ h("div", { class: "column is-8" }, /* @__PURE__ */ h("div", { class: "title" }, /* @__PURE__ */ h(i18n2.Translate, null, "Payment details")), /* @__PURE__ */ h( @@ -44639,22 +47980,10 @@ function PaidPage({ order, onRefund }) { + const now2 = /* @__PURE__ */ new Date(); + const refundable = order.contract_terms.refund_deadline.t_s !== "never" && now2.getTime() < order.contract_terms.refund_deadline.t_s * 1e3; const events2 = []; - if (order.contract_terms.timestamp.t_s !== "never") { - events2.push({ - when: new Date(order.contract_terms.timestamp.t_s * 1e3), - description: "order created", - type: "start" - }); - } - if (order.contract_terms.pay_deadline.t_s !== "never") { - events2.push({ - when: new Date(order.contract_terms.pay_deadline.t_s * 1e3), - description: "pay deadline", - type: "deadline" - }); - } - if (order.contract_terms.refund_deadline.t_s !== "never") { + if (order.contract_terms.refund_deadline.t_s !== "never" && refundable) { events2.push({ when: new Date(order.contract_terms.refund_deadline.t_s * 1e3), description: "refund deadline", @@ -44685,59 +48014,61 @@ function PaidPage({ }); } }); - if (order.wire_details && order.wire_details.length) { - if (order.wire_details.length > 1) { - let last = null; - let first = null; - let total = null; - order.wire_details.forEach((w5) => { - if (last === null || last.execution_time.t_s < w5.execution_time.t_s) { - last = w5; - } - if (first === null || first.execution_time.t_s > w5.execution_time.t_s) { - first = w5; - } - total = total === null ? Amounts.parseOrThrow(w5.amount) : Amounts.add(total, Amounts.parseOrThrow(w5.amount)).amount; - }); - const last_time = last.execution_time.t_s; - if (last_time !== "never") { - events2.push({ - when: new Date(last_time * 1e3), - description: `wired ${Amounts.stringify(total)}`, - type: "wired-range" - }); - } - const first_time = first.execution_time.t_s; - if (first_time !== "never") { - events2.push({ - when: new Date(first_time * 1e3), - description: `wire transfer started...`, - type: "wired-range" + const ra = !order.refunded ? void 0 : Amounts.parse(order.refund_amount); + const am = Amounts.parseOrThrow(order.contract_terms.amount); + if (ra && Amounts.cmp(ra, am) === 1) { + if (order.wire_details && order.wire_details.length) { + if (order.wire_details.length > 1) { + let last = null; + let first = null; + let total = null; + order.wire_details.forEach((w5) => { + if (last === null || last.execution_time.t_s < w5.execution_time.t_s) { + last = w5; + } + if (first === null || first.execution_time.t_s > w5.execution_time.t_s) { + first = w5; + } + total = total === null ? Amounts.parseOrThrow(w5.amount) : Amounts.add(total, Amounts.parseOrThrow(w5.amount)).amount; }); - } - } else { - order.wire_details.forEach((e4) => { - if (e4.execution_time.t_s !== "never") { + const last_time = last.execution_time.t_s; + if (last_time !== "never") { events2.push({ - when: new Date(e4.execution_time.t_s * 1e3), - description: `wired ${e4.amount}`, - type: "wired" + when: new Date(last_time * 1e3), + description: `wired ${Amounts.stringify(total)}`, + type: "wired-range" }); } - }); + const first_time = first.execution_time.t_s; + if (first_time !== "never") { + events2.push({ + when: new Date(first_time * 1e3), + description: `wire transfer started...`, + type: "wired-range" + }); + } + } else { + order.wire_details.forEach((e4) => { + if (e4.execution_time.t_s !== "never") { + events2.push({ + when: new Date(e4.execution_time.t_s * 1e3), + description: `wired ${e4.amount}`, + type: "wired" + }); + } + }); + } } } - const now2 = /* @__PURE__ */ new Date(); const nextEvent = events2.find((e4) => { return e4.when.getTime() > now2.getTime(); }); const [value, valueHandler] = p3(order); - const { url: backendURL } = useBackendContext(); + const { url: backendUrl } = useMerchantApiContext(); const refundurl = stringifyRefundUri({ - merchantBaseUrl: backendURL, + merchantBaseUrl: backendUrl.href, orderId: order.contract_terms.order_id }); - const refundable = (/* @__PURE__ */ new Date()).getTime() < order.contract_terms.refund_deadline.t_s * 1e3; const { i18n: i18n2 } = useTranslationContext(); const amount = Amounts.parseOrThrow(order.contract_terms.amount); const refund_taken = order.refund_details.reduce((prev, cur) => { @@ -44838,7 +48169,7 @@ function UnpaidPage({ }) { const [value, valueHandler] = p3(order); const { i18n: i18n2 } = useTranslationContext(); - const [settings] = useSettings(); + const [settings] = usePreference(); return /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("section", { class: "hero is-hero-bar" }, /* @__PURE__ */ h("div", { class: "hero-body" }, /* @__PURE__ */ h("div", { class: "level" }, /* @__PURE__ */ h("div", { class: "level-left" }, /* @__PURE__ */ h("div", { class: "level-item" }, /* @__PURE__ */ h("h1", { class: "title" }, /* @__PURE__ */ h(i18n2.Translate, null, "Order"), " #", id)), /* @__PURE__ */ h("div", { class: "tag is-dark" }, /* @__PURE__ */ h(i18n2.Translate, null, "unpaid")))), /* @__PURE__ */ h("div", { class: "level" }, /* @__PURE__ */ h("div", { class: "level-left", style: { maxWidth: "100%" } }, /* @__PURE__ */ h("div", { class: "level-item", style: { maxWidth: "100%" } }, /* @__PURE__ */ h( "div", { @@ -44930,44 +48261,59 @@ function DetailPage({ id, selected, onRefund, onBack }) { } // src/paths/instance/orders/details/index.tsx -function Update({ - oid, - onBack, - onLoadError, - onNotFound, - onUnauthorized -}) { - const { refundOrder } = useOrderAPI(); +function Update({ oid, onBack }) { const result = useOrderDetails(oid); const [notif, setNotif] = p3(void 0); + const { lib: api } = useMerchantApiContext(); + const { state } = useSessionContext(); const { i18n: i18n2 } = useTranslationContext(); - if (result.loading) + if (!result) return /* @__PURE__ */ h(Loading, null); - if (!result.ok) { - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.Unauthorized) - return onUnauthorized(); - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.NotFound) - return onNotFound(); - return onLoadError(result); + if (result instanceof TalerError) { + return /* @__PURE__ */ h(ErrorLoadingMerchant, { error: result }); + } + if (result.type === "fail") { + switch (result.case) { + case HttpStatusCode.NotFound: { + return /* @__PURE__ */ h(NotFoundPageOrAdminCreate, null); + } + case HttpStatusCode.BadGateway: { + return /* @__PURE__ */ h("div", null, "Failed to obtain a response from the exchange"); + } + case HttpStatusCode.GatewayTimeout: { + return /* @__PURE__ */ h("div", null, "The merchant's interaction with the exchange took too long"); + } + case HttpStatusCode.Unauthorized: { + return /* @__PURE__ */ h(LoginPage, null); + } + default: { + assertUnreachable(result); + } + } } return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(NotificationCard, { notification: notif }), /* @__PURE__ */ h( DetailPage, { onBack, id: oid, - onRefund: (id, value) => refundOrder(id, value).then( - () => setNotif({ - message: i18n2.str`refund created successfully`, - type: "SUCCESS" - }) - ).catch( - (error2) => setNotif({ - message: i18n2.str`could not create the refund`, - type: "ERROR", - description: error2.message - }) - ), - selected: result.data + onRefund: (id, value) => { + if (state.status !== "loggedIn") { + return; + } + api.instance.addRefund(state.token, id, value).then( + () => setNotif({ + message: i18n2.str`refund created successfully`, + type: "SUCCESS" + }) + ).catch( + (error2) => setNotif({ + message: i18n2.str`could not create the refund`, + type: "ERROR", + description: error2.message + }) + ); + }, + selected: result.body } )); } @@ -44976,12 +48322,62 @@ function Update({ init_preact_module(); init_hooks_module(); +// src/components/form/JumpToElementById.tsx +init_preact_module(); +init_hooks_module(); +function JumpToElementById({ testIfExist, onSelect, placeholder, description }) { + const { i18n: i18n2 } = useTranslationContext(); + const [error2, setError] = p3( + void 0 + ); + const [id, setId] = p3(); + async function check(currentId) { + if (!currentId) { + setError(i18n2.str`missing id`); + return; + } + try { + const exi = await testIfExist(currentId); + if (exi) { + onSelect(currentId); + setError(void 0); + } else { + setError(i18n2.str`not found`); + } + } catch { + setError(i18n2.str`not found`); + } + } + return /* @__PURE__ */ h("div", { class: "level" }, /* @__PURE__ */ h("div", { class: "level-left" }, /* @__PURE__ */ h("div", { class: "level-item" }, /* @__PURE__ */ h("div", { class: "field has-addons" }, /* @__PURE__ */ h("div", { class: "control" }, /* @__PURE__ */ h( + "input", + { + class: error2 ? "input is-danger" : "input", + type: "text", + value: id ?? "", + onChange: (e4) => setId(e4.currentTarget.value), + placeholder + } + ), error2 && /* @__PURE__ */ h("p", { class: "help is-danger" }, error2)), /* @__PURE__ */ h( + "span", + { + class: "has-tooltip-bottom", + "data-tooltip": description + }, + /* @__PURE__ */ h( + "button", + { + class: "button", + onClick: (e4) => check(id) + }, + /* @__PURE__ */ h("span", { class: "icon" }, /* @__PURE__ */ h("i", { class: "mdi mdi-arrow-right" })) + ) + ))))); +} + // src/paths/instance/orders/list/ListPage.tsx init_preact_module(); init_hooks_module(); function ListPage3({ - hasMoreAfter, - hasMoreBefore, onLoadMoreAfter, onLoadMoreBefore, orders, @@ -45007,7 +48403,7 @@ function ListPage3({ const { i18n: i18n2 } = useTranslationContext(); const dateTooltip = i18n2.str`select date to show nearby orders`; const [pickDate, setPickDate] = p3(false); - const [settings] = useSettings(); + const [settings] = usePreference(); return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h("div", { class: "columns" }, /* @__PURE__ */ h("div", { class: "column is-two-thirds" }, /* @__PURE__ */ h("div", { class: "tabs", style: { overflow: "inherit" } }, /* @__PURE__ */ h("ul", null, /* @__PURE__ */ h("li", { class: isNotPaidActive }, /* @__PURE__ */ h( "div", { @@ -45063,7 +48459,7 @@ function ListPage3({ class: "input", type: "text", readonly: true, - value: !jumpToDate ? "" : format(jumpToDate, dateFormatForSettings(settings)), + value: !jumpToDate || jumpToDate.t_ms === "never" ? "" : format(jumpToDate.t_ms, dateFormatForSettings(settings)), placeholder: i18n2.str`date (${dateFormatForSettings(settings)})`, onClick: () => { setPickDate(true); @@ -45083,7 +48479,9 @@ function ListPage3({ { opened: pickDate, closeFunction: () => setPickDate(false), - dateReceiver: onSelectDate + dateReceiver: (d5) => { + onSelectDate(AbsoluteTime.fromMilliseconds(d5.getTime())); + } } ), /* @__PURE__ */ h( CardTable3, @@ -45093,96 +48491,56 @@ function ListPage3({ onCopyURL, onSelect: onSelectOrder, onRefund: onRefundOrder, - hasMoreAfter, - hasMoreBefore, onLoadMoreAfter, onLoadMoreBefore } )); } -// src/components/form/JumpToElementById.tsx -init_preact_module(); -init_hooks_module(); -function JumpToElementById({ testIfExist, onSelect, placeholder, description }) { - const { i18n: i18n2 } = useTranslationContext(); - const [error2, setError] = p3( - void 0 - ); - const [id, setId] = p3(); - async function check(currentId) { - if (!currentId) { - setError(i18n2.str`missing id`); - return; - } - try { - await testIfExist(currentId); - onSelect(currentId); - setError(void 0); - } catch { - setError(i18n2.str`not found`); - } - } - return /* @__PURE__ */ h("div", { class: "level" }, /* @__PURE__ */ h("div", { class: "level-left" }, /* @__PURE__ */ h("div", { class: "level-item" }, /* @__PURE__ */ h("div", { class: "field has-addons" }, /* @__PURE__ */ h("div", { class: "control" }, /* @__PURE__ */ h( - "input", - { - class: error2 ? "input is-danger" : "input", - type: "text", - value: id ?? "", - onChange: (e4) => setId(e4.currentTarget.value), - placeholder - } - ), error2 && /* @__PURE__ */ h("p", { class: "help is-danger" }, error2)), /* @__PURE__ */ h( - "span", - { - class: "has-tooltip-bottom", - "data-tooltip": description - }, - /* @__PURE__ */ h( - "button", - { - class: "button", - onClick: (e4) => check(id) - }, - /* @__PURE__ */ h("span", { class: "icon" }, /* @__PURE__ */ h("i", { class: "mdi mdi-arrow-right" })) - ) - ))))); -} - // src/paths/instance/orders/list/index.tsx -function OrderList({ - onUnauthorized, - onLoadError, - onCreate, - onSelect, - onNotFound -}) { - const [filter, setFilter] = p3({ paid: "no" }); +function OrderList({ onCreate, onSelect }) { + const [filter, setFilter] = p3({ paid: false }); const [orderToBeRefunded, setOrderToBeRefunded] = p3(void 0); const setNewDate = (date2) => setFilter((prev) => ({ ...prev, date: date2 })); - const result = useInstanceOrders(filter, setNewDate); - const { refundOrder, getPaymentURL } = useOrderAPI(); + const result = useInstanceOrders( + filter, + (d5) => setFilter({ ...filter, position: d5 }) + ); + const { lib } = useMerchantApiContext(); const [notif, setNotif] = p3(void 0); const { i18n: i18n2 } = useTranslationContext(); - if (result.loading) + const { state } = useSessionContext(); + if (!result) return /* @__PURE__ */ h(Loading, null); - if (!result.ok) { - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.Unauthorized) - return onUnauthorized(); - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.NotFound) - return onNotFound(); - return onLoadError(result); - } - const isNotPaidActive = filter.paid === "no" ? "is-active" : ""; - const isPaidActive = filter.paid === "yes" && filter.wired === void 0 ? "is-active" : ""; - const isRefundedActive = filter.refunded === "yes" ? "is-active" : ""; - const isNotWiredActive = filter.wired === "no" && filter.paid === "yes" ? "is-active" : ""; - const isWiredActive = filter.wired === "yes" ? "is-active" : ""; + if (result instanceof TalerError) { + return /* @__PURE__ */ h(ErrorLoadingMerchant, { error: result }); + } + if (result.type === "fail") { + switch (result.case) { + case HttpStatusCode.NotFound: { + return /* @__PURE__ */ h(NotFoundPageOrAdminCreate, null); + } + case HttpStatusCode.Unauthorized: { + return /* @__PURE__ */ h(LoginPage, null); + } + default: { + assertUnreachable(result); + } + } + } + const isNotPaidActive = filter.paid === false ? "is-active" : ""; + const isPaidActive = filter.paid === true && filter.wired === void 0 ? "is-active" : ""; + const isRefundedActive = filter.refunded === true ? "is-active" : ""; + const isNotWiredActive = filter.wired === false && filter.paid === true ? "is-active" : ""; + const isWiredActive = filter.wired === true ? "is-active" : ""; const isAllActive = filter.paid === void 0 && filter.refunded === void 0 && filter.wired === void 0 ? "is-active" : ""; return /* @__PURE__ */ h("section", { class: "section is-main-section" }, /* @__PURE__ */ h(NotificationCard, { notification: notif }), /* @__PURE__ */ h( JumpToElementById, { - testIfExist: getPaymentURL, + testIfExist: async (order) => { + const resp = await lib.instance.getOrderDetails(state.token, order); + return resp.type === "ok"; + }, onSelect, description: i18n2.str`jump to order with the given product ID`, placeholder: i18n2.str`order id` @@ -45190,11 +48548,9 @@ function OrderList({ ), /* @__PURE__ */ h( ListPage3, { - orders: result.data.orders.map((o3) => ({ ...o3, id: o3.order_id })), - onLoadMoreBefore: result.loadMorePrev, - hasMoreBefore: !result.isReachingStart, - onLoadMoreAfter: result.loadMore, - hasMoreAfter: !result.isReachingEnd, + orders: result.body.map((o3) => ({ ...o3, id: o3.order_id })), + onLoadMoreBefore: result.isFirstPage ? void 0 : result.loadFirst, + onLoadMoreAfter: result.isLastPage ? void 0 : result.loadNext, onSelectOrder: (order) => onSelect(order.id), onRefundOrder: (value) => setOrderToBeRefunded(value), isAllActive, @@ -45204,77 +48560,80 @@ function OrderList({ isNotPaidActive, isRefundedActive, jumpToDate: filter.date, - onCopyURL: (id) => getPaymentURL(id).then((resp) => copyToClipboard(resp.data)), - onCreate, onSelectDate: setNewDate, + onCopyURL: async (id) => { + const resp = await lib.instance.getOrderDetails(state.token, id); + if (resp.type === "ok") { + if (resp.body.order_status === "unpaid") { + copyToClipboard(resp.body.taler_pay_uri); + } else { + if (resp.body.contract_terms.fulfillment_url) { + copyToClipboard(resp.body.contract_terms.fulfillment_url); + } + } + copyToClipboard(resp.body.order_status); + } + }, + onCreate, onShowAll: () => setFilter({}), - onShowNotPaid: () => setFilter({ paid: "no" }), - onShowPaid: () => setFilter({ paid: "yes" }), - onShowRefunded: () => setFilter({ refunded: "yes" }), - onShowNotWired: () => setFilter({ wired: "no", paid: "yes" }), - onShowWired: () => setFilter({ wired: "yes" }) + onShowNotPaid: () => setFilter({ paid: false }), + onShowPaid: () => setFilter({ paid: true }), + onShowRefunded: () => setFilter({ refunded: true }), + onShowNotWired: () => setFilter({ wired: false, paid: true }), + onShowWired: () => setFilter({ wired: true }) } ), orderToBeRefunded && /* @__PURE__ */ h( RefundModalForTable, { id: orderToBeRefunded.order_id, onCancel: () => setOrderToBeRefunded(void 0), - onConfirm: (value) => refundOrder(orderToBeRefunded.order_id, value).then( - () => setNotif({ - message: i18n2.str`refund created successfully`, - type: "SUCCESS" - }) - ).catch( - (error2) => setNotif({ - message: i18n2.str`could not create the refund`, - type: "ERROR", - description: error2.message - }) - ).then(() => setOrderToBeRefunded(void 0)), - onLoadError: (error2) => { - setNotif({ - message: i18n2.str`could not create the refund`, - type: "ERROR", - description: error2.message - }); - setOrderToBeRefunded(void 0); - return /* @__PURE__ */ h("div", null); - }, - onUnauthorized, - onNotFound: () => { - setNotif({ - message: i18n2.str`could not get the order to refund`, - type: "ERROR" - // description: error.message - }); - setOrderToBeRefunded(void 0); - return /* @__PURE__ */ h("div", null); + onConfirm: (value) => { + lib.instance.addRefund(state.token, orderToBeRefunded.order_id, value).then( + () => setNotif({ + message: i18n2.str`refund created successfully`, + type: "SUCCESS" + }) + ).catch( + (error2) => setNotif({ + message: i18n2.str`could not create the refund`, + type: "ERROR", + description: error2.message + }) + ).then(() => setOrderToBeRefunded(void 0)); } } )); } -function RefundModalForTable({ - id, - onUnauthorized, - onLoadError, - onNotFound, - onConfirm, - onCancel -}) { +function RefundModalForTable({ id, onConfirm, onCancel }) { const result = useOrderDetails(id); - if (result.loading) + if (!result) return /* @__PURE__ */ h(Loading, null); - if (!result.ok) { - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.Unauthorized) - return onUnauthorized(); - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.NotFound) - return onNotFound(); - return onLoadError(result); + if (result instanceof TalerError) { + return /* @__PURE__ */ h(ErrorLoadingMerchant, { error: result }); + } + if (result.type === "fail") { + switch (result.case) { + case HttpStatusCode.NotFound: { + return /* @__PURE__ */ h(NotFoundPageOrAdminCreate, null); + } + case HttpStatusCode.BadGateway: { + return /* @__PURE__ */ h("div", null, "Failed to obtain a response from the exchange"); + } + case HttpStatusCode.GatewayTimeout: { + return /* @__PURE__ */ h("div", null, "The merchant's interaction with the exchange took too long"); + } + case HttpStatusCode.Unauthorized: { + return /* @__PURE__ */ h(LoginPage, null); + } + default: { + assertUnreachable(result); + } + } } return /* @__PURE__ */ h( RefundModal, { - order: result.data, + order: result.body, onCancel, onConfirm } @@ -45288,6 +48647,101 @@ async function copyToClipboard(text) { init_preact_module(); init_hooks_module(); +// src/paths/instance/otp_devices/create/CreatedSuccessfully.tsx +init_preact_module(); + +// src/components/exception/QR.tsx +init_preact_module(); +init_hooks_module(); +var import_qrcode_generator = __toESM(require_qrcode(), 1); +function QR({ text }) { + const divRef = _2(null); + h2(() => { + const qr = (0, import_qrcode_generator.default)(0, "L"); + qr.addData(text); + qr.make(); + if (divRef.current) { + divRef.current.innerHTML = qr.createSvgTag({ + scalable: true + }); + } + }); + return /* @__PURE__ */ h( + "div", + { + style: { + width: "100%", + display: "flex", + flexDirection: "column", + alignItems: "center" + } + }, + /* @__PURE__ */ h( + "div", + { + style: { width: "50%", minWidth: 200, maxWidth: 300 }, + ref: divRef + } + ) + ); +} + +// src/components/notifications/CreatedSuccessfully.tsx +init_preact_module(); +function CreatedSuccessfully({ + children, + onConfirm, + onCreateAnother +}) { + return /* @__PURE__ */ h("div", { class: "columns is-fullwidth is-vcentered mt-3" }, /* @__PURE__ */ h("div", { class: "column" }), /* @__PURE__ */ h("div", { class: "column is-four-fifths" }, /* @__PURE__ */ h("div", { class: "card" }, /* @__PURE__ */ h("header", { class: "card-header has-background-success" }, /* @__PURE__ */ h("p", { class: "card-header-title has-text-white-ter" }, "Success.")), /* @__PURE__ */ h("div", { class: "card-content" }, children)), /* @__PURE__ */ h("div", { class: "buttons is-right" }, onCreateAnother && /* @__PURE__ */ h("button", { class: "button is-info", onClick: onCreateAnother }, "Create another"), /* @__PURE__ */ h("button", { class: "button is-info", onClick: onConfirm }, "Continue"))), /* @__PURE__ */ h("div", { class: "column" })); +} + +// src/paths/instance/otp_devices/create/CreatedSuccessfully.tsx +function CreatedSuccessfully2({ + entity, + onConfirm +}) { + const { i18n: i18n2 } = useTranslationContext(); + const { url: backendUrl } = useMerchantApiContext(); + const { state } = useSessionContext(); + const issuer = backendUrl.href; + const qrText = `otpauth://totp/${state.instance}/${entity.otp_device_id}?issuer=${issuer}&algorithm=SHA1&digits=8&period=30&secret=${entity.otp_key}`; + const qrTextSafe = `otpauth://totp/${state.instance}/${entity.otp_device_id}?issuer=${issuer}&algorithm=SHA1&digits=8&period=30&secret=${entity.otp_key.substring(0, 6)}...`; + return /* @__PURE__ */ h(CreatedSuccessfully, { onConfirm }, /* @__PURE__ */ h("p", { class: "is-size-5" }, /* @__PURE__ */ h(i18n2.Translate, null, "You can scan the next QR code with your device or save the key before continuing.")), /* @__PURE__ */ h("div", { class: "field is-horizontal" }, /* @__PURE__ */ h("div", { class: "field-label is-normal" }, /* @__PURE__ */ h("label", { class: "label" }, "ID")), /* @__PURE__ */ h("div", { class: "field-body is-flex-grow-3" }, /* @__PURE__ */ h("div", { class: "field" }, /* @__PURE__ */ h("p", { class: "control" }, /* @__PURE__ */ h( + "input", + { + readonly: true, + class: "input", + value: entity.otp_device_id + } + ))))), /* @__PURE__ */ h("div", { class: "field is-horizontal" }, /* @__PURE__ */ h("div", { class: "field-label is-normal" }, /* @__PURE__ */ h("label", { class: "label" }, /* @__PURE__ */ h(i18n2.Translate, null, "Description"))), /* @__PURE__ */ h("div", { class: "field-body is-flex-grow-3" }, /* @__PURE__ */ h("div", { class: "field" }, /* @__PURE__ */ h("p", { class: "control" }, /* @__PURE__ */ h( + "input", + { + class: "input", + readonly: true, + value: entity.otp_device_description + } + ))))), /* @__PURE__ */ h( + QR, + { + text: qrText + } + ), /* @__PURE__ */ h( + "div", + { + style: { + color: "grey", + fontSize: "small", + width: 200, + textAlign: "center", + margin: "auto", + wordBreak: "break-all" + } + }, + qrTextSafe + )); +} + // src/paths/instance/otp_devices/create/CreatePage.tsx init_preact_module(); init_hooks_module(); @@ -45295,7 +48749,6 @@ var algorithms = [0, 1, 2]; var algorithmsNames = ["off", "30s 8d TOTP-SHA1", "30s 8d eTOTP-SHA1"]; function CreatePage4({ onCreate, onBack }) { const { i18n: i18n2 } = useTranslationContext(); - const backend = useBackendContext(); const [state, setState] = p3({}); const [showKey, setShowKey] = p3(false); const errors2 = { @@ -45346,7 +48799,7 @@ function CreatePage4({ onCreate, onBack }) { fromStr: (v3) => Number(v3) } ), - state.otp_algorithm && state.otp_algorithm > 0 ? /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h( + state.otp_algorithm ? /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h( InputWithAddon, { expand: true, @@ -45370,6 +48823,7 @@ function CreatePage4({ onCreate, onBack }) { ...s5, otp_key: randomRfc3548Base32Key() })); + e4.preventDefault(); } }, /* @__PURE__ */ h(i18n2.Translate, null, "random") @@ -45387,207 +48841,10 @@ function CreatePage4({ onCreate, onBack }) { ))), /* @__PURE__ */ h("div", { class: "column" })))); } -// src/hooks/otp.ts -init_hooks_module(); -var useSWR6 = useSWR; -function useOtpDeviceAPI() { - const mutateAll = useMatchMutate(); - const { request } = useBackendInstanceRequest(); - const createOtpDevice = async (data) => { - const res = await request(`/private/otp-devices`, { - method: "POST", - data - }); - await mutateAll(/.*private\/otp-devices.*/); - return res; - }; - const updateOtpDevice = async (deviceId, data) => { - const res = await request(`/private/otp-devices/${deviceId}`, { - method: "PATCH", - data - }); - await mutateAll(/.*private\/otp-devices.*/); - return res; - }; - const deleteOtpDevice = async (deviceId) => { - const res = await request(`/private/otp-devices/${deviceId}`, { - method: "DELETE" - }); - await mutateAll(/.*private\/otp-devices.*/); - return res; - }; - return { - createOtpDevice, - updateOtpDevice, - deleteOtpDevice - }; -} -function useInstanceOtpDevices(args, updatePosition) { - const { fetcher } = useBackendInstanceRequest(); - const [pageAfter, setPageAfter] = p3(1); - const totalAfter = pageAfter * PAGE_SIZE; - const { - data: afterData, - error: afterError, - isValidating: loadingAfter - } = useSWR6([`/private/otp-devices`], fetcher); - const [lastAfter, setLastAfter] = p3({ loading: true }); - h2(() => { - if (afterData) - setLastAfter(afterData); - }, [ - afterData - /*, beforeData*/ - ]); - if (afterError) - return afterError.cause; - const isReachingEnd = afterData && afterData.data.otp_devices.length < totalAfter; - const isReachingStart = true; - const pagination = { - isReachingEnd, - isReachingStart, - loadMore: () => { - if (!afterData || isReachingEnd) - return; - if (afterData.data.otp_devices.length < MAX_RESULT_SIZE) { - setPageAfter(pageAfter + 1); - } else { - const from = `${afterData.data.otp_devices[afterData.data.otp_devices.length - 1].otp_device_id}`; - if (from && updatePosition) - updatePosition(from); - } - }, - loadMorePrev: () => { - } - }; - const otp_devices = !afterData ? [] : (afterData || lastAfter).data.otp_devices; - if (loadingAfter) - return { loading: true, data: { otp_devices } }; - if ( - /*beforeData &&*/ - afterData - ) { - return { ok: true, data: { otp_devices }, ...pagination }; - } - return { loading: true }; -} -function useOtpDeviceDetails(deviceId) { - const { fetcher } = useBackendInstanceRequest(); - const { data, error: error2, isValidating } = useSWR6([`/private/otp-devices/${deviceId}`], fetcher, { - refreshInterval: 0, - refreshWhenHidden: false, - revalidateOnFocus: false, - revalidateOnReconnect: false, - refreshWhenOffline: false - }); - if (isValidating) - return { loading: true, data: data?.data }; - if (data) { - return data; - } - if (error2) - return error2.cause; - return { loading: true }; -} - -// src/paths/instance/otp_devices/create/CreatedSuccessfully.tsx -init_preact_module(); - -// src/components/exception/QR.tsx -init_preact_module(); -init_hooks_module(); -var import_qrcode_generator = __toESM(require_qrcode(), 1); -function QR({ text }) { - const divRef = _2(null); - h2(() => { - const qr = (0, import_qrcode_generator.default)(0, "L"); - qr.addData(text); - qr.make(); - if (divRef.current) { - divRef.current.innerHTML = qr.createSvgTag({ - scalable: true - }); - } - }); - return /* @__PURE__ */ h( - "div", - { - style: { - width: "100%", - display: "flex", - flexDirection: "column", - alignItems: "center" - } - }, - /* @__PURE__ */ h( - "div", - { - style: { width: "50%", minWidth: 200, maxWidth: 300 }, - ref: divRef - } - ) - ); -} - -// src/components/notifications/CreatedSuccessfully.tsx -init_preact_module(); -function CreatedSuccessfully({ - children, - onConfirm, - onCreateAnother -}) { - return /* @__PURE__ */ h("div", { class: "columns is-fullwidth is-vcentered mt-3" }, /* @__PURE__ */ h("div", { class: "column" }), /* @__PURE__ */ h("div", { class: "column is-four-fifths" }, /* @__PURE__ */ h("div", { class: "card" }, /* @__PURE__ */ h("header", { class: "card-header has-background-success" }, /* @__PURE__ */ h("p", { class: "card-header-title has-text-white-ter" }, "Success.")), /* @__PURE__ */ h("div", { class: "card-content" }, children)), /* @__PURE__ */ h("div", { class: "buttons is-right" }, onCreateAnother && /* @__PURE__ */ h("button", { class: "button is-info", onClick: onCreateAnother }, "Create another"), /* @__PURE__ */ h("button", { class: "button is-info", onClick: onConfirm }, "Continue"))), /* @__PURE__ */ h("div", { class: "column" })); -} - -// src/paths/instance/otp_devices/create/CreatedSuccessfully.tsx -function CreatedSuccessfully2({ - entity, - onConfirm -}) { - const { i18n: i18n2 } = useTranslationContext(); - const { url: backendURL } = useBackendContext(); - const { id: instanceId } = useInstanceContext(); - const issuer = new URL(backendURL).hostname; - const qrText = `otpauth://totp/${instanceId}/${entity.otp_device_id}?issuer=${issuer}&algorithm=SHA1&digits=8&period=30&secret=${entity.otp_key}`; - const qrTextSafe = `otpauth://totp/${instanceId}/${entity.otp_device_id}?issuer=${issuer}&algorithm=SHA1&digits=8&period=30&secret=${entity.otp_key.substring(0, 6)}...`; - return /* @__PURE__ */ h(CreatedSuccessfully, { onConfirm }, /* @__PURE__ */ h("p", { class: "is-size-5" }, /* @__PURE__ */ h(i18n2.Translate, null, "You can scan the next QR code with your device or save the key before continuing.")), /* @__PURE__ */ h("div", { class: "field is-horizontal" }, /* @__PURE__ */ h("div", { class: "field-label is-normal" }, /* @__PURE__ */ h("label", { class: "label" }, "ID")), /* @__PURE__ */ h("div", { class: "field-body is-flex-grow-3" }, /* @__PURE__ */ h("div", { class: "field" }, /* @__PURE__ */ h("p", { class: "control" }, /* @__PURE__ */ h( - "input", - { - readonly: true, - class: "input", - value: entity.otp_device_id - } - ))))), /* @__PURE__ */ h("div", { class: "field is-horizontal" }, /* @__PURE__ */ h("div", { class: "field-label is-normal" }, /* @__PURE__ */ h("label", { class: "label" }, /* @__PURE__ */ h(i18n2.Translate, null, "Description"))), /* @__PURE__ */ h("div", { class: "field-body is-flex-grow-3" }, /* @__PURE__ */ h("div", { class: "field" }, /* @__PURE__ */ h("p", { class: "control" }, /* @__PURE__ */ h( - "input", - { - class: "input", - readonly: true, - value: entity.otp_device_description - } - ))))), /* @__PURE__ */ h( - QR, - { - text: qrText - } - ), /* @__PURE__ */ h( - "div", - { - style: { - color: "grey", - fontSize: "small", - width: 200, - textAlign: "center", - margin: "auto", - wordBreak: "break-all" - } - }, - qrTextSafe - )); -} - // src/paths/instance/otp_devices/create/index.tsx function CreateValidator2({ onConfirm, onBack }) { - const { createOtpDevice } = useOtpDeviceAPI(); + const { lib: api } = useMerchantApiContext(); + const { state } = useSessionContext(); const [notif, setNotif] = p3(void 0); const { i18n: i18n2 } = useTranslationContext(); const [created, setCreated] = p3(null); @@ -45599,7 +48856,7 @@ function CreateValidator2({ onConfirm, onBack }) { { onBack, onCreate: (request) => { - return createOtpDevice(request).then((d5) => { + return api.instance.addOtpDevice(state.token, request).then((d5) => { setCreated(request); }).catch((error2) => { setNotif({ @@ -45617,6 +48874,55 @@ function CreateValidator2({ onConfirm, onBack }) { init_preact_module(); init_hooks_module(); +// src/hooks/otp.ts +var useSWR7 = useSWR; +function revalidateInstanceOtpDevices() { + return mutate( + (key) => Array.isArray(key) && key[key.length - 1] === "listOtpDevices", + void 0, + { revalidate: true } + ); +} +function useInstanceOtpDevices() { + const { state: session } = useSessionContext(); + const { lib: { instance } } = useMerchantApiContext(); + async function fetcher([token, bid]) { + return await instance.listOtpDevices(token, { + // limit: PAGINATED_LIST_REQUEST, + // offset: bid, + // order: "dec", + }); + } + const { data, error: error2 } = useSWR7([session.token, "offset", "listOtpDevices"], fetcher); + if (error2) + return error2; + if (data === void 0) + return void 0; + if (data.type !== "ok") + return data; + return data; +} +function revalidateOtpDeviceDetails() { + return mutate( + (key) => Array.isArray(key) && key[key.length - 1] === "getOtpDeviceDetails", + void 0, + { revalidate: true } + ); +} +function useOtpDeviceDetails(deviceId) { + const { state: session } = useSessionContext(); + const { lib: { instance } } = useMerchantApiContext(); + async function fetcher([dId, token]) { + return await instance.getOtpDeviceDetails(token, dId); + } + const { data, error: error2 } = useSWR7([deviceId, session.token, "getOtpDeviceDetails"], fetcher); + if (data) + return data; + if (error2) + return error2; + return void 0; +} + // src/paths/instance/otp_devices/list/ListPage.tsx init_preact_module(); @@ -45629,9 +48935,7 @@ function CardTable4({ onDelete, onSelect, onLoadMoreAfter, - onLoadMoreBefore, - hasMoreAfter, - hasMoreBefore + onLoadMoreBefore }) { const [rowSelection, rowSelectionHandler] = p3([]); const { i18n: i18n2 } = useTranslationContext(); @@ -45651,9 +48955,7 @@ function CardTable4({ rowSelection, rowSelectionHandler, onLoadMoreAfter, - onLoadMoreBefore, - hasMoreAfter, - hasMoreBefore + onLoadMoreBefore } ) : /* @__PURE__ */ h(EmptyTable5, null))))); } @@ -45662,19 +48964,17 @@ function Table4({ onLoadMoreAfter, onDelete, onSelect, - onLoadMoreBefore, - hasMoreAfter, - hasMoreBefore + onLoadMoreBefore }) { const { i18n: i18n2 } = useTranslationContext(); - return /* @__PURE__ */ h("div", { class: "table-container" }, hasMoreBefore && /* @__PURE__ */ h( + return /* @__PURE__ */ h("div", { class: "table-container" }, onLoadMoreBefore && /* @__PURE__ */ h( "button", { class: "button is-fullwidth", "data-tooltip": i18n2.str`load more devices before the first one`, onClick: onLoadMoreBefore }, - /* @__PURE__ */ h(i18n2.Translate, null, "load newer devices") + /* @__PURE__ */ h(i18n2.Translate, null, "load first page") ), /* @__PURE__ */ h("table", { class: "table is-fullwidth is-striped is-hoverable is-fullwidth" }, /* @__PURE__ */ h("thead", null, /* @__PURE__ */ h("tr", null, /* @__PURE__ */ h("th", null, /* @__PURE__ */ h(i18n2.Translate, null, "ID")), /* @__PURE__ */ h("th", null, /* @__PURE__ */ h(i18n2.Translate, null, "Description")), /* @__PURE__ */ h("th", null))), /* @__PURE__ */ h("tbody", null, instances.map((i4) => { return /* @__PURE__ */ h("tr", { key: i4.otp_device_id }, /* @__PURE__ */ h( "td", @@ -45699,19 +48999,19 @@ function Table4({ }, "Delete" )))); - }))), hasMoreAfter && /* @__PURE__ */ h( + }))), onLoadMoreAfter && /* @__PURE__ */ h( "button", { class: "button is-fullwidth", "data-tooltip": i18n2.str`load more devices after the last one`, onClick: onLoadMoreAfter }, - /* @__PURE__ */ h(i18n2.Translate, null, "load older devices") + /* @__PURE__ */ h(i18n2.Translate, null, "load next page") )); } function EmptyTable5() { const { i18n: i18n2 } = useTranslationContext(); - return /* @__PURE__ */ h("div", { class: "content has-text-grey has-text-centered" }, /* @__PURE__ */ h("p", null, /* @__PURE__ */ h("span", { class: "icon is-large" }, /* @__PURE__ */ h("i", { class: "mdi mdi-emoticon-sad mdi-48px" }))), /* @__PURE__ */ h("p", null, /* @__PURE__ */ h(i18n2.Translate, null, "There is no devices yet, add more pressing the + sign"))); + return /* @__PURE__ */ h("div", { class: "content has-text-grey has-text-centered" }, /* @__PURE__ */ h("p", null, /* @__PURE__ */ h("span", { class: "icon is-large" }, /* @__PURE__ */ h("i", { class: "mdi mdi-magnify mdi-48px" }))), /* @__PURE__ */ h("p", null, /* @__PURE__ */ h(i18n2.Translate, null, "There is no devices yet, add more pressing the + sign"))); } // src/paths/instance/otp_devices/list/ListPage.tsx @@ -45723,8 +49023,6 @@ function ListPage4({ onLoadMoreBefore, onLoadMoreAfter }) { - const form = { payto_uri: "" }; - const { i18n: i18n2 } = useTranslationContext(); return /* @__PURE__ */ h("section", { class: "section is-main-section" }, /* @__PURE__ */ h( CardTable4, { @@ -45736,57 +49034,60 @@ function ListPage4({ onDelete, onSelect, onLoadMoreBefore, - hasMoreBefore: !onLoadMoreBefore, - onLoadMoreAfter, - hasMoreAfter: !onLoadMoreAfter + onLoadMoreAfter } )); } // src/paths/instance/otp_devices/list/index.tsx -function ListOtpDevices2({ - onUnauthorized, - onLoadError, - onCreate, - onSelect, - onNotFound -}) { - const [position, setPosition] = p3(void 0); +function ListOtpDevices2({ onCreate, onSelect }) { const { i18n: i18n2 } = useTranslationContext(); const [notif, setNotif] = p3(void 0); - const { deleteOtpDevice } = useOtpDeviceAPI(); - const result = useInstanceOtpDevices({ position }, (id) => setPosition(id)); - if (result.loading) + const { lib } = useMerchantApiContext(); + const { state } = useSessionContext(); + const result = useInstanceOtpDevices(); + if (!result) return /* @__PURE__ */ h(Loading, null); - if (!result.ok) { - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.Unauthorized) - return onUnauthorized(); - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.NotFound) - return onNotFound(); - return onLoadError(result); + if (result instanceof TalerError) { + return /* @__PURE__ */ h(ErrorLoadingMerchant, { error: result }); + } + if (result.type === "fail") { + switch (result.case) { + case HttpStatusCode.NotFound: { + return /* @__PURE__ */ h(NotFoundPageOrAdminCreate, null); + } + case HttpStatusCode.Unauthorized: { + return /* @__PURE__ */ h(LoginPage, null); + } + default: { + assertUnreachable(result); + } + } } return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(NotificationCard, { notification: notif }), /* @__PURE__ */ h( ListPage4, { - devices: result.data.otp_devices, - onLoadMoreBefore: result.isReachingStart ? result.loadMorePrev : void 0, - onLoadMoreAfter: result.isReachingEnd ? result.loadMore : void 0, + devices: result.body.otp_devices, + onLoadMoreBefore: void 0, + onLoadMoreAfter: void 0, onCreate, onSelect: (e4) => { onSelect(e4.otp_device_id); }, - onDelete: (e4) => deleteOtpDevice(e4.otp_device_id).then( - () => setNotif({ - message: i18n2.str`validator delete successfully`, - type: "SUCCESS" - }) - ).catch( - (error2) => setNotif({ - message: i18n2.str`could not delete the validator`, - type: "ERROR", - description: error2.message - }) - ) + onDelete: (e4) => { + return lib.instance.deleteOtpDevice(state.token, e4.otp_device_id).then( + () => setNotif({ + message: i18n2.str`validator delete successfully`, + type: "SUCCESS" + }) + ).catch( + (error2) => setNotif({ + message: i18n2.str`could not delete the validator`, + type: "ERROR", + description: error2.message + }) + ); + } } )); } @@ -45903,24 +49204,31 @@ function UpdatePage2({ device, onUpdate, onBack }) { function UpdateValidator2({ vid, onConfirm, - onBack, - onUnauthorized, - onNotFound, - onLoadError + onBack }) { - const { updateOtpDevice } = useOtpDeviceAPI(); const result = useOtpDeviceDetails(vid); const [notif, setNotif] = p3(void 0); const [keyUpdated, setKeyUpdated] = p3(null); + const { lib } = useMerchantApiContext(); + const { state } = useSessionContext(); const { i18n: i18n2 } = useTranslationContext(); - if (result.loading) + if (!result) return /* @__PURE__ */ h(Loading, null); - if (!result.ok) { - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.Unauthorized) - return onUnauthorized(); - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.NotFound) - return onNotFound(); - return onLoadError(result); + if (result instanceof TalerError) { + return /* @__PURE__ */ h(ErrorLoadingMerchant, { error: result }); + } + if (result.type === "fail") { + switch (result.case) { + case HttpStatusCode.NotFound: { + return /* @__PURE__ */ h(NotFoundPageOrAdminCreate, null); + } + case HttpStatusCode.Unauthorized: { + return /* @__PURE__ */ h(LoginPage, null); + } + default: { + assertUnreachable(result); + } + } } if (keyUpdated) { return /* @__PURE__ */ h(CreatedSuccessfully2, { entity: keyUpdated, onConfirm }); @@ -45930,24 +49238,45 @@ function UpdateValidator2({ { device: { id: vid, - otp_algorithm: result.data.otp_algorithm, - otp_device_description: result.data.device_description, - otp_key: void 0, - otp_ctr: result.data.otp_ctr + otp_algorithm: result.body.otp_algorithm, + otp_device_description: result.body.device_description, + otp_key: "", + otp_ctr: result.body.otp_ctr }, onBack, onUpdate: async (newInfo) => { - return updateOtpDevice(vid, newInfo).then((d5) => { - if (newInfo.otp_key) { - setKeyUpdated({ - otp_algorithm: newInfo.otp_algorithm, - otp_device_description: newInfo.otp_device_description, - otp_device_id: newInfo.id, - otp_key: newInfo.otp_key, - otp_ctr: newInfo.otp_ctr - }); + return lib.instance.updateOtpDevice(state.token, vid, newInfo).then((d5) => { + if (d5.type === "ok") { + if (newInfo.otp_key) { + setKeyUpdated({ + otp_algorithm: newInfo.otp_algorithm, + otp_device_description: newInfo.otp_device_description, + otp_device_id: newInfo.id, + otp_key: newInfo.otp_key, + otp_ctr: newInfo.otp_ctr + }); + } else { + onConfirm(); + } } else { - onConfirm(); + switch (d5.case) { + case HttpStatusCode.NotFound: { + setNotif({ + message: i18n2.str`Could not update template`, + type: "ERROR", + description: i18n2.str`Template id is unknown` + }); + break; + } + case HttpStatusCode.Conflict: { + setNotif({ + message: i18n2.str`Could not update template`, + type: "ERROR", + description: i18n2.str`The provided information is inconsistent with the current state of the template` + }); + break; + } + } } }).catch((error2) => { setNotif({ @@ -46078,20 +49407,20 @@ function InputStock({ } // src/components/product/ProductForm.tsx -function ProductForm2({ onSubscribe, initial: initial2, alreadyExist }) { +function ProductForm2({ onSubscribe, initial: initial3, alreadyExist }) { const [value, valueHandler] = p3({ address: {}, description_i18n: {}, taxes: [], next_restock: { t_s: "never" }, price: ":0", - ...initial2, - stock: !initial2 || initial2.total_stock === -1 ? void 0 : { - current: initial2.total_stock || 0, - lost: initial2.total_lost || 0, - sold: initial2.total_sold || 0, - address: initial2.address, - nextRestock: initial2.next_restock + ...initial3, + stock: !initial3 || initial3.total_stock === -1 ? void 0 : { + current: initial3.total_stock || 0, + lost: initial3.total_lost || 0, + sold: initial3.total_sold || 0, + address: initial3.address, + nextRestock: initial3.next_restock } }); let errors2 = {}; @@ -46130,7 +49459,7 @@ function ProductForm2({ onSubscribe, initial: initial2, alreadyExist }) { h2(() => { onSubscribe(hasErrors ? void 0 : submit); }, [submit, hasErrors]); - const { url: backendURL } = useBackendContext(); + const { url: backendUrl } = useMerchantApiContext(); const { i18n: i18n2 } = useTranslationContext(); return /* @__PURE__ */ h("div", null, /* @__PURE__ */ h( FormProvider, @@ -46144,7 +49473,7 @@ function ProductForm2({ onSubscribe, initial: initial2, alreadyExist }) { InputWithAddon, { name: "product_id", - addonBefore: `${backendURL}/product/`, + addonBefore: new URL("product/", backendUrl.href).href, label: i18n2.str`ID`, tooltip: i18n2.str`product identification to use in URLs (for internal use only)` } @@ -46235,7 +49564,8 @@ function CreatePage5({ onCreate, onBack }) { // src/paths/instance/products/create/index.tsx function CreateProduct({ onConfirm, onBack }) { - const { createProduct } = useProductAPI(); + const { lib } = useMerchantApiContext(); + const { state } = useSessionContext(); const [notif, setNotif] = p3(void 0); const { i18n: i18n2 } = useTranslationContext(); return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(NotificationCard, { notification: notif }), /* @__PURE__ */ h( @@ -46243,7 +49573,7 @@ function CreateProduct({ onConfirm, onBack }) { { onBack, onCreate: (request) => { - return createProduct(request).then(() => onConfirm()).catch((error2) => { + return lib.instance.addProduct(state.token, request).then(() => onConfirm()).catch((error2) => { setNotif({ message: i18n2.str`could not create product`, type: "ERROR", @@ -46267,7 +49597,9 @@ function CardTable5({ onCreate, onSelect, onUpdate, - onDelete + onDelete, + onLoadMoreAfter, + onLoadMoreBefore }) { const [rowSelection, rowSelectionHandler] = p3( void 0 @@ -46287,6 +49619,8 @@ function CardTable5({ onSelect, onDelete, onUpdate, + onLoadMoreAfter, + onLoadMoreBefore, rowSelection, rowSelectionHandler } @@ -46298,11 +49632,13 @@ function Table5({ instances, onSelect, onUpdate, - onDelete + onDelete, + onLoadMoreAfter, + onLoadMoreBefore }) { const { i18n: i18n2 } = useTranslationContext(); - const [settings] = useSettings(); - return /* @__PURE__ */ h("div", { class: "table-container" }, /* @__PURE__ */ h("table", { class: "table is-fullwidth is-striped is-hoverable is-fullwidth" }, /* @__PURE__ */ h("thead", null, /* @__PURE__ */ h("tr", null, /* @__PURE__ */ h("th", null, /* @__PURE__ */ h(i18n2.Translate, null, "Image")), /* @__PURE__ */ h("th", null, /* @__PURE__ */ h(i18n2.Translate, null, "Description")), /* @__PURE__ */ h("th", null, /* @__PURE__ */ h(i18n2.Translate, null, "Price per unit")), /* @__PURE__ */ h("th", null, /* @__PURE__ */ h(i18n2.Translate, null, "Taxes")), /* @__PURE__ */ h("th", null, /* @__PURE__ */ h(i18n2.Translate, null, "Sales")), /* @__PURE__ */ h("th", null, /* @__PURE__ */ h(i18n2.Translate, null, "Stock")), /* @__PURE__ */ h("th", null, /* @__PURE__ */ h(i18n2.Translate, null, "Sold")), /* @__PURE__ */ h("th", null))), /* @__PURE__ */ h("tbody", null, instances.map((i4) => { + const [settings] = usePreference(); + return /* @__PURE__ */ h("div", { class: "table-container" }, onLoadMoreBefore && /* @__PURE__ */ h("button", { class: "button is-fullwidth", onClick: onLoadMoreBefore }, /* @__PURE__ */ h(i18n2.Translate, null, "load first page")), /* @__PURE__ */ h("table", { class: "table is-fullwidth is-striped is-hoverable is-fullwidth" }, /* @__PURE__ */ h("thead", null, /* @__PURE__ */ h("tr", null, /* @__PURE__ */ h("th", null, /* @__PURE__ */ h(i18n2.Translate, null, "Image")), /* @__PURE__ */ h("th", null, /* @__PURE__ */ h(i18n2.Translate, null, "Description")), /* @__PURE__ */ h("th", null, /* @__PURE__ */ h(i18n2.Translate, null, "Price per unit")), /* @__PURE__ */ h("th", null, /* @__PURE__ */ h(i18n2.Translate, null, "Taxes")), /* @__PURE__ */ h("th", null, /* @__PURE__ */ h(i18n2.Translate, null, "Sales")), /* @__PURE__ */ h("th", null, /* @__PURE__ */ h(i18n2.Translate, null, "Stock")), /* @__PURE__ */ h("th", null, /* @__PURE__ */ h(i18n2.Translate, null, "Sold")), /* @__PURE__ */ h("th", null))), /* @__PURE__ */ h("tbody", null, instances.map((i4) => { const restStockInfo = !i4.next_restock ? "" : i4.next_restock.t_s === "never" ? "never" : `restock at ${format( new Date(i4.next_restock.t_s * 1e3), dateFormatForSettings(settings) @@ -46412,12 +49748,20 @@ function Table5({ { product: i4, onUpdate: (prod) => onUpdate(i4.id, prod).then( - (r3) => rowSelectionHandler(void 0) + () => rowSelectionHandler(void 0) ), onCancel: () => rowSelectionHandler(void 0) } )))); - })))); + }))), onLoadMoreAfter && /* @__PURE__ */ h( + "button", + { + class: "button is-fullwidth", + "data-tooltip": i18n2.str`load more products after the last one`, + onClick: onLoadMoreAfter + }, + /* @__PURE__ */ h(i18n2.Translate, null, "load next page") + )); } function FastProductWithInfiniteStockUpdateForm({ product, @@ -46441,7 +49785,7 @@ function FastProductWithInfiniteStockUpdateForm({ tooltip: i18n2.str`update the product with new price` } ) - ), /* @__PURE__ */ h("div", { class: "buttons is-expanded" }, /* @__PURE__ */ h("div", { class: "buttons mt-5" }, /* @__PURE__ */ h("button", { class: "button mt-5", onClick: onCancel }, /* @__PURE__ */ h(i18n2.Translate, null, "Clone"))), /* @__PURE__ */ h("div", { class: "buttons is-right mt-5" }, /* @__PURE__ */ h("button", { class: "button", onClick: onCancel }, /* @__PURE__ */ h(i18n2.Translate, null, "Cancel")), /* @__PURE__ */ h( + ), /* @__PURE__ */ h("div", { class: "buttons is-expanded" }, /* @__PURE__ */ h("div", { class: "buttons is-right mt-5" }, /* @__PURE__ */ h("button", { class: "button", onClick: onCancel }, /* @__PURE__ */ h(i18n2.Translate, null, "Cancel")), /* @__PURE__ */ h( "span", { class: "has-tooltip-left", @@ -46537,7 +49881,7 @@ function FastProductUpdateForm(props) { } function EmptyTable6() { const { i18n: i18n2 } = useTranslationContext(); - return /* @__PURE__ */ h("div", { class: "content has-text-grey has-text-centered" }, /* @__PURE__ */ h("p", null, /* @__PURE__ */ h("span", { class: "icon is-large" }, /* @__PURE__ */ h("i", { class: "mdi mdi-emoticon-sad mdi-48px" }))), /* @__PURE__ */ h("p", null, /* @__PURE__ */ h(i18n2.Translate, null, "There is no products yet, add more pressing the + sign"))); + return /* @__PURE__ */ h("div", { class: "content has-text-grey has-text-centered" }, /* @__PURE__ */ h("p", null, /* @__PURE__ */ h("span", { class: "icon is-large" }, /* @__PURE__ */ h("i", { class: "mdi mdi-magnify mdi-48px" }))), /* @__PURE__ */ h("p", null, /* @__PURE__ */ h(i18n2.Translate, null, "There is no products yet, add more pressing the + sign"))); } function difference(price, tax) { if (!tax) @@ -46553,30 +49897,40 @@ function sum(taxes) { // src/paths/instance/products/list/index.tsx function ProductList2({ - onUnauthorized, - onLoadError, onCreate, - onSelect, - onNotFound + onSelect }) { const result = useInstanceProducts(); - const { deleteProduct, updateProduct, getProduct } = useProductAPI(); + const { lib } = useMerchantApiContext(); + const { state } = useSessionContext(); const [deleting, setDeleting] = p3(null); const [notif, setNotif] = p3(void 0); const { i18n: i18n2 } = useTranslationContext(); - if (result.loading) + if (!result) return /* @__PURE__ */ h(Loading, null); - if (!result.ok) { - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.Unauthorized) - return onUnauthorized(); - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.NotFound) - return onNotFound(); - return onLoadError(result); + if (result instanceof TalerError) { + return /* @__PURE__ */ h(ErrorLoadingMerchant, { error: result }); + } + if (result.type === "fail") { + switch (result.case) { + case HttpStatusCode.NotFound: { + return /* @__PURE__ */ h(NotFoundPageOrAdminCreate, null); + } + case HttpStatusCode.Unauthorized: { + return /* @__PURE__ */ h(LoginPage, null); + } + default: { + assertUnreachable(result); + } + } } return /* @__PURE__ */ h("section", { class: "section is-main-section" }, /* @__PURE__ */ h(NotificationCard, { notification: notif }), /* @__PURE__ */ h( JumpToElementById, { - testIfExist: getProduct, + testIfExist: async (id) => { + const resp = await lib.instance.getProductDetails(state.token, id); + return resp.type === "ok"; + }, onSelect, description: i18n2.str`jump to product with the given product ID`, placeholder: i18n2.str`product id` @@ -46584,20 +49938,26 @@ function ProductList2({ ), /* @__PURE__ */ h( CardTable5, { - instances: result.data, + instances: result.body, + onLoadMoreBefore: result.isFirstPage ? void 0 : result.loadFirst, + onLoadMoreAfter: result.isLastPage ? void 0 : result.loadNext, onCreate, - onUpdate: (id, prod) => updateProduct(id, prod).then( - () => setNotif({ - message: i18n2.str`product updated successfully`, - type: "SUCCESS" - }) - ).catch( - (error2) => setNotif({ - message: i18n2.str`could not update the product`, - type: "ERROR", - description: error2.message - }) - ), + onUpdate: async (id, prod) => { + try { + await lib.instance.updateProduct(state.token, id, prod); + setNotif({ + message: i18n2.str`product updated successfully`, + type: "SUCCESS" + }); + } catch (error2) { + setNotif({ + message: i18n2.str`could not update the product`, + type: "ERROR", + description: error2 instanceof Error ? error2.message : void 0 + }); + } + return; + }, onSelect: (product) => onSelect(product.id), onDelete: (prod) => setDeleting(prod) } @@ -46611,7 +49971,7 @@ function ProductList2({ onCancel: () => setDeleting(null), onConfirm: async () => { try { - await deleteProduct(deleting.id); + await lib.instance.deleteProduct(state.token, deleting.id); setNotif({ message: i18n2.str`Product "${deleting.description}" (ID: ${deleting.id}) has been deleted`, type: "SUCCESS" @@ -46668,31 +50028,38 @@ function UpdatePage3({ product, onUpdate, onBack }) { function UpdateProduct({ pid, onConfirm, - onBack, - onUnauthorized, - onNotFound, - onLoadError + onBack }) { - const { updateProduct } = useProductAPI(); const result = useProductDetails(pid); const [notif, setNotif] = p3(void 0); + const { lib } = useMerchantApiContext(); + const { state } = useSessionContext(); const { i18n: i18n2 } = useTranslationContext(); - if (result.loading) + if (!result) return /* @__PURE__ */ h(Loading, null); - if (!result.ok) { - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.Unauthorized) - return onUnauthorized(); - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.NotFound) - return onNotFound(); - return onLoadError(result); + if (result instanceof TalerError) { + return /* @__PURE__ */ h(ErrorLoadingMerchant, { error: result }); + } + if (result.type === "fail") { + switch (result.case) { + case HttpStatusCode.NotFound: { + return /* @__PURE__ */ h(NotFoundPageOrAdminCreate, null); + } + case HttpStatusCode.Unauthorized: { + return /* @__PURE__ */ h(LoginPage, null); + } + default: { + assertUnreachable(result); + } + } } return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(NotificationCard, { notification: notif }), /* @__PURE__ */ h( UpdatePage3, { - product: { ...result.data, product_id: pid }, + product: { ...result.body, product_id: pid }, onBack, onUpdate: (data) => { - return updateProduct(pid, data).then(onConfirm).catch((error2) => { + return lib.instance.updateProduct(state.token, pid, data).then(onConfirm).catch((error2) => { setNotif({ message: i18n2.str`could not create product`, type: "ERROR", @@ -46708,279 +50075,82 @@ function UpdateProduct({ init_preact_module(); init_hooks_module(); -// src/hooks/templates.ts -init_hooks_module(); -var useSWR7 = useSWR; -function useTemplateAPI() { - const mutateAll = useMatchMutate(); - const { request } = useBackendInstanceRequest(); - const createTemplate = async (data) => { - const res = await request(`/private/templates`, { - method: "POST", - data - }); - await mutateAll(/.*private\/templates.*/); - return res; - }; - const updateTemplate = async (templateId, data) => { - const res = await request(`/private/templates/${templateId}`, { - method: "PATCH", - data - }); - await mutateAll(/.*private\/templates.*/); - return res; - }; - const deleteTemplate = async (templateId) => { - const res = await request(`/private/templates/${templateId}`, { - method: "DELETE" - }); - await mutateAll(/.*private\/templates.*/); - return res; - }; - const createOrderFromTemplate = async (templateId, data) => { - const res = await request( - `/templates/${templateId}`, - { - method: "POST", - data - } - ); - await mutateAll(/.*private\/templates.*/); - return res; - }; - const testTemplateExist = async (templateId) => { - const res = await request(`/private/templates/${templateId}`, { method: "GET" }); - return res; - }; - return { - createTemplate, - updateTemplate, - deleteTemplate, - testTemplateExist, - createOrderFromTemplate - }; -} -function useInstanceTemplates(args, updatePosition) { - const { templateFetcher } = useBackendInstanceRequest(); - const [pageBefore, setPageBefore] = p3(1); - const [pageAfter, setPageAfter] = p3(1); - const totalAfter = pageAfter * PAGE_SIZE; - const totalBefore = args?.position ? pageBefore * PAGE_SIZE : 0; - const { - data: beforeData, - error: beforeError, - isValidating: loadingBefore - } = useSWR7( - [ - `/private/templates`, - args?.position, - totalBefore - ], - templateFetcher - ); - const { - data: afterData, - error: afterError, - isValidating: loadingAfter - } = useSWR7([`/private/templates`, args?.position, -totalAfter], templateFetcher); - const [lastBefore, setLastBefore] = p3({ loading: true }); - const [lastAfter, setLastAfter] = p3({ loading: true }); - h2(() => { - if (afterData) - setLastAfter(afterData); - if (beforeData) - setLastBefore(beforeData); - }, [afterData, beforeData]); - if (beforeError) - return beforeError.cause; - if (afterError) - return afterError.cause; - const isReachingEnd = afterData && afterData.data.templates.length < totalAfter; - const isReachingStart = args?.position === void 0 || beforeData && beforeData.data.templates.length < totalBefore; - const pagination = { - isReachingEnd, - isReachingStart, - loadMore: () => { - if (!afterData || isReachingEnd) - return; - if (afterData.data.templates.length < MAX_RESULT_SIZE) { - setPageAfter(pageAfter + 1); - } else { - const from = `${afterData.data.templates[afterData.data.templates.length - 1].template_id}`; - if (from && updatePosition) - updatePosition(from); - } - }, - loadMorePrev: () => { - if (!beforeData || isReachingStart) - return; - if (beforeData.data.templates.length < MAX_RESULT_SIZE) { - setPageBefore(pageBefore + 1); - } else if (beforeData) { - const from = `${beforeData.data.templates[beforeData.data.templates.length - 1].template_id}`; - if (from && updatePosition) - updatePosition(from); - } - } - }; - const templates = !beforeData || !afterData ? [] : (beforeData || lastBefore).data.templates.slice().reverse().concat((afterData || lastAfter).data.templates); - if (loadingAfter || loadingBefore) - return { loading: true, data: { templates } }; - if (beforeData && afterData) { - return { ok: true, data: { templates }, ...pagination }; - } - return { loading: true }; -} -function useTemplateDetails(templateId) { - const { templateFetcher } = useBackendInstanceRequest(); - const { data, error: error2, isValidating } = useSWR7([`/private/templates/${templateId}`], templateFetcher, { - refreshInterval: 0, - refreshWhenHidden: false, - revalidateOnFocus: false, - revalidateOnReconnect: false, - refreshWhenOffline: false - }); - if (isValidating) - return { loading: true, data: data?.data }; - if (data) { - return data; - } - if (error2) - return error2.cause; - return { loading: true }; -} - // src/paths/instance/templates/create/CreatePage.tsx init_preact_module(); init_hooks_module(); - -// src/components/form/InputTab.tsx -init_preact_module(); -var defaultToString4 = (f3) => f3 || ""; -var defaultFromString4 = (v3) => v3; -function InputTab({ - name, - readonly, - expand, - placeholder, - tooltip, - label, - help, - values, - fromStr = defaultFromString4, - toStr = defaultToString4 -}) { - const { error: error2, value, onChange, required } = useField(name); - return /* @__PURE__ */ h("div", { class: "field is-horizontal" }, /* @__PURE__ */ h("div", { class: "field-label is-normal" }, /* @__PURE__ */ h("label", { class: "label" }, label, tooltip && /* @__PURE__ */ h("span", { class: "icon has-tooltip-right", "data-tooltip": tooltip }, /* @__PURE__ */ h("i", { class: "mdi mdi-information" })))), /* @__PURE__ */ h("div", { class: "field-body is-flex-grow-3" }, /* @__PURE__ */ h("div", { class: "field has-icons-right" }, /* @__PURE__ */ h("p", { class: expand ? "control is-expanded " : "control " }, /* @__PURE__ */ h("div", { class: "tabs is-toggle is-fullwidth is-small" }, /* @__PURE__ */ h("ul", null, values.map((v3, i4) => { - return /* @__PURE__ */ h( - "li", - { - key: i4, - class: value === v3 ? "is-active" : "", - onClick: (e4) => { - onChange(v3); - } - }, - /* @__PURE__ */ h("a", { style: { cursor: "initial" } }, /* @__PURE__ */ h("span", null, toStr(v3))) - ); - }))), help), required && /* @__PURE__ */ h("span", { class: "icon has-text-danger is-right", style: { height: "2.5em" } }, /* @__PURE__ */ h("i", { class: "mdi mdi-alert" })), error2 && /* @__PURE__ */ h("p", { class: "help is-danger" }, error2)))); -} - -// src/paths/instance/templates/create/CreatePage.tsx function CreatePage6({ onCreate, onBack }) { const { i18n: i18n2 } = useTranslationContext(); - const { url: backendURL } = useBackendContext(); + const { url: backendUrl, config } = useMerchantApiContext(); const devices = useInstanceOtpDevices(); const [state, setState] = p3({ minimum_age: 0, pay_duration: { d_ms: 1e3 * 60 * 30 //30 min - }, - type: 3 /* NON_FIXED */ + } }); + function updateState(up) { + setState((old) => { + const newState = up(old); + if (!newState.amount_editable) { + newState.currency_editable = false; + } + return newState; + }); + } const parsedPrice = !state.amount ? void 0 : Amounts.parse(state.amount); const errors2 = { id: !state.id ? i18n2.str`should not be empty` : !/[a-zA-Z0-9]*/.test(state.id) ? i18n2.str`no valid. only characters and numbers` : void 0, description: !state.description ? i18n2.str`should not be empty` : void 0, - amount: !(state.type === 1 /* FIXED_PRICE */ || state.type === 0 /* BOTH_FIXED */) ? void 0 : !state.amount ? i18n2.str`required` : !parsedPrice ? i18n2.str`not valid` : Amounts.isZero(parsedPrice) ? i18n2.str`must be greater than 0` : void 0, - summary: !(state.type === 2 /* FIXED_SUMMARY */ || state.type === 0 /* BOTH_FIXED */) ? void 0 : !state.summary ? i18n2.str`required` : void 0, + amount: !state.amount ? void 0 : !parsedPrice ? i18n2.str`not valid` : Amounts.isZero(parsedPrice) ? i18n2.str`must be greater than 0` : void 0, minimum_age: state.minimum_age && state.minimum_age < 0 ? i18n2.str`should be greater that 0` : void 0, pay_duration: !state.pay_duration ? i18n2.str`can't be empty` : state.pay_duration.d_ms === "forever" ? void 0 : state.pay_duration.d_ms < 1e3 ? i18n2.str`to short` : void 0 }; + const cList = Object.values(config.currencies).map((d5) => d5.name); const hasErrors = Object.keys(errors2).some( (k5) => errors2[k5] !== void 0 ); const submitForm = () => { - if (hasErrors || state.type === void 0) + if (hasErrors) return Promise.reject(); - switch (state.type) { - case 1 /* FIXED_PRICE */: - return onCreate({ - template_id: state.id, - template_description: state.description, - template_contract: { - minimum_age: state.minimum_age, - pay_duration: Duration.toTalerProtocolDuration(state.pay_duration), - amount: state.amount - // summary: state.summary, - }, - otp_id: state.otpId - }); - case 2 /* FIXED_SUMMARY */: - return onCreate({ - template_id: state.id, - template_description: state.description, - template_contract: { - minimum_age: state.minimum_age, - pay_duration: Duration.toTalerProtocolDuration(state.pay_duration), - // amount: state.amount!, - summary: state.summary - }, - otp_id: state.otpId - }); - case 3 /* NON_FIXED */: - return onCreate({ - template_id: state.id, - template_description: state.description, - template_contract: { - minimum_age: state.minimum_age, - pay_duration: Duration.toTalerProtocolDuration(state.pay_duration) - // amount: state.amount!, - // summary: state.summary, - }, - otp_id: state.otpId - }); - case 0 /* BOTH_FIXED */: - return onCreate({ - template_id: state.id, - template_description: state.description, - template_contract: { - minimum_age: state.minimum_age, - pay_duration: Duration.toTalerProtocolDuration(state.pay_duration), - amount: state.amount, - summary: state.summary - }, - otp_id: state.otpId - }); - default: - assertUnreachable(state.type); - } - ; + return onCreate({ + template_id: state.id, + template_description: state.description, + template_contract: { + minimum_age: state.minimum_age, + pay_duration: Duration.toTalerProtocolDuration(state.pay_duration), + amount: state.amount_editable ? void 0 : state.amount, + summary: state.summary_editable ? void 0 : state.summary, + currency: cList.length > 1 && state.currency_editable ? void 0 : config.currency + }, + editable_defaults: { + amount: !state.amount_editable ? void 0 : state.amount, + summary: !state.summary_editable ? void 0 : state.summary, + currency: cList.length === 1 || !state.currency_editable ? void 0 : config.currency + }, + otp_id: state.otpId + }); }; - const deviceList = !devices.ok ? [] : devices.data.otp_devices; + const deviceList = !devices || devices instanceof TalerError || devices.type === "fail" ? [] : devices.body.otp_devices; + const deviceMap = deviceList.reduce( + (prev, cur) => { + prev[cur.otp_device_id] = cur.device_description; + return prev; + }, + {} + ); return /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("section", { class: "section is-main-section" }, /* @__PURE__ */ h("div", { class: "columns" }, /* @__PURE__ */ h("div", { class: "column" }), /* @__PURE__ */ h("div", { class: "column is-four-fifths" }, /* @__PURE__ */ h( FormProvider, { object: state, - valueHandler: setState, + valueHandler: updateState, errors: errors2 }, /* @__PURE__ */ h( InputWithAddon, { name: "id", - help: `${backendURL}/templates/${state.id ?? ""}`, + help: new URL(`templates/${state.id ?? ""}`, backendUrl.href).href, label: i18n2.str`Identifier`, tooltip: i18n2.str`Name of the template in URLs.` } @@ -46995,62 +50165,47 @@ function CreatePage6({ onCreate, onBack }) { } ), /* @__PURE__ */ h( - InputTab, - { - name: "type", - label: i18n2.str`Type`, - help: (() => { - if (state.type === void 0) - return ""; - switch (state.type) { - case 3 /* NON_FIXED */: - return i18n2.str`User will be able to input price and summary before payment.`; - case 1 /* FIXED_PRICE */: - return i18n2.str`User will be able to add a summary before payment.`; - case 2 /* FIXED_SUMMARY */: - return i18n2.str`User will be able to set the price before payment.`; - case 0 /* BOTH_FIXED */: - return i18n2.str`User will not be able to change the price or the summary.`; - } - })(), - tooltip: i18n2.str`Define what the user be allowed to modify`, - values: [ - 3 /* NON_FIXED */, - 1 /* FIXED_PRICE */, - 2 /* FIXED_SUMMARY */, - 0 /* BOTH_FIXED */ - ], - toStr: (v3) => { - switch (v3) { - case 3 /* NON_FIXED */: - return i18n2.str`Simple`; - case 1 /* FIXED_PRICE */: - return i18n2.str`With price`; - case 2 /* FIXED_SUMMARY */: - return i18n2.str`With summary`; - case 0 /* BOTH_FIXED */: - return i18n2.str`With price and summary`; - } - } - } - ), - state.type === 0 /* BOTH_FIXED */ || state.type === 2 /* FIXED_SUMMARY */ ? /* @__PURE__ */ h( Input, { name: "summary", inputType: "multiline", - label: i18n2.str`Fixed summary`, + label: i18n2.str`Summary`, tooltip: i18n2.str`If specified, this template will create order with the same summary` } - ) : void 0, - state.type === 0 /* BOTH_FIXED */ || state.type === 1 /* FIXED_PRICE */ ? /* @__PURE__ */ h( + ), + /* @__PURE__ */ h( + InputToggle, + { + name: "summary_editable", + label: i18n2.str`Summary is editable`, + tooltip: i18n2.str`Allow the user to change the summary.` + } + ), + /* @__PURE__ */ h( InputCurrency, { name: "amount", - label: i18n2.str`Fixed price`, + label: i18n2.str`Amount`, tooltip: i18n2.str`If specified, this template will create order with the same price` } - ) : void 0, + ), + /* @__PURE__ */ h( + InputToggle, + { + name: "amount_editable", + label: i18n2.str`Amount is editable`, + tooltip: i18n2.str`Allow the user to select the amount to pay.` + } + ), + cList.length > 1 && /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h( + InputToggle, + { + name: "currency_editable", + readonly: !state.amount_editable, + label: i18n2.str`Currency is editable`, + tooltip: i18n2.str`Allow the user to change currency.` + } + ), /* @__PURE__ */ h(TextField, { name: "sc", label: i18n2.str`Supported currencies` }, /* @__PURE__ */ h(i18n2.Translate, null, "supported currencies: ", cList.join(", ")))), /* @__PURE__ */ h( InputNumber2, { @@ -47069,35 +50224,32 @@ function CreatePage6({ onCreate, onBack }) { tooltip: i18n2.str`How much time has the customer to complete the payment once the order was created.` } ), - /* @__PURE__ */ h( - Input, + !deviceList.length ? /* @__PURE__ */ h( + TextField, { name: "otpId", label: i18n2.str`OTP device`, - readonly: true, - side: /* @__PURE__ */ h( - "button", - { - class: "button is-danger", - "data-tooltip": i18n2.str`without otp device`, - onClick: () => { - setState((v3) => ({ ...v3, otpId: void 0 })); - } - }, - /* @__PURE__ */ h("span", null, /* @__PURE__ */ h(i18n2.Translate, null, "remove")) - ), - tooltip: i18n2.str`Use to verify transaction in offline mode.` - } - ), - /* @__PURE__ */ h( - InputSearchOnList, + tooltip: i18n2.str`Use to verify transaction while offline.` + }, + /* @__PURE__ */ h(i18n2.Translate, null, "No OTP device."), + "\xA0", + /* @__PURE__ */ h("a", { href: "/otp-devices/new" }, /* @__PURE__ */ h(i18n2.Translate, null, "Add one first")) + ) : /* @__PURE__ */ h( + InputSelector, { - label: i18n2.str`Search device`, - onChange: (p4) => setState((v3) => ({ ...v3, otpId: p4?.id })), - list: deviceList.map((e4) => ({ - description: e4.device_description, - id: e4.otp_device_id - })) + name: "otpId", + label: i18n2.str`OTP device`, + values: [ + void 0, + ...deviceList.map((e4) => e4.otp_device_id) + ], + toStr: (v3) => { + if (!v3) { + return i18n2.str`No device`; + } + return deviceMap[v3]; + }, + tooltip: i18n2.str`Use to verify transaction in offline mode.` } ) ), /* @__PURE__ */ h("div", { class: "buttons is-right mt-5" }, onBack && /* @__PURE__ */ h("button", { class: "button", onClick: onBack }, /* @__PURE__ */ h(i18n2.Translate, null, "Cancel")), /* @__PURE__ */ h( @@ -47113,7 +50265,8 @@ function CreatePage6({ onCreate, onBack }) { // src/paths/instance/templates/create/index.tsx function CreateTransfer({ onConfirm, onBack }) { - const { createTemplate } = useTemplateAPI(); + const { lib } = useMerchantApiContext(); + const { state } = useSessionContext(); const [notif, setNotif] = p3(void 0); const { i18n: i18n2 } = useTranslationContext(); return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(NotificationCard, { notification: notif }), /* @__PURE__ */ h( @@ -47121,7 +50274,7 @@ function CreateTransfer({ onConfirm, onBack }) { { onBack, onCreate: (request) => { - return createTemplate(request).then(() => onConfirm()).catch((error2) => { + return lib.instance.addTemplate(state.token, request).then(() => onConfirm()).catch((error2) => { setNotif({ message: i18n2.str`could not inform template`, type: "ERROR", @@ -47137,6 +50290,57 @@ function CreateTransfer({ onConfirm, onBack }) { init_preact_module(); init_hooks_module(); +// src/hooks/templates.ts +init_hooks_module(); +var useSWR8 = useSWR; +function revalidateInstanceTemplates() { + return mutate( + (key) => Array.isArray(key) && key[key.length - 1] === "listTemplates", + void 0, + { revalidate: true } + ); +} +function useInstanceTemplates() { + const { state: session } = useSessionContext(); + const { lib: { instance } } = useMerchantApiContext(); + const [offset, setOffset] = p3(); + async function fetcher([token, bid]) { + return await instance.listTemplates(token, { + limit: PAGINATED_LIST_REQUEST, + offset: bid, + order: "dec" + }); + } + const { data, error: error2 } = useSWR8([session.token, offset, "listTemplates"], fetcher); + if (error2) + return error2; + if (data === void 0) + return void 0; + if (data.type !== "ok") + return data; + return buildPaginatedResult(data.body.templates, offset, setOffset, (d5) => d5.template_id); +} +function revalidateTemplateDetails() { + return mutate( + (key) => Array.isArray(key) && key[key.length - 1] === "getTemplateDetails", + void 0, + { revalidate: true } + ); +} +function useTemplateDetails(templateId) { + const { state: session } = useSessionContext(); + const { lib: { instance } } = useMerchantApiContext(); + async function fetcher([tid, token]) { + return await instance.getTemplateDetails(token, tid); + } + const { data, error: error2 } = useSWR8([templateId, session.token, "getTemplateDetails"], fetcher); + if (data) + return data; + if (error2) + return error2; + return void 0; +} + // src/paths/instance/templates/list/ListPage.tsx init_preact_module(); @@ -47151,9 +50355,7 @@ function CardTable6({ onQR, onNewOrder, onLoadMoreAfter, - onLoadMoreBefore, - hasMoreAfter, - hasMoreBefore + onLoadMoreBefore }) { const [rowSelection, rowSelectionHandler] = p3([]); const { i18n: i18n2 } = useTranslationContext(); @@ -47175,9 +50377,7 @@ function CardTable6({ rowSelection, rowSelectionHandler, onLoadMoreAfter, - onLoadMoreBefore, - hasMoreAfter, - hasMoreBefore + onLoadMoreBefore } ) : /* @__PURE__ */ h(EmptyTable7, null))))); } @@ -47188,19 +50388,17 @@ function Table6({ onNewOrder, onQR, onSelect, - onLoadMoreBefore, - hasMoreAfter, - hasMoreBefore + onLoadMoreBefore }) { const { i18n: i18n2 } = useTranslationContext(); - return /* @__PURE__ */ h("div", { class: "table-container" }, hasMoreBefore && /* @__PURE__ */ h( + return /* @__PURE__ */ h("div", { class: "table-container" }, onLoadMoreBefore && /* @__PURE__ */ h( "button", { class: "button is-fullwidth", "data-tooltip": i18n2.str`load more templates before the first one`, onClick: onLoadMoreBefore }, - /* @__PURE__ */ h(i18n2.Translate, null, "load newer templates") + /* @__PURE__ */ h(i18n2.Translate, null, "load first page") ), /* @__PURE__ */ h("table", { class: "table is-fullwidth is-striped is-hoverable is-fullwidth" }, /* @__PURE__ */ h("thead", null, /* @__PURE__ */ h("tr", null, /* @__PURE__ */ h("th", null, /* @__PURE__ */ h(i18n2.Translate, null, "ID")), /* @__PURE__ */ h("th", null, /* @__PURE__ */ h(i18n2.Translate, null, "Description")), /* @__PURE__ */ h("th", null))), /* @__PURE__ */ h("tbody", null, instances.map((i4) => { return /* @__PURE__ */ h("tr", { key: i4.template_id }, /* @__PURE__ */ h( "td", @@ -47241,19 +50439,19 @@ function Table6({ }, "QR" )))); - }))), hasMoreAfter && /* @__PURE__ */ h( + }))), onLoadMoreAfter && /* @__PURE__ */ h( "button", { class: "button is-fullwidth", "data-tooltip": i18n2.str`load more templates after the last one`, onClick: onLoadMoreAfter }, - /* @__PURE__ */ h(i18n2.Translate, null, "load older templates") + /* @__PURE__ */ h(i18n2.Translate, null, "load next page") )); } function EmptyTable7() { const { i18n: i18n2 } = useTranslationContext(); - return /* @__PURE__ */ h("div", { class: "content has-text-grey has-text-centered" }, /* @__PURE__ */ h("p", null, /* @__PURE__ */ h("span", { class: "icon is-large" }, /* @__PURE__ */ h("i", { class: "mdi mdi-emoticon-sad mdi-48px" }))), /* @__PURE__ */ h("p", null, /* @__PURE__ */ h(i18n2.Translate, null, "There is no templates yet, add more pressing the + sign"))); + return /* @__PURE__ */ h("div", { class: "content has-text-grey has-text-centered" }, /* @__PURE__ */ h("p", null, /* @__PURE__ */ h("span", { class: "icon is-large" }, /* @__PURE__ */ h("i", { class: "mdi mdi-magnify mdi-48px" }))), /* @__PURE__ */ h("p", null, /* @__PURE__ */ h(i18n2.Translate, null, "There is no templates yet, add more pressing the + sign"))); } // src/paths/instance/templates/list/ListPage.tsx @@ -47267,8 +50465,6 @@ function ListPage5({ onLoadMoreBefore, onLoadMoreAfter }) { - const form = { payto_uri: "" }; - const { i18n: i18n2 } = useTranslationContext(); return /* @__PURE__ */ h( CardTable6, { @@ -47282,42 +50478,49 @@ function ListPage5({ onSelect, onNewOrder, onLoadMoreBefore, - hasMoreBefore: !onLoadMoreBefore, - onLoadMoreAfter, - hasMoreAfter: !onLoadMoreAfter + onLoadMoreAfter } ); } // src/paths/instance/templates/list/index.tsx function ListTemplates({ - onUnauthorized, - onLoadError, onCreate, onQR, onSelect, - onNewOrder, - onNotFound + onNewOrder }) { - const [position, setPosition] = p3(void 0); const { i18n: i18n2 } = useTranslationContext(); const [notif, setNotif] = p3(void 0); - const { deleteTemplate, testTemplateExist } = useTemplateAPI(); - const result = useInstanceTemplates({ position }, (id) => setPosition(id)); + const { lib } = useMerchantApiContext(); + const result = useInstanceTemplates(); const [deleting, setDeleting] = p3(null); - if (result.loading) + const { state } = useSessionContext(); + if (!result) return /* @__PURE__ */ h(Loading, null); - if (!result.ok) { - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.Unauthorized) - return onUnauthorized(); - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.NotFound) - return onNotFound(); - return onLoadError(result); + if (result instanceof TalerError) { + return /* @__PURE__ */ h(ErrorLoadingMerchant, { error: result }); + } + if (result.type === "fail") { + switch (result.case) { + case HttpStatusCode.NotFound: { + return /* @__PURE__ */ h(NotFoundPageOrAdminCreate, null); + } + case HttpStatusCode.Unauthorized: { + return /* @__PURE__ */ h(LoginPage, null); + } + default: { + assertUnreachable(result); + } + } } return /* @__PURE__ */ h("section", { class: "section is-main-section" }, /* @__PURE__ */ h(NotificationCard, { notification: notif }), /* @__PURE__ */ h( JumpToElementById, { - testIfExist: testTemplateExist, + testIfExist: async (id) => { + const resp = await lib.instance.getTemplateDetails(state.token, id); + return resp.type === "ok"; + }, onSelect, description: i18n2.str`jump to template with the given template ID`, placeholder: i18n2.str`template id` @@ -47325,9 +50528,9 @@ function ListTemplates({ ), /* @__PURE__ */ h( ListPage5, { - templates: result.data.templates, - onLoadMoreBefore: result.isReachingStart ? result.loadMorePrev : void 0, - onLoadMoreAfter: result.isReachingEnd ? result.loadMore : void 0, + templates: result.body, + onLoadMoreBefore: result.isFirstPage ? void 0 : result.loadFirst, + onLoadMoreAfter: result.isLastPage ? void 0 : result.loadNext, onCreate, onSelect: (e4) => { onSelect(e4.template_id); @@ -47352,7 +50555,7 @@ function ListTemplates({ onCancel: () => setDeleting(null), onConfirm: async () => { try { - await deleteTemplate(deleting.template_id); + await lib.instance.deleteTemplate(state.token, deleting.template_id); setNotif({ message: i18n2.str`Template "${deleting.template_description}" (ID: ${deleting.template_id}) has been deleted`, type: "SUCCESS" @@ -47374,77 +50577,26 @@ function ListTemplates({ // src/paths/instance/templates/qr/index.tsx init_preact_module(); -init_hooks_module(); // src/paths/instance/templates/qr/QrPage.tsx init_preact_module(); -init_hooks_module(); function QrPage({ contract, id: templateId, onBack }) { const { i18n: i18n2 } = useTranslationContext(); - const { url: backendURL } = useBackendContext(); - const { id: instanceId } = useInstanceContext(); - const config = useConfigContext(); - const [state, setState] = p3({ - amount: contract.amount, - summary: contract.summary - }); - const errors2 = {}; - const fixedAmount = !!contract.amount; - const fixedSummary = !!contract.summary; - const templateParams = {}; - if (!fixedAmount) { - if (state.amount) { - templateParams.amount = state.amount; - } else { - templateParams.amount = config.currency; - } - } - if (!fixedSummary) { - templateParams.summary = state.summary ?? ""; - } - const merchantBaseUrl = new URL(backendURL).href; + const { config, url: backendUrl } = useMerchantApiContext(); + const merchantBaseUrl = backendUrl.href; const payTemplateUri = stringifyPayTemplateUri({ merchantBaseUrl, templateId, - templateParams + templateParams: {} }); - const issuer = encodeURIComponent( - `${new URL(backendURL).host}/${instanceId}` - ); - return /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("section", { class: "section is-main-section" }, /* @__PURE__ */ h("div", { class: "columns" }, /* @__PURE__ */ h("div", { class: "column" }), /* @__PURE__ */ h("div", { class: "column is-four-fifths" }, /* @__PURE__ */ h("p", { class: "is-size-5 mt-5 mb-5" }, /* @__PURE__ */ h(i18n2.Translate, null, "Here you can specify a default value for fields that are not fixed. Default values can be edited by the customer before the payment.")), /* @__PURE__ */ h("p", null), /* @__PURE__ */ h( - FormProvider, - { - object: state, - valueHandler: setState, - errors: errors2 - }, - /* @__PURE__ */ h( - InputCurrency, - { - name: "amount", - label: fixedAmount ? i18n2.str`Fixed amount` : i18n2.str`Default amount`, - readonly: fixedAmount, - tooltip: i18n2.str`Amount of the order` - } - ), - /* @__PURE__ */ h( - Input, - { - name: "summary", - inputType: "multiline", - readonly: fixedSummary, - label: fixedSummary ? i18n2.str`Fixed summary` : i18n2.str`Default summary`, - tooltip: i18n2.str`Title of the order to be shown to the customer` - } - ) - ), /* @__PURE__ */ h("div", { class: "buttons is-right mt-5" }, onBack && /* @__PURE__ */ h("button", { class: "button", onClick: onBack }, /* @__PURE__ */ h(i18n2.Translate, null, "Cancel")), /* @__PURE__ */ h( + return /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("section", { id: "printThis" }, /* @__PURE__ */ h(QR, { text: payTemplateUri }), /* @__PURE__ */ h("pre", { style: { textAlign: "center" } }, /* @__PURE__ */ h("a", { href: payTemplateUri }, payTemplateUri))), /* @__PURE__ */ h("section", { class: "section is-main-section" }, /* @__PURE__ */ h("div", { class: "columns" }, /* @__PURE__ */ h("div", { class: "column" }), /* @__PURE__ */ h("div", { class: "column is-four-fifths" }, /* @__PURE__ */ h("p", null), /* @__PURE__ */ h("div", { class: "buttons is-right mt-5" }, onBack && /* @__PURE__ */ h("button", { class: "button", onClick: onBack }, /* @__PURE__ */ h(i18n2.Translate, null, "Cancel")), /* @__PURE__ */ h( "button", { class: "button is-info", onClick: () => saveAsPDF(templateId) }, /* @__PURE__ */ h(i18n2.Translate, null, "Print") - ))), /* @__PURE__ */ h("div", { class: "column" }))), /* @__PURE__ */ h("section", { id: "printThis" }, /* @__PURE__ */ h(QR, { text: payTemplateUri }), /* @__PURE__ */ h("pre", { style: { textAlign: "center" } }, /* @__PURE__ */ h("a", { href: payTemplateUri }, payTemplateUri)))); + ))), /* @__PURE__ */ h("div", { class: "column" })))); } function saveAsPDF(name) { const printWindow = window.open("", "", "height=400,width=800"); @@ -47461,30 +50613,34 @@ function saveAsPDF(name) { printWindow.document.body.appendChild(divContents.cloneNode(true)); printWindow.addEventListener("load", () => { printWindow.print(); - printWindow.close(); }); } // src/paths/instance/templates/qr/index.tsx function TemplateQrPage({ tid, - onBack, - onLoadError, - onNotFound, - onUnauthorized + onBack }) { const result = useTemplateDetails(tid); - const [notif, setNotif] = p3(void 0); - if (result.loading) + if (!result) return /* @__PURE__ */ h(Loading, null); - if (!result.ok) { - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.Unauthorized) - return onUnauthorized(); - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.NotFound) - return onNotFound(); - return onLoadError(result); + if (result instanceof TalerError) { + return /* @__PURE__ */ h(ErrorLoadingMerchant, { error: result }); } - return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(NotificationCard, { notification: notif }), /* @__PURE__ */ h(QrPage, { contract: result.data.template_contract, id: tid, onBack })); + if (result.type === "fail") { + switch (result.case) { + case HttpStatusCode.NotFound: { + return /* @__PURE__ */ h(NotFoundPageOrAdminCreate, null); + } + case HttpStatusCode.Unauthorized: { + return /* @__PURE__ */ h(LoginPage, null); + } + default: { + assertUnreachable(result); + } + } + } + return /* @__PURE__ */ h(QrPage, { contract: result.body.template_contract, id: tid, onBack }); } // src/paths/instance/templates/update/index.tsx @@ -47496,87 +50652,74 @@ init_preact_module(); init_hooks_module(); function UpdatePage4({ template, onUpdate, onBack }) { const { i18n: i18n2 } = useTranslationContext(); - const { url: backendURL } = useBackendContext(); - const intialStep = template.template_contract.amount === void 0 && template.template_contract.summary === void 0 ? 3 /* NON_FIXED */ : template.template_contract.summary === void 0 ? 1 /* FIXED_PRICE */ : template.template_contract.amount === void 0 ? 2 /* FIXED_SUMMARY */ : 0 /* BOTH_FIXED */; + const { url: backendUrl, config } = useMerchantApiContext(); const [state, setState] = p3({ - amount: template.template_contract.amount, description: template.template_description, minimum_age: template.template_contract.minimum_age, otpId: template.otp_id, - pay_duration: template.template_contract.pay_duration ? Duration.fromTalerProtocolDuration(template.template_contract.pay_duration) : void 0, - summary: template.template_contract.summary, - type: intialStep + pay_duration: template.template_contract.pay_duration ? Duration.fromTalerProtocolDuration( + template.template_contract.pay_duration + ) : void 0, + summary: template.editable_defaults?.summary ?? template.template_contract.summary, + amount: template.editable_defaults?.amount ?? template.template_contract.amount, + currency_editable: !!template.editable_defaults?.currency, + summary_editable: !!template.editable_defaults?.summary, + amount_editable: !!template.editable_defaults?.amount }); + function updateState(up) { + setState((old) => { + const newState = up(old); + if (!newState.amount_editable) { + newState.currency_editable = false; + } + return newState; + }); + } const devices = useInstanceOtpDevices(); - const deviceList = !devices.ok ? [] : devices.data.otp_devices; + const deviceList = !devices || devices instanceof TalerError || devices.type === "fail" ? [] : devices.body.otp_devices; + const deviceMap = deviceList.reduce( + (prev, cur) => { + prev[cur.otp_device_id] = cur.device_description; + return prev; + }, + {} + ); const parsedPrice = !state.amount ? void 0 : Amounts.parse(state.amount); const errors2 = { description: !state.description ? i18n2.str`should not be empty` : void 0, - amount: !(state.type === 1 /* FIXED_PRICE */ || state.type === 0 /* BOTH_FIXED */) ? void 0 : !state.amount ? i18n2.str`required` : !parsedPrice ? i18n2.str`not valid` : Amounts.isZero(parsedPrice) ? i18n2.str`must be greater than 0` : void 0, - summary: !(state.type === 2 /* FIXED_SUMMARY */ || state.type === 0 /* BOTH_FIXED */) ? void 0 : !state.summary ? i18n2.str`required` : void 0, + amount: !state.amount ? void 0 : !parsedPrice ? i18n2.str`not valid` : Amounts.isZero(parsedPrice) ? i18n2.str`must be greater than 0` : void 0, minimum_age: state.minimum_age && state.minimum_age < 0 ? i18n2.str`should be greater that 0` : void 0, pay_duration: !state.pay_duration ? i18n2.str`can't be empty` : state.pay_duration.d_ms === "forever" ? void 0 : state.pay_duration.d_ms < 1e3 ? i18n2.str`to short` : void 0 }; + const cList = Object.values(config.currencies).map((d5) => d5.name); const hasErrors = Object.keys(errors2).some( (k5) => errors2[k5] !== void 0 ); const submitForm = () => { - if (hasErrors || state.type === void 0) + if (hasErrors) return Promise.reject(); - switch (state.type) { - case 1 /* FIXED_PRICE */: - return onUpdate({ - template_description: state.description, - template_contract: { - minimum_age: state.minimum_age, - pay_duration: Duration.toTalerProtocolDuration(state.pay_duration), - amount: state.amount - // summary: state.summary, - }, - otp_id: state.otpId - }); - case 2 /* FIXED_SUMMARY */: - return onUpdate({ - template_description: state.description, - template_contract: { - minimum_age: state.minimum_age, - pay_duration: Duration.toTalerProtocolDuration(state.pay_duration), - // amount: state.amount!, - summary: state.summary - }, - otp_id: state.otpId - }); - case 3 /* NON_FIXED */: - return onUpdate({ - template_description: state.description, - template_contract: { - minimum_age: state.minimum_age, - pay_duration: Duration.toTalerProtocolDuration(state.pay_duration) - // amount: state.amount!, - // summary: state.summary, - }, - otp_id: state.otpId - }); - case 0 /* BOTH_FIXED */: - return onUpdate({ - template_description: state.description, - template_contract: { - minimum_age: state.minimum_age, - pay_duration: Duration.toTalerProtocolDuration(state.pay_duration), - amount: state.amount, - summary: state.summary - }, - otp_id: state.otpId - }); - default: - assertUnreachable(state.type); - } + return onUpdate({ + template_description: state.description, + template_contract: { + minimum_age: state.minimum_age, + pay_duration: Duration.toTalerProtocolDuration(state.pay_duration), + amount: state.amount_editable ? void 0 : state.amount, + summary: state.summary_editable ? void 0 : state.summary, + currency: cList.length > 1 && state.currency_editable ? void 0 : config.currency + }, + editable_defaults: { + amount: !state.amount_editable ? void 0 : state.amount, + summary: !state.summary_editable ? void 0 : state.summary, + currency: cList.length === 1 || !state.currency_editable ? void 0 : config.currency + }, + otp_id: state.otpId + }); }; - return /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("section", { class: "section" }, /* @__PURE__ */ h("section", { class: "hero is-hero-bar" }, /* @__PURE__ */ h("div", { class: "hero-body" }, /* @__PURE__ */ h("div", { class: "level" }, /* @__PURE__ */ h("div", { class: "level-left" }, /* @__PURE__ */ h("div", { class: "level-item" }, /* @__PURE__ */ h("span", { class: "is-size-4" }, backendURL, "/templates/", template.otp_id)))))), /* @__PURE__ */ h("hr", null), /* @__PURE__ */ h("section", { class: "section is-main-section" }, /* @__PURE__ */ h("div", { class: "columns" }, /* @__PURE__ */ h("div", { class: "column is-four-fifths" }, /* @__PURE__ */ h( + return /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("section", { class: "section" }, /* @__PURE__ */ h("section", { class: "hero is-hero-bar" }, /* @__PURE__ */ h("div", { class: "hero-body" }, /* @__PURE__ */ h("div", { class: "level" }, /* @__PURE__ */ h("div", { class: "level-left" }, /* @__PURE__ */ h("div", { class: "level-item" }, /* @__PURE__ */ h("span", { class: "is-size-4" }, new URL(`templates/${template.id}`, backendUrl.href).href)))))), /* @__PURE__ */ h("hr", null), /* @__PURE__ */ h("section", { class: "section is-main-section" }, /* @__PURE__ */ h("div", { class: "columns" }, /* @__PURE__ */ h("div", { class: "column is-four-fifths" }, /* @__PURE__ */ h( FormProvider, { object: state, - valueHandler: setState, + valueHandler: updateState, errors: errors2 }, /* @__PURE__ */ h( @@ -47589,60 +50732,47 @@ function UpdatePage4({ template, onUpdate, onBack }) { } ), /* @__PURE__ */ h( - InputTab, - { - name: "type", - label: i18n2.str`Type`, - help: (() => { - switch (state.type) { - case 3 /* NON_FIXED */: - return i18n2.str`User will be able to input price and summary before payment.`; - case 1 /* FIXED_PRICE */: - return i18n2.str`User will be able to add a summary before payment.`; - case 2 /* FIXED_SUMMARY */: - return i18n2.str`User will be able to set the price before payment.`; - case 0 /* BOTH_FIXED */: - return i18n2.str`User will not be able to change the price or the summary.`; - } - })(), - tooltip: i18n2.str`Define what the user be allowed to modify`, - values: [ - 3 /* NON_FIXED */, - 1 /* FIXED_PRICE */, - 2 /* FIXED_SUMMARY */, - 0 /* BOTH_FIXED */ - ], - toStr: (v3) => { - switch (v3) { - case 3 /* NON_FIXED */: - return i18n2.str`Simple`; - case 1 /* FIXED_PRICE */: - return i18n2.str`With price`; - case 2 /* FIXED_SUMMARY */: - return i18n2.str`With summary`; - case 0 /* BOTH_FIXED */: - return i18n2.str`With price and summary`; - } - } - } - ), - state.type === 0 /* BOTH_FIXED */ || state.type === 2 /* FIXED_SUMMARY */ ? /* @__PURE__ */ h( Input, { name: "summary", inputType: "multiline", - label: i18n2.str`Fixed summary`, + label: i18n2.str`Summary`, tooltip: i18n2.str`If specified, this template will create order with the same summary` } - ) : void 0, - state.type === 0 /* BOTH_FIXED */ || state.type === 1 /* FIXED_PRICE */ ? /* @__PURE__ */ h( + ), + /* @__PURE__ */ h( + InputToggle, + { + name: "summary_editable", + label: i18n2.str`Summary is editable`, + tooltip: i18n2.str`Allow the user to change the summary.` + } + ), + /* @__PURE__ */ h( InputCurrency, { name: "amount", - label: i18n2.str`Fixed price`, + label: i18n2.str`Amount`, tooltip: i18n2.str`If specified, this template will create order with the same price` } - ) : void 0, + ), + /* @__PURE__ */ h( + InputToggle, + { + name: "amount_editable", + label: i18n2.str`Amount is editable`, + tooltip: i18n2.str`Allow the user to select the amount to pay.` + } + ), + cList.length > 1 && /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h( + InputToggle, + { + name: "currency_editable", + readonly: !state.amount_editable, + label: i18n2.str`Currency is editable`, + tooltip: i18n2.str`Allow the user to change currency.` + } + ), /* @__PURE__ */ h(TextField, { name: "sc", label: i18n2.str`Supported currencies` }, /* @__PURE__ */ h(i18n2.Translate, null, "supported currencies: ", cList.join(", ")))), /* @__PURE__ */ h( InputNumber2, { @@ -47661,35 +50791,32 @@ function UpdatePage4({ template, onUpdate, onBack }) { tooltip: i18n2.str`How much time has the customer to complete the payment once the order was created.` } ), - /* @__PURE__ */ h( - Input, + !deviceList.length ? /* @__PURE__ */ h( + TextField, { name: "otpId", label: i18n2.str`OTP device`, - readonly: true, - side: /* @__PURE__ */ h( - "button", - { - class: "button is-danger", - "data-tooltip": i18n2.str`remove otp device for this template`, - onClick: () => { - setState((v3) => ({ ...v3, otpId: null })); - } - }, - /* @__PURE__ */ h("span", null, /* @__PURE__ */ h(i18n2.Translate, null, "remove")) - ), - tooltip: i18n2.str`Use to verify transaction in offline mode.` - } - ), - /* @__PURE__ */ h( - InputSearchOnList, + tooltip: i18n2.str`Use to verify transaction while offline.` + }, + /* @__PURE__ */ h(i18n2.Translate, null, "No OTP device."), + "\xA0", + /* @__PURE__ */ h("a", { href: "/otp-devices/new" }, /* @__PURE__ */ h(i18n2.Translate, null, "Add one first")) + ) : /* @__PURE__ */ h( + InputSelector, { - label: i18n2.str`Search device`, - onChange: (p4) => setState((v3) => ({ ...v3, otpId: p4?.id })), - list: deviceList.map((e4) => ({ - description: e4.device_description, - id: e4.otp_device_id - })) + name: "otpId", + label: i18n2.str`OTP device`, + values: [ + void 0, + ...deviceList.map((e4) => e4.otp_device_id) + ], + toStr: (v3) => { + if (!v3) { + return i18n2.str`No device`; + } + return deviceMap[v3]; + }, + tooltip: i18n2.str`Use to verify transaction in offline mode.` } ) ), /* @__PURE__ */ h("div", { class: "buttons is-right mt-5" }, onBack && /* @__PURE__ */ h("button", { class: "button", onClick: onBack }, /* @__PURE__ */ h(i18n2.Translate, null, "Cancel")), /* @__PURE__ */ h( @@ -47707,31 +50834,38 @@ function UpdatePage4({ template, onUpdate, onBack }) { function UpdateTemplate({ tid, onConfirm, - onBack, - onUnauthorized, - onNotFound, - onLoadError + onBack }) { - const { updateTemplate } = useTemplateAPI(); + const { lib } = useMerchantApiContext(); + const { state } = useSessionContext(); const result = useTemplateDetails(tid); const [notif, setNotif] = p3(void 0); const { i18n: i18n2 } = useTranslationContext(); - if (result.loading) + if (!result) return /* @__PURE__ */ h(Loading, null); - if (!result.ok) { - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.Unauthorized) - return onUnauthorized(); - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.NotFound) - return onNotFound(); - return onLoadError(result); + if (result instanceof TalerError) { + return /* @__PURE__ */ h(ErrorLoadingMerchant, { error: result }); + } + if (result.type === "fail") { + switch (result.case) { + case HttpStatusCode.NotFound: { + return /* @__PURE__ */ h(NotFoundPageOrAdminCreate, null); + } + case HttpStatusCode.Unauthorized: { + return /* @__PURE__ */ h(LoginPage, null); + } + default: { + assertUnreachable(result); + } + } } return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(NotificationCard, { notification: notif }), /* @__PURE__ */ h( UpdatePage4, { - template: { ...result.data }, + template: { ...result.body, id: tid }, onBack, onUpdate: (data) => { - return updateTemplate(tid, data).then(onConfirm).catch((error2) => { + return lib.instance.updateTemplate(state.token, tid, data).then(onConfirm).catch((error2) => { setNotif({ message: i18n2.str`could not update template`, type: "ERROR", @@ -47753,12 +50887,13 @@ init_hooks_module(); function UsePage({ id, template, onCreateOrder, onBack }) { const { i18n: i18n2 } = useTranslationContext(); const [state, setState] = p3({ - amount: template.template_contract.amount, - summary: template.template_contract.summary + currency: template.editable_defaults?.currency ?? template.template_contract.currency, + amount: template.editable_defaults?.amount ?? template.template_contract.amount, + summary: template.editable_defaults?.summary ?? template.template_contract.summary }); const errors2 = { - amount: !template.template_contract.amount && !state.amount ? i18n2.str`Amount is required` : void 0, - summary: !template.template_contract.summary && !state.summary ? i18n2.str`Order summary is required` : void 0 + amount: !state.amount ? i18n2.str`Amount is required` : void 0, + summary: !state.summary ? i18n2.str`Order summary is required` : void 0 }; const hasErrors = Object.keys(errors2).some( (k5) => errors2[k5] !== void 0 @@ -47815,32 +50950,47 @@ function UsePage({ id, template, onCreateOrder, onBack }) { function TemplateUsePage({ tid, onOrderCreated, - onBack, - onLoadError, - onNotFound, - onUnauthorized + onBack }) { - const { createOrderFromTemplate } = useTemplateAPI(); + const { lib } = useMerchantApiContext(); const result = useTemplateDetails(tid); const [notif, setNotif] = p3(void 0); const { i18n: i18n2 } = useTranslationContext(); - if (result.loading) + if (!result) return /* @__PURE__ */ h(Loading, null); - if (!result.ok) { - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.Unauthorized) - return onUnauthorized(); - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.NotFound) - return onNotFound(); - return onLoadError(result); + if (result instanceof TalerError) { + return /* @__PURE__ */ h(ErrorLoadingMerchant, { error: result }); + } + if (result.type === "fail") { + switch (result.case) { + case HttpStatusCode.NotFound: { + return /* @__PURE__ */ h(NotFoundPageOrAdminCreate, null); + } + case HttpStatusCode.Unauthorized: { + return /* @__PURE__ */ h(LoginPage, null); + } + default: { + assertUnreachable(result); + } + } } return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(NotificationCard, { notification: notif }), /* @__PURE__ */ h( UsePage, { - template: result.data, + template: result.body, id: tid, onBack, onCreateOrder: (request) => { - return createOrderFromTemplate(tid, request).then((res) => onOrderCreated(res.data.order_id)).catch((error2) => { + return lib.instance.useTemplateCreateOrder(tid, request).then((res) => { + if (res.type === "ok") { + onOrderCreated(res.body.order_id); + } else { + setNotif({ + message: i18n2.str`could not create order from template`, + type: "ERROR" + }); + } + }).catch((error2) => { setNotif({ message: i18n2.str`could not create order from template`, type: "ERROR", @@ -47854,11 +51004,17 @@ function TemplateUsePage({ // src/paths/instance/token/index.tsx init_preact_module(); +init_hooks_module(); // src/paths/instance/token/DetailPage.tsx init_preact_module(); init_hooks_module(); -function DetailPage2({ instanceId, hasToken, onBack, onNewToken, onClearToken }) { +function DetailPage2({ + hasToken, + onBack, + onNewToken, + onClearToken +}) { const [form, setValue] = p3({ old_token: "", new_token: "", @@ -47873,14 +51029,14 @@ function DetailPage2({ instanceId, hasToken, onBack, onNewToken, onClearToken }) const hasErrors = Object.keys(errors2).some( (k5) => errors2[k5] !== void 0 ); - const instance = useInstanceContext(); - const text = i18n2.str`You are updating the access token from instance with id "${instance.id}"`; + const { state } = useSessionContext(); + const text = i18n2.str`You are updating the access token from instance with id "${state.instance}"`; async function submitForm() { if (hasErrors) return; - const oldToken = hasToken ? `secret-token:${form.old_token}` : void 0; - const newToken = `secret-token:${form.new_token}`; - onNewToken(oldToken, newToken); + const oldToken = hasToken ? form.old_token : void 0; + const newToken = form.new_token; + onNewToken(oldToken, `secret-token:${newToken}`); } return /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("section", { class: "section" }, /* @__PURE__ */ h("section", { class: "hero is-hero-bar" }, /* @__PURE__ */ h("div", { class: "hero-body" }, /* @__PURE__ */ h("div", { class: "level" }, /* @__PURE__ */ h("div", { class: "level-left" }, /* @__PURE__ */ h("div", { class: "level-item" }, /* @__PURE__ */ h("span", { class: "is-size-4" }, text)))))), /* @__PURE__ */ h("hr", null), !hasToken && /* @__PURE__ */ h( NotificationCard, @@ -47905,7 +51061,7 @@ function DetailPage2({ instanceId, hasToken, onBack, onNewToken, onClearToken }) class: "button", onClick: () => { if (hasToken) { - const oldToken = `secret-token:${form.old_token}`; + const oldToken = form.old_token; onClearToken(oldToken); } else { onClearToken(void 0); @@ -47929,50 +51085,57 @@ function DetailPage2({ instanceId, hasToken, onBack, onNewToken, onClearToken }) tooltip: i18n2.str`confirm the same access token`, inputType: "password" } - ))), /* @__PURE__ */ h("div", { class: "buttons is-right mt-5" }, onBack && /* @__PURE__ */ h("button", { class: "button", onClick: onBack }, /* @__PURE__ */ h(i18n2.Translate, null, "Cancel")), /* @__PURE__ */ h( + )), /* @__PURE__ */ h("div", { class: "buttons is-right mt-5" }, onBack && /* @__PURE__ */ h("a", { class: "button", onClick: onBack }, /* @__PURE__ */ h(i18n2.Translate, null, "Cancel")), /* @__PURE__ */ h( AsyncButton, { + type: "submit", disabled: hasErrors, "data-tooltip": hasErrors ? i18n2.str`Need to complete marked fields` : "confirm operation", onClick: submitForm }, /* @__PURE__ */ h(i18n2.Translate, null, "Confirm change") - ))), /* @__PURE__ */ h("div", { class: "column" })))); + )))), /* @__PURE__ */ h("div", { class: "column" })))); } // src/paths/instance/token/index.tsx -init_hooks_module(); function Token({ - onLoadError, onChange, - onUnauthorized, - onNotFound, onCancel }) { const { i18n: i18n2 } = useTranslationContext(); + const { lib } = useMerchantApiContext(); + const { logIn } = useSessionContext(); const [notif, setNotif] = p3(void 0); - const { clearAccessToken, setNewAccessToken } = useInstanceAPI(); - const { id } = useInstanceContext(); const result = useInstanceDetails(); - if (result.loading) + if (!result) return /* @__PURE__ */ h(Loading, null); - if (!result.ok) { - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.Unauthorized) - return onUnauthorized(); - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.NotFound) - return onNotFound(); - return onLoadError(result); - } - const hasToken = result.data.auth.method === "token"; + if (result instanceof TalerError) { + return /* @__PURE__ */ h(ErrorLoadingMerchant, { error: result }); + } + if (result.type === "fail") { + switch (result.case) { + case HttpStatusCode.Unauthorized: { + return /* @__PURE__ */ h(LoginPage, null); + } + case HttpStatusCode.NotFound: { + return /* @__PURE__ */ h(NotFoundPageOrAdminCreate, null); + } + default: { + assertUnreachable(result); + } + } + } + const hasToken = result.body.auth.method === "token"; return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(NotificationCard, { notification: notif }), /* @__PURE__ */ h( DetailPage2, { - instanceId: id, onBack: onCancel, hasToken, onClearToken: async (currentToken) => { try { - await clearAccessToken(currentToken); + await lib.instance.updateCurrentInstanceAuthentication(currentToken, { + method: "external" + }); onChange(); } catch (error2) { if (error2 instanceof Error) { @@ -47986,8 +51149,26 @@ function Token({ }, onNewToken: async (currentToken, newToken) => { try { - await setNewAccessToken(currentToken, newToken); - onChange(); + await lib.instance.updateCurrentInstanceAuthentication(currentToken, { + token: newToken, + method: "token" + }); + const resp = await lib.authenticate.createAccessTokenBearer(newToken, { + scope: "write", + duration: { + d_us: "forever" + }, + refreshable: true + }); + if (resp.type === "ok") { + logIn({ token: resp.body.token }); + onChange(); + } else { + setNotif({ + message: i18n2.str`Failed to set new token`, + type: "ERROR" + }); + } } catch (error2) { if (error2 instanceof Error) { setNotif({ @@ -48006,111 +51187,11 @@ function Token({ init_preact_module(); init_hooks_module(); -// src/hooks/transfer.ts -init_hooks_module(); -var useSWR8 = useSWR; -function useTransferAPI() { - const mutateAll = useMatchMutate(); - const { request } = useBackendInstanceRequest(); - const informTransfer = async (data) => { - const res = await request(`/private/transfers`, { - method: "POST", - data - }); - await mutateAll(/.*private\/transfers.*/); - return res; - }; - return { informTransfer }; -} -function useInstanceTransfers(args, updatePosition) { - const { transferFetcher } = useBackendInstanceRequest(); - const [pageBefore, setPageBefore] = p3(1); - const [pageAfter, setPageAfter] = p3(1); - const totalAfter = pageAfter * PAGE_SIZE; - const totalBefore = args?.position !== void 0 ? pageBefore * PAGE_SIZE : 0; - const { - data: beforeData, - error: beforeError, - isValidating: loadingBefore - } = useSWR8( - [ - `/private/transfers`, - args?.payto_uri, - args?.verified, - args?.position, - totalBefore - ], - transferFetcher - ); - const { - data: afterData, - error: afterError, - isValidating: loadingAfter - } = useSWR8( - [ - `/private/transfers`, - args?.payto_uri, - args?.verified, - args?.position, - -totalAfter - ], - transferFetcher - ); - const [lastBefore, setLastBefore] = p3({ loading: true }); - const [lastAfter, setLastAfter] = p3({ loading: true }); - h2(() => { - if (afterData) - setLastAfter(afterData); - if (beforeData) - setLastBefore(beforeData); - }, [afterData, beforeData]); - if (beforeError) - return beforeError.cause; - if (afterError) - return afterError.cause; - const isReachingEnd = afterData && afterData.data.transfers.length < totalAfter; - const isReachingStart = args?.position === void 0 || beforeData && beforeData.data.transfers.length < totalBefore; - const pagination = { - isReachingEnd, - isReachingStart, - loadMore: () => { - if (!afterData || isReachingEnd) - return; - if (afterData.data.transfers.length < MAX_RESULT_SIZE) { - setPageAfter(pageAfter + 1); - } else { - const from = `${afterData.data.transfers[afterData.data.transfers.length - 1].transfer_serial_id}`; - if (from && updatePosition) - updatePosition(from); - } - }, - loadMorePrev: () => { - if (!beforeData || isReachingStart) - return; - if (beforeData.data.transfers.length < MAX_RESULT_SIZE) { - setPageBefore(pageBefore + 1); - } else if (beforeData) { - const from = `${beforeData.data.transfers[beforeData.data.transfers.length - 1].transfer_serial_id}`; - if (from && updatePosition) - updatePosition(from); - } - } - }; - const transfers = !beforeData || !afterData ? [] : (beforeData || lastBefore).data.transfers.slice().reverse().concat((afterData || lastAfter).data.transfers); - if (loadingAfter || loadingBefore) - return { loading: true, data: { transfers } }; - if (beforeData && afterData) { - return { ok: true, data: { transfers }, ...pagination }; - } - return { loading: true }; -} - // src/paths/instance/transfers/create/CreatePage.tsx init_preact_module(); init_hooks_module(); function CreatePage7({ accounts, onCreate, onBack }) { const { i18n: i18n2 } = useTranslationContext(); - const { currency } = useConfigContext(); const [state, setState] = p3({ wtid: "", // payto_uri: , @@ -48187,18 +51268,19 @@ function CreatePage7({ accounts, onCreate, onBack }) { // src/paths/instance/transfers/create/index.tsx function CreateTransfer2({ onConfirm, onBack }) { - const { informTransfer } = useTransferAPI(); + const { lib } = useMerchantApiContext(); + const { state } = useSessionContext(); const [notif, setNotif] = p3(void 0); const { i18n: i18n2 } = useTranslationContext(); const instance = useInstanceBankAccounts(); - const accounts = !instance.ok ? [] : instance.data.accounts.map((a5) => a5.payto_uri); + const accounts = !instance || instance instanceof TalerError || instance.type === "fail" ? [] : instance.body.accounts.map((a5) => a5.payto_uri); return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(NotificationCard, { notification: notif }), /* @__PURE__ */ h( CreatePage7, { onBack, accounts, onCreate: (request) => { - return informTransfer(request).then(() => onConfirm()).catch((error2) => { + return lib.instance.informWireTransfer(state.token, request).then(() => onConfirm()).catch((error2) => { setNotif({ message: i18n2.str`could not inform transfer`, type: "ERROR", @@ -48214,6 +51296,38 @@ function CreateTransfer2({ onConfirm, onBack }) { init_preact_module(); init_hooks_module(); +// src/hooks/transfer.ts +var useSWR9 = useSWR; +function revalidateInstanceTransfers() { + return mutate( + (key) => Array.isArray(key) && key[key.length - 1] === "listWireTransfers", + void 0, + { revalidate: true } + ); +} +function useInstanceTransfers(args, updatePosition = () => { +}) { + const { state: session } = useSessionContext(); + const { lib: { instance } } = useMerchantApiContext(); + async function fetcher([token, o3, p4, v3]) { + return await instance.listWireTransfers(token, { + paytoURI: p4, + verified: v3, + limit: PAGINATED_LIST_REQUEST, + offset: o3, + order: "dec" + }); + } + const { data, error: error2 } = useSWR9([session.token, args?.position, args?.payto_uri, args?.verified, "listWireTransfers"], fetcher); + if (error2) + return error2; + if (data === void 0) + return void 0; + if (data.type !== "ok") + return data; + return buildPaginatedResult(data.body.transfers, args?.position, updatePosition, (d5) => String(d5.transfer_serial_id)); +} + // src/paths/instance/transfers/list/ListPage.tsx init_preact_module(); @@ -48225,9 +51339,7 @@ function CardTable7({ onCreate, onDelete, onLoadMoreAfter, - onLoadMoreBefore, - hasMoreAfter, - hasMoreBefore + onLoadMoreBefore }) { const [rowSelection, rowSelectionHandler] = p3([]); const { i18n: i18n2 } = useTranslationContext(); @@ -48246,9 +51358,7 @@ function CardTable7({ rowSelection, rowSelectionHandler, onLoadMoreAfter, - onLoadMoreBefore, - hasMoreAfter, - hasMoreBefore + onLoadMoreBefore } ) : /* @__PURE__ */ h(EmptyTable8, null))))); } @@ -48256,20 +51366,18 @@ function Table7({ instances, onLoadMoreAfter, onDelete, - onLoadMoreBefore, - hasMoreAfter, - hasMoreBefore + onLoadMoreBefore }) { const { i18n: i18n2 } = useTranslationContext(); - const [settings] = useSettings(); - return /* @__PURE__ */ h("div", { class: "table-container" }, hasMoreBefore && /* @__PURE__ */ h( + const [settings] = usePreference(); + return /* @__PURE__ */ h("div", { class: "table-container" }, onLoadMoreBefore && /* @__PURE__ */ h( "button", { class: "button is-fullwidth", "data-tooltip": i18n2.str`load more transfers before the first one`, onClick: onLoadMoreBefore }, - /* @__PURE__ */ h(i18n2.Translate, null, "load newer transfers") + /* @__PURE__ */ h(i18n2.Translate, null, "load first page") ), /* @__PURE__ */ h("table", { class: "table is-fullwidth is-striped is-hoverable is-fullwidth" }, /* @__PURE__ */ h("thead", null, /* @__PURE__ */ h("tr", null, /* @__PURE__ */ h("th", null, /* @__PURE__ */ h(i18n2.Translate, null, "ID")), /* @__PURE__ */ h("th", null, /* @__PURE__ */ h(i18n2.Translate, null, "Credit")), /* @__PURE__ */ h("th", null, /* @__PURE__ */ h(i18n2.Translate, null, "Address")), /* @__PURE__ */ h("th", null, /* @__PURE__ */ h(i18n2.Translate, null, "Exchange URL")), /* @__PURE__ */ h("th", null, /* @__PURE__ */ h(i18n2.Translate, null, "Confirmed")), /* @__PURE__ */ h("th", null, /* @__PURE__ */ h(i18n2.Translate, null, "Verified")), /* @__PURE__ */ h("th", null, /* @__PURE__ */ h(i18n2.Translate, null, "Executed at")), /* @__PURE__ */ h("th", null))), /* @__PURE__ */ h("tbody", null, instances.map((i4) => { return /* @__PURE__ */ h("tr", { key: i4.id }, /* @__PURE__ */ h("td", null, i4.id), /* @__PURE__ */ h("td", null, i4.credit_amount), /* @__PURE__ */ h("td", null, i4.payto_uri), /* @__PURE__ */ h("td", null, i4.exchange_url), /* @__PURE__ */ h("td", null, i4.confirmed ? i18n2.str`yes` : i18n2.str`no`), /* @__PURE__ */ h("td", null, i4.verified ? i18n2.str`yes` : i18n2.str`no`), /* @__PURE__ */ h("td", null, i4.execution_time ? i4.execution_time.t_s == "never" ? i18n2.str`never` : format( i4.execution_time.t_s * 1e3, @@ -48283,19 +51391,19 @@ function Table7({ }, "Delete" ) : void 0)); - }))), hasMoreAfter && /* @__PURE__ */ h( + }))), onLoadMoreAfter && /* @__PURE__ */ h( "button", { class: "button is-fullwidth", - "data-tooltip": i18n2.str`load more transfer after the last one`, + "data-tooltip": i18n2.str`load more transfers after the last one`, onClick: onLoadMoreAfter }, - /* @__PURE__ */ h(i18n2.Translate, null, "load older transfers") + /* @__PURE__ */ h(i18n2.Translate, null, "load next page") )); } function EmptyTable8() { const { i18n: i18n2 } = useTranslationContext(); - return /* @__PURE__ */ h("div", { class: "content has-text-grey has-text-centered" }, /* @__PURE__ */ h("p", null, /* @__PURE__ */ h("span", { class: "icon is-large" }, /* @__PURE__ */ h("i", { class: "mdi mdi-emoticon-sad mdi-48px" }))), /* @__PURE__ */ h("p", null, /* @__PURE__ */ h(i18n2.Translate, null, "There is no transfer yet, add more pressing the + sign"))); + return /* @__PURE__ */ h("div", { class: "content has-text-grey has-text-centered" }, /* @__PURE__ */ h("p", null, /* @__PURE__ */ h("span", { class: "icon is-large" }, /* @__PURE__ */ h("i", { class: "mdi mdi-magnify mdi-48px" }))), /* @__PURE__ */ h("p", null, /* @__PURE__ */ h(i18n2.Translate, null, "There is no transfer yet, add more pressing the + sign"))); } // src/paths/instance/transfers/list/ListPage.tsx @@ -48329,6 +51437,12 @@ function ListPage6({ name: "payto_uri", label: i18n2.str`Account URI`, values: accounts, + fromStr: (d5) => { + const idx = accounts.indexOf(d5); + if (idx === -1) + return void 0; + return d5; + }, placeholder: i18n2.str`Select one account`, tooltip: i18n2.str`filter by account address` } @@ -48365,24 +51479,19 @@ function ListPage6({ onCreate, onDelete, onLoadMoreBefore, - hasMoreBefore: !onLoadMoreBefore, - onLoadMoreAfter, - hasMoreAfter: !onLoadMoreAfter + onLoadMoreAfter } )); } // src/paths/instance/transfers/list/index.tsx function ListTransfer({ - onUnauthorized, - onLoadError, - onCreate, - onNotFound + onCreate }) { const setFilter = (s5) => setForm({ ...form, verified: s5 }); const [position, setPosition] = p3(void 0); const instance = useInstanceBankAccounts(); - const accounts = !instance.ok ? [] : instance.data.accounts.map((a5) => a5.payto_uri); + const accounts = !instance || instance instanceof TalerError || instance.type === "fail" ? [] : instance.body.accounts.map((a5) => a5.payto_uri); const [form, setForm] = p3({ payto_uri: "" }); const shoulUseDefaultAccount = accounts.length === 1; h2(() => { @@ -48390,8 +51499,8 @@ function ListTransfer({ setForm({ ...form, payto_uri: accounts[0] }); } }, [shoulUseDefaultAccount]); - const isVerifiedTransfers = form.verified === "yes"; - const isNonVerifiedTransfers = form.verified === "no"; + const isVerifiedTransfers = form.verified === true; + const isNonVerifiedTransfers = form.verified === false; const isAllTransfers = form.verified === void 0; const result = useInstanceTransfers( { @@ -48401,29 +51510,38 @@ function ListTransfer({ }, (id) => setPosition(id) ); - if (result.loading) + if (!result) return /* @__PURE__ */ h(Loading, null); - if (!result.ok) { - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.Unauthorized) - return onUnauthorized(); - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.NotFound) - return onNotFound(); - return onLoadError(result); + if (result instanceof TalerError) { + return /* @__PURE__ */ h(ErrorLoadingMerchant, { error: result }); + } + if (result.type === "fail") { + switch (result.case) { + case HttpStatusCode.Unauthorized: { + return /* @__PURE__ */ h(LoginPage, null); + } + case HttpStatusCode.NotFound: { + return /* @__PURE__ */ h(NotFoundPageOrAdminCreate, null); + } + default: { + assertUnreachable(result); + } + } } return /* @__PURE__ */ h( ListPage6, { accounts, - transfers: result.data.transfers, - onLoadMoreBefore: result.isReachingStart ? result.loadMorePrev : void 0, - onLoadMoreAfter: result.isReachingEnd ? result.loadMore : void 0, + transfers: result.body, + onLoadMoreBefore: result.isFirstPage ? void 0 : result.loadFirst, + onLoadMoreAfter: result.isLastPage ? void 0 : result.loadNext, onCreate, onDelete: () => { null; }, onShowAll: () => setFilter(void 0), - onShowUnverified: () => setFilter("no"), - onShowVerified: () => setFilter("yes"), + onShowUnverified: () => setFilter(false), + onShowVerified: () => setFilter(true), isAllTransfers, isVerifiedTransfers, isNonVerifiedTransfers, @@ -48454,7 +51572,7 @@ function UpdatePage5({ selected, onBack }) { - const { id } = useInstanceContext(); + const { state } = useSessionContext(); const [value, valueHandler] = p3(convert2(selected)); const { i18n: i18n2 } = useTranslationContext(); const errors2 = { @@ -48481,7 +51599,7 @@ function UpdatePage5({ }; await onUpdate(result); }; - return /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("section", { class: "section" }, /* @__PURE__ */ h("section", { class: "hero is-hero-bar" }, /* @__PURE__ */ h("div", { class: "hero-body" }, /* @__PURE__ */ h("div", { class: "level" }, /* @__PURE__ */ h("div", { class: "level-left" }, /* @__PURE__ */ h("div", { class: "level-item" }, /* @__PURE__ */ h("span", { class: "is-size-4" }, /* @__PURE__ */ h(i18n2.Translate, null, "Instance id"), ": ", /* @__PURE__ */ h("b", null, id))))))), /* @__PURE__ */ h("hr", null), /* @__PURE__ */ h("div", { class: "columns" }, /* @__PURE__ */ h("div", { class: "column" }), /* @__PURE__ */ h("div", { class: "column is-four-fifths" }, /* @__PURE__ */ h( + return /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("section", { class: "section" }, /* @__PURE__ */ h("section", { class: "hero is-hero-bar" }, /* @__PURE__ */ h("div", { class: "hero-body" }, /* @__PURE__ */ h("div", { class: "level" }, /* @__PURE__ */ h("div", { class: "level-left" }, /* @__PURE__ */ h("div", { class: "level-item" }, /* @__PURE__ */ h("span", { class: "is-size-4" }, /* @__PURE__ */ h(i18n2.Translate, null, "Instance id"), ": ", /* @__PURE__ */ h("b", null, state.instance))))))), /* @__PURE__ */ h("hr", null), /* @__PURE__ */ h("div", { class: "columns" }, /* @__PURE__ */ h("div", { class: "column" }), /* @__PURE__ */ h("div", { class: "column is-four-fifths" }, /* @__PURE__ */ h( FormProvider, { errors: errors2, @@ -48510,46 +51628,56 @@ function UpdatePage5({ // src/paths/instance/update/index.tsx function Update2(props) { - const { updateInstance } = useInstanceAPI(); + const { lib } = useMerchantApiContext(); + const updateInstance = lib.instance.updateCurrentInstance.bind(lib.instance); const result = useInstanceDetails(); return CommonUpdate(props, result, updateInstance); } function AdminUpdate(props) { - const { updateInstance } = useManagementAPI( - props.instanceId - ); + const { lib } = useMerchantApiContext(); + const t4 = lib.subInstanceApi(props.instanceId).instance; + const updateInstance = t4.updateCurrentInstance.bind(t4); const result = useManagedInstanceDetails(props.instanceId); return CommonUpdate(props, result, updateInstance); } function CommonUpdate({ onBack, - onConfirm, - onLoadError, - onNotFound, - onUpdateError, - onUnauthorized + onConfirm }, result, updateInstance) { const [notif, setNotif] = p3(void 0); const { i18n: i18n2 } = useTranslationContext(); - if (result.loading) + const { state } = useSessionContext(); + if (!result) return /* @__PURE__ */ h(Loading, null); - if (!result.ok) { - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.Unauthorized) - return onUnauthorized(); - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.NotFound) - return onNotFound(); - return onLoadError(result); + if (result instanceof TalerError) { + return /* @__PURE__ */ h(ErrorLoadingMerchant, { error: result }); + } + if (result.type === "fail") { + switch (result.case) { + case HttpStatusCode.Unauthorized: { + return /* @__PURE__ */ h(LoginPage, null); + } + case HttpStatusCode.NotFound: { + return /* @__PURE__ */ h(NotFoundPageOrAdminCreate, null); + } + default: { + assertUnreachable(result); + } + } } return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(NotificationCard, { notification: notif }), /* @__PURE__ */ h( UpdatePage5, { onBack, isLoading: false, - selected: result.data, + selected: result.body, onUpdate: (d5) => { - return updateInstance(d5).then(onConfirm).catch( + if (state.status !== "loggedIn") { + return Promise.resolve(); + } + return updateInstance(state.token, d5).then(onConfirm).catch( (error2) => setNotif({ - message: i18n2.str`Failed to create instance`, + message: i18n2.str`Failed to update instance`, type: "ERROR", description: error2.message }) @@ -48563,101 +51691,6 @@ function CommonUpdate({ init_preact_module(); init_hooks_module(); -// src/hooks/webhooks.ts -init_hooks_module(); -var useSWR9 = useSWR; -function useWebhookAPI() { - const mutateAll = useMatchMutate(); - const { request } = useBackendInstanceRequest(); - const createWebhook = async (data) => { - const res = await request(`/private/webhooks`, { - method: "POST", - data - }); - await mutateAll(/.*private\/webhooks.*/); - return res; - }; - const updateWebhook = async (webhookId, data) => { - const res = await request(`/private/webhooks/${webhookId}`, { - method: "PATCH", - data - }); - await mutateAll(/.*private\/webhooks.*/); - return res; - }; - const deleteWebhook = async (webhookId) => { - const res = await request(`/private/webhooks/${webhookId}`, { - method: "DELETE" - }); - await mutateAll(/.*private\/webhooks.*/); - return res; - }; - return { createWebhook, updateWebhook, deleteWebhook }; -} -function useInstanceWebhooks(args, updatePosition) { - const { webhookFetcher } = useBackendInstanceRequest(); - const [pageBefore, setPageBefore] = p3(1); - const [pageAfter, setPageAfter] = p3(1); - const totalAfter = pageAfter * PAGE_SIZE; - const totalBefore = args?.position ? pageBefore * PAGE_SIZE : 0; - const { - data: afterData, - error: afterError, - isValidating: loadingAfter - } = useSWR9([`/private/webhooks`, args?.position, -totalAfter], webhookFetcher); - const [lastAfter, setLastAfter] = p3({ loading: true }); - h2(() => { - if (afterData) - setLastAfter(afterData); - }, [afterData]); - if (afterError) - return afterError.cause; - const isReachingEnd = afterData && afterData.data.webhooks.length < totalAfter; - const isReachingStart = true; - const pagination = { - isReachingEnd, - isReachingStart, - loadMore: () => { - if (!afterData || isReachingEnd) - return; - if (afterData.data.webhooks.length < MAX_RESULT_SIZE) { - setPageAfter(pageAfter + 1); - } else { - const from = `${afterData.data.webhooks[afterData.data.webhooks.length - 1].webhook_id}`; - if (from && updatePosition) - updatePosition(from); - } - }, - loadMorePrev: () => { - return; - } - }; - const webhooks = !afterData ? [] : (afterData || lastAfter).data.webhooks; - if (loadingAfter) - return { loading: true, data: { webhooks } }; - if (afterData) { - return { ok: true, data: { webhooks }, ...pagination }; - } - return { loading: true }; -} -function useWebhookDetails(webhookId) { - const { webhookFetcher } = useBackendInstanceRequest(); - const { data, error: error2, isValidating } = useSWR9([`/private/webhooks/${webhookId}`], webhookFetcher, { - refreshInterval: 0, - refreshWhenHidden: false, - revalidateOnFocus: false, - revalidateOnReconnect: false, - refreshWhenOffline: false - }); - if (isValidating) - return { loading: true, data: data?.data }; - if (data) - return data; - if (error2) - return error2.cause; - return { loading: true }; -} - // src/paths/instance/webhooks/create/CreatePage.tsx init_preact_module(); init_hooks_module(); @@ -48757,15 +51790,16 @@ function CreatePage8({ onCreate, onBack }) { // src/paths/instance/webhooks/create/index.tsx function CreateWebhook({ onConfirm, onBack }) { - const { createWebhook } = useWebhookAPI(); const [notif, setNotif] = p3(void 0); const { i18n: i18n2 } = useTranslationContext(); + const { lib } = useMerchantApiContext(); + const { state } = useSessionContext(); return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(NotificationCard, { notification: notif }), /* @__PURE__ */ h( CreatePage8, { onBack, onCreate: (request) => { - return createWebhook(request).then(() => onConfirm()).catch((error2) => { + return lib.instance.addWebhook(state.token, request).then(() => onConfirm()).catch((error2) => { setNotif({ message: i18n2.str`could not inform template`, type: "ERROR", @@ -48793,9 +51827,7 @@ function CardTable8({ onDelete, onSelect, onLoadMoreAfter, - onLoadMoreBefore, - hasMoreAfter, - hasMoreBefore + onLoadMoreBefore }) { const [rowSelection, rowSelectionHandler] = p3([]); const { i18n: i18n2 } = useTranslationContext(); @@ -48815,9 +51847,7 @@ function CardTable8({ rowSelection, rowSelectionHandler, onLoadMoreAfter, - onLoadMoreBefore, - hasMoreAfter, - hasMoreBefore + onLoadMoreBefore } ) : /* @__PURE__ */ h(EmptyTable9, null))))); } @@ -48826,19 +51856,17 @@ function Table8({ onLoadMoreAfter, onDelete, onSelect, - onLoadMoreBefore, - hasMoreAfter, - hasMoreBefore + onLoadMoreBefore }) { const { i18n: i18n2 } = useTranslationContext(); - return /* @__PURE__ */ h("div", { class: "table-container" }, hasMoreBefore && /* @__PURE__ */ h( + return /* @__PURE__ */ h("div", { class: "table-container" }, onLoadMoreBefore && /* @__PURE__ */ h( "button", { class: "button is-fullwidth", "data-tooltip": i18n2.str`load more webhooks before the first one`, onClick: onLoadMoreBefore }, - /* @__PURE__ */ h(i18n2.Translate, null, "load newer webhooks") + /* @__PURE__ */ h(i18n2.Translate, null, "load first page") ), /* @__PURE__ */ h("table", { class: "table is-fullwidth is-striped is-hoverable is-fullwidth" }, /* @__PURE__ */ h("thead", null, /* @__PURE__ */ h("tr", null, /* @__PURE__ */ h("th", null, /* @__PURE__ */ h(i18n2.Translate, null, "ID")), /* @__PURE__ */ h("th", null, /* @__PURE__ */ h(i18n2.Translate, null, "Event type")), /* @__PURE__ */ h("th", null))), /* @__PURE__ */ h("tbody", null, instances.map((i4) => { return /* @__PURE__ */ h("tr", { key: i4.webhook_id }, /* @__PURE__ */ h( "td", @@ -48863,19 +51891,19 @@ function Table8({ }, "Delete" )))); - }))), hasMoreAfter && /* @__PURE__ */ h( + }))), onLoadMoreAfter && /* @__PURE__ */ h( "button", { class: "button is-fullwidth", "data-tooltip": i18n2.str`load more webhooks after the last one`, onClick: onLoadMoreAfter }, - /* @__PURE__ */ h(i18n2.Translate, null, "load older webhooks") + /* @__PURE__ */ h(i18n2.Translate, null, "load next page") )); } function EmptyTable9() { const { i18n: i18n2 } = useTranslationContext(); - return /* @__PURE__ */ h("div", { class: "content has-text-grey has-text-centered" }, /* @__PURE__ */ h("p", null, /* @__PURE__ */ h("span", { class: "icon is-large" }, /* @__PURE__ */ h("i", { class: "mdi mdi-emoticon-sad mdi-48px" }))), /* @__PURE__ */ h("p", null, /* @__PURE__ */ h(i18n2.Translate, null, "There is no webhooks yet, add more pressing the + sign"))); + return /* @__PURE__ */ h("div", { class: "content has-text-grey has-text-centered" }, /* @__PURE__ */ h("p", null, /* @__PURE__ */ h("span", { class: "icon is-large" }, /* @__PURE__ */ h("i", { class: "mdi mdi-magnify mdi-48px" }))), /* @__PURE__ */ h("p", null, /* @__PURE__ */ h(i18n2.Translate, null, "There is no webhooks yet, add more pressing the + sign"))); } // src/paths/instance/webhooks/list/ListPage.tsx @@ -48900,57 +51928,60 @@ function ListPage7({ onDelete, onSelect, onLoadMoreBefore, - hasMoreBefore: !onLoadMoreBefore, - onLoadMoreAfter, - hasMoreAfter: !onLoadMoreAfter + onLoadMoreAfter } )); } // src/paths/instance/webhooks/list/index.tsx -function ListWebhooks({ - onUnauthorized, - onLoadError, - onCreate, - onSelect, - onNotFound -}) { - const [position, setPosition] = p3(void 0); +function ListWebhooks({ onCreate, onSelect }) { const { i18n: i18n2 } = useTranslationContext(); const [notif, setNotif] = p3(void 0); - const { deleteWebhook } = useWebhookAPI(); - const result = useInstanceWebhooks({ position }, (id) => setPosition(id)); - if (result.loading) + const { lib } = useMerchantApiContext(); + const { state } = useSessionContext(); + const result = useInstanceWebhooks(); + if (!result) return /* @__PURE__ */ h(Loading, null); - if (!result.ok) { - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.Unauthorized) - return onUnauthorized(); - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.NotFound) - return onNotFound(); - return onLoadError(result); + if (result instanceof TalerError) { + return /* @__PURE__ */ h(ErrorLoadingMerchant, { error: result }); + } + if (result.type === "fail") { + switch (result.case) { + case HttpStatusCode.NotFound: { + return /* @__PURE__ */ h(NotFoundPageOrAdminCreate, null); + } + case HttpStatusCode.Unauthorized: { + return /* @__PURE__ */ h(LoginPage, null); + } + default: { + assertUnreachable(result); + } + } } return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(NotificationCard, { notification: notif }), /* @__PURE__ */ h( ListPage7, { - webhooks: result.data.webhooks, - onLoadMoreBefore: result.isReachingStart ? result.loadMorePrev : void 0, - onLoadMoreAfter: result.isReachingEnd ? result.loadMore : void 0, + webhooks: result.body.webhooks, + onLoadMoreBefore: void 0, + onLoadMoreAfter: void 0, onCreate, onSelect: (e4) => { onSelect(e4.webhook_id); }, - onDelete: (e4) => deleteWebhook(e4.webhook_id).then( - () => setNotif({ - message: i18n2.str`webhook delete successfully`, - type: "SUCCESS" - }) - ).catch( - (error2) => setNotif({ - message: i18n2.str`could not delete the webhook`, - type: "ERROR", - description: error2.message - }) - ) + onDelete: (e4) => { + return lib.instance.deleteWebhook(state.token, e4.webhook_id).then( + () => setNotif({ + message: i18n2.str`webhook delete successfully`, + type: "SUCCESS" + }) + ).catch( + (error2) => setNotif({ + message: i18n2.str`could not delete the webhook`, + type: "ERROR", + description: error2.message + }) + ); + } } )); } @@ -49043,31 +52074,38 @@ function UpdatePage6({ webhook, onUpdate, onBack }) { function UpdateWebhook({ tid, onConfirm, - onBack, - onUnauthorized, - onNotFound, - onLoadError + onBack }) { - const { updateWebhook } = useWebhookAPI(); + const { lib } = useMerchantApiContext(); + const { state } = useSessionContext(); const result = useWebhookDetails(tid); const [notif, setNotif] = p3(void 0); const { i18n: i18n2 } = useTranslationContext(); - if (result.loading) + if (!result) return /* @__PURE__ */ h(Loading, null); - if (!result.ok) { - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.Unauthorized) - return onUnauthorized(); - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.NotFound) - return onNotFound(); - return onLoadError(result); + if (result instanceof TalerError) { + return /* @__PURE__ */ h(ErrorLoadingMerchant, { error: result }); + } + if (result.type === "fail") { + switch (result.case) { + case HttpStatusCode.NotFound: { + return /* @__PURE__ */ h(NotFoundPageOrAdminCreate, null); + } + case HttpStatusCode.Unauthorized: { + return /* @__PURE__ */ h(LoginPage, null); + } + default: { + assertUnreachable(result); + } + } } return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(NotificationCard, { notification: notif }), /* @__PURE__ */ h( UpdatePage6, { - webhook: { ...result.data, id: tid }, + webhook: { ...result.body, id: tid }, onBack, onUpdate: (data) => { - return updateWebhook(tid, data).then(onConfirm).catch((error2) => { + return lib.instance.updateWebhook(state.token, tid, data).then(onConfirm).catch((error2) => { setNotif({ message: i18n2.str`could not update template`, type: "ERROR", @@ -49079,145 +52117,6 @@ function UpdateWebhook({ )); } -// src/paths/login/index.tsx -init_preact_module(); -init_hooks_module(); -function normalizeToken(r3) { - return `secret-token:${r3}`; -} -function LoginPage({ onConfirm }) { - const { url: backendURL } = useBackendContext(); - const { admin, id } = useInstanceContext(); - const { requestNewLoginToken } = useCredentialsChecker(); - const [token, setToken] = p3(""); - const [notif, setNotif] = p3(void 0); - const { i18n: i18n2 } = useTranslationContext(); - const doLogin = T2(async function doLoginImpl() { - const secretToken = normalizeToken(token); - const baseUrl = id === void 0 ? backendURL : `${backendURL}/instances/${id}`; - const result = await requestNewLoginToken(baseUrl, secretToken); - if (result.valid) { - const { token: token2, expiration } = result; - onConfirm({ token: token2, expiration }); - } else { - onConfirm(void 0); - setNotif({ - message: "Your password is incorrect", - type: "ERROR" - }); - } - }, [id, token]); - if (admin && id !== "default") { - return /* @__PURE__ */ h("div", { class: "columns is-centered", style: { margin: "auto" } }, /* @__PURE__ */ h("div", { class: "column is-two-thirds " }, /* @__PURE__ */ h("div", { class: "modal-card", style: { width: "100%", margin: 0 } }, /* @__PURE__ */ h( - "header", - { - class: "modal-card-head", - style: { border: "1px solid", borderBottom: 0 } - }, - /* @__PURE__ */ h("p", { class: "modal-card-title" }, i18n2.str`Login required`) - ), /* @__PURE__ */ h( - "section", - { - class: "modal-card-body", - style: { border: "1px solid", borderTop: 0, borderBottom: 0 } - }, - /* @__PURE__ */ h("p", null, /* @__PURE__ */ h(i18n2.Translate, null, "Need the access token for the instance.")), - /* @__PURE__ */ h("div", { class: "field is-horizontal" }, /* @__PURE__ */ h("div", { class: "field-label is-normal" }, /* @__PURE__ */ h("label", { class: "label" }, /* @__PURE__ */ h(i18n2.Translate, null, "Access Token"))), /* @__PURE__ */ h("div", { class: "field-body" }, /* @__PURE__ */ h("div", { class: "field" }, /* @__PURE__ */ h("p", { class: "control is-expanded" }, /* @__PURE__ */ h( - "input", - { - class: "input", - type: "password", - placeholder: "current access token", - name: "token", - onKeyPress: (e4) => e4.keyCode === 13 ? doLogin() : null, - value: token, - onInput: (e4) => setToken(e4?.currentTarget.value) - } - ))))) - ), /* @__PURE__ */ h( - "footer", - { - class: "modal-card-foot ", - style: { - justifyContent: "flex-end", - border: "1px solid", - borderTop: 0 - } - }, - /* @__PURE__ */ h( - AsyncButton2, - { - onClick: doLogin - }, - /* @__PURE__ */ h(i18n2.Translate, null, "Confirm") - ) - )))); - } - return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(NotificationCard, { notification: notif }), /* @__PURE__ */ h("div", { class: "columns is-centered", style: { margin: "auto" } }, /* @__PURE__ */ h("div", { class: "column is-two-thirds " }, /* @__PURE__ */ h("div", { class: "modal-card", style: { width: "100%", margin: 0 } }, /* @__PURE__ */ h( - "header", - { - class: "modal-card-head", - style: { border: "1px solid", borderBottom: 0 } - }, - /* @__PURE__ */ h("p", { class: "modal-card-title" }, i18n2.str`Login required`) - ), /* @__PURE__ */ h( - "section", - { - class: "modal-card-body", - style: { border: "1px solid", borderTop: 0, borderBottom: 0 } - }, - /* @__PURE__ */ h(i18n2.Translate, null, "Please enter your access token."), - /* @__PURE__ */ h("div", { class: "field is-horizontal" }, /* @__PURE__ */ h("div", { class: "field-label is-normal" }, /* @__PURE__ */ h("label", { class: "label" }, /* @__PURE__ */ h(i18n2.Translate, null, "Access Token"))), /* @__PURE__ */ h("div", { class: "field-body" }, /* @__PURE__ */ h("div", { class: "field" }, /* @__PURE__ */ h("p", { class: "control is-expanded" }, /* @__PURE__ */ h( - "input", - { - class: "input", - type: "password", - placeholder: "current access token", - name: "token", - onKeyPress: (e4) => e4.keyCode === 13 ? doLogin() : null, - value: token, - onInput: (e4) => setToken(e4?.currentTarget.value) - } - ))))) - ), /* @__PURE__ */ h( - "footer", - { - class: "modal-card-foot ", - style: { - justifyContent: "space-between", - border: "1px solid", - borderTop: 0 - } - }, - /* @__PURE__ */ h("div", null), - /* @__PURE__ */ h( - AsyncButton2, - { - type: "is-info", - onClick: doLogin - }, - /* @__PURE__ */ h(i18n2.Translate, null, "Confirm") - ) - ))))); -} -function AsyncButton2({ onClick, disabled, type = "", children }) { - const [running, setRunning] = p3(false); - return /* @__PURE__ */ h("button", { class: "button " + type, disabled: disabled || running, onClick: () => { - setRunning(true); - onClick().then(() => { - setRunning(false); - }).catch(() => { - setRunning(false); - }); - } }, children); -} - -// src/paths/notfound/index.tsx -init_preact_module(); -function NotFoundPage() { - return /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("p", null, "That page doesn't exist."), /* @__PURE__ */ h(Link, { href: "/" }, /* @__PURE__ */ h("h4", null, "Back to Home"))); -} - // src/paths/settings/index.tsx init_preact_module(); function getBrowserLang2() { @@ -49233,12 +52132,14 @@ function Settings({ onClose }) { const { i18n: i18n2 } = useTranslationContext(); const borwserLang = getBrowserLang2(); const { update } = useLang(void 0, {}); - const [value, updateValue] = useSettings(); + const [value, , updateValue] = usePreference(); const errors2 = {}; function valueHandler(s5) { const next = s5(value); const v3 = { advanceOrderMode: next.advanceOrderMode ?? false, + hideMissingAccountUntil: next.hideMissingAccountUntil ?? AbsoluteTime.never(), + hideKycUntil: next.hideKycUntil ?? AbsoluteTime.never(), dateFormat: next.dateFormat ?? "ymd" }; updateValue(v3); @@ -49251,13 +52152,21 @@ function Settings({ onClose }) { object: value, valueHandler }, - /* @__PURE__ */ h("div", { class: "field is-horizontal" }, /* @__PURE__ */ h("div", { class: "field-label is-normal" }, /* @__PURE__ */ h("label", { class: "label" }, /* @__PURE__ */ h(i18n2.Translate, null, "Language"), /* @__PURE__ */ h("span", { class: "icon has-tooltip-right", "data-tooltip": "Force language setting instance of taking the browser" }, /* @__PURE__ */ h("i", { class: "mdi mdi-information" })))), /* @__PURE__ */ h("div", { class: "field field-body has-addons is-flex-grow-3" }, /* @__PURE__ */ h(LangSelector, null), "\xA0", borwserLang !== void 0 && /* @__PURE__ */ h( + /* @__PURE__ */ h("div", { class: "field is-horizontal" }, /* @__PURE__ */ h("div", { class: "field-label is-normal" }, /* @__PURE__ */ h("label", { class: "label" }, /* @__PURE__ */ h(i18n2.Translate, null, "Language"), /* @__PURE__ */ h( + "span", + { + class: "icon has-tooltip-right", + "data-tooltip": "Force language setting instance of taking the browser" + }, + /* @__PURE__ */ h("i", { class: "mdi mdi-information" }) + ))), /* @__PURE__ */ h("div", { class: "field field-body has-addons is-flex-grow-3" }, /* @__PURE__ */ h(LangSelector, null), "\xA0", borwserLang !== void 0 && /* @__PURE__ */ h( "button", { "data-tooltip": i18n2.str`generate random secret key`, class: "button is-info mr-2", onClick: (e4) => { update(borwserLang.substring(0, 2)); + e4.preventDefault(); } }, /* @__PURE__ */ h(i18n2.Translate, null, "Set default") @@ -49286,161 +52195,59 @@ function Settings({ onClose }) { return "day month year"; return "choose one"; }, - values: [ - "ymd", - "mdy", - "dmy" - ], + values: ["ymd", "mdy", "dmy"], tooltip: i18n2.str`how the date is going to be displayed` } ) - ))), /* @__PURE__ */ h("div", { class: "column" }))), onClose && /* @__PURE__ */ h("section", { class: "section is-main-section" }, /* @__PURE__ */ h( - "button", - { - class: "button", - onClick: onClose - }, - /* @__PURE__ */ h(i18n2.Translate, null, "Close") - ))); + ))), /* @__PURE__ */ h("div", { class: "column" }))), onClose && /* @__PURE__ */ h("section", { class: "section is-main-section" }, /* @__PURE__ */ h("button", { class: "button", onClick: onClose }, /* @__PURE__ */ h(i18n2.Translate, null, "Close")))); } -// src/InstanceRoutes.tsx -var noop2 = () => { +// src/Routing.tsx +var privatePages = { + home: urlPattern(/\/home/, () => "#/home"), + go: urlPattern(/\/home/, () => "#/home") }; -function InstanceRoutes({ - id, - admin, - path, - // onUnauthorized, - onLoginPass, - setInstanceName -}) { - const [defaultToken, updateDefaultToken] = useBackendDefaultToken(); - const [token, updateToken] = useBackendInstanceToken(id); - const { i18n: i18n2 } = useTranslationContext(); +var publicPages = { + home: urlPattern(/\/home/, () => "#/home"), + go: urlPattern(/\/home/, () => "#/home") +}; +var history2 = createHashHistory(); +function Routing(_p) { + const { state } = useSessionContext(); const [globalNotification, setGlobalNotification] = p3(void 0); - const changeToken = (token2) => { - if (admin) { - updateToken(token2); - } else { - updateDefaultToken(token2); - } - onLoginPass(); - }; const [error2] = P2(); - const value = F( - () => ({ id, token, admin, changeToken }), - [id, token, admin] - ); + const [preference] = usePreference(); + const now2 = AbsoluteTime.now(); const instance = useInstanceBankAccounts(); - const accounts = !instance.ok ? void 0 : instance.data.accounts; - function ServerErrorRedirectTo(to) { - return function ServerErrorRedirectToImpl(error3) { - if (error3.type === ErrorType.TIMEOUT) { - setGlobalNotification({ - message: i18n2.str`The request to the backend take too long and was cancelled`, - description: i18n2.str`Diagnostic from ${error3.info.url} is "${error3.message}"`, - type: "ERROR", - to - }); - } else { - setGlobalNotification({ - message: i18n2.str`The backend reported a problem: HTTP status #${error3.status}`, - description: i18n2.str`Diagnostic from ${error3.info.url} is '${error3.message}'`, - details: error3.type === ErrorType.CLIENT || error3.type === ErrorType.SERVER ? error3.payload.detail : void 0, - type: "ERROR", - to - }); - } - return /* @__PURE__ */ h(Redirect, { to }); - }; - } - const LoginPageAccessDenied = () => { - return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h( - NotificationCard, + const accounts = !instance || instance instanceof TalerError || instance.type === "fail" ? void 0 : instance.body; + const shouldWarnAboutMissingBankAccounts = !state.isAdmin && accounts !== void 0 && accounts.accounts.length < 1 && (AbsoluteTime.isNever(preference.hideMissingAccountUntil) || AbsoluteTime.cmp(now2, preference.hideMissingAccountUntil) > 1); + const shouldLogin = state.status === "loggedOut" || state.status === "expired"; + if (shouldLogin) { + return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(NotConnectedAppMenu, { title: "Welcome!" }), /* @__PURE__ */ h(LoginPage, null)); + } + if (shouldWarnAboutMissingBankAccounts) { + return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(Menu, null), /* @__PURE__ */ h(BankAccountBanner, null), /* @__PURE__ */ h( + CreateValidator, { - notification: { - message: i18n2.str`Access denied`, - description: i18n2.str`Session expired or password changed.`, - type: "ERROR" + onConfirm: () => { + route("/bank" /* bank_list */); } } - ), /* @__PURE__ */ h(LoginPage, { onConfirm: changeToken })); - }; - function IfAdminCreateDefaultOr(Next) { - return function IfAdminCreateDefaultOrImpl(props) { - if (admin && id === "default") { - return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h( - NotificationCard, - { - notification: { - message: i18n2.str`No 'default' instance configured yet.`, - description: i18n2.str`Create a 'default' instance to begin using the merchant backoffice.`, - type: "INFO" - } - } - ), /* @__PURE__ */ h( - Create, - { - forceId: "default", - onConfirm: () => { - route("/bank" /* bank_list */); - } - } - )); - } - if (props) { - return /* @__PURE__ */ h(Next, { ...props }); - } - return /* @__PURE__ */ h(Next, null); - }; + )); } - const clearTokenAndGoToRoot = () => { - route("/"); - updateToken(void 0); - updateDefaultToken(void 0); - }; - if (accounts !== void 0 && !admin && accounts.length < 1) { - return /* @__PURE__ */ h(InstanceContextProvider, { value }, /* @__PURE__ */ h( - Menu, - { - instance: id, - admin, - onShowSettings: () => { - route("/interface" /* interface */); - }, - path, - onLogout: clearTokenAndGoToRoot, - setInstanceName, - isPasswordOk: defaultToken !== void 0 - } - ), /* @__PURE__ */ h(NotificationCard, { notification: { - type: "INFO", - message: i18n2.str`You need to associate a bank account to receive revenue.`, - description: i18n2.str`Without this the merchant backend will refuse to create new orders.` - } }), /* @__PURE__ */ h(CreateValidator, { onConfirm: () => { - } })); - } - return /* @__PURE__ */ h(InstanceContextProvider, { value }, /* @__PURE__ */ h( - Menu, + return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(Menu, null), /* @__PURE__ */ h(KycBanner, null), /* @__PURE__ */ h(NotificationCard, { notification: globalNotification }), error2 && /* @__PURE__ */ h( + NotificationCard, { - instance: id, - admin, - onShowSettings: () => { - route("/interface" /* interface */); - }, - path, - onLogout: clearTokenAndGoToRoot, - setInstanceName, - isPasswordOk: defaultToken !== void 0 - } - ), /* @__PURE__ */ h(KycBanner, null), /* @__PURE__ */ h(NotificationCard, { notification: globalNotification }), error2 && /* @__PURE__ */ h(NotificationCard, { notification: { - message: "Internal error, please repot", - type: "ERROR", - description: /* @__PURE__ */ h("pre", null, error2 instanceof Error ? error2.stack : String(error2)) - } }), /* @__PURE__ */ h( + notification: { + message: "Internal error, please repot", + type: "ERROR", + description: /* @__PURE__ */ h("pre", null, error2 instanceof Error ? error2.stack : String(error2)) + } + } + ), /* @__PURE__ */ h( Router, { + history: history2, onChange: (e4) => { const movingOutFromNotification = globalNotification && e4.url !== globalNotification.to; if (movingOutFromNotification) { @@ -49449,7 +52256,7 @@ function InstanceRoutes({ } }, /* @__PURE__ */ h(Route, { path: "/", component: Redirect, to: "/orders" /* order_list */ }), - admin && /* @__PURE__ */ h( + state.isAdmin && /* @__PURE__ */ h( Route, { path: "/instances" /* list_instances */, @@ -49457,26 +52264,23 @@ function InstanceRoutes({ onCreate: () => { route("/instance/new" /* new_instance */); }, - onUpdate: (id2) => { - route(`/instance/${id2}/update`); - }, - setInstanceName, - onUnauthorized: LoginPageAccessDenied, - onLoadError: ServerErrorRedirectTo("/error" /* error */) + onUpdate: (id) => { + route(`/instance/${id}/update`); + } } ), - admin && /* @__PURE__ */ h( + state.isAdmin && /* @__PURE__ */ h( Route, { path: "/instance/new" /* new_instance */, component: Create, onBack: () => route("/instances" /* list_instances */), onConfirm: () => { - route("/orders" /* order_list */); + route("/instances" /* list_instances */); } } ), - admin && /* @__PURE__ */ h( + state.isAdmin && /* @__PURE__ */ h( Route, { path: "/instance/:id/update" /* update_instance */, @@ -49484,10 +52288,7 @@ function InstanceRoutes({ onBack: () => route("/instances" /* list_instances */), onConfirm: () => { route("/instances" /* list_instances */); - }, - onUpdateError: ServerErrorRedirectTo("/instances" /* list_instances */), - onLoadError: ServerErrorRedirectTo("/instances" /* list_instances */), - onNotFound: NotFoundPage + } } ), /* @__PURE__ */ h( @@ -49500,11 +52301,7 @@ function InstanceRoutes({ }, onConfirm: () => { route(`/`); - }, - onUpdateError: noop2, - onNotFound: IfAdminCreateDefaultOr(NotFoundPage), - onUnauthorized: LoginPageAccessDenied, - onLoadError: ServerErrorRedirectTo("/error" /* error */) + } } ), /* @__PURE__ */ h( @@ -49517,10 +52314,7 @@ function InstanceRoutes({ }, onCancel: () => { route("/orders" /* order_list */); - }, - onNotFound: IfAdminCreateDefaultOr(NotFoundPage), - onUnauthorized: LoginPageAccessDenied, - onLoadError: ServerErrorRedirectTo("/error" /* error */) + } } ), /* @__PURE__ */ h( @@ -49528,15 +52322,12 @@ function InstanceRoutes({ { path: "/inventory" /* inventory_list */, component: ProductList2, - onUnauthorized: LoginPageAccessDenied, - onLoadError: ServerErrorRedirectTo("/settings" /* settings */), onCreate: () => { route("/inventory/new" /* inventory_new */); }, - onSelect: (id2) => { - route("/inventory/:pid/update" /* inventory_update */.replace(":pid", id2)); - }, - onNotFound: IfAdminCreateDefaultOr(NotFoundPage) + onSelect: (id) => { + route("/inventory/:pid/update" /* inventory_update */.replace(":pid", id)); + } } ), /* @__PURE__ */ h( @@ -49544,15 +52335,12 @@ function InstanceRoutes({ { path: "/inventory/:pid/update" /* inventory_update */, component: UpdateProduct, - onUnauthorized: LoginPageAccessDenied, - onLoadError: ServerErrorRedirectTo("/inventory" /* inventory_list */), onConfirm: () => { route("/inventory" /* inventory_list */); }, onBack: () => { route("/inventory" /* inventory_list */); - }, - onNotFound: IfAdminCreateDefaultOr(NotFoundPage) + } } ), /* @__PURE__ */ h( @@ -49573,15 +52361,12 @@ function InstanceRoutes({ { path: "/bank" /* bank_list */, component: ListOtpDevices, - onUnauthorized: LoginPageAccessDenied, - onLoadError: ServerErrorRedirectTo("/settings" /* settings */), onCreate: () => { route("/bank/new" /* bank_new */); }, - onSelect: (id2) => { - route("/bank/:bid/update" /* bank_update */.replace(":bid", id2)); - }, - onNotFound: IfAdminCreateDefaultOr(NotFoundPage) + onSelect: (id) => { + route("/bank/:bid/update" /* bank_update */.replace(":bid", id)); + } } ), /* @__PURE__ */ h( @@ -49589,15 +52374,12 @@ function InstanceRoutes({ { path: "/bank/:bid/update" /* bank_update */, component: UpdateValidator, - onUnauthorized: LoginPageAccessDenied, - onLoadError: ServerErrorRedirectTo("/inventory" /* inventory_list */), onConfirm: () => { route("/bank" /* bank_list */); }, onBack: () => { route("/bank" /* bank_list */); - }, - onNotFound: IfAdminCreateDefaultOr(NotFoundPage) + } } ), /* @__PURE__ */ h( @@ -49621,12 +52403,9 @@ function InstanceRoutes({ onCreate: () => { route("/order/new" /* order_new */); }, - onSelect: (id2) => { - route("/order/:oid/details" /* order_details */.replace(":oid", id2)); - }, - onUnauthorized: LoginPageAccessDenied, - onLoadError: ServerErrorRedirectTo("/settings" /* settings */), - onNotFound: IfAdminCreateDefaultOr(NotFoundPage) + onSelect: (id) => { + route("/order/:oid/details" /* order_details */.replace(":oid", id)); + } } ), /* @__PURE__ */ h( @@ -49634,9 +52413,6 @@ function InstanceRoutes({ { path: "/order/:oid/details" /* order_details */, component: Update, - onUnauthorized: LoginPageAccessDenied, - onLoadError: ServerErrorRedirectTo("/orders" /* order_list */), - onNotFound: IfAdminCreateDefaultOr(NotFoundPage), onBack: () => { route("/orders" /* order_list */); } @@ -49660,9 +52436,6 @@ function InstanceRoutes({ { path: "/transfers" /* transfers_list */, component: ListTransfer, - onUnauthorized: LoginPageAccessDenied, - onNotFound: IfAdminCreateDefaultOr(NotFoundPage), - onLoadError: ServerErrorRedirectTo("/settings" /* settings */), onCreate: () => { route("/transfer/new" /* transfers_new */); } @@ -49686,14 +52459,11 @@ function InstanceRoutes({ { path: "/webhooks" /* webhooks_list */, component: ListWebhooks, - onUnauthorized: LoginPageAccessDenied, - onNotFound: IfAdminCreateDefaultOr(NotFoundPage), - onLoadError: ServerErrorRedirectTo("/settings" /* settings */), onCreate: () => { route("/webhooks/new" /* webhooks_new */); }, - onSelect: (id2) => { - route("/webhooks/:tid/update" /* webhooks_update */.replace(":tid", id2)); + onSelect: (id) => { + route("/webhooks/:tid/update" /* webhooks_update */.replace(":tid", id)); } } ), @@ -49705,9 +52475,6 @@ function InstanceRoutes({ onConfirm: () => { route("/webhooks" /* webhooks_list */); }, - onUnauthorized: LoginPageAccessDenied, - onLoadError: ServerErrorRedirectTo("/webhooks" /* webhooks_list */), - onNotFound: IfAdminCreateDefaultOr(NotFoundPage), onBack: () => { route("/webhooks" /* webhooks_list */); } @@ -49731,14 +52498,11 @@ function InstanceRoutes({ { path: "/otp-devices" /* otp_devices_list */, component: ListOtpDevices2, - onUnauthorized: LoginPageAccessDenied, - onNotFound: IfAdminCreateDefaultOr(NotFoundPage), - onLoadError: ServerErrorRedirectTo("/settings" /* settings */), onCreate: () => { route("/otp-devices/new" /* otp_devices_new */); }, - onSelect: (id2) => { - route("/otp-devices/:vid/update" /* otp_devices_update */.replace(":vid", id2)); + onSelect: (id) => { + route("/otp-devices/:vid/update" /* otp_devices_update */.replace(":vid", id)); } } ), @@ -49750,9 +52514,6 @@ function InstanceRoutes({ onConfirm: () => { route("/otp-devices" /* otp_devices_list */); }, - onUnauthorized: LoginPageAccessDenied, - onLoadError: ServerErrorRedirectTo("/otp-devices" /* otp_devices_list */), - onNotFound: IfAdminCreateDefaultOr(NotFoundPage), onBack: () => { route("/otp-devices" /* otp_devices_list */); } @@ -49776,20 +52537,17 @@ function InstanceRoutes({ { path: "/templates" /* templates_list */, component: ListTemplates, - onUnauthorized: LoginPageAccessDenied, - onNotFound: IfAdminCreateDefaultOr(NotFoundPage), - onLoadError: ServerErrorRedirectTo("/settings" /* settings */), onCreate: () => { route("/templates/new" /* templates_new */); }, - onNewOrder: (id2) => { - route("/templates/:tid/use" /* templates_use */.replace(":tid", id2)); + onNewOrder: (id) => { + route("/templates/:tid/use" /* templates_use */.replace(":tid", id)); }, - onQR: (id2) => { - route("/templates/:tid/qr" /* templates_qr */.replace(":tid", id2)); + onQR: (id) => { + route("/templates/:tid/qr" /* templates_qr */.replace(":tid", id)); }, - onSelect: (id2) => { - route("/templates/:tid/update" /* templates_update */.replace(":tid", id2)); + onSelect: (id) => { + route("/templates/:tid/update" /* templates_update */.replace(":tid", id)); } } ), @@ -49801,9 +52559,6 @@ function InstanceRoutes({ onConfirm: () => { route("/templates" /* templates_list */); }, - onUnauthorized: LoginPageAccessDenied, - onLoadError: ServerErrorRedirectTo("/templates" /* templates_list */), - onNotFound: IfAdminCreateDefaultOr(NotFoundPage), onBack: () => { route("/templates" /* templates_list */); } @@ -49827,12 +52582,9 @@ function InstanceRoutes({ { path: "/templates/:tid/use" /* templates_use */, component: TemplateUsePage, - onOrderCreated: (id2) => { - route("/order/:oid/details" /* order_details */.replace(":oid", id2)); + onOrderCreated: (id) => { + route("/order/:oid/details" /* order_details */.replace(":oid", id)); }, - onUnauthorized: LoginPageAccessDenied, - onLoadError: ServerErrorRedirectTo("/templates" /* templates_list */), - onNotFound: IfAdminCreateDefaultOr(NotFoundPage), onBack: () => { route("/templates" /* templates_list */); } @@ -49843,9 +52595,6 @@ function InstanceRoutes({ { path: "/templates/:tid/qr" /* templates_qr */, component: TemplateQrPage, - onUnauthorized: LoginPageAccessDenied, - onLoadError: ServerErrorRedirectTo("/templates" /* templates_list */), - onNotFound: IfAdminCreateDefaultOr(NotFoundPage), onBack: () => { route("/templates" /* templates_list */); } @@ -49867,263 +52616,398 @@ function AdminInstanceUpdatePage({ id, ...rest }) { - const [token, changeToken] = useBackendInstanceToken(id); - const updateLoginStatus = (token2) => { - changeToken(token2); - }; - const value = F( - () => ({ id, token, admin: true, changeToken }), - [id, token] - ); - const { i18n: i18n2 } = useTranslationContext(); - return /* @__PURE__ */ h(InstanceContextProvider, { value }, /* @__PURE__ */ h( + return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h( AdminUpdate, { ...rest, - instanceId: id, - onLoadError: (error2) => { - const notif = error2.type === ErrorType.TIMEOUT ? { - message: i18n2.str`The request to the backend take too long and was cancelled`, - description: i18n2.str`Diagnostic from ${error2.info.url} is '${error2.message}'`, - type: "ERROR" - } : { - message: i18n2.str`The backend reported a problem: HTTP status #${error2.status}`, - description: i18n2.str`Diagnostic from ${error2.info.url} is '${error2.message}'`, - details: error2.type === ErrorType.CLIENT || error2.type === ErrorType.SERVER ? error2.payload.detail : void 0, - type: "ERROR" - }; - return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(NotificationCard, { notification: notif }), /* @__PURE__ */ h(LoginPage, { onConfirm: updateLoginStatus })); - }, - onUnauthorized: () => { - return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h( - NotificationCard, + instanceId: id + } + )); +} +function BankAccountBanner() { + const { i18n: i18n2 } = useTranslationContext(); + const [, updatePref] = usePreference(); + const now2 = AbsoluteTime.now(); + const oneDay = { d_ms: 1e3 * 60 * 60 * 24 }; + const tomorrow = AbsoluteTime.addDuration(now2, oneDay); + return /* @__PURE__ */ h( + NotificationCard, + { + notification: { + type: "INFO", + message: i18n2.str`You need to associate a bank account to receive revenue.`, + description: /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("p", null, /* @__PURE__ */ h(i18n2.Translate, null, "Without this the merchant backend will refuse to create new orders.")), /* @__PURE__ */ h("div", { class: "buttons is-right" }, /* @__PURE__ */ h( + "button", { - notification: { - message: i18n2.str`Access denied`, - description: i18n2.str`The access token provided is invalid`, - type: "ERROR" - } - } - ), /* @__PURE__ */ h(LoginPage, { onConfirm: updateLoginStatus })); + class: "button", + onClick: () => updatePref("hideMissingAccountUntil", tomorrow) + }, + /* @__PURE__ */ h(i18n2.Translate, null, "Hide for today") + ))) } } - )); + ); } function KycBanner() { const kycStatus = useInstanceKYCDetails(); const { i18n: i18n2 } = useTranslationContext(); - const [settings] = useSettings(); - const today = format(/* @__PURE__ */ new Date(), dateFormatForSettings(settings)); - const [lastHide, setLastHide] = useSimpleLocalStorage("kyc-last-hide"); - const hasBeenHidden = today === lastHide; - const needsToBeShown = kycStatus.ok && kycStatus.data.type === "redirect"; - if (hasBeenHidden || !needsToBeShown) + const [prefs, updatePref] = usePreference(); + const now2 = AbsoluteTime.now(); + const needsToBeShown = kycStatus !== void 0 && !(kycStatus instanceof TalerError) && kycStatus.type === "ok" && !!kycStatus.body; + const hidden = AbsoluteTime.cmp(now2, prefs.hideKycUntil) < 1; + if (hidden || !needsToBeShown) return /* @__PURE__ */ h(p2, null); + const oneDay = { d_ms: 1e3 * 60 * 60 * 24 }; + const tomorrow = AbsoluteTime.addDuration(now2, oneDay); return /* @__PURE__ */ h( NotificationCard, { notification: { type: "WARN", message: "KYC verification needed", - description: /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("p", null, "Some transfer are on hold until a KYC process is completed. Go to the KYC section in the left panel for more information"), /* @__PURE__ */ h("div", { class: "buttons is-right" }, /* @__PURE__ */ h("button", { class: "button", onClick: () => setLastHide(today) }, /* @__PURE__ */ h(i18n2.Translate, null, "Hide for today")))) + description: /* @__PURE__ */ h("div", null, /* @__PURE__ */ h("p", null, /* @__PURE__ */ h(i18n2.Translate, null, "Some transfer are on hold until a KYC process is completed. Go to the KYC section in the left panel for more information")), /* @__PURE__ */ h("div", { class: "buttons is-right" }, /* @__PURE__ */ h( + "button", + { + class: "button", + onClick: () => updatePref("hideKycUntil", tomorrow) + }, + /* @__PURE__ */ h(i18n2.Translate, null, "Hide for today") + ))) } } ); } -// src/ApplicationReadyRoutes.tsx -function ApplicationReadyRoutes() { - const { i18n: i18n2 } = useTranslationContext(); - const [unauthorized, setUnauthorized] = p3(false); - const { - url: backendURL, - updateToken, - alreadyTriedLogin - } = useBackendContext(); - function updateLoginStatus(token) { - updateToken(token); - setUnauthorized(false); - } - const result = useBackendInstancesTestForAdmin(); - const clearTokenAndGoToRoot = () => { - route("/"); - }; - const [showSettings, setShowSettings] = p3(false); - const unauthorizedAdmin = !result.loading && !result.ok && result.type === ErrorType.CLIENT && result.status === HttpStatusCode.Unauthorized; - if (!alreadyTriedLogin && !result.ok) { - return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(NotConnectedAppMenu, { title: "Welcome!" }), /* @__PURE__ */ h(LoginPage, { onConfirm: updateToken })); - } - if (showSettings) { - return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(NotYetReadyAppMenu, { onShowSettings: () => setShowSettings(true), title: "UI Settings", onLogout: clearTokenAndGoToRoot, isPasswordOk: false }), /* @__PURE__ */ h(Settings, { onClose: () => setShowSettings(false) })); - } - if (result.loading) { - return /* @__PURE__ */ h(NotYetReadyAppMenu, { onShowSettings: () => setShowSettings(true), title: "Loading...", isPasswordOk: false }); - } - let admin = result.ok || unauthorizedAdmin; - let instanceNameByBackendURL; - if (!admin) { - const path = new URL(backendURL).pathname; - const match6 = INSTANCE_ID_LOOKUP.exec(path); - if (!match6 || !match6[1]) { - return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(NotYetReadyAppMenu, { onShowSettings: () => setShowSettings(true), title: "Error", onLogout: clearTokenAndGoToRoot, isPasswordOk: false }), /* @__PURE__ */ h( - NotificationCard, - { - notification: { - message: i18n2.str`Couldn't access the server.`, - description: i18n2.str`Could not infer instance id from url ${backendURL}`, - type: "ERROR" - } - } - )); +// src/context/settings.ts +init_preact_module(); +init_hooks_module(); +var initial2 = {}; +var Context5 = B(initial2); +var SettingsProvider = ({ + children, + value +}) => { + return h(Context5.Provider, { + value, + children + }); +}; + +// src/settings.ts +var defaultSettings2 = { + backendBaseURL: buildDefaultBackendBaseURL() +}; +var codecForBankUISettings = () => buildCodecForObject().property("backendBaseURL", codecOptional(codecForString())).build("MerchantUiSettings"); +function removeUndefineField(obj) { + const keys = Object.keys(obj); + return keys.reduce((prev, cur) => { + if (typeof prev[cur] === "undefined") { + delete prev[cur]; } - instanceNameByBackendURL = match6[1]; + return prev; + }, obj); +} +function fetchSettings(listener) { + fetch("./settings.json").then((resp) => resp.json()).then((json) => codecForBankUISettings().decode(json)).then( + (result) => listener({ + ...defaultSettings2, + ...removeUndefineField(result) + }) + ).catch((e4) => { + console.log("failed to fetch settings", e4); + listener(defaultSettings2); + }); +} +function buildDefaultBackendBaseURL() { + if (typeof window !== "undefined") { + const currentLocation = new URL( + window.location.pathname, + window.location.origin + ).href; + return canonicalizeBaseUrl(currentLocation.replace("/webui", "")); } - if (unauthorized || unauthorizedAdmin) { - return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(NotYetReadyAppMenu, { onShowSettings: () => setShowSettings(true), title: "Login", onLogout: clearTokenAndGoToRoot, isPasswordOk: false }), /* @__PURE__ */ h( - NotificationCard, + throw Error("No default URL"); +} + +// src/Application.tsx +var WITH_LOCAL_STORAGE_CACHE = false; +function Application() { + const [settings, setSettings] = p3(); + h2(() => { + fetchSettings(setSettings); + }, []); + if (!settings) + return /* @__PURE__ */ h(Loading, null); + const baseUrl = getInitialBackendBaseURL(settings.backendBaseURL); + return /* @__PURE__ */ h(SettingsProvider, { value: settings }, /* @__PURE__ */ h( + TranslationProvider, + { + source: strings, + completeness: { + es: strings["es"].completeness, + de: strings["de"].completeness + } + }, + /* @__PURE__ */ h(MerchantApiProvider, { baseUrl: new URL("./", baseUrl), frameOnError: OnConfigError, evictors: { + management: swrCacheEvictor + } }, /* @__PURE__ */ h( + SWRConfig2, { - notification: { - message: i18n2.str`Access denied`, - description: i18n2.str`Check your token is valid`, - type: "ERROR" + value: { + provider: WITH_LOCAL_STORAGE_CACHE ? localStorageProvider : void 0, + // normally, do not revalidate + revalidateOnFocus: false, + revalidateOnReconnect: false, + revalidateIfStale: false, + revalidateOnMount: void 0, + focusThrottleInterval: void 0, + // normally, do not refresh + refreshInterval: void 0, + dedupingInterval: 2e3, + refreshWhenHidden: false, + refreshWhenOffline: false, + // ignore errors + shouldRetryOnError: false, + errorRetryCount: 0, + errorRetryInterval: void 0, + // do not go to loading again if already has data + keepPreviousData: true } - } - ), /* @__PURE__ */ h(LoginPage, { onConfirm: updateLoginStatus })); - } - const history2 = createHashHistory(); - return /* @__PURE__ */ h(Router, { history: history2 }, /* @__PURE__ */ h( - Route, - { - default: true, - component: DefaultMainRoute, - admin, - onUnauthorized: () => setUnauthorized(true), - onLoginPass: () => { - setUnauthorized(false); }, - instanceNameByBackendURL - } + /* @__PURE__ */ h(TalerWalletIntegrationBrowserProvider, null, /* @__PURE__ */ h(BrowserHashNavigationProvider, null, /* @__PURE__ */ h(Routing, null))) + )) )); } -function DefaultMainRoute({ - instance, - admin, - onUnauthorized, - onLoginPass, - instanceNameByBackendURL, - url - //from preact-router -}) { - const [instanceName, setInstanceName] = p3( - instanceNameByBackendURL || instance || "default" - ); - return /* @__PURE__ */ h( - InstanceRoutes, - { - admin, - path: url, - onUnauthorized, - onLoginPass, - id: instanceName, - setInstanceName +function getInitialBackendBaseURL(backendFromSettings) { + const overrideUrl = typeof localStorage !== "undefined" ? localStorage.getItem("merchant-base-url") : void 0; + let result; + if (overrideUrl) { + result = overrideUrl; + } else { + if (!backendFromSettings) { + console.error( + "ERROR: backendBaseURL was overridden by a setting file and missing. Setting value to 'window.origin'" + ); + result = buildDefaultBackendBaseURL(); + } else { + result = backendFromSettings; } - ); + } + try { + return canonicalizeBaseUrl(result); + } catch (e4) { + return canonicalizeBaseUrl(window.origin); + } } - -// src/Application.tsx -function Application() { - return /* @__PURE__ */ h(BackendContextProvider, null, /* @__PURE__ */ h(TranslationProvider, { source: strings }, /* @__PURE__ */ h(ApplicationStatusRoutes, null))); +function localStorageProvider() { + const map3 = new Map(JSON.parse(localStorage.getItem("app-cache") || "[]")); + window.addEventListener("beforeunload", () => { + const appCache = JSON.stringify(Array.from(map3.entries())); + localStorage.setItem("app-cache", appCache); + }); + return map3; } -function ApplicationStatusRoutes() { - const result = useBackendConfig(); +function OnConfigError({ state }) { const { i18n: i18n2 } = useTranslationContext(); - const configData = result.ok && result.data ? result.data : void 0; - const ctx = F(() => configData, [configData]); - if (!result.ok) { - if (result.loading) - return /* @__PURE__ */ h(Loading, null); - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.Unauthorized) { - return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(NotConnectedAppMenu, { title: "Login" }), /* @__PURE__ */ h( - NotificationCard, - { - notification: { - message: i18n2.str`Checking the /config endpoint got authorization error`, - type: "ERROR", - description: `The /config endpoint of the backend server should be accessible` - } - } - )); - } - if (result.type === ErrorType.CLIENT && result.status === HttpStatusCode.NotFound) { - return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(NotConnectedAppMenu, { title: "Error" }), /* @__PURE__ */ h( - NotificationCard, - { - notification: { - message: i18n2.str`Could not find /config endpoint on this URL`, - type: "ERROR", - description: `Check the URL or contact the system administrator.` - } - } - )); - } - if (result.type === ErrorType.SERVER) { - /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(NotConnectedAppMenu, { title: "Error" }), /* @__PURE__ */ h( + if (!state) { + return /* @__PURE__ */ h(i18n2.Translate, null, "checking compatibility with server..."); + } + switch (state.type) { + case "error": { + return /* @__PURE__ */ h( NotificationCard, { notification: { - message: i18n2.str`Server response with an error code`, - type: "ERROR", - description: i18n2.str`Got message "${result.message}" from ${result.info?.url}` + message: i18n2.str`Contacting the server failed`, + description: state.error.message, + details: JSON.stringify(state.error.errorDetail, void 0, 2), + type: "ERROR" } } - )); + ); } - if (result.type === ErrorType.UNREADABLE) { - /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(NotConnectedAppMenu, { title: "Error" }), /* @__PURE__ */ h( + case "incompatible": { + return /* @__PURE__ */ h( NotificationCard, { notification: { - message: i18n2.str`Response from server is unreadable, http status: ${result.status}`, - type: "ERROR", - description: i18n2.str`Got message "${result.message}" from ${result.info?.url}` + message: i18n2.str`The server version is not supported`, + description: i18n2.str`Supported version "${state.supported}", server version "${state.result.version}".`, + type: "WARN" } } - )); + ); } - return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(NotConnectedAppMenu, { title: "Error" }), /* @__PURE__ */ h( - NotificationCard, - { - notification: { - message: i18n2.str`Unexpected Error`, - type: "ERROR", - description: i18n2.str`Got message "${result.message}" from ${result.info?.url}` - } - } - )); + default: + assertUnreachable(state); } - const SUPPORTED_VERSION = "8:1:4"; - if (result.data && !LibtoolVersion.compare( - SUPPORTED_VERSION, - result.data.version - )?.compatible) { - return /* @__PURE__ */ h(p2, null, /* @__PURE__ */ h(NotConnectedAppMenu, { title: "Error" }), /* @__PURE__ */ h( - NotificationCard, - { - notification: { - message: i18n2.str`Incompatible version`, - type: "ERROR", - description: i18n2.str`Merchant backend server version ${result.data.version} is not compatible with the supported version ${SUPPORTED_VERSION}` - } +} +var swrCacheEvictor = new class { + async notifySuccess(op) { + switch (op) { + case TalerMerchantManagementCacheEviction.CREATE_INSTANCE: { + await Promise.all([ + revalidateBackendInstances() + ]); + return; } - )); + case TalerMerchantManagementCacheEviction.UPDATE_INSTANCE: { + await Promise.all([ + revalidateManagedInstanceDetails() + ]); + return; + } + case TalerMerchantManagementCacheEviction.DELETE_INSTANCE: { + await Promise.all([ + revalidateBackendInstances() + ]); + return; + } + case TalerMerchantInstanceCacheEviction.UPDATE_CURRENT_INSTANCE: { + await Promise.all([ + revalidateInstanceDetails() + ]); + return; + } + case TalerMerchantInstanceCacheEviction.DELETE_CURRENT_INSTANCE: { + await Promise.all([ + revalidateInstanceDetails() + ]); + return; + } + case TalerMerchantInstanceCacheEviction.CREATE_BANK_ACCOUNT: { + await Promise.all([ + revalidateInstanceBankAccounts() + ]); + return; + } + case TalerMerchantInstanceCacheEviction.UPDATE_BANK_ACCOUNT: { + await Promise.all([ + revalidateBankAccountDetails() + ]); + return; + } + case TalerMerchantInstanceCacheEviction.DELETE_BANK_ACCOUNT: { + await Promise.all([ + revalidateInstanceBankAccounts() + ]); + return; + } + case TalerMerchantInstanceCacheEviction.CREATE_PRODUCT: { + await Promise.all([ + revalidateInstanceProducts() + ]); + return; + } + case TalerMerchantInstanceCacheEviction.UPDATE_PRODUCT: { + await Promise.all([ + revalidateProductDetails() + ]); + return; + } + case TalerMerchantInstanceCacheEviction.DELETE_PRODUCT: { + await Promise.all([ + revalidateInstanceProducts() + ]); + return; + } + case TalerMerchantInstanceCacheEviction.CREATE_TRANSFER: { + await Promise.all([ + revalidateInstanceTransfers() + ]); + return; + } + case TalerMerchantInstanceCacheEviction.DELETE_TRANSFER: { + await Promise.all([ + revalidateInstanceTransfers() + ]); + return; + } + case TalerMerchantInstanceCacheEviction.CREATE_DEVICE: { + await Promise.all([ + revalidateInstanceOtpDevices() + ]); + return; + } + case TalerMerchantInstanceCacheEviction.UPDATE_DEVICE: { + await Promise.all([ + revalidateOtpDeviceDetails() + ]); + return; + } + case TalerMerchantInstanceCacheEviction.DELETE_DEVICE: { + await Promise.all([ + revalidateInstanceOtpDevices() + ]); + return; + } + case TalerMerchantInstanceCacheEviction.CREATE_TEMPLATE: { + await Promise.all([ + revalidateInstanceTemplates() + ]); + return; + } + case TalerMerchantInstanceCacheEviction.UPDATE_TEMPLATE: { + await Promise.all([ + revalidateTemplateDetails() + ]); + return; + } + case TalerMerchantInstanceCacheEviction.DELETE_TEMPLATE: { + await Promise.all([ + revalidateInstanceTemplates() + ]); + return; + } + case TalerMerchantInstanceCacheEviction.CREATE_WEBHOOK: { + await Promise.all([ + revalidateInstanceWebhooks() + ]); + return; + } + case TalerMerchantInstanceCacheEviction.UPDATE_WEBHOOK: { + await Promise.all([ + revalidateWebhookDetails() + ]); + return; + } + case TalerMerchantInstanceCacheEviction.DELETE_WEBHOOK: { + await Promise.all([ + revalidateInstanceWebhooks() + ]); + return; + } + case TalerMerchantInstanceCacheEviction.CREATE_ORDER: { + await Promise.all([ + revalidateInstanceOrders() + ]); + return; + } + case TalerMerchantInstanceCacheEviction.UPDATE_ORDER: { + await Promise.all([ + revalidateOrderDetails() + ]); + return; + } + case TalerMerchantInstanceCacheEviction.DELETE_ORDER: { + await Promise.all([ + revalidateInstanceOrders() + ]); + return; + } + case TalerMerchantInstanceCacheEviction.LAST: + } } - return /* @__PURE__ */ h("div", { class: "has-navbar-fixed-top" }, /* @__PURE__ */ h(ConfigContextProvider, { value: ctx }, /* @__PURE__ */ h(ApplicationReadyRoutes, null))); -} +}(); // src/index.tsx init_preact_module(); var app = document.getElementById("app"); -P(/* @__PURE__ */ h(Application, null), app); +if (app) { + P(/* @__PURE__ */ h(Application, null), app); +} else { + console.error("HTML element with id 'app' not found."); +} /*! Bundled license information: jed/jed.js: |