diff --git a/types/invity-api/index.d.ts b/types/invity-api/index.d.ts index 711ed66b675e4a..a2728cddcc2c38 100644 --- a/types/invity-api/index.d.ts +++ b/types/invity-api/index.d.ts @@ -69,6 +69,31 @@ export type FiatCurrencyCode = export type FiatCurrenciesProps = Record; +export interface ClientVersion { + client: string; + version: string; +} + +export interface ProviderMetadata { + name: string; // unique internal name, e.g. "changenow" + companyName: string; // name visible to clients, e.g. "ChangeNow" + logo: string; // logo image filename, e.g. "changenow-icon.jpg" + isActive: boolean; + isDisabled?: boolean; + disabledCurrencies?: string[]; // ['BTC', 'USD'] + supportedCountries?: string[]; // ['CZ', 'NL'] + disabledCountries?: string[]; + supportUrl?: string; // https://www.simplex.com/support/ + statusUrl?: string; // https://payment-status.simplex.com/api/v1/user/payments?uuid={{paymentId}} + termsUrl?: string; // https://www.simplex.com/terms-of-use/payment-terms + disabledClientVersions?: ClientVersion[]; +} + +export interface BuySellProviderMetadata extends ProviderMetadata { + supportedCountries: string[]; // ['AT', 'BE'] + tradedCoins: CryptoId[]; // ['BTC', 'BCH', 'LTC', 'XRP', 'ETH', 'bitcoin', 'ethereum', 'litecoin', 'ethereum--0xdac17f958d2ee523a2206206994597c13d831ec7'] +} + // buy types export type BuyTradeFinalStatus = @@ -119,22 +144,12 @@ export type BuyTradeTag = | "widget" | "noExternalAddress"; -export interface BuyProviderInfo { - name: string; // simplex - companyName: string; // UAB Invity Finance - brandName?: string; // Invity - logo: string; // simplex-icon.jpg - isActive: boolean; - isDisabled?: boolean; - tradedCoins: CryptoId[]; // ['bitcoin', 'ethereum', 'litecoin', 'ethereum--0xdac17f958d2ee523a2206206994597c13d831ec7'] +export interface BuyProviderInfo extends BuySellProviderMetadata { tradedFiatCurrencies: string[]; // ['EUR', 'USD'] - disabledCurrencies?: string[]; - supportedCountries: string[]; // ['CZ', 'NL'] - disabledCountries?: string[]; paymentMethods: BuyCryptoPaymentMethod[]; - statusUrl?: string; // https://payment-status.simplex.com/api/v1/user/payments?uuid={{paymentId}} - supportUrl?: string; // https://www.simplex.com/support/ - pendingTimeoutSeconds?: number; // Time until a SUBMITTED transaction automatically changes to APPROVAL_PENDING. Null means it does not change. + disabledPaymentMethods?: BuyCryptoPaymentMethod[]; + brandName?: string; // Invity + pendingTimeoutSeconds?: number; // time until a SUBMITTED transaction automatically changes to APPROVAL_PENDING, null means it does not change } export interface BuyListResponse { @@ -250,23 +265,18 @@ export type ExchangeMaximum = export type ExchangeTradeTag = "renewed" | "bestRate" | "favorite" | "kyc" | "widget" | "noExternalAddress"; export type ExchangeKYCType = "KYC-required" | "KYC-norefund" | "KYC-yesrefund" | "noKYC" | "DEX"; -export interface ExchangeProviderInfo { - name: string; // changenow - companyName: string; // ChangeNow - logo: string; // changenow-icon.jpg - isActive: boolean; +export interface ExchangeProviderInfo extends ProviderMetadata { isFixedRate: boolean; isDex: boolean; buyTickers: CryptoId[]; sellTickers: CryptoId[]; - addressFormats: StringMap; // specification of formats required by selected exchange - statusUrl: string; // https://changenow.io/exchange/txs/{{orderId}} + addressFormats: StringMap; kycUrl?: string; // https://changenow.io/faq#kyc supportUrl: string; // https://support.changenow.io // TODO region of operation - kycPolicy?: string | undefined; + kycPolicy?: string; kycPolicyType: ExchangeKYCType; - isRefundRequired?: boolean | undefined; + isRefundRequired?: boolean; } export type ExchangeListResponse = ExchangeProviderInfo[]; @@ -463,25 +473,16 @@ export type SellProviderType = "Fiat" | "Voucher"; export type SellFiatFlowType = "BANK_ACCOUNT" | "PAYMENT_GATE" | "N/A"; -export interface SellProviderInfo { - name: string; // simplex - companyName: string; // Simplex - logo: string; // simplex-icon.jpg +export interface SellProviderInfo extends BuySellProviderMetadata { type: SellProviderType; - isActive: boolean; - tradedCoins: CryptoId[]; // ['bitcoin', 'bitcoin-cash', 'litecoin'] - tradedFiatCurrencies?: string[] | undefined; // ['EUR', 'USD'] - supportedCountries: string[]; // ['AT', 'BE'] - statusUrl?: string | undefined; // https://payment-status.simplex.com/api/v1/user/payments?uuid={{paymentId}} - supportUrl?: string | undefined; // https://www.simplex.com/support/ - quoteInfo?: string | undefined; // some info text shown on quote - voucherSiteOrigin?: string | undefined; - paymentMethods?: SellCryptoPaymentMethod[] | undefined; - flow?: SellFiatFlowType | undefined; - isRefundAddressRequired?: boolean | undefined; - pendingTimeout?: number | undefined; // Time until a SUBMITTED transaction automatically changes to PENDING. Null means it does not change. - /** Should be used when it's necessary to have the exact amount match between the trade and the transaction */ - lockSendAmount?: boolean; + tradedFiatCurrencies?: string[]; // ['EUR', 'USD'] + quoteInfo?: string; // some info text shown on quote + paymentMethods?: SellCryptoPaymentMethod[]; + disabledPaymentMethods?: SellCryptoPaymentMethod[]; + flow?: SellFiatFlowType; + isRefundAddressRequired?: boolean; + pendingTimeout?: number; // time until a SUBMITTED transaction automatically changes to PENDING, null means it does not change + lockSendAmount?: boolean; // should be used when it's necessary to have the exact amount match between the trade and the transaction */ } export interface SellListResponse { diff --git a/types/invity-api/invity-api-tests.ts b/types/invity-api/invity-api-tests.ts index 8ee1e61da1d624..74412b7324ae8c 100644 --- a/types/invity-api/invity-api-tests.ts +++ b/types/invity-api/invity-api-tests.ts @@ -67,6 +67,9 @@ const providerInfo: BuyProviderInfo = { tradedFiatCurrencies: [], supportedCountries: [], paymentMethods: [], + statusUrl: "https://test-finance.invity.io/#status/{{paymentId}}", + supportUrl: "", + termsUrl: "https://invity.io/terms-of-use-invity-finance", }; const infoResponse: InfoResponse = { @@ -105,7 +108,8 @@ const exchangeProviderInfo: ExchangeProviderInfo = { }, statusUrl: "https://example.com/txs/{{orderId}}", kycUrl: "https://example.com/faq#kyc", - supportUrl: " https://support.example.com", + supportUrl: "https://support.example.com", + termsUrl: "https://example.com/legal/terms-of-use", kycPolicy: "KYC is required...", kycPolicyType: "KYC-norefund", isRefundRequired: false, @@ -122,6 +126,7 @@ const sellProviderInfo: SellProviderInfo = { supportedCountries: ["US"], statusUrl: "https://example.com/txs/{{orderId}}", supportUrl: " https://support.example.com", + termsUrl: "https://example.com/legal/terms-of-use", flow: "PAYMENT_GATE", isRefundAddressRequired: false, lockSendAmount: false, diff --git a/types/mokapi/faker.d.ts b/types/mokapi/faker.d.ts index 3a8ec9953466ef..5bd637b19a52f8 100644 --- a/types/mokapi/faker.d.ts +++ b/types/mokapi/faker.d.ts @@ -13,9 +13,13 @@ export function fake(schema: Schema | JSONSchema): any; /** - * Retrieves a node from the faker tree by its name. + * Retrieves a node from the faker tree by its name or path. * - * @param name name - The name of the node to find. + * A node can be referenced either by its simple name (e.g. `"name"`) or by a path + * that describes its location in the tree (e.g. `"/person/name"` for an absolute + * path from the root, or `"middle/name"` for a relative path). + * + * @param name name - The name or path of the node to find. * @returns The matching {@link Node} from the faker tree. * * @example diff --git a/types/mokapi/http.d.ts b/types/mokapi/http.d.ts index 16cac176152f1f..18410b02215956 100644 --- a/types/mokapi/http.d.ts +++ b/types/mokapi/http.d.ts @@ -86,13 +86,105 @@ export function del(url: string, body?: JSONValue, args?: Args): Response; */ export function options(url: string, body?: JSONValue, args?: Args): Response; +/** + * Sends an HTTP request and returns a Promise resolving to the response. + * + * @param {string} url - The URL to request. + * @param {FetchOptions} opts - Optional fetch configuration. + * @returns {Promise} A Promise that resolves with the response. + * + * @example + * // Simple GET request + * const res = await fetch('https://foo.bar/api'); + * const data = await res.json(); + * + * @example + * // POST request with JSON body + * const res = await fetch('https://foo.bar/api', { + * method: 'POST', + * headers: { 'Content-Type': 'application/json' }, + * body: { name: 'Alice' } + * }); + * + * @example + * // Request with timeout and redirect settings + * const res = await fetch('https://foo.bar/api', { + * timeout: '5s', + * maxRedirects: 2 + * }); + */ +export function fetch(url: string, opts?: FetchOptions): Promise; + /** * Request arguments. * Used to add headers to a request. */ export interface Args { /** Request headers. */ - header?: { [name: string]: string }; + headers?: { [name: string]: string }; + /** + * The number of redirects to follow for this request. + * @default 5 + */ + maxRedirects?: number; + /** + * Maximum time to wait for the request to complete. Default + * timeout is 60 seconds ("60s"). The type can also be a number, in which + * case Mokapi interprets it as milliseconds + * @example + * const res = get(url, { timeout: '5m' }) + */ + timeout?: number | string; +} + +/** + * Options for the {@link fetch} function. + */ +export interface FetchOptions { + /** + * HTTP method to use for the request. + * @default "GET" + * @example + * const res = await fetch(url, { method: 'POST' }); + */ + method?: string; + + /** + * The body of the request, such as a string or object. + * @example + * const res = await fetch(url, { body: JSON.stringify({ name: 'Alice' }) }); + */ + body?: any; + + /** + * Request headers. + * @example + * const res = await fetch(url, { + * headers: { 'Authorization': 'Bearer token123' } + * }); + */ + headers?: { [name: string]: string }; + + /** + * The number of redirects to follow for this request. + * @default 5 + * @example + * const res = await fetch(url, { maxRedirects: 1 }); + */ + maxRedirects?: number; + + /** + * Maximum time to wait for the request to complete. Default + * timeout is 60 seconds ("60s"). The type can also be a number, in which + * case Mokapi interprets it as milliseconds + * @default "60s" + * @example + * const res = get(url, { timeout: '5m' }) + * @example + * // Timeout as milliseconds + * const res = await fetch(url, { timeout: 3000 }); + */ + timeout?: number | string; } /** diff --git a/types/mokapi/index.d.ts b/types/mokapi/index.d.ts index 0cba30baa8e02c..481866a3b7c3da 100644 --- a/types/mokapi/index.d.ts +++ b/types/mokapi/index.d.ts @@ -130,7 +130,10 @@ export type HttpEventHandler = (request: HttpRequest, response: HttpResponse) => * https://mokapi.io/docs/javascript-api/mokapi/eventhandler/httprequest */ export interface HttpRequest { - /** Request method. */ + /** + * Request method. + * @example GET + */ readonly method: string; /** Represents a parsed URL. */ @@ -151,6 +154,9 @@ export interface HttpRequest { /** Object contains cookie parameters specified by OpenAPI cookie parameters. */ readonly cookie: { [key: string]: any }; + /** Object contains querystring parameters specified by OpenAPI querystring parameters. */ + readonly querystring: any; + /** Path value specified by the OpenAPI path */ readonly key: string; @@ -406,13 +412,33 @@ export type DateLayout = | "RFC3339Nano"; /** - * Additional event arguments + * EventArgs object contains additional arguments for an event handler. + * https://mokapi.io/docs/javascript-api/mokapi/on + * + * Use this to customize how the event appears in the dashboard or to control tracking. + * + * @example + * export default function() { + * on('http', function(req, res) { + * res.data = { message: "tracked event" } + * }, { + * tags: { feature: 'beta', owner: 'team-a' }, + * track: true + * }) + * } */ export interface EventArgs { /** - * Adds or overrides existing tags used in dashboard + * Optional key-value pairs used to label the event in the dashboard. */ tags?: { [key: string]: string }; + + /** + * Set to `true` to enable tracking of this event handler in the dashboard. + * If omitted, Mokapi automatically checks whether the response object has + * been modified and tracks the handler only if a change is detected. + */ + track?: boolean; } /** @@ -510,3 +536,99 @@ export function patch(target: any, patch: any): any; * // result: { name: "foo" } */ export const Delete: unique symbol; + +export interface SharedMemory { + /** + * Returns the value associated with the given key. + * @param key The key to retrieve. + * @returns The stored value, or `undefined` if not found. + */ + get(key: string): any; + + /** + * Sets a value for the given key. + * If the key already exists, its value will be replaced. + * @param key The key to store the value under. + * @param value The value to store. + */ + set(key: string, value: any): void; + + /** + * Updates a value atomically using an updater function. + * The current value is passed into the updater function. + * The returned value is stored and also returned by this method. + * + * Example: + * ```js + * mokapi.shared.update("requests", count => (count ?? 0) + 1) + * ``` + * + * @param key The key to update. + * @param updater Function that receives the current value and returns the new value. + * @returns The new value after update. + */ + update(key: string, updater: (value: T | undefined) => T): T; + + /** + * Checks if the given key exists in shared memory. + * @param key The key to check. + * @returns `true` if the key exists, otherwise `false`. + */ + has(key: string): boolean; + + /** + * Removes the specified key and its value from shared memory. + * @param key The key to remove. + */ + delete(key: string): void; + + /** + * Removes all stored entries from shared memory. + * Use with caution — this clears all shared state. + */ + clear(): void; + + /** + * Returns a list of all stored keys. + * @returns An array of key names. + */ + keys(): string[]; + + /** + * Creates or returns a namespaced shared memory store. + * Namespaces help avoid key collisions between unrelated scripts. + * + * Example: + * ```js + * const petstore = mokapi.shared.namespace("petstore") + * petstore.set("sessions", []) + * ``` + * + * @param name The namespace identifier. + * @returns A `SharedMemory` object scoped to the given namespace. + */ + namespace(name: string): SharedMemory; +} + +/** + * Shared memory API for Mokapi scripts. + * + * The `mokapi.shared` object provides a way to persist and share + * data between multiple scripts running in the same Mokapi instance. + * + * Values are stored in memory and shared across all scripts. + * This allows you to coordinate state, cache data, or simulate + * application-level variables without using global variables. + * All values are persisted for the lifetime of the Mokapi process. + * + * Example: + * ```js + * // Increment a shared counter + * mokapi.shared.update("counter", c => (c ?? 0) + 1) + * + * // Retrieve the current counter value + * const count = mokapi.shared.get("counter") + * mokapi.log(`Current counter: ${count}`) + * ``` + */ +export const shared: SharedMemory; diff --git a/types/mokapi/package.json b/types/mokapi/package.json index 94d052ea2e9a0d..8cbbcb8a79e11d 100644 --- a/types/mokapi/package.json +++ b/types/mokapi/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "@types/mokapi", - "version": "0.20.9999", + "version": "0.29.9999", "nonNpm": true, "nonNpmDescription": "Mokapi", "projects": [ diff --git a/types/mokapi/test/http-test.ts b/types/mokapi/test/http-test.ts index 939be4304db460..0a05334599f597 100644 --- a/types/mokapi/test/http-test.ts +++ b/types/mokapi/test/http-test.ts @@ -1,4 +1,4 @@ -import { del, get, head, options, patch, post, put } from "mokapi/http"; +import { del, fetch, get, head, options, patch, post, put } from "mokapi/http"; // @ts-expect-error get(); @@ -8,7 +8,10 @@ get("http://foo.bar"); // @ts-expect-error get("", 123); get("", {}); -get("", { header: { "Accept": "application/json" } }); +get("", { headers: { "Accept": "application/json" } }); +get("", { maxRedirects: 3 }); +get("http://foo.bar", { timeout: 3000 }); +get("http://foo.bar", { timeout: "3s" }); // @ts-expect-error post(); @@ -19,7 +22,10 @@ post("", 123); post("", { foo: "bar" }); // @ts-expect-error post("", {}, 123); -post("", "", { header: { "Accept": "application/json" } }); +post("", "", { headers: { "Accept": "application/json" } }); +post("", undefined, { maxRedirects: 3 }); +post("http://foo.bar", undefined, { timeout: 3000 }); +post("http://foo.bar", undefined, { timeout: "3s" }); // @ts-expect-error put(); @@ -30,14 +36,20 @@ put("", 123); put("", { foo: "bar" }); // @ts-expect-error put("", {}, 123); -put("", "", { header: { "Accept": "application/json" } }); +put("", "", { headers: { "Accept": "application/json" } }); +put("", undefined, { maxRedirects: 3 }); +put("http://foo.bar", undefined, { timeout: 3000 }); +put("http://foo.bar", undefined, { timeout: "3s" }); // @ts-expect-error head(); // @ts-expect-error head(123); head("http://foo.bar"); -head("", { header: { "Accept": "application/json" } }); +head("", { headers: { "Accept": "application/json" } }); +head("", { maxRedirects: 3 }); +head("http://foo.bar", { timeout: 3000 }); +head("http://foo.bar", { timeout: "3s" }); // @ts-expect-error patch(); @@ -48,7 +60,10 @@ patch("", 123); patch("", { foo: "bar" }); // @ts-expect-error patch("", {}, 123); -patch("", "", { header: { "Accept": "application/json" } }); +patch("", "", { headers: { "Accept": "application/json" } }); +patch("", undefined, { maxRedirects: 3 }); +patch("http://foo.bar", undefined, { timeout: 3000 }); +patch("http://foo.bar", undefined, { timeout: "3s" }); // @ts-expect-error del(); @@ -59,7 +74,10 @@ del("", 123); del("", { foo: "bar" }); // @ts-expect-error del("", {}, 123); -del("", "", { header: { "Accept": "application/json" } }); +del("", "", { headers: { "Accept": "application/json" } }); +del("", undefined, { maxRedirects: 3 }); +del("http://foo.bar", undefined, { timeout: 3000 }); +del("http://foo.bar", undefined, { timeout: "3s" }); // @ts-expect-error options(); @@ -70,4 +88,20 @@ options("", 123); options("", { foo: "bar" }); // @ts-expect-error options("", {}, 123); -options("", "", { header: { "Accept": "application/json" } }); +options("", "", { headers: { "Accept": "application/json" } }); +options("", { maxRedirects: 3 }); +options("http://foo.bar", undefined, { timeout: 3000 }); +options("http://foo.bar", undefined, { timeout: "3s" }); + +// @ts-expect-error +fetch(); +fetch("http://foo.bar"); +fetch("http://foo.bar", {}); +fetch("http://foo.bar", { method: "POST" }); +// @ts-expect-error +fetch("http://foo.bar", { method: 12 }); +fetch("http://foo.bar", { headers: { "Accept": "application/json" } }); +fetch("http://foo.bar", { body: { foo: "bar" } }); +fetch("http://foo.bar", { maxRedirects: 1 }); +fetch("http://foo.bar", { timeout: 3000 }); +fetch("http://foo.bar", { timeout: "3s" }); diff --git a/types/mokapi/test/mokapi-tests.ts b/types/mokapi/test/mokapi-tests.ts index 071aad7946c7d5..f658ef792fda0d 100644 --- a/types/mokapi/test/mokapi-tests.ts +++ b/types/mokapi/test/mokapi-tests.ts @@ -14,6 +14,7 @@ import { LdapSearchResponse, on, patch, + shared, sleep, SmtpEventHandler, SmtpEventMessage, @@ -44,7 +45,11 @@ on("ldap", (req: LdapSearchRequest, res: LdapSearchResponse) => {}); on("http", handler, ""); on("http", handler, {}); on("http", handler, { tags: { foo: "bar" } }); +on("http", handler, { track: true }); on("http", async () => {}); +on("http", (request) => { + request.querystring; +}); // @ts-expect-error every(12, () => {}); @@ -307,3 +312,14 @@ patch({ x: 1 }, { y: 1 }); patch({ x: 1 }, { x: Delete }); patch([1, 2], [3, 4]); patch([1, 2], [undefined, Delete]); + +shared.set("foo", 123); +shared.set("foo", {}); +shared.delete("foo"); +let s: string | undefined = shared.get("foo"); +let n: number | undefined = shared.get("foo"); +let b: boolean = shared.has("foo"); +let keys: string[] = shared.keys(); +shared.namespace("foo").set("bar", 123); +shared.update("foo", (v) => v ?? "new value"); +shared.clear();