diff --git a/.gitignore b/.gitignore index 93f1361..060587b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ node_modules npm-debug.log + +.idea diff --git a/README.md b/README.md index 909b2af..9b7105d 100644 --- a/README.md +++ b/README.md @@ -35,22 +35,28 @@ for a more natural declaration. ## Quickstart ```js -const WyreClient = require('@wyre/api').WyreClient +const WyreClient = require('@wyre/api') -let wyre = new WyreClient({ - format: "json_numberstring", - apiKey: "AK-AAAAAAA-AAAAAAA-AAAAAAA-AAAAAAA", - secretKey: "SK-AAAAAAA-AAAAAAA-AAAAAAA-AAAAAAA" - // baseUrl: "https://api.testwyre.com" // todo uncomment this line to use the testwyre environment -}); - -wyre.get("/v2/account") - .then(account => { - console.log("I am Wyre account ", account.id); +const client = new WyreClient({ + auth: { + apiKey: 'AK-api-key', + secretKey: 'SK-secret-key' }, - err => { + version: '3', // Keep this unless doing manual api calls + // uri: 'https://api.testwyre.com', // Uncomment this line to use the testwyre environment + format: 'json_numberstring', + headers: {}, + qs: {} +}) + +// Get account from auth credentials +client.fetchAccount() + .then((account) => { + console.log("I am Wyre account ", account.id); + }) + .catch((err) => { console.log("Problems, cap'n: ", err); - }); + }) ``` You're all set to begin coding! @@ -59,7 +65,7 @@ You're all set to begin coding! Attempt a $10 USD->BTC conversion: ```js -wyre.post("/transfers", { +account.createTransfer({ sourceAmount: "10", sourceCurrency: "USD", destCurrency: "BTC", @@ -71,7 +77,7 @@ Upload a document: ```js var fs = require('fs'); let my_id = fs.readFileSync('./my_id.jpg'); -wyre.post('/v3/accounts/' + account.id + '/individualGovernmentId', +client.api.post('accounts/' + account.id + '/individualGovernmentId', my_id, { headers: { 'Content-Type': 'image/jpeg' }}) .then(successCallback, errorCallback); @@ -89,11 +95,15 @@ Constructor parameters: | parameter | description | ----------|-------------- -| apiKey | your environment-specific Wyre API key -| secretKey | your environment-specific Wyre API secret -| baseUrl | specifies the Wyre environment you'd like to use. please use either:
`https://api.sendwyre.com` for production
`https://api.testwyre.com` for testwyre +| auth.apiKey | your environment-specific Wyre API key +| auth.secretKey | your environment-specific Wyre API secret +| auth.masqueradeTarget | sub-account id to masquerade as +| uri | specifies the Wyre environment you'd like to use. please use either:
`https://api.sendwyre.com` for production
`https://api.testwyre.com` for testwyre +| version | specifies the Wyre API version to use. Defaults to 3. | format | the data format you're requesting.
`json` for straight JSON
`json_numberstring` for JSON with all decimals as strings (see [above](#regarding-decimal-numbers)] -| options | options that are passed to the underlying [Request](https://github.com/request/request) for _every_ request +| headers | headers that are passed to the underlying [Request](https://github.com/request/request) for _every_ request +| qs | query string parameters that are passed to the underlying [Request](https://github.com/request/request) for _every_ request +| timeout | timeout limit for API request in milliseconds Note that the ability to override options used by the [Request](https://github.com/request/request) client is available both generally as well as per-request. @@ -106,10 +116,10 @@ or per-request (as with all options). Each of these methods performs a single Wyre API request and returns a promise for the resulting API response. ```js -wyre.get(path, parameters, options) -wyre.post(path, body, options) -wyre.put(path, body, options) -wyre.delete(path, body, options) +client.api.get(path, parameters, options) +client.api.post(path, body, options) +client.api.put(path, body, options) +client.api.delete(path, body, options) ``` ### Masquerading API @@ -118,14 +128,16 @@ This is an alternative to supplying the `masqueradeAs` parameter as a query para ```js // init the wyre client as usual -let wyre = new WyreClient({ /* your master api access setup here */ }); - -// create another sub-client authenticated as a particular user -let user1_wyre = wyre.masqueraded('AC-ABCDE12345'); - -// now use that client as normal! -user1_wyre.get('/v3/accounts/AC-ABCDE12345').then(successCallback, failureCallback); - +const client = new WyreClient({ /* your master api access setup here */ }); + +// Get sub-account with masquerade = true +client.fetchAccount('AC-sub-account-id', true) + .then((account) => { + console.log("I am Wyre sub-account ", account.id); + }) + .catch((err) => { + console.log("Problems, cap'n: ", err); + }) ``` ### Errors diff --git a/dist/Account.d.ts b/dist/Account.d.ts new file mode 100644 index 0000000..3206b4a --- /dev/null +++ b/dist/Account.d.ts @@ -0,0 +1,36 @@ +import Model from './Model'; +import Transfer from './Transfer'; +import PaymentMethod from './PaymentMethod'; +import Api from './utils/Api'; +import type { IAccount, IAccountResponse, ICreateAccountParams, IProfileField } from './Account/IAccount'; +import type { ICreateTransferParams } from './Transfer/ITransfer'; +import type { ILimits } from './wyre/ILimits'; +export default class Account extends Model implements IAccount { + id: string; + status: 'OPEN' | 'PENDING' | 'APPROVED'; + type: 'INDIVIDUAL' | 'BUSINESS'; + country: string; + createdAt: number; + depositAddresses: { + ETH: string; + BTC: string; + }; + totalBalances: { + BTC: number; + ETH: number; + }; + availableBalances: { + BTC: number; + ETH: number; + }; + profileFields: Array; + paymentMethods: Array; + static create(api: Api, params: ICreateAccountParams): Promise; + static fetch(api: Api, id: string): Promise; + protected static postFetch(data: IAccountResponse, api: Api): Promise; + save(): Promise; + createTransfer(params: ICreateTransferParams): Promise; + fetchTransfers(): Promise>; + fetchLimits(): Promise; +} +//# sourceMappingURL=Account.d.ts.map \ No newline at end of file diff --git a/dist/Account.d.ts.map b/dist/Account.d.ts.map new file mode 100644 index 0000000..9702544 --- /dev/null +++ b/dist/Account.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Account.d.ts","sourceRoot":"","sources":["../src/Account.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,SAAS,CAAA;AAC3B,OAAO,QAAQ,MAAM,YAAY,CAAA;AACjC,OAAO,aAAa,MAAM,iBAAiB,CAAA;AAC3C,OAAO,GAAG,MAAM,aAAa,CAAA;AAC7B,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AACzG,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAA;AACjE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AAE7C,MAAM,CAAC,OAAO,OAAO,OAAQ,SAAQ,KAAK,CAAC,OAAO,EAAE,QAAQ,CAAE,YAAW,QAAQ;IACxE,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,CAAA;IACvC,IAAI,EAAE,YAAY,GAAG,UAAU,CAAA;IAC/B,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,gBAAgB,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;IAC9C,aAAa,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;IAC3C,iBAAiB,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;IAC/C,aAAa,EAAE,KAAK,CAAC,aAAa,CAAC,CAAA;IACnC,cAAc,EAAE,KAAK,CAAC,aAAa,CAAC,CAAA;WAEvB,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,OAAO,CAAC;WAShE,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;qBAM1C,SAAS,CAAC,IAAI,EAAE,gBAAgB,EAAE,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC;IAKvE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAMrB,cAAc,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,QAAQ,CAAC;IAMhE,cAAc,IAAI,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAI1C,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;CAK7C"} \ No newline at end of file diff --git a/dist/Account.js b/dist/Account.js new file mode 100644 index 0000000..bea8cc2 --- /dev/null +++ b/dist/Account.js @@ -0,0 +1,161 @@ +"use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var Model_1 = require("./Model"); +var Transfer_1 = require("./Transfer"); +var PaymentMethod_1 = require("./PaymentMethod"); +var Account = (function (_super) { + __extends(Account, _super); + function Account() { + return _super !== null && _super.apply(this, arguments) || this; + } + Account.create = function (api, params) { + return __awaiter(this, void 0, void 0, function () { + var data; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + api.requireAuthed(); + return [4, api.post('accounts', params)]; + case 1: + data = _a.sent(); + if (params.subaccount) + api = api.masqueradeAs(data.id); + return [2, this.postFetch(data, api)]; + } + }); + }); + }; + Account.fetch = function (api, id) { + return __awaiter(this, void 0, void 0, function () { + var data; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + api.requireAuthed(); + return [4, api.get("accounts/" + id)]; + case 1: + data = _a.sent(); + return [2, this.postFetch(data, api)]; + } + }); + }); + }; + Account.postFetch = function (data, api) { + return __awaiter(this, void 0, void 0, function () { + var paymentMethods; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4, PaymentMethod_1.default.fetchAll(api)]; + case 1: + paymentMethods = _a.sent(); + return [2, new Account(__assign(__assign({}, data), { paymentMethods: paymentMethods }), api)]; + } + }); + }); + }; + Account.prototype.save = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + if (!this.data.isChanged) + return [2]; + return [4, this.api.post("accounts/" + this.id, this.data.updatedValues)]; + case 1: + _a.sent(); + return [2]; + } + }); + }); + }; + Account.prototype.createTransfer = function (params) { + return __awaiter(this, void 0, void 0, function () { + var transfer; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4, Transfer_1.default.create(this.api, params)]; + case 1: + transfer = _a.sent(); + return [2, transfer]; + } + }); + }); + }; + Account.prototype.fetchTransfers = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2, Transfer_1.default.fetchAll(this.api)]; + }); + }); + }; + Account.prototype.fetchLimits = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + this.api.requireAuthed(); + return [2, this.api.get('limits')]; + }); + }); + }; + return Account; +}(Model_1.default)); +exports.default = Account; diff --git a/dist/Account/IAccount.d.ts b/dist/Account/IAccount.d.ts new file mode 100644 index 0000000..20885e9 --- /dev/null +++ b/dist/Account/IAccount.d.ts @@ -0,0 +1,53 @@ +import type { IPaymentMethod } from '../PaymentMethod/IPaymentMethod'; +export interface IAccount extends IAccountResponse { + paymentMethods: Array; +} +export interface IAccountResponse { + id: string; + status: 'OPEN' | 'PENDING' | 'APPROVED'; + type: 'INDIVIDUAL' | 'BUSINESS'; + country: string; + createdAt: number; + depositAddresses: { + ETH: string; + BTC: string; + }; + totalBalances: { + BTC: number; + ETH: number; + }; + availableBalances: { + BTC: number; + ETH: number; + }; + profileFields: Array; +} +export interface IProfileField { + fieldId: IProfileFieldId; + fieldType: IProfileFieldType; + value: string | object | IProfileFieldValueAddress | Array | null; + note: string | null; + status: IProfileFieldStatus; +} +declare type IProfileFieldId = 'individualCellphoneNumber' | 'individualEmail' | 'individualLegalName' | 'individualDateOfBirth' | 'individualSsn' | 'individualResidenceAddress' | 'individualGovernmentId' | 'individualSourceOfFunds'; +declare type IProfileFieldType = 'CELLPHONE' | 'EMAIL' | 'STRING' | 'DATE' | 'ADDRESS' | 'DOCUMENT' | 'PAYMENT_METHOD'; +declare type IProfileFieldValueAddress = { + street1: string; + street2?: string; + city: string; + state: string; + postalCode: string; + country: string | 'US'; +}; +declare type IProfileFieldValueDocument = {}; +declare type IProfileFieldStatus = 'OPEN' | 'PENDING' | 'APPROVED' | 'NULL'; +export interface ICreateAccountParams { + type: string; + country: string; + profileFields: Array; + referrerAccountId?: string; + subaccount?: boolean; + disableEmail?: boolean; +} +export {}; +//# sourceMappingURL=IAccount.d.ts.map \ No newline at end of file diff --git a/dist/Account/IAccount.d.ts.map b/dist/Account/IAccount.d.ts.map new file mode 100644 index 0000000..bccd5e8 --- /dev/null +++ b/dist/Account/IAccount.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"IAccount.d.ts","sourceRoot":"","sources":["../../src/Account/IAccount.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAA;AAErE,MAAM,WAAW,QAAS,SAAQ,gBAAgB;IAChD,cAAc,EAAE,KAAK,CAAC,cAAc,CAAC,CAAA;CACtC;AACD,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,CAAA;IACvC,IAAI,EAAE,YAAY,GAAG,UAAU,CAAA;IAC/B,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,gBAAgB,EAAE;QAChB,GAAG,EAAE,MAAM,CAAA;QACX,GAAG,EAAE,MAAM,CAAA;KACZ,CAAA;IACD,aAAa,EAAE;QACb,GAAG,EAAE,MAAM,CAAA;QACX,GAAG,EAAE,MAAM,CAAA;KACZ,CAAA;IACD,iBAAiB,EAAE;QACjB,GAAG,EAAE,MAAM,CAAA;QACX,GAAG,EAAE,MAAM,CAAA;KACZ,CAAA;IACD,aAAa,EAAE,KAAK,CAAC,aAAa,CAAC,CAAA;CACpC;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,eAAe,CAAA;IACxB,SAAS,EAAE,iBAAiB,CAAA;IAC5B,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,yBAAyB,GAAG,KAAK,CAAC,0BAA0B,CAAC,GAAG,IAAI,CAAA;IAC7F,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,MAAM,EAAE,mBAAmB,CAAA;CAC5B;AACD,aAAK,eAAe,GAAG,2BAA2B,GAAG,iBAAiB,GAAG,qBAAqB,GAAG,uBAAuB,GAAG,eAAe,GAAG,4BAA4B,GAAG,wBAAwB,GAAG,yBAAyB,CAAA;AAChO,aAAK,iBAAiB,GAAG,WAAW,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,GAAG,UAAU,GAAG,gBAAgB,CAAA;AAC9G,aAAK,yBAAyB,GAAG;IAC/B,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CACvB,CAAA;AAED,aAAK,0BAA0B,GAAG,EAEjC,CAAA;AACD,aAAK,mBAAmB,GAAG,MAAM,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM,CAAA;AAEnE,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,aAAa,EAAE,KAAK,CAAC,aAAa,CAAC,CAAA;IACnC,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB"} \ No newline at end of file diff --git a/dist/Account/IAccount.js b/dist/Account/IAccount.js new file mode 100644 index 0000000..c8ad2e5 --- /dev/null +++ b/dist/Account/IAccount.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/dist/Model.d.ts b/dist/Model.d.ts new file mode 100644 index 0000000..7bdf0f6 --- /dev/null +++ b/dist/Model.d.ts @@ -0,0 +1,11 @@ +import Api from './utils/Api'; +import Data from './Model/Data'; +export default abstract class Model { + readonly api: Api; + readonly data: Data; + constructor(data: TData, api: Api); + set(data: object): void; + set(key: PropertyKey, value: any): void; + get(key: PropertyKey): T; +} +//# sourceMappingURL=Model.d.ts.map \ No newline at end of file diff --git a/dist/Model.d.ts.map b/dist/Model.d.ts.map new file mode 100644 index 0000000..e571ad1 --- /dev/null +++ b/dist/Model.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Model.d.ts","sourceRoot":"","sources":["../src/Model.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,aAAa,CAAA;AAC7B,OAAO,IAAI,MAAM,cAAc,CAAA;AAE/B,MAAM,CAAC,OAAO,CAAC,QAAQ,OAAO,KAAK,CAAC,CAAC,EAAE,KAAK,SAAS,MAAM;IACzD,SAAgB,GAAG,EAAE,GAAG,CAAA;IACxB,SAAgB,IAAI,EAAE,IAAI,CAAA;gBAEd,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG;IAS1B,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IACvB,GAAG,CAAC,GAAG,EAAE,WAAW,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI;IAKvC,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,WAAW,GAAG,CAAC;CAGnC"} \ No newline at end of file diff --git a/dist/Model.js b/dist/Model.js new file mode 100644 index 0000000..30e5856 --- /dev/null +++ b/dist/Model.js @@ -0,0 +1,38 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var Data_1 = require("./Model/Data"); +var Model = (function () { + function Model(data, api) { + this.api = api; + this.data = new Data_1.default(data); + var proxy = new Proxy(this, new ModelProxyHandler()); + return proxy; + } + Model.prototype.set = function (key, value) { + this.data.set(key, value); + }; + Model.prototype.get = function (key) { + return this.data.get(key); + }; + return Model; +}()); +exports.default = Model; +var ModelProxyHandler = (function () { + function ModelProxyHandler() { + } + ModelProxyHandler.prototype.getOwnPropertyDescriptor = function (target, p) { + return { enumerable: true, configurable: true }; + }; + ModelProxyHandler.prototype.set = function (target, key, value) { + key in target.data.updatedValues + ? target.set(key, value) + : target[key] = value; + return true; + }; + ModelProxyHandler.prototype.get = function (target, key) { + return key in target.data.updatedValues + ? target.get(key) + : target[key]; + }; + return ModelProxyHandler; +}()); diff --git a/dist/Model/Data.d.ts b/dist/Model/Data.d.ts new file mode 100644 index 0000000..ccbc913 --- /dev/null +++ b/dist/Model/Data.d.ts @@ -0,0 +1,9 @@ +export default class Data { + readonly initValues: object; + readonly updatedValues: object; + constructor(data: object); + get isChanged(): boolean; + set(key: PropertyKey | object, value?: any): void; + get(key: PropertyKey): T; +} +//# sourceMappingURL=Data.d.ts.map \ No newline at end of file diff --git a/dist/Model/Data.d.ts.map b/dist/Model/Data.d.ts.map new file mode 100644 index 0000000..47db31a --- /dev/null +++ b/dist/Model/Data.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Data.d.ts","sourceRoot":"","sources":["../../src/Model/Data.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,OAAO,IAAI;IACvB,SAAgB,UAAU,EAAE,MAAM,CAAA;IAClC,SAAgB,aAAa,EAAE,MAAM,CAAA;gBAEzB,IAAI,EAAE,MAAM;IAKxB,IAAW,SAAS,IAAI,OAAO,CAI9B;IAEM,GAAG,CAAC,GAAG,EAAE,WAAW,GAAG,MAAM,EAAE,KAAK,CAAC,EAAE,GAAG,GAAG,IAAI;IAUjD,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,WAAW,GAAG,CAAC;CAGnC"} \ No newline at end of file diff --git a/dist/Model/Data.js b/dist/Model/Data.js new file mode 100644 index 0000000..b07a26c --- /dev/null +++ b/dist/Model/Data.js @@ -0,0 +1,33 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var Data = (function () { + function Data(data) { + this.initValues = data; + this.updatedValues = data; + } + Object.defineProperty(Data.prototype, "isChanged", { + get: function () { + var initValues = JSON.stringify(this.initValues); + var updatedValues = JSON.stringify(this.updatedValues); + return initValues !== updatedValues; + }, + enumerable: true, + configurable: true + }); + Data.prototype.set = function (key, value) { + if (typeof key === 'object') { + for (var _i = 0, _a = Object.entries(key); _i < _a.length; _i++) { + var _b = _a[_i], k = _b[0], v = _b[1]; + this.updatedValues[k] = v; + } + } + else { + this.updatedValues[key] = value; + } + }; + Data.prototype.get = function (key) { + return this.updatedValues[key]; + }; + return Data; +}()); +exports.default = Data; diff --git a/dist/PaymentMethod.d.ts b/dist/PaymentMethod.d.ts new file mode 100644 index 0000000..b590abe --- /dev/null +++ b/dist/PaymentMethod.d.ts @@ -0,0 +1,44 @@ +import Model from './Model'; +import Api from './utils/Api'; +import type { IPaymentMethod, IPaymentMethodAttachBlockchainOptions, IPaymentMethodBlockchain, IPaymentMethodWireCreateParams } from './PaymentMethod/IPaymentMethod'; +export default class PaymentMethod extends Model implements IPaymentMethod { + beneficiaryType: string; + blockchains: object; + brand: null; + chargeFeeSchedule: null; + chargeableCurrencies: Array; + countryCode: string; + createdAt: number; + defaultCurrency: string; + depositFeeSchedule: null; + depositableCurrencies: Array; + disabled: boolean; + documents: Array; + expirationDisplay: string; + id: string; + last4Digits: string; + linkType: 'INTERNATIONAL_TRANSFER' | 'LOCAL_TRANSFER'; + liquidationBalances: object; + maxCharge: null; + maxDeposit: null; + minCharge: null; + minDeposit: null; + name: string; + nameOnMethod: string | null; + nickname: string | null; + owner: string; + rejectionMessage: string | null; + srn: string; + status: 'PENDING' | 'AWAITING_FOLLOWUP' | 'ACTIVE' | 'REJECTED'; + statusMessage: string; + supportsDeposit: boolean; + supportsPayment: boolean; + waitingPrompts: Array; + static createACH(api: Api, publicToken: string): Promise; + static createWire(api: Api, params: IPaymentMethodWireCreateParams): Promise; + static fetchAll(api: Api): Promise>; + static fetch(api: Api, id: string): Promise; + attachBlockchain(blockchain: IPaymentMethodBlockchain | Array, opts?: IPaymentMethodAttachBlockchainOptions): Promise; + delete(): Promise; +} +//# sourceMappingURL=PaymentMethod.d.ts.map \ No newline at end of file diff --git a/dist/PaymentMethod.d.ts.map b/dist/PaymentMethod.d.ts.map new file mode 100644 index 0000000..f3957f2 --- /dev/null +++ b/dist/PaymentMethod.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"PaymentMethod.d.ts","sourceRoot":"","sources":["../src/PaymentMethod.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,SAAS,CAAA;AAC3B,OAAO,GAAG,MAAM,aAAa,CAAA;AAC7B,OAAO,KAAK,EACV,cAAc,EACiB,qCAAqC,EAAE,wBAAwB,EACrE,8BAA8B,EACxD,MAAM,gCAAgC,CAAA;AAEvC,MAAM,CAAC,OAAO,OAAO,aAAc,SAAQ,KAAK,CAAC,aAAa,EAAE,cAAc,CAAE,YAAW,cAAc;IAChG,eAAe,EAAE,MAAM,CAAA;IACvB,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,IAAI,CAAA;IACX,iBAAiB,EAAE,IAAI,CAAA;IACvB,oBAAoB,EAAE,KAAK,CAAC,MAAM,CAAC,CAAA;IACnC,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,eAAe,EAAE,MAAM,CAAA;IACvB,kBAAkB,EAAE,IAAI,CAAA;IACxB,qBAAqB,EAAE,KAAK,CAAC,MAAM,CAAC,CAAA;IACpC,QAAQ,EAAE,OAAO,CAAA;IACjB,SAAS,EAAE,KAAK,CAAC,GAAG,CAAC,CAAA;IACrB,iBAAiB,EAAE,MAAM,CAAA;IACzB,EAAE,EAAE,MAAM,CAAA;IACV,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,wBAAwB,GAAG,gBAAgB,CAAA;IACrD,mBAAmB,EAAE,MAAM,CAAA;IAC3B,SAAS,EAAE,IAAI,CAAA;IACf,UAAU,EAAE,IAAI,CAAA;IAChB,SAAS,EAAE,IAAI,CAAA;IACf,UAAU,EAAE,IAAI,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,SAAS,GAAG,mBAAmB,GAAG,QAAQ,GAAG,UAAU,CAAA;IAC/D,aAAa,EAAE,MAAM,CAAA;IACrB,eAAe,EAAE,OAAO,CAAA;IACxB,eAAe,EAAE,OAAO,CAAA;IACxB,cAAc,EAAE,KAAK,CAAC,GAAG,CAAC,CAAA;WAEb,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;WAYhE,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,8BAA8B,GAAG,OAAO,CAAC,aAAa,CAAC;WAUpF,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;WAmBjD,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAO1D,gBAAgB,CAAC,UAAU,EAAE,wBAAwB,GAAG,KAAK,CAAC,wBAAwB,CAAC,EAAE,IAAI,GAAE,qCAA0C;IASzI,MAAM;CAGpB"} \ No newline at end of file diff --git a/dist/PaymentMethod.js b/dist/PaymentMethod.js new file mode 100644 index 0000000..51d57b4 --- /dev/null +++ b/dist/PaymentMethod.js @@ -0,0 +1,181 @@ +"use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var Model_1 = require("./Model"); +var PaymentMethod = (function (_super) { + __extends(PaymentMethod, _super); + function PaymentMethod() { + return _super !== null && _super.apply(this, arguments) || this; + } + PaymentMethod.createACH = function (api, publicToken) { + return __awaiter(this, void 0, void 0, function () { + var params, data; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + api.requireAuthed(); + params = { + publicToken: publicToken, + paymentMethodType: 'LOCAL_TRANSFER', + country: 'US' + }; + return [4, api.post('paymentMethods', params, { version: '2' })]; + case 1: + data = _a.sent(); + return [2, new PaymentMethod(data, api)]; + } + }); + }); + }; + PaymentMethod.createWire = function (api, params) { + return __awaiter(this, void 0, void 0, function () { + var data; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + api.requireAuthed(); + params.paymentMethodType = 'INTERNATIONAL_TRANSFER'; + params.paymentType = 'LOCAL_BANK_WIRE'; + return [4, api.post('paymentMethods', params, { version: '2' })]; + case 1: + data = _a.sent(); + return [2, new PaymentMethod(data, api)]; + } + }); + }); + }; + PaymentMethod.fetchAll = function (api) { + return __awaiter(this, void 0, void 0, function () { + var paymentMethods, offset, length, hasMore, _a, data, recordsTotal, position, methods; + return __generator(this, function (_b) { + switch (_b.label) { + case 0: + api.requireAuthed(); + paymentMethods = []; + offset = 0; + length = 20; + hasMore = true; + _b.label = 1; + case 1: return [4, api.get('paymentMethods', { offset: offset, length: length }, { version: '2' })]; + case 2: + _a = _b.sent(), data = _a.data, recordsTotal = _a.recordsTotal, position = _a.position; + methods = data.map(function (paymentData) { return new PaymentMethod(paymentData, api); }); + paymentMethods.push.apply(paymentMethods, methods); + hasMore = Math.ceil(recordsTotal / length) - 1 !== position; + if (hasMore) + offset += length; + _b.label = 3; + case 3: + if (hasMore) return [3, 1]; + _b.label = 4; + case 4: return [2, paymentMethods]; + } + }); + }); + }; + PaymentMethod.fetch = function (api, id) { + return __awaiter(this, void 0, void 0, function () { + var data; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + api.requireAuthed(); + return [4, api.get("paymentMethod/" + id, null, { version: '2' })]; + case 1: + data = _a.sent(); + return [2, new PaymentMethod(data, api)]; + } + }); + }); + }; + PaymentMethod.prototype.attachBlockchain = function (blockchain, opts) { + if (opts === void 0) { opts = {}; } + return __awaiter(this, void 0, void 0, function () { + var params, data; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + params = __assign(__assign({}, opts), { blockchain: Array.isArray(blockchain) ? blockchain.join(',') : blockchain }); + return [4, this.api.get("paymentMethod/" + this.id + "/attach", params, { version: '2' })]; + case 1: + data = _a.sent(); + this.set(data); + return [2]; + } + }); + }); + }; + PaymentMethod.prototype.delete = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4, this.api.delete("paymentMethod/" + this.id, null, { version: '2' })]; + case 1: + _a.sent(); + return [2]; + } + }); + }); + }; + return PaymentMethod; +}(Model_1.default)); +exports.default = PaymentMethod; diff --git a/dist/PaymentMethod/IPaymentMethod.d.ts b/dist/PaymentMethod/IPaymentMethod.d.ts new file mode 100644 index 0000000..93769d1 --- /dev/null +++ b/dist/PaymentMethod/IPaymentMethod.d.ts @@ -0,0 +1,74 @@ +export interface IPaymentMethod { + id: string; + owner: string; + createdAt: number; + name: string; + defaultCurrency: string; + status: 'PENDING' | 'AWAITING_FOLLOWUP' | 'ACTIVE' | 'REJECTED'; + statusMessage: string; + waitingPrompts: Array; + linkType: 'INTERNATIONAL_TRANSFER' | 'LOCAL_TRANSFER'; + beneficiaryType: string; + supportsDeposit: boolean; + nameOnMethod: string | null; + last4Digits: string; + brand: null; + expirationDisplay: string; + countryCode: string; + nickname: string | null; + rejectionMessage: string | null; + disabled: boolean; + supportsPayment: boolean; + chargeableCurrencies: Array; + depositableCurrencies: Array; + srn: string; + chargeFeeSchedule: null; + depositFeeSchedule: null; + minCharge: null; + maxCharge: null; + minDeposit: null; + maxDeposit: null; + documents: Array; + blockchains: object; + liquidationBalances: object; +} +export interface IPaymentMethodsResponse { + data: Array; + recordsTotal: number; + position: number; +} +export interface IPaymentMethodACHCreateParams { + publicToken: string; + paymentMethodType: 'LOCAL_TRANSFER'; + country: 'US'; +} +export interface IPaymentMethodWireCreateParams extends IPaymentMethodWireCreateParamsInternal { + country: string; + currency: string; + beneficiaryType: 'INDIVIDUAL' | 'BUSINESS'; + beneficiaryAddress: string; + beneficiaryAddress2?: string; + beneficiaryCity: string; + beneficiaryState: string; + beneficiaryPostal: string; + beneficiaryPhoneNumber: string; + beneficiaryDobDay: string; + beneficiaryDobMonth: string; + beneficiaryDobYear: string; + firstNameOnAccount: string; + lastNameOnAccount: string; + accountNumber: string; + routingNumber: string; + accountType: 'CHECKING' | 'SAVINGS'; + chargeablePM: boolean; +} +export interface IPaymentMethodWireCreateParamsInternal { + paymentMethodType: 'INTERNATIONAL_TRANSFER'; + paymentType: 'LOCAL_BANK_WIRE'; +} +export declare type IPaymentMethodBlockchain = 'BTC' | 'ETH' | 'ALL'; +export interface IPaymentMethodAttachBlockchainOptions { + notifyUrl?: string; + muteMessages?: boolean; +} +//# sourceMappingURL=IPaymentMethod.d.ts.map \ No newline at end of file diff --git a/dist/PaymentMethod/IPaymentMethod.d.ts.map b/dist/PaymentMethod/IPaymentMethod.d.ts.map new file mode 100644 index 0000000..930f597 --- /dev/null +++ b/dist/PaymentMethod/IPaymentMethod.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"IPaymentMethod.d.ts","sourceRoot":"","sources":["../../src/PaymentMethod/IPaymentMethod.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,eAAe,EAAE,MAAM,CAAA;IACvB,MAAM,EAAE,SAAS,GAAG,mBAAmB,GAAG,QAAQ,GAAG,UAAU,CAAA;IAC/D,aAAa,EAAE,MAAM,CAAA;IAErB,cAAc,EAAE,KAAK,CAAC,GAAG,CAAC,CAAA;IAC1B,QAAQ,EAAE,wBAAwB,GAAG,gBAAgB,CAAA;IACrD,eAAe,EAAE,MAAM,CAAA;IACvB,eAAe,EAAE,OAAO,CAAA;IACxB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,WAAW,EAAE,MAAM,CAAA;IAEnB,KAAK,EAAE,IAAI,CAAA;IACX,iBAAiB,EAAE,MAAM,CAAA;IACzB,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,QAAQ,EAAE,OAAO,CAAA;IACjB,eAAe,EAAE,OAAO,CAAA;IACxB,oBAAoB,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACpC,qBAAqB,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACrC,GAAG,EAAE,MAAM,CAAA;IAGX,iBAAiB,EAAE,IAAI,CAAA;IACvB,kBAAkB,EAAE,IAAI,CAAA;IACxB,SAAS,EAAE,IAAI,CAAA;IACf,SAAS,EAAE,IAAI,CAAA;IACf,UAAU,EAAE,IAAI,CAAA;IAChB,UAAU,EAAE,IAAI,CAAA;IAChB,SAAS,EAAE,KAAK,CAAC,GAAG,CAAC,CAAA;IACrB,WAAW,EAAE,MAAM,CAAA;IACnB,mBAAmB,EAAE,MAAM,CAAA;CAC5B;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,KAAK,CAAC,cAAc,CAAC,CAAA;IAC3B,YAAY,EAAE,MAAM,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,6BAA6B;IAC5C,WAAW,EAAE,MAAM,CAAA;IACnB,iBAAiB,EAAE,gBAAgB,CAAA;IACnC,OAAO,EAAE,IAAI,CAAA;CACd;AAED,MAAM,WAAW,8BAA+B,SAAQ,sCAAsC;IAC5F,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,eAAe,EAAE,YAAY,GAAG,UAAU,CAAA;IAC1C,kBAAkB,EAAE,MAAM,CAAA;IAC1B,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,eAAe,EAAG,MAAM,CAAA;IACxB,gBAAgB,EAAG,MAAM,CAAA;IACzB,iBAAiB,EAAG,MAAM,CAAA;IAC1B,sBAAsB,EAAG,MAAM,CAAA;IAC/B,iBAAiB,EAAG,MAAM,CAAA;IAC1B,mBAAmB,EAAE,MAAM,CAAA;IAC3B,kBAAkB,EAAE,MAAM,CAAA;IAC1B,kBAAkB,EAAG,MAAM,CAAA;IAC3B,iBAAiB,EAAE,MAAM,CAAA;IACzB,aAAa,EAAE,MAAM,CAAA;IACrB,aAAa,EAAE,MAAM,CAAA;IACrB,WAAW,EAAE,UAAU,GAAG,SAAS,CAAA;IACnC,YAAY,EAAE,OAAO,CAAA;CACtB;AACD,MAAM,WAAW,sCAAsC;IACrD,iBAAiB,EAAE,wBAAwB,CAAA;IAC3C,WAAW,EAAE,iBAAiB,CAAA;CAC/B;AAED,oBAAY,wBAAwB,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAA;AAC5D,MAAM,WAAW,qCAAqC;IACpD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB"} \ No newline at end of file diff --git a/dist/PaymentMethod/IPaymentMethod.js b/dist/PaymentMethod/IPaymentMethod.js new file mode 100644 index 0000000..c8ad2e5 --- /dev/null +++ b/dist/PaymentMethod/IPaymentMethod.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/dist/Subscription.d.ts b/dist/Subscription.d.ts new file mode 100644 index 0000000..72508a3 --- /dev/null +++ b/dist/Subscription.d.ts @@ -0,0 +1,15 @@ +import Api from './utils/Api'; +import Model from './Model'; +import type { ISubscription } from './Subscription/ISubscription'; +export default class Subscription extends Model implements ISubscription { + id: string; + subscribed: string; + notifyTarget: string; + createdAt: number; + failure: any; + failCount: number; + static create(api: Api, srn: string, target: string): Promise; + static fetchAll(api: Api): Promise>; + delete(): Promise; +} +//# sourceMappingURL=Subscription.d.ts.map \ No newline at end of file diff --git a/dist/Subscription.d.ts.map b/dist/Subscription.d.ts.map new file mode 100644 index 0000000..7211ebd --- /dev/null +++ b/dist/Subscription.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Subscription.d.ts","sourceRoot":"","sources":["../src/Subscription.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,aAAa,CAAA;AAC7B,OAAO,KAAK,MAAM,SAAS,CAAA;AAC3B,OAAO,KAAK,EAAE,aAAa,EAA0B,MAAM,8BAA8B,CAAA;AAEzF,MAAM,CAAC,OAAO,OAAO,YAAa,SAAQ,KAAK,CAAC,YAAY,EAAE,aAAa,CAAE,YAAW,aAAa;IAC5F,EAAE,EAAE,MAAM,CAAA;IACV,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,GAAG,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;WAEJ,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;WAWpE,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IAmBvD,MAAM;CAGpB"} \ No newline at end of file diff --git a/dist/Subscription.js b/dist/Subscription.js new file mode 100644 index 0000000..63067f7 --- /dev/null +++ b/dist/Subscription.js @@ -0,0 +1,120 @@ +"use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var Model_1 = require("./Model"); +var Subscription = (function (_super) { + __extends(Subscription, _super); + function Subscription() { + return _super !== null && _super.apply(this, arguments) || this; + } + Subscription.create = function (api, srn, target) { + return __awaiter(this, void 0, void 0, function () { + var params, data; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + api.requireAuthed(); + params = { + subscribeTo: srn, + notifyTarget: target + }; + return [4, api.post('subscriptions', params)]; + case 1: + data = _a.sent(); + return [2, new Subscription(data, api)]; + } + }); + }); + }; + Subscription.fetchAll = function (api) { + return __awaiter(this, void 0, void 0, function () { + var subscriptions, offset, length, hasMore, _a, data, recordsTotal, position, subs; + return __generator(this, function (_b) { + switch (_b.label) { + case 0: + api.requireAuthed(); + subscriptions = []; + offset = 0; + length = 20; + hasMore = true; + _b.label = 1; + case 1: return [4, api.get('subscriptions', { offset: offset, length: length })]; + case 2: + _a = _b.sent(), data = _a.data, recordsTotal = _a.recordsTotal, position = _a.position; + subs = data.map(function (subData) { return new Subscription(subData, api); }); + subscriptions.push.apply(subscriptions, subs); + hasMore = Math.ceil(recordsTotal / length) - 1 !== position; + if (hasMore) + offset += length; + _b.label = 3; + case 3: + if (hasMore) return [3, 1]; + _b.label = 4; + case 4: return [2, subscriptions]; + } + }); + }); + }; + Subscription.prototype.delete = function () { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4, this.api.delete("subscriptions/" + this.id)]; + case 1: + _a.sent(); + return [2]; + } + }); + }); + }; + return Subscription; +}(Model_1.default)); +exports.default = Subscription; diff --git a/dist/Subscription/ISubscription.d.ts b/dist/Subscription/ISubscription.d.ts new file mode 100644 index 0000000..e6afe50 --- /dev/null +++ b/dist/Subscription/ISubscription.d.ts @@ -0,0 +1,14 @@ +export interface ISubscription { + id: string; + subscribed: string; + notifyTarget: string; + createdAt: number; + failure: any; + failCount: number; +} +export interface ISubscriptionsResponse { + data: Array; + recordsTotal: number; + position: number; +} +//# sourceMappingURL=ISubscription.d.ts.map \ No newline at end of file diff --git a/dist/Subscription/ISubscription.d.ts.map b/dist/Subscription/ISubscription.d.ts.map new file mode 100644 index 0000000..da0890e --- /dev/null +++ b/dist/Subscription/ISubscription.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"ISubscription.d.ts","sourceRoot":"","sources":["../../src/Subscription/ISubscription.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAA;IACV,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IAEjB,OAAO,EAAE,GAAG,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,KAAK,CAAC,aAAa,CAAC,CAAA;IAC1B,YAAY,EAAE,MAAM,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;CACjB"} \ No newline at end of file diff --git a/dist/Subscription/ISubscription.js b/dist/Subscription/ISubscription.js new file mode 100644 index 0000000..c8ad2e5 --- /dev/null +++ b/dist/Subscription/ISubscription.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/dist/Transfer.d.ts b/dist/Transfer.d.ts new file mode 100644 index 0000000..e1dfb47 --- /dev/null +++ b/dist/Transfer.d.ts @@ -0,0 +1,35 @@ +import Model from './Model'; +import Api from './utils/Api'; +import type { ITransferStatusHistory, ITransfer, ITransferFees, ICreateTransferParams } from './Transfer/ITransfer'; +export default class Transfer extends Model implements ITransfer { + blockchainTx: string; + cancelledAt: number; + completedAt: number; + createdAt: number; + customId: string; + dest: string; + destAmount: number; + destCurrency: string; + exchangeRate: number; + expiresAt: number; + failureReason: string; + fees: ITransferFees; + id: string; + message: string; + owner: string; + pendingSubStatus: string; + reversalReason: string; + reversingSubStatus: string; + source: string; + sourceAmount: number; + sourceCurrency: string; + status: string; + statusHistories: Array; + totalFees: number; + static verifyCreateParams(params: ICreateTransferParams): void; + static create(api: Api, params: ICreateTransferParams): Promise; + static fetchAll(api: Api): Promise>; + static fetch(api: Api, id: string): Promise; + confirm(): Promise; +} +//# sourceMappingURL=Transfer.d.ts.map \ No newline at end of file diff --git a/dist/Transfer.d.ts.map b/dist/Transfer.d.ts.map new file mode 100644 index 0000000..dd43b07 --- /dev/null +++ b/dist/Transfer.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Transfer.d.ts","sourceRoot":"","sources":["../src/Transfer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,SAAS,CAAA;AAC3B,OAAO,GAAG,MAAM,aAAa,CAAA;AAE7B,OAAO,KAAK,EACV,sBAAsB,EACtB,SAAS,EACT,aAAa,EACb,qBAAqB,EAEtB,MAAM,sBAAsB,CAAA;AAE7B,MAAM,CAAC,OAAO,OAAO,QAAS,SAAQ,KAAK,CAAC,QAAQ,EAAE,SAAS,CAAE,YAAW,SAAS;IAC5E,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,MAAM,CAAA;IACpB,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,EAAE,MAAM,CAAA;IACrB,IAAI,EAAE,aAAa,CAAA;IACnB,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,gBAAgB,EAAE,MAAM,CAAA;IACxB,cAAc,EAAE,MAAM,CAAA;IACtB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,YAAY,EAAE,MAAM,CAAA;IACpB,cAAc,EAAE,MAAM,CAAA;IACtB,MAAM,EAAE,MAAM,CAAA;IACd,eAAe,EAAE,KAAK,CAAC,sBAAsB,CAAC,CAAA;IAC9C,SAAS,EAAE,MAAM,CAAA;WAEV,kBAAkB,CAAC,MAAM,EAAE,qBAAqB;WAK1C,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,QAAQ,CAAC;WAmBlE,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;WAmB5C,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IAOrD,OAAO;CAIrB"} \ No newline at end of file diff --git a/dist/Transfer.js b/dist/Transfer.js new file mode 100644 index 0000000..8d8b2a3 --- /dev/null +++ b/dist/Transfer.js @@ -0,0 +1,150 @@ +"use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var Model_1 = require("./Model"); +var PaymentMethod_1 = require("./PaymentMethod"); +var Transfer = (function (_super) { + __extends(Transfer, _super); + function Transfer() { + return _super !== null && _super.apply(this, arguments) || this; + } + Transfer.verifyCreateParams = function (params) { + if (params.sourceAmount && params.destinationAmount) + throw new Error('Cannot have both source and destination amounts defined.'); + }; + Transfer.create = function (api, params) { + return __awaiter(this, void 0, void 0, function () { + var paymentMethods, isACH, data; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + api.requireAuthed(); + this.verifyCreateParams(params); + if (!(params.source instanceof PaymentMethod_1.default && params.source.linkType === 'LOCAL_TRANSFER')) return [3, 1]; + params.source = params.source.srn + ":ach"; + return [3, 3]; + case 1: + if (!(typeof params.source === 'string' && /paymentmethod:/.test(params.source))) return [3, 3]; + return [4, PaymentMethod_1.default.fetchAll(api)]; + case 2: + paymentMethods = _a.sent(); + isACH = paymentMethods.some(function (method) { return method.srn === params.source && method.linkType === 'LOCAL_TRANSFER'; }); + params.source += ':ach'; + _a.label = 3; + case 3: return [4, api.post('transfers', params)]; + case 4: + data = _a.sent(); + return [2, new Transfer(data, api)]; + } + }); + }); + }; + Transfer.fetchAll = function (api) { + return __awaiter(this, void 0, void 0, function () { + var transfers, offset, length, hasMore, _a, data, recordsTotal, position, mappedTransfers; + return __generator(this, function (_b) { + switch (_b.label) { + case 0: + api.requireAuthed(); + transfers = []; + offset = 0; + length = 20; + hasMore = true; + _b.label = 1; + case 1: return [4, api.get('transfers', { offset: offset, length: length })]; + case 2: + _a = _b.sent(), data = _a.data, recordsTotal = _a.recordsTotal, position = _a.position; + mappedTransfers = data.map(function (transferData) { return new Transfer(transferData, api); }); + transfers.push.apply(transfers, mappedTransfers); + hasMore = Math.ceil(recordsTotal / length) - 1 !== position; + if (hasMore) + offset += length; + _b.label = 3; + case 3: + if (hasMore) return [3, 1]; + _b.label = 4; + case 4: return [2, transfers]; + } + }); + }); + }; + Transfer.fetch = function (api, id) { + return __awaiter(this, void 0, void 0, function () { + var data; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + api.requireAuthed(); + return [4, api.get("transfers/" + id)]; + case 1: + data = _a.sent(); + return [2, new Transfer(data, api)]; + } + }); + }); + }; + Transfer.prototype.confirm = function () { + return __awaiter(this, void 0, void 0, function () { + var data; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4, this.api.post("transfers/" + this.id + "/confirm")]; + case 1: + data = _a.sent(); + this.set(data); + return [2]; + } + }); + }); + }; + return Transfer; +}(Model_1.default)); +exports.default = Transfer; diff --git a/dist/Transfer/ITransfer.d.ts b/dist/Transfer/ITransfer.d.ts new file mode 100644 index 0000000..9c243d4 --- /dev/null +++ b/dist/Transfer/ITransfer.d.ts @@ -0,0 +1,62 @@ +import PaymentMethod from '../PaymentMethod'; +export interface ITransfer { + id: string; + sourceAmount: number; + sourceCurrency: string; + destAmount: number; + destCurrency: string; + status: string; + message: string; + customId: string; + exchangeRate: number; + createdAt: number; + fees: ITransferFees; + totalFees: number; + completedAt: number; + cancelledAt: number; + failureReason: string; + expiresAt: number; + reversingSubStatus: string; + reversalReason: string; + pendingSubStatus: string; + dest: string; + blockchainTx: string; + statusHistories: Array; + owner: string; + source: string; +} +export interface ITransferFees { + [assetTicker: string]: number; +} +export interface ITransferStatusHistory { + id: string; + transferId: string; + createdAt: number; + type: string; + statusOrder: number; + statusDetail: string; + state: string; + failedState: boolean; +} +export interface ICreateTransferParams { + source: string | PaymentMethod; + sourceCurrency: string; + sourceAmount?: string; + destination: string | PaymentMethod; + destinationCurrency: string; + destinationAmount?: string; + message?: string; + notifyUrl?: string; + autoConfirm?: boolean; + customId?: string; + amountIncludesFees?: boolean; + preview?: boolean; + muteMessages?: boolean; +} +export interface ITransferHistoryResponse { + data: Array; + position: number; + recordsTotal: number; + recordsFiltered: number; +} +//# sourceMappingURL=ITransfer.d.ts.map \ No newline at end of file diff --git a/dist/Transfer/ITransfer.d.ts.map b/dist/Transfer/ITransfer.d.ts.map new file mode 100644 index 0000000..51adda5 --- /dev/null +++ b/dist/Transfer/ITransfer.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"ITransfer.d.ts","sourceRoot":"","sources":["../../src/Transfer/ITransfer.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,kBAAkB,CAAA;AAE5C,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAA;IACV,YAAY,EAAE,MAAM,CAAA;IACpB,cAAc,EAAE,MAAM,CAAA;IACtB,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,MAAM,CAAA;IACpB,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,aAAa,CAAA;IACnB,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;IACnB,aAAa,EAAE,MAAM,CAAA;IACrB,SAAS,EAAE,MAAM,CAAA;IACjB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,cAAc,EAAE,MAAM,CAAA;IACtB,gBAAgB,EAAE,MAAM,CAAA;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,YAAY,EAAE,MAAM,CAAA;IACpB,eAAe,EAAE,KAAK,CAAC,sBAAsB,CAAC,CAAA;IAC9C,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAAA;CAC9B;AAED,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAA;IACV,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,OAAO,CAAA;CACrB;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,GAAG,aAAa,CAAA;IAC9B,cAAc,EAAE,MAAM,CAAA;IACtB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,WAAW,EAAE,MAAM,GAAG,aAAa,CAAA;IACnC,mBAAmB,EAAE,MAAM,CAAA;IAC3B,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC,CAAA;IACtB,QAAQ,EAAE,MAAM,CAAA;IAChB,YAAY,EAAE,MAAM,CAAA;IACpB,eAAe,EAAE,MAAM,CAAA;CACxB"} \ No newline at end of file diff --git a/dist/Transfer/ITransfer.js b/dist/Transfer/ITransfer.js new file mode 100644 index 0000000..c8ad2e5 --- /dev/null +++ b/dist/Transfer/ITransfer.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/dist/utils/API/IApiConfig.d.ts b/dist/utils/API/IApiConfig.d.ts new file mode 100644 index 0000000..9fb4d4f --- /dev/null +++ b/dist/utils/API/IApiConfig.d.ts @@ -0,0 +1,22 @@ +export interface IApiConfig extends IApiOptions { + version?: string; + uri?: string; + auth?: IAuth; +} +export interface IApiOptions { + version?: string; + format?: string; + headers?: { + [key: string]: string; + }; + qs?: { + [key: string]: string; + }; + timeout?: number; +} +export interface IAuth { + secretKey: string; + apiKey: string; + masqueradeTarget?: string; +} +//# sourceMappingURL=IApiConfig.d.ts.map \ No newline at end of file diff --git a/dist/utils/API/IApiConfig.d.ts.map b/dist/utils/API/IApiConfig.d.ts.map new file mode 100644 index 0000000..f146536 --- /dev/null +++ b/dist/utils/API/IApiConfig.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"IApiConfig.d.ts","sourceRoot":"","sources":["../../../src/utils/API/IApiConfig.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAW,SAAQ,WAAW;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,KAAK,CAAA;CACb;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAA;IACnC,EAAE,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAA;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,KAAK;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B"} \ No newline at end of file diff --git a/dist/utils/API/IApiConfig.js b/dist/utils/API/IApiConfig.js new file mode 100644 index 0000000..c8ad2e5 --- /dev/null +++ b/dist/utils/API/IApiConfig.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/dist/utils/Api.d.ts b/dist/utils/Api.d.ts new file mode 100644 index 0000000..5185055 --- /dev/null +++ b/dist/utils/Api.d.ts @@ -0,0 +1,17 @@ +import 'es6-shim'; +import { IApiConfig, IApiOptions } from './API/IApiConfig'; +export default class Api { + readonly config: IApiConfig; + constructor(config?: IApiConfig); + get isAuthed(): boolean; + requireAuthed(): void; + masqueradeAs(id: string): Api; + get(path: string, params?: object, options?: IApiOptions): Promise; + post(path: string, body?: object, options?: IApiOptions): Promise; + put(path: string, body?: object, options?: IApiOptions): Promise; + delete(path: string, body?: object, options?: IApiOptions): Promise; + private request; + private buildRequestOptions; + private buildSignature; +} +//# sourceMappingURL=Api.d.ts.map \ No newline at end of file diff --git a/dist/utils/Api.d.ts.map b/dist/utils/Api.d.ts.map new file mode 100644 index 0000000..d74cc8e --- /dev/null +++ b/dist/utils/Api.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"Api.d.ts","sourceRoot":"","sources":["../../src/utils/Api.ts"],"names":[],"mappings":"AAIA,OAAO,UAAU,CAAA;AAEjB,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAE1D,MAAM,CAAC,OAAO,OAAO,GAAG;IACtB,SAAgB,MAAM,EAAE,UAAU,CAAA;gBAEtB,MAAM,CAAC,EAAE,UAAU;IAc/B,IAAW,QAAQ,IAAI,OAAO,CAE7B;IAEM,aAAa;IAKb,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,GAAG;IAU7B,GAAG,CAAC,CAAC,SAAS,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC;IAIpF,IAAI,CAAC,CAAC,SAAS,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC;IAInF,GAAG,CAAC,CAAC,SAAS,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC;IAIlF,MAAM,CAAC,CAAC,SAAS,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC;IAI5F,OAAO,CAAC,OAAO;IAkBf,OAAO,CAAC,mBAAmB;IAiD3B,OAAO,CAAC,cAAc;CAuBvB"} \ No newline at end of file diff --git a/dist/utils/Api.js b/dist/utils/Api.js new file mode 100644 index 0000000..4180605 --- /dev/null +++ b/dist/utils/Api.js @@ -0,0 +1,118 @@ +"use strict"; +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var request = require("request"); +var crypto = require("crypto"); +var querystring = require("querystring"); +var url = require("url"); +require("es6-shim"); +var Api = (function () { + function Api(config) { + var defaultConfig = { + uri: 'https://api.sendwyre.com', + version: '3', + format: 'json', + qs: {}, + headers: { + 'Content-Type': 'application/json' + } + }; + this.config = Object.assign({}, defaultConfig, config); + } + Object.defineProperty(Api.prototype, "isAuthed", { + get: function () { + return !!this.config.auth && !!this.config.auth.secretKey && !!this.config.auth.apiKey; + }, + enumerable: true, + configurable: true + }); + Api.prototype.requireAuthed = function () { + if (!this.isAuthed) + throw new Error('Must be authenticated for this endpoint.'); + }; + Api.prototype.masqueradeAs = function (id) { + if (!this.isAuthed) + throw new Error('Cannot masquerade with no authorization.'); + var newConfig = Object.assign({}, this.config); + newConfig.auth.masqueradeTarget = id; + return new Api(newConfig); + }; + Api.prototype.get = function (path, params, options) { + return this.request('GET', path, params, options); + }; + Api.prototype.post = function (path, body, options) { + return this.request('POST', path, body, options); + }; + Api.prototype.put = function (path, body, options) { + return this.request('PUT', path, body, options); + }; + Api.prototype.delete = function (path, body, options) { + return this.request('DELETE', path, body, options); + }; + Api.prototype.request = function (method, path, params, options) { + if (params === void 0) { params = {}; } + if (options === void 0) { options = {}; } + if (!path) + throw 'path required'; + var requestOptions = this.buildRequestOptions(method, path, params, options); + return new Promise(function (resolve, reject) { + request(requestOptions, function (err, res) { + if (err) + throw err; + else if (res.statusCode >= 200 && res.statusCode < 300) + resolve(res.body || {}); + else + reject(res.body || { statusCode: res.statusCode }); + }); + }); + }; + Api.prototype.buildRequestOptions = function (method, path, params, options) { + var config = __assign(__assign(__assign({}, this.config), options), { headers: __assign(__assign({}, this.config.headers), options.headers), qs: __assign(__assign({}, this.config.qs), options.qs) }); + var parsedUrl = url.parse(url.resolve(config.uri, "v" + config.version + "/" + path), true); + var json = config.headers['Content-Type'] === 'application/json'; + var requestOptions = __assign(__assign({}, options), { url: parsedUrl.protocol + '//' + parsedUrl.host + parsedUrl.pathname, method: method, headers: __assign({}, config.headers), qs: __assign(__assign({}, config.qs), { timestamp: new Date().getTime(), format: this.config.format }), json: json }); + if (requestOptions.method == 'GET') + requestOptions.qs = Object.assign(requestOptions.qs, params); + else + requestOptions.body = params; + Object.assign(requestOptions.qs, parsedUrl.query); + if (this.isAuthed && config.auth.masqueradeTarget && !('masqueradeAs' in requestOptions)) + requestOptions.qs.masqueradeAs = config.auth.masqueradeTarget; + if (this.isAuthed) { + requestOptions.headers['X-Api-Key'] = config.auth.apiKey; + requestOptions.headers['X-Api-Signature'] = this.buildSignature(requestOptions); + } + return requestOptions; + }; + Api.prototype.buildSignature = function (requestOptions) { + this.requireAuthed(); + var buffers = []; + var encoding = 'utf8'; + buffers.push(Buffer.from(requestOptions.url.toString(), encoding)); + buffers.push(Buffer.from(requestOptions.url.toString().indexOf('?') < 0 ? '?' : '&', encoding)); + buffers.push(Buffer.from(querystring.stringify(requestOptions.qs), encoding)); + if (requestOptions.body) { + if (typeof requestOptions.body == 'string') + buffers.push(Buffer.from(requestOptions.body, encoding)); + else if (requestOptions.body instanceof Buffer) + buffers.push(requestOptions.body); + else + buffers.push(Buffer.from(JSON.stringify(requestOptions.body), encoding)); + } + return crypto.createHmac('sha256', this.config.auth.secretKey) + .update(Buffer.concat(buffers)) + .digest('hex'); + }; + return Api; +}()); +exports.default = Api; diff --git a/dist/wyre.d.ts b/dist/wyre.d.ts index bffd362..de7162e 100644 --- a/dist/wyre.d.ts +++ b/dist/wyre.d.ts @@ -1,14 +1,17 @@ -import 'es6-shim'; -export declare class WyreClient { - private config; - private masqueradeTarget?; - constructor(config: any, masqueradeTarget?: string); - get(path: string, params?: any, options?: any): Promise; - post(path: string, body?: any, options?: any): Promise; - put(path: string, body?: any, options?: any): Promise; - delete(path: string, body?: any, options?: any): Promise; - masqueraded(target: string): WyreClient; - private request; - private buildRequestOptions; - private buildSignature; +import Account from './Account'; +import Api from './utils/Api'; +import type { IApiConfig } from './utils/API/IApiConfig'; +import type { ICreateAccountParams } from './Account/IAccount'; +import type { IRates, IRatesPriced } from './wyre/IRates'; +export default class WyreClient { + readonly api: Api; + constructor(config: IApiConfig); + createAccount(params: ICreateAccountParams): Promise; + fetchAccount(): Promise; + fetchAccount(id: string, masquerade?: boolean): Promise; + fetchRates(): Promise; + fetchRates(as: 'DIVISOR'): Promise; + fetchRates(as: 'MULTIPLIER'): Promise; + fetchRates(as: 'PRICED'): Promise; } +//# sourceMappingURL=wyre.d.ts.map \ No newline at end of file diff --git a/dist/wyre.d.ts.map b/dist/wyre.d.ts.map new file mode 100644 index 0000000..2ace124 --- /dev/null +++ b/dist/wyre.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"wyre.d.ts","sourceRoot":"","sources":["../src/wyre.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,WAAW,CAAA;AAC/B,OAAO,GAAG,MAAM,aAAa,CAAA;AAC7B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AAC9D,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAEzD,MAAM,CAAC,OAAO,OAAO,UAAU;IAC7B,SAAgB,GAAG,EAAE,GAAG,CAAA;gBAEZ,MAAM,EAAE,UAAU;IAIjB,aAAa,CAAC,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,OAAO,CAAC;IAI7D,YAAY,IAAI,OAAO,CAAC,OAAO,CAAC;IAChC,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAahE,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAC7B,UAAU,CAAC,EAAE,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC;IAC1C,UAAU,CAAC,EAAE,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAC7C,UAAU,CAAC,EAAE,EAAE,QAAQ,GAAG,OAAO,CAAC,YAAY,CAAC;CAI7D"} \ No newline at end of file diff --git a/dist/wyre.js b/dist/wyre.js index 5e71a92..ae35884 100644 --- a/dist/wyre.js +++ b/dist/wyre.js @@ -1,96 +1,80 @@ "use strict"; -var __assign = (this && this.__assign) || Object.assign || function(t) { - for (var s, i = 1, n = arguments.length; i < n; i++) { - s = arguments[i]; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) - t[p] = s[p]; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } - return t; }; Object.defineProperty(exports, "__esModule", { value: true }); -var request = require("request"); -var crypto = require("crypto"); -var querystring = require("querystring"); -var url = require("url"); -require("es6-shim"); -var WYRE_BASEURL = "https://api.sendwyre.com"; -var WYRE_DEFAULT_API_VERSION = "2"; -var WYRE_DEFAULT_API_FORMAT = "json"; +var Account_1 = require("./Account"); +var Api_1 = require("./utils/Api"); var WyreClient = (function () { - function WyreClient(config, masqueradeTarget) { - this.config = config; - this.masqueradeTarget = masqueradeTarget; - if (!config.secretKey) - throw new Error('config.secretKey is missing'); - if (!config.apiKey) - throw new Error('config.apiKey is missing'); - this.config.options = this.config.options || {}; + function WyreClient(config) { + this.api = new Api_1.default(config); } - WyreClient.prototype.get = function (path, params, options) { - return this.request("GET", path, params, options); - }; - WyreClient.prototype.post = function (path, body, options) { - return this.request("POST", path, body, options); - }; - WyreClient.prototype.put = function (path, body, options) { - return this.request("PUT", path, body, options); - }; - WyreClient.prototype.delete = function (path, body, options) { - return this.request("DELETE", path, body, options); - }; - WyreClient.prototype.masqueraded = function (target) { - return new WyreClient(this.config, target); - }; - WyreClient.prototype.request = function (method, path, params, options) { - if (params === void 0) { params = {}; } - if (options === void 0) { options = {}; } - if (!path) - throw "path required"; - var requestOptions = this.buildRequestOptions(method, path, params, options); - return new Promise(function (resolve, reject) { - request(requestOptions, function (err, res) { - if (err) - throw err; - else if (res.statusCode >= 200 && res.statusCode < 300) - resolve(res.body || {}); - else - reject(res.body || { statusCode: res.statusCode }); + WyreClient.prototype.createAccount = function (params) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2, Account_1.default.create(this.api, params)]; }); }); }; - WyreClient.prototype.buildRequestOptions = function (method, path, params, options) { - options = options || {}; - var parsedUrl = url.parse(url.resolve(this.config.baseUrl || WYRE_BASEURL, path), true); - var json = !(options.headers || {}).hasOwnProperty('Content-Type') || options.headers['Content-Type'] == 'application/json'; - var requestOptions = __assign({}, this.config.options, options, { url: parsedUrl.protocol + "//" + parsedUrl.host + parsedUrl.pathname, method: method, headers: __assign({}, this.config.options.headers, options.headers, { "X-Api-Version": this.config.apiVersion || WYRE_DEFAULT_API_VERSION, "X-Api-Key": this.config.apiKey }), qs: __assign({}, this.config.qs, options.qs, { timestamp: new Date().getTime(), format: this.config.format || WYRE_DEFAULT_API_FORMAT }), json: json }); - if (requestOptions.method == "GET") - requestOptions.qs = Object.assign(requestOptions.qs, params); - else - requestOptions.body = params; - Object.assign(requestOptions.qs, parsedUrl.query); - if (this.masqueradeTarget && !('masqueradeAs' in requestOptions)) - requestOptions.qs.masqueradeAs = this.masqueradeTarget; - requestOptions.headers["X-Api-Signature"] = this.buildSignature(requestOptions); - return requestOptions; + WyreClient.prototype.fetchAccount = function (id, masquerade) { + if (masquerade === void 0) { masquerade = false; } + return __awaiter(this, void 0, void 0, function () { + var api, data; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: + api = masquerade ? this.api.masqueradeAs(id) : this.api; + if (!!id) return [3, 2]; + return [4, api.get("account", null, { version: '2' })]; + case 1: + data = _a.sent(); + id = data.id; + _a.label = 2; + case 2: return [2, Account_1.default.fetch(api, id)]; + } + }); + }); }; - WyreClient.prototype.buildSignature = function (requestOptions) { - var buffers = []; - var encoding = 'utf8'; - buffers.push(Buffer.from(requestOptions.url.toString(), encoding)); - buffers.push(Buffer.from(requestOptions.url.toString().indexOf('?') < 0 ? "?" : "&", encoding)); - buffers.push(Buffer.from(querystring.stringify(requestOptions.qs), encoding)); - if (requestOptions.body) { - if (typeof requestOptions.body == 'string') - buffers.push(Buffer.from(requestOptions.body, encoding)); - else if (requestOptions.body instanceof Buffer) - buffers.push(requestOptions.body); - else - buffers.push(Buffer.from(JSON.stringify(requestOptions.body), encoding)); - } - return crypto.createHmac("sha256", this.config.secretKey) - .update(Buffer.concat(buffers)) - .digest("hex"); + WyreClient.prototype.fetchRates = function (as) { + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_a) { + return [2, this.api.get('rates', { as: as })]; + }); + }); }; return WyreClient; }()); -exports.WyreClient = WyreClient; +exports.default = WyreClient; diff --git a/dist/wyre/ILimits.d.ts b/dist/wyre/ILimits.d.ts new file mode 100644 index 0000000..0ec9607 --- /dev/null +++ b/dist/wyre/ILimits.d.ts @@ -0,0 +1,19 @@ +export interface ILimits { + ACCOUNT?: ILimitsTime; + ACH?: ILimitsTime; + DEBIT_CARD?: ILimitsTime; +} +interface ILimitsTime { + 24?: ILimitValues; + 168?: ILimitValues; + 720?: ILimitValues; + 1440?: ILimitValues; +} +interface ILimitValues { + in: number; + out: number; + availIn: number; + availOut: number; +} +export {}; +//# sourceMappingURL=ILimits.d.ts.map \ No newline at end of file diff --git a/dist/wyre/ILimits.d.ts.map b/dist/wyre/ILimits.d.ts.map new file mode 100644 index 0000000..5ee9b5e --- /dev/null +++ b/dist/wyre/ILimits.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"ILimits.d.ts","sourceRoot":"","sources":["../../src/wyre/ILimits.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,OAAO;IACtB,OAAO,CAAC,EAAE,WAAW,CAAA;IACrB,GAAG,CAAC,EAAE,WAAW,CAAA;IACjB,UAAU,CAAC,EAAE,WAAW,CAAA;CACzB;AAED,UAAU,WAAW;IACnB,EAAE,CAAC,EAAE,YAAY,CAAA;IACjB,GAAG,CAAC,EAAE,YAAY,CAAA;IAClB,GAAG,CAAC,EAAE,YAAY,CAAA;IAClB,IAAI,CAAC,EAAE,YAAY,CAAA;CACpB;AAED,UAAU,YAAY;IACpB,EAAE,EAAE,MAAM,CAAA;IACV,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;CACjB"} \ No newline at end of file diff --git a/dist/wyre/ILimits.js b/dist/wyre/ILimits.js new file mode 100644 index 0000000..c8ad2e5 --- /dev/null +++ b/dist/wyre/ILimits.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/dist/wyre/IRates.d.ts b/dist/wyre/IRates.d.ts new file mode 100644 index 0000000..321face --- /dev/null +++ b/dist/wyre/IRates.d.ts @@ -0,0 +1,9 @@ +export interface IRates { + [symbolPair: string]: number; +} +export interface IRatesPriced { + [symbolPair: string]: { + [symbol: string]: number; + }; +} +//# sourceMappingURL=IRates.d.ts.map \ No newline at end of file diff --git a/dist/wyre/IRates.d.ts.map b/dist/wyre/IRates.d.ts.map new file mode 100644 index 0000000..81d6abe --- /dev/null +++ b/dist/wyre/IRates.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"IRates.d.ts","sourceRoot":"","sources":["../../src/wyre/IRates.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,MAAM;IACrB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAAA;CAC7B;AAED,MAAM,WAAW,YAAY;IAC3B,CAAC,UAAU,EAAE,MAAM,GAAG;QACpB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAA;KACzB,CAAA;CACF"} \ No newline at end of file diff --git a/dist/wyre/IRates.js b/dist/wyre/IRates.js new file mode 100644 index 0000000..c8ad2e5 --- /dev/null +++ b/dist/wyre/IRates.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/package-lock.json b/package-lock.json index 0737729..0f6124e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@wyre/api", - "version": "1.0.3", + "version": "1.0.4", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -20,9 +20,9 @@ } }, "@types/node": { - "version": "10.10.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.10.1.tgz", - "integrity": "sha512-nzsx28VwfaIykfzMAG9TB3jxF5Nn+1/WMKnmVZc8TsB+LMIVvwUscVn7PAq+LFaY5ng5u4jp5mRROSswo76PPA==", + "version": "13.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.9.1.tgz", + "integrity": "sha512-E6M6N0blf/jiZx8Q3nb0vNaswQeEyn0XlupO+xN6DtJ6r6IT4nXrTry7zhIfYvFCl3/8Cu6WIysmUBKiqV0bqQ==", "dev": true }, "@types/request": { @@ -54,6 +54,12 @@ "json-schema-traverse": "^0.3.0" } }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, "asn1": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", @@ -91,6 +97,12 @@ "tweetnacl": "^0.14.3" } }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -127,6 +139,12 @@ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -261,6 +279,12 @@ "verror": "1.10.0" } }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, "mime-db": { "version": "1.36.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz", @@ -336,6 +360,22 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz", + "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, "sshpk": { "version": "1.14.2", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", @@ -361,6 +401,19 @@ "punycode": "^1.4.1" } }, + "ts-node": { + "version": "8.6.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.6.2.tgz", + "integrity": "sha512-4mZEbofxGqLL2RImpe3zMJukvEvcO1XP8bj8ozBPySdCUXEcU5cIRwR0aM3R+VoZq7iXc8N86NC0FspGRqP4gg==", + "dev": true, + "requires": { + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.6", + "yn": "3.1.1" + } + }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -376,9 +429,9 @@ "optional": true }, "typescript": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz", - "integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==", + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz", + "integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==", "dev": true }, "uuid": { @@ -395,6 +448,12 @@ "core-util-is": "1.0.2", "extsprintf": "^1.2.0" } + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true } } } diff --git a/package.json b/package.json index c81e0ba..9ab3547 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,9 @@ "request": "2.88.0" }, "devDependencies": { + "@types/node": "^13.9.1", "@types/request": "2.47.1", - "typescript": "2.9.2" + "ts-node": "^8.6.2", + "typescript": "^3.8.3" } } diff --git a/src/Account.ts b/src/Account.ts new file mode 100644 index 0000000..888fe7c --- /dev/null +++ b/src/Account.ts @@ -0,0 +1,62 @@ +import Model from './Model' +import Transfer from './Transfer' +import PaymentMethod from './PaymentMethod' +import Api from './utils/Api' +import type { IAccount, IAccountResponse, ICreateAccountParams, IProfileField } from './Account/IAccount' +import type { ICreateTransferParams } from './Transfer/ITransfer' +import type { ILimits } from './wyre/ILimits' + +export default class Account extends Model implements IAccount { + public id: string + public status: 'OPEN' | 'PENDING' | 'APPROVED' + public type: 'INDIVIDUAL' | 'BUSINESS' + public country: string + public createdAt: number + public depositAddresses: { ETH: string; BTC: string } + public totalBalances: { BTC: number; ETH: number } + public availableBalances: { BTC: number; ETH: number } + public profileFields: Array + public paymentMethods: Array + + public static async create(api: Api, params: ICreateAccountParams): Promise { + api.requireAuthed() + + const data = await api.post('accounts', params) + if (params.subaccount) + api = api.masqueradeAs(data.id) + return this.postFetch(data, api) + } + + public static async fetch(api: Api, id: string): Promise { + api.requireAuthed() + + const data = await api.get(`accounts/${id}`) + return this.postFetch(data, api) + } + protected static async postFetch(data: IAccountResponse, api: Api): Promise { + const paymentMethods = await PaymentMethod.fetchAll(api) + return new Account({ ...data, paymentMethods }, api) + } + + public async save(): Promise { + if (!this.data.isChanged) return + + await this.api.post(`accounts/${this.id}`, this.data.updatedValues) + } + + public async createTransfer(params: ICreateTransferParams): Promise { + const transfer = await Transfer.create(this.api, params) + + return transfer + } + + public async fetchTransfers(): Promise> { + return Transfer.fetchAll(this.api) + } + + public async fetchLimits(): Promise { + this.api.requireAuthed() + + return this.api.get('limits') + } +} \ No newline at end of file diff --git a/src/Account/IAccount.ts b/src/Account/IAccount.ts new file mode 100644 index 0000000..4545c98 --- /dev/null +++ b/src/Account/IAccount.ts @@ -0,0 +1,57 @@ +import type { IPaymentMethod } from '../PaymentMethod/IPaymentMethod' + +export interface IAccount extends IAccountResponse { + paymentMethods: Array +} +export interface IAccountResponse { + id: string + status: 'OPEN' | 'PENDING' | 'APPROVED' + type: 'INDIVIDUAL' | 'BUSINESS' + country: string + createdAt: number + depositAddresses: { + ETH: string + BTC: string + } + totalBalances: { + BTC: number + ETH: number + } + availableBalances: { + BTC: number + ETH: number + } + profileFields: Array +} + +export interface IProfileField { + fieldId: IProfileFieldId + fieldType: IProfileFieldType + value: string | object | IProfileFieldValueAddress | Array | null + note: string | null + status: IProfileFieldStatus +} +type IProfileFieldId = 'individualCellphoneNumber' | 'individualEmail' | 'individualLegalName' | 'individualDateOfBirth' | 'individualSsn' | 'individualResidenceAddress' | 'individualGovernmentId' | 'individualSourceOfFunds' +type IProfileFieldType = 'CELLPHONE' | 'EMAIL' | 'STRING' | 'DATE' | 'ADDRESS' | 'DOCUMENT' | 'PAYMENT_METHOD' +type IProfileFieldValueAddress = { + street1: string + street2?: string + city: string + state: string + postalCode: string + country: string | 'US' +} +// TODO: unknown values +type IProfileFieldValueDocument = { + +} +type IProfileFieldStatus = 'OPEN' | 'PENDING' | 'APPROVED' | 'NULL' + +export interface ICreateAccountParams { + type: string + country: string + profileFields: Array + referrerAccountId?: string + subaccount?: boolean + disableEmail?: boolean +} diff --git a/src/Model.ts b/src/Model.ts new file mode 100644 index 0000000..1f7efb0 --- /dev/null +++ b/src/Model.ts @@ -0,0 +1,46 @@ +import Api from './utils/Api' +import Data from './Model/Data' + +export default abstract class Model { + public readonly api: Api + public readonly data: Data + + constructor(data: TData, api: Api) { + this.api = api + this.data = new Data(data) + + const proxy = new Proxy(this, new ModelProxyHandler()) + + return proxy + } + + public set(data: object): void + public set(key: PropertyKey, value: any): void + public set(key: PropertyKey | object, value?: any): void { + this.data.set(key, value) + } + + public get(key: PropertyKey): T { + return this.data.get(key) + } +} + +class ModelProxyHandler, TData extends object> implements ProxyHandler { + public getOwnPropertyDescriptor(target: T, p: PropertyKey): PropertyDescriptor | undefined { + return { enumerable: true, configurable: true } + } + + public set(target: T, key: PropertyKey, value: any): boolean { + key in target.data.updatedValues + ? target.set(key, value) + : target[key] = value + + return true + } + + public get(target: T, key: PropertyKey): any { + return key in target.data.updatedValues + ? target.get(key) + : target[key] + } +} \ No newline at end of file diff --git a/src/Model/Data.ts b/src/Model/Data.ts new file mode 100644 index 0000000..d64af7a --- /dev/null +++ b/src/Model/Data.ts @@ -0,0 +1,29 @@ +export default class Data { + public readonly initValues: object + public readonly updatedValues: object + + constructor(data: object) { + this.initValues = data + this.updatedValues = data + } + + public get isChanged(): boolean { + const initValues = JSON.stringify(this.initValues) + const updatedValues = JSON.stringify(this.updatedValues) + return initValues !== updatedValues + } + + public set(key: PropertyKey | object, value?: any): void { + if (typeof key === 'object') { + for (const [ k, v ] of Object.entries(key)) { + this.updatedValues[k] = v + } + } else { + this.updatedValues[key] = value + } + } + + public get(key: PropertyKey): T { + return this.updatedValues[key] + } +} \ No newline at end of file diff --git a/src/PaymentMethod.ts b/src/PaymentMethod.ts new file mode 100644 index 0000000..195c148 --- /dev/null +++ b/src/PaymentMethod.ts @@ -0,0 +1,103 @@ +import Model from './Model' +import Api from './utils/Api' +import type { + IPaymentMethod, + IPaymentMethodACHCreateParams, IPaymentMethodAttachBlockchainOptions, IPaymentMethodBlockchain, + IPaymentMethodsResponse, IPaymentMethodWireCreateParams +} from './PaymentMethod/IPaymentMethod' + +export default class PaymentMethod extends Model implements IPaymentMethod { + public beneficiaryType: string + public blockchains: object + public brand: null + public chargeFeeSchedule: null + public chargeableCurrencies: Array + public countryCode: string + public createdAt: number + public defaultCurrency: string + public depositFeeSchedule: null + public depositableCurrencies: Array + public disabled: boolean + public documents: Array + public expirationDisplay: string + public id: string + public last4Digits: string + public linkType: 'INTERNATIONAL_TRANSFER' | 'LOCAL_TRANSFER' + public liquidationBalances: object + public maxCharge: null + public maxDeposit: null + public minCharge: null + public minDeposit: null + public name: string + public nameOnMethod: string | null + public nickname: string | null + public owner: string + public rejectionMessage: string | null + public srn: string + public status: 'PENDING' | 'AWAITING_FOLLOWUP' | 'ACTIVE' | 'REJECTED' + public statusMessage: string + public supportsDeposit: boolean + public supportsPayment: boolean + public waitingPrompts: Array + + public static async createACH(api: Api, publicToken: string): Promise { + api.requireAuthed() + + const params: IPaymentMethodACHCreateParams = { + publicToken, + paymentMethodType: 'LOCAL_TRANSFER', + country: 'US' + } + const data = await api.post('paymentMethods', params, { version: '2' }) + return new PaymentMethod(data, api) + } + + public static async createWire(api: Api, params: IPaymentMethodWireCreateParams): Promise { + api.requireAuthed() + + params.paymentMethodType = 'INTERNATIONAL_TRANSFER' + params.paymentType = 'LOCAL_BANK_WIRE' + + const data = await api.post('paymentMethods', params, { version: '2' }) + return new PaymentMethod(data, api) + } + + public static async fetchAll(api: Api): Promise> { + api.requireAuthed() + + const paymentMethods: Array = [] + let offset = 0 + let length = 20 + let hasMore = true + do { + const { data, recordsTotal, position} = await api.get('paymentMethods', { offset, length }, { version: '2' }) + const methods = data.map((paymentData) => new PaymentMethod(paymentData, api)) + paymentMethods.push(...methods) + + hasMore = Math.ceil(recordsTotal / length) - 1 !== position + if (hasMore) offset += length + } while (hasMore) + + return paymentMethods + } + + public static async fetch(api: Api, id: string): Promise { + api.requireAuthed() + + const data = await api.get(`paymentMethod/${id}`, null, { version: '2' }) + return new PaymentMethod(data, api) + } + + public async attachBlockchain(blockchain: IPaymentMethodBlockchain | Array, opts: IPaymentMethodAttachBlockchainOptions = {}) { + const params = { + ...opts, + blockchain: Array.isArray(blockchain) ? blockchain.join(',') : blockchain + } + const data = await this.api.get(`paymentMethod/${this.id}/attach`, params, { version: '2' }) + this.set(data) + } + + public async delete() { + await this.api.delete(`paymentMethod/${this.id}`, null, { version: '2' }) + } +} \ No newline at end of file diff --git a/src/PaymentMethod/IPaymentMethod.ts b/src/PaymentMethod/IPaymentMethod.ts new file mode 100644 index 0000000..39457ad --- /dev/null +++ b/src/PaymentMethod/IPaymentMethod.ts @@ -0,0 +1,81 @@ +export interface IPaymentMethod { + id: string + owner: string + createdAt: number + name: string + defaultCurrency: string + status: 'PENDING' | 'AWAITING_FOLLOWUP' | 'ACTIVE' | 'REJECTED' + statusMessage: string + // TODO: unknown type + waitingPrompts: Array + linkType: 'INTERNATIONAL_TRANSFER' | 'LOCAL_TRANSFER' + beneficiaryType: string + supportsDeposit: boolean + nameOnMethod: string | null + last4Digits: string + // TODO: unknown type + brand: null + expirationDisplay: string + countryCode: string + nickname: string | null + rejectionMessage: string | null + disabled: boolean + supportsPayment: boolean + chargeableCurrencies: Array, + depositableCurrencies: Array, + srn: string + + // TODO: unknown types + chargeFeeSchedule: null + depositFeeSchedule: null + minCharge: null + maxCharge: null + minDeposit: null + maxDeposit: null + documents: Array + blockchains: object + liquidationBalances: object +} + +export interface IPaymentMethodsResponse { + data: Array + recordsTotal: number + position: number +} + +export interface IPaymentMethodACHCreateParams { + publicToken: string + paymentMethodType: 'LOCAL_TRANSFER' + country: 'US' +} + +export interface IPaymentMethodWireCreateParams extends IPaymentMethodWireCreateParamsInternal { + country: string + currency: string + beneficiaryType: 'INDIVIDUAL' | 'BUSINESS' + beneficiaryAddress: string + beneficiaryAddress2?: string + beneficiaryCity: string + beneficiaryState: string + beneficiaryPostal: string + beneficiaryPhoneNumber: string + beneficiaryDobDay: string + beneficiaryDobMonth: string + beneficiaryDobYear: string + firstNameOnAccount: string + lastNameOnAccount: string + accountNumber: string + routingNumber: string + accountType: 'CHECKING' | 'SAVINGS' + chargeablePM: boolean +} +export interface IPaymentMethodWireCreateParamsInternal { + paymentMethodType: 'INTERNATIONAL_TRANSFER' + paymentType: 'LOCAL_BANK_WIRE' +} + +export type IPaymentMethodBlockchain = 'BTC' | 'ETH' | 'ALL' +export interface IPaymentMethodAttachBlockchainOptions { + notifyUrl?: string + muteMessages?: boolean +} \ No newline at end of file diff --git a/src/Subscription.ts b/src/Subscription.ts new file mode 100644 index 0000000..aa931d6 --- /dev/null +++ b/src/Subscription.ts @@ -0,0 +1,46 @@ +import Api from './utils/Api' +import Model from './Model' +import type { ISubscription, ISubscriptionsResponse } from './Subscription/ISubscription' + +export default class Subscription extends Model implements ISubscription { + public id: string + public subscribed: string + public notifyTarget: string + public createdAt: number + public failure: any + public failCount: number + + public static async create(api: Api, srn: string, target: string): Promise { + api.requireAuthed() + + const params = { + subscribeTo: srn, + notifyTarget: target + } + const data = await api.post('subscriptions', params) + return new Subscription(data, api) + } + + public static async fetchAll(api: Api): Promise> { + api.requireAuthed() + + const subscriptions: Array = [] + let offset = 0 + let length = 20 + let hasMore = true + do { + const { data, recordsTotal, position} = await api.get('subscriptions', { offset, length }) + const subs = data.map((subData) => new Subscription(subData, api)) + subscriptions.push(...subs) + + hasMore = Math.ceil(recordsTotal / length) - 1 !== position + if (hasMore) offset += length + } while (hasMore) + + return subscriptions + } + + public async delete() { + await this.api.delete(`subscriptions/${this.id}`) + } +} \ No newline at end of file diff --git a/src/Subscription/ISubscription.ts b/src/Subscription/ISubscription.ts new file mode 100644 index 0000000..93922e7 --- /dev/null +++ b/src/Subscription/ISubscription.ts @@ -0,0 +1,15 @@ +export interface ISubscription { + id: string + subscribed: string + notifyTarget: string + createdAt: number + // TODO: unknown type + failure: any + failCount: number +} + +export interface ISubscriptionsResponse { + data: Array + recordsTotal: number + position: number +} \ No newline at end of file diff --git a/src/Transfer.ts b/src/Transfer.ts new file mode 100644 index 0000000..8ecaae6 --- /dev/null +++ b/src/Transfer.ts @@ -0,0 +1,92 @@ +import Model from './Model' +import Api from './utils/Api' +import PaymentMethod from './PaymentMethod' +import type { + ITransferStatusHistory, + ITransfer, + ITransferFees, + ICreateTransferParams, + ITransferHistoryResponse +} from './Transfer/ITransfer' + +export default class Transfer extends Model implements ITransfer { + public blockchainTx: string + public cancelledAt: number + public completedAt: number + public createdAt: number + public customId: string + public dest: string + public destAmount: number + public destCurrency: string + public exchangeRate: number + public expiresAt: number + public failureReason: string + public fees: ITransferFees + public id: string + public message: string + public owner: string + public pendingSubStatus: string + public reversalReason: string + public reversingSubStatus: string + public source: string + public sourceAmount: number + public sourceCurrency: string + public status: string + public statusHistories: Array + public totalFees: number + + public static verifyCreateParams(params: ICreateTransferParams) { + if (params.sourceAmount && params.destinationAmount) + throw new Error('Cannot have both source and destination amounts defined.') + } + + public static async create(api: Api, params: ICreateTransferParams): Promise { + api.requireAuthed() + + this.verifyCreateParams(params) + + // NOTE: Need to attach the suffix `:ach` if source is a LOCAL_TRANSFER + if (params.source instanceof PaymentMethod && params.source.linkType === 'LOCAL_TRANSFER') { + params.source = `${params.source.srn}:ach` + } else if (typeof params.source === 'string' && /paymentmethod:/.test(params.source)) { + const paymentMethods = await PaymentMethod.fetchAll(api) + const isACH = paymentMethods.some((method) => method.srn === params.source && method.linkType === 'LOCAL_TRANSFER') + params.source += ':ach' + } + + const data = await api.post('transfers', params) + + return new Transfer(data, api) + } + + public static async fetchAll(api: Api): Promise> { + api.requireAuthed() + + const transfers: Array = [] + let offset = 0 + let length = 20 + let hasMore = true + do { + const { data, recordsTotal, position} = await api.get('transfers', { offset, length }) + const mappedTransfers = data.map((transferData) => new Transfer(transferData, api)) + transfers.push(...mappedTransfers) + + hasMore = Math.ceil(recordsTotal / length) - 1 !== position + if (hasMore) offset += length + } while (hasMore) + + return transfers + } + + public static async fetch(api: Api, id: string): Promise { + api.requireAuthed() + + const data = await api.get(`transfers/${id}`) + return new Transfer(data, api) + } + + public async confirm() { + const data = await this.api.post(`transfers/${this.id}/confirm`) + this.set(data) + } +} diff --git a/src/Transfer/ITransfer.ts b/src/Transfer/ITransfer.ts new file mode 100644 index 0000000..f9c76c5 --- /dev/null +++ b/src/Transfer/ITransfer.ts @@ -0,0 +1,66 @@ +import PaymentMethod from '../PaymentMethod' + +export interface ITransfer { + id: string + sourceAmount: number + sourceCurrency: string + destAmount: number + destCurrency: string + status: string + message: string + customId: string + exchangeRate: number + createdAt: number + fees: ITransferFees + totalFees: number + completedAt: number + cancelledAt: number + failureReason: string + expiresAt: number + reversingSubStatus: string + reversalReason: string + pendingSubStatus: string + dest: string + blockchainTx: string + statusHistories: Array + owner: string + source: string +} + +export interface ITransferFees { + [assetTicker: string]: number +} + +export interface ITransferStatusHistory { + id: string + transferId: string + createdAt: number + type: string + statusOrder: number + statusDetail: string + state: string + failedState: boolean +} + +export interface ICreateTransferParams { + source: string | PaymentMethod + sourceCurrency: string + sourceAmount?: string + destination: string | PaymentMethod + destinationCurrency: string + destinationAmount?: string + message?: string + notifyUrl?: string + autoConfirm?: boolean + customId?: string + amountIncludesFees?: boolean + preview?: boolean + muteMessages?: boolean +} + +export interface ITransferHistoryResponse { + data: Array + position: number + recordsTotal: number + recordsFiltered: number +} diff --git a/src/utils/API/IApiConfig.ts b/src/utils/API/IApiConfig.ts new file mode 100644 index 0000000..5b3d03f --- /dev/null +++ b/src/utils/API/IApiConfig.ts @@ -0,0 +1,19 @@ +export interface IApiConfig extends IApiOptions { + version?: string + uri?: string + auth?: IAuth +} + +export interface IApiOptions { + version?: string + format?: string + headers?: { [key: string]: string } + qs?: { [key: string]: string } + timeout?: number +} + +export interface IAuth { + secretKey: string + apiKey: string + masqueradeTarget?: string +} diff --git a/src/utils/Api.ts b/src/utils/Api.ts new file mode 100644 index 0000000..03c0bd9 --- /dev/null +++ b/src/utils/Api.ts @@ -0,0 +1,151 @@ +import * as request from 'request' +import * as crypto from 'crypto' +import * as querystring from 'querystring' +import * as url from 'url' +import 'es6-shim' + +import { IApiConfig, IApiOptions } from './API/IApiConfig' + +export default class Api { + public readonly config: IApiConfig + + constructor(config?: IApiConfig) { + const defaultConfig: IApiConfig = { + uri: 'https://api.sendwyre.com', + version: '3', + format: 'json', + qs: {}, + headers: { + 'Content-Type': 'application/json' + } + } + + this.config = Object.assign({}, defaultConfig, config) + } + + public get isAuthed(): boolean { + return !!this.config.auth && !!this.config.auth.secretKey && !!this.config.auth.apiKey + } + + public requireAuthed() { + if (!this.isAuthed) + throw new Error('Must be authenticated for this endpoint.') + } + + public masqueradeAs(id: string): Api { + if (!this.isAuthed) + throw new Error('Cannot masquerade with no authorization.') + + const newConfig = Object.assign({}, this.config) + newConfig.auth.masqueradeTarget = id + + return new Api(newConfig) + } + + public get(path: string, params?: object, options?: IApiOptions): Promise { + return this.request('GET', path, params, options) + } + + public post(path: string, body?: object, options?: IApiOptions): Promise { + return this.request('POST', path, body, options) + } + + public put(path: string, body?: object, options?: IApiOptions): Promise { + return this.request('PUT', path, body, options) + } + + public delete(path: string, body?: object, options?: IApiOptions): Promise { + return this.request('DELETE', path, body, options) + } + + private request(method: string, path: string, params: object = {}, options: IApiOptions = {}): Promise { + if (!path) + throw 'path required' + + let requestOptions = this.buildRequestOptions(method, path, params, options) + + return new Promise((resolve, reject) => { + request(requestOptions, (err, res) => { + if (err) + throw err + else if (res.statusCode >= 200 && res.statusCode < 300) + resolve(res.body || {}) + else + reject(res.body || { statusCode: res.statusCode }) + }) + }) + } + + private buildRequestOptions(method: string, path: string, params: any, options: IApiOptions): request.UrlOptions & request.CoreOptions { + const config: IApiConfig = { + ...this.config, + ...options, + headers: { + ...this.config.headers, + ...options.headers + }, + qs: { + ...this.config.qs, + ...options.qs + } + } + + const parsedUrl = url.parse(url.resolve(config.uri, `v${config.version}/${path}`), true) + const json = config.headers['Content-Type'] === 'application/json' + + let requestOptions: request.UrlOptions & request.CoreOptions = { + ...options, + url: parsedUrl.protocol + '//' + parsedUrl.host + parsedUrl.pathname, // no querystring here! + method: method, + headers: { + ...config.headers + }, + qs: { + ...config.qs, + timestamp: new Date().getTime(), + format: this.config.format + }, + json: json + } + + if (requestOptions.method == 'GET') + requestOptions.qs = Object.assign(requestOptions.qs, params) + else + requestOptions.body = params + + Object.assign(requestOptions.qs, parsedUrl.query) + if (this.isAuthed && config.auth.masqueradeTarget && !('masqueradeAs' in requestOptions)) + requestOptions.qs.masqueradeAs = config.auth.masqueradeTarget + + if (this.isAuthed) { + requestOptions.headers['X-Api-Key'] = config.auth.apiKey + requestOptions.headers['X-Api-Signature'] = this.buildSignature(requestOptions) + } + + return requestOptions + } + + private buildSignature(requestOptions: request.UrlOptions & request.CoreOptions): string { + this.requireAuthed() + + let buffers: Buffer[] = [] + const encoding = 'utf8' + + buffers.push(Buffer.from(requestOptions.url.toString(), encoding)) + buffers.push(Buffer.from(requestOptions.url.toString().indexOf('?') < 0 ? '?' : '&', encoding)) + buffers.push(Buffer.from(querystring.stringify(requestOptions.qs), encoding)) + + if (requestOptions.body) { + if (typeof requestOptions.body == 'string') + buffers.push(Buffer.from(requestOptions.body, encoding)) + else if (requestOptions.body instanceof Buffer) + buffers.push(requestOptions.body) + else + buffers.push(Buffer.from(JSON.stringify(requestOptions.body), encoding)) + } + + return crypto.createHmac('sha256', this.config.auth.secretKey) + .update(Buffer.concat(buffers)) + .digest('hex') + } +} \ No newline at end of file diff --git a/src/wyre.ts b/src/wyre.ts index 9062f17..d2b3ee9 100644 --- a/src/wyre.ts +++ b/src/wyre.ts @@ -1,124 +1,39 @@ -import * as request from 'request' -import * as crypto from 'crypto' -import * as querystring from 'querystring' -import * as url from 'url' -import 'es6-shim' - -const WYRE_BASEURL = "https://api.sendwyre.com" -const WYRE_DEFAULT_API_VERSION = "2" -const WYRE_DEFAULT_API_FORMAT = "json" - -export class WyreClient { - - constructor(private config: any, private masqueradeTarget?: string) { - if(!config.secretKey) throw new Error('config.secretKey is missing'); - if(!config.apiKey) throw new Error('config.apiKey is missing'); - this.config.options = this.config.options || {}; - } - - public get(path: string, params?: any, options?: any): Promise { - return this.request("GET", path, params, options) - } - - public post(path: string, body?: any, options?: any): Promise { - return this.request("POST", path, body, options) - } - - public put(path: string, body?: any, options?: any): Promise { - return this.request("PUT", path, body, options) - } - - public delete(path: string, body?: any, options?: any): Promise { - return this.request("DELETE", path, body, options) - } - - /** - * returns a new wyre client which is ostensibly authenticated as the supplied - * target - * - * @param target an account ID or an SRN - */ - public masqueraded(target: string): WyreClient { - return new WyreClient(this.config, target); - } - - private request(method: string, path: string, params: any = {}, options: any = {}): Promise { - if(!path) - throw "path required" - - let requestOptions = this.buildRequestOptions(method, path, params, options) - - return new Promise((resolve, reject) => { - request(requestOptions, (err, res) => { - if(err) - throw err; - else if(res.statusCode >= 200 && res.statusCode < 300) - resolve(res.body || {}) - else - reject(res.body || { statusCode: res.statusCode }) - }) - }) - } - - private buildRequestOptions(method: string, path: string, params: any, options: any): request.UrlOptions & request.CoreOptions { - options = options || {}; - - let parsedUrl = url.parse(url.resolve(this.config.baseUrl || WYRE_BASEURL, path), true) - let json = !(options.headers || {}).hasOwnProperty('Content-Type') || options.headers['Content-Type'] == 'application/json'; - - let requestOptions: request.UrlOptions & request.CoreOptions = { - ...this.config.options, - ...options, - url: parsedUrl.protocol + "//" + parsedUrl.host + parsedUrl.pathname, // no querystring here! - method: method, - headers: { - ...this.config.options.headers, - ...options.headers, - "X-Api-Version": this.config.apiVersion || WYRE_DEFAULT_API_VERSION, - "X-Api-Key": this.config.apiKey - }, - qs: { - ...this.config.qs, - ...options.qs, - timestamp: new Date().getTime(), - format: this.config.format || WYRE_DEFAULT_API_FORMAT - }, - json: json - }; - - if(requestOptions.method == "GET") - requestOptions.qs = Object.assign(requestOptions.qs, params) - else - requestOptions.body = params - - Object.assign(requestOptions.qs, parsedUrl.query); - if(this.masqueradeTarget && !('masqueradeAs' in requestOptions)) - requestOptions.qs.masqueradeAs = this.masqueradeTarget; - - requestOptions.headers["X-Api-Signature"] = this.buildSignature(requestOptions); - - return requestOptions - } - - private buildSignature(requestOptions: request.UrlOptions & request.CoreOptions): string { - let buffers: Buffer[] = []; - const encoding = 'utf8'; - - buffers.push(Buffer.from(requestOptions.url.toString(), encoding)); - buffers.push(Buffer.from(requestOptions.url.toString().indexOf('?') < 0 ? "?" : "&", encoding)); - buffers.push(Buffer.from(querystring.stringify(requestOptions.qs), encoding)); - - if(requestOptions.body) { - if(typeof requestOptions.body == 'string') - buffers.push(Buffer.from(requestOptions.body, encoding)); - else if(requestOptions.body instanceof Buffer) - buffers.push(requestOptions.body); - else - buffers.push(Buffer.from(JSON.stringify(requestOptions.body), encoding)); - } - - return crypto.createHmac("sha256", this.config.secretKey) - .update(Buffer.concat(buffers)) - .digest("hex") - } +import Account from './Account' +import Api from './utils/Api' +import type { IApiConfig } from './utils/API/IApiConfig' +import type { ICreateAccountParams } from './Account/IAccount' +import type { IRates, IRatesPriced } from './wyre/IRates' + +export default class WyreClient { + public readonly api: Api + + constructor(config: IApiConfig) { + this.api = new Api(config) + } + + public async createAccount(params: ICreateAccountParams): Promise { + return Account.create(this.api, params) + } + + public async fetchAccount(): Promise + public async fetchAccount(id: string, masquerade?: boolean): Promise + public async fetchAccount(id?: string, masquerade = false): Promise { + const api = masquerade ? this.api.masqueradeAs(id) : this.api + + // TODO: Update V3 of API to return account from auth params + if (!id) { + const data = await api.get(`account`, null, { version: '2' }) + id = data.id + } + + return Account.fetch(api, id) + } + + public async fetchRates(): Promise + public async fetchRates(as: 'DIVISOR'): Promise + public async fetchRates(as: 'MULTIPLIER'): Promise + public async fetchRates(as: 'PRICED'): Promise + public async fetchRates(as?: string): Promise { + return this.api.get('rates', { as }) + } } diff --git a/src/wyre/ILimits.ts b/src/wyre/ILimits.ts new file mode 100644 index 0000000..492f483 --- /dev/null +++ b/src/wyre/ILimits.ts @@ -0,0 +1,19 @@ +export interface ILimits { + ACCOUNT?: ILimitsTime + ACH?: ILimitsTime + DEBIT_CARD?: ILimitsTime +} + +interface ILimitsTime { + 24?: ILimitValues + 168?: ILimitValues + 720?: ILimitValues + 1440?: ILimitValues +} + +interface ILimitValues { + in: number + out: number + availIn: number + availOut: number +} \ No newline at end of file diff --git a/src/wyre/IRates.ts b/src/wyre/IRates.ts new file mode 100644 index 0000000..a644368 --- /dev/null +++ b/src/wyre/IRates.ts @@ -0,0 +1,9 @@ +export interface IRates { + [symbolPair: string]: number +} + +export interface IRatesPriced { + [symbolPair: string]: { + [symbol: string]: number + } +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 2b27242..50aae22 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,18 +1,19 @@ { - "compilerOptions": { - "declaration": true, - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "lib": ["es2015"], - "module": "commonjs", - "moduleResolution": "node", - "noImplicitAny": true, - "noImplicitUseStrict": false, - "noLib": false, - "outDir" : "dist", - "removeComments": true, - "rootDir": "src", - "suppressImplicitAnyIndexErrors": true, - "target": "es5" - } + "compilerOptions": { + "declaration": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "lib": ["es2015"], + "module": "commonjs", + "moduleResolution": "node", + "noImplicitAny": true, + "noImplicitUseStrict": false, + "noLib": false, + "outDir" : "dist", + "removeComments": true, + "rootDir": "src", + "suppressImplicitAnyIndexErrors": true, + "target": "es5", + "declarationMap": true + } } \ No newline at end of file