@moneylion/engine-api 1.3.3 → 1.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -85,6 +85,62 @@ new AsyncRateTable({ uuid: rateTableUuid, client: client }).resolve();
85
85
  new AsyncRateTable({ rateTable: rateTable, client: client }).resolve();
86
86
  ```
87
87
 
88
+ ### Offer Catalog Rate Tables
89
+
90
+ Offer catalog rate tables work similarly to regular rate tables but use different endpoints and require `offerCatalogProductTypes` instead of `productTypes`.
91
+
92
+ #### Creating an Offer Catalog Rate Table
93
+
94
+ ```
95
+ import { Leads } from "@moneylion/engine-api";
96
+
97
+ const leads = new Leads(endpoint, authentication_token);
98
+
99
+ // The lead data should include offerCatalogProductTypes
100
+ const leadData = {
101
+ personalInformation: {
102
+ firstName: "John",
103
+ lastName: "Doe",
104
+ email: "john@example.com",
105
+ // ... other fields
106
+ },
107
+ financialInformation: {
108
+ annualIncome: 75000,
109
+ // ... other fields
110
+ },
111
+ loanInformation: {
112
+ purpose: "debt_consolidation",
113
+ loanAmount: 10000
114
+ },
115
+ offerCatalogProductTypes: ["DebtSettlement"] // Note: different from productTypes
116
+ };
117
+
118
+ // Non-blocking: returns AsyncOfferCatalogRateTable that you can resolve
119
+ const asyncRateTable = await leads.getOfferCatalogRateTable(leadData);
120
+ const rateTable = await asyncRateTable.resolve();
121
+
122
+ // Blocking: waits for the final rate table
123
+ const rateTable = await leads.getOfferCatalogRateTableBlocking(leadData);
124
+ ```
125
+
126
+ #### Fetching an Existing Offer Catalog Rate Table
127
+
128
+ If you already have a rate table UUID, you can fetch it directly:
129
+
130
+ ```
131
+ import { AsyncOfferCatalogRateTable } from "@moneylion/engine-api";
132
+
133
+ new AsyncOfferCatalogRateTable({ uuid: offerCatalogRateTableUuid, host: endpoint, auth_token: authentication_token }).resolve();
134
+
135
+ // You can also pass a pre-created client instead of endpoint and token
136
+ new AsyncOfferCatalogRateTable({ uuid: offerCatalogRateTableUuid, client: client }).resolve();
137
+
138
+ // You can also pass an OfferCatalogRateTable object instead of a uuid.
139
+ new AsyncOfferCatalogRateTable({ rateTable: offerCatalogRateTable, client: client }).resolve();
140
+ ```
141
+
142
+ The `AsyncOfferCatalogRateTable` class handles polling automatically, just like `AsyncRateTable`, waiting for all pending responses to complete before resolving.
143
+
88
144
  ## For Contributors
89
145
 
90
146
  This is a relatively normal NPM and Typescript project.
@@ -43,4 +43,35 @@ type TempRateTableWithNulledFields = {
43
43
  export type FixedRateTable = FixNull<TempRateTableWithNulledFields>;
44
44
  export declare const rateTableDecoder: Decoder<FixedRateTable>;
45
45
  export declare const leadUuidDecoder: Decoder<components["schemas"]["LeadUuid"]>;
46
+ type OfferCatalogOffer = FixNull<{
47
+ uuid: string;
48
+ version?: number;
49
+ productVersions?: number[];
50
+ productType: string;
51
+ productDisplayName?: string;
52
+ headline: string;
53
+ descriptionPoints: string[];
54
+ stateExclusions?: string[];
55
+ badges?: string[];
56
+ url: string;
57
+ financialInstitutionUuid: string;
58
+ financialInstitutionDisplayName: string;
59
+ financialInstitutionImageUrl: string;
60
+ enrollmentFeeBasisPointsMin?: number;
61
+ enrollmentFeeBasisPointsMax?: number;
62
+ debtAmountCentsMin?: number;
63
+ recommendationScore: number;
64
+ isMonetized?: boolean;
65
+ status?: string;
66
+ createdAt?: string;
67
+ updatedAt?: string;
68
+ }>;
69
+ export declare const offerCatalogOfferDecoder: Decoder<OfferCatalogOffer>;
70
+ export type FixedOfferCatalogRateTable = FixNull<{
71
+ uuid: string;
72
+ leadUuid: string;
73
+ offers: Array<OfferCatalogOffer>;
74
+ pendingResponses?: Array<FixNull<components["schemas"]["PendingResponse"]>>;
75
+ }>;
76
+ export declare const offerCatalogRateTableDecoder: Decoder<FixedOfferCatalogRateTable>;
46
77
  export {};
package/dist/decoders.js CHANGED
@@ -221,3 +221,32 @@ export const rateTableDecoder = object({
221
221
  export const leadUuidDecoder = object({
222
222
  uuid: string(),
223
223
  });
224
+ export const offerCatalogOfferDecoder = object({
225
+ uuid: string(),
226
+ version: optional(number()),
227
+ productVersions: optional(array(number())),
228
+ productType: string(),
229
+ productDisplayName: optional(string()),
230
+ headline: string(),
231
+ descriptionPoints: array(string()),
232
+ stateExclusions: optional(array(string())),
233
+ badges: optional(array(string())),
234
+ url: string(),
235
+ financialInstitutionUuid: string(),
236
+ financialInstitutionDisplayName: string(),
237
+ financialInstitutionImageUrl: string(),
238
+ enrollmentFeeBasisPointsMin: optional(number()),
239
+ enrollmentFeeBasisPointsMax: optional(number()),
240
+ debtAmountCentsMin: optional(number()),
241
+ recommendationScore: number(),
242
+ isMonetized: optional(boolean()),
243
+ status: optional(string()),
244
+ createdAt: optional(string()),
245
+ updatedAt: optional(string()),
246
+ });
247
+ export const offerCatalogRateTableDecoder = object({
248
+ uuid: string(),
249
+ leadUuid: string(),
250
+ offers: array(offerCatalogOfferDecoder),
251
+ pendingResponses: optional(array(pendingResponseDecoder)),
252
+ });
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- export { Client } from "./client.js";
1
+ export { Client, ApiError } from "./client.js";
2
2
  export * from "./leads.js";
3
3
  export * from "./rate_tables.js";
4
+ export * from "./offer_catalog_rate_tables.js";
4
5
  export * from "./client_tags.js";
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
- export { Client } from "./client.js";
1
+ export { Client, ApiError } from "./client.js";
2
2
  export * from "./leads.js";
3
3
  export * from "./rate_tables.js";
4
+ export * from "./offer_catalog_rate_tables.js";
4
5
  export * from "./client_tags.js";
package/dist/leads.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { AsyncRateTable, type RateTable } from "./rate_tables.js";
2
+ import { AsyncOfferCatalogRateTable, type OfferCatalogRateTable } from "./offer_catalog_rate_tables.js";
2
3
  import type { components } from "./generated/schema";
3
4
  export type LeadCreateData = components["schemas"]["LeadCreateData"];
4
5
  /**
@@ -89,4 +90,31 @@ export declare class Leads {
89
90
  * Only use this if you can handle waiting for that amount of time.
90
91
  */
91
92
  getRateTableBlocking(leadUuid: string, lead: LeadCreateData): Promise<RateTable>;
93
+ /**
94
+ * Create a new offer catalog rate table for a lead.
95
+ *
96
+ * @param lead - An object representing the lead information including offerCatalogProductTypes.
97
+ *
98
+ * @returns AsyncOfferCatalogRateTable
99
+ *
100
+ * @remarks
101
+ * This method returns an AsyncOfferCatalogRateTable.
102
+ * Use the resolve method on the returned object to retrieve the final Offer Catalog Rate Table.
103
+ * The lead data should include offerCatalogProductTypes (e.g., ["DebtSettlement"]) instead of productTypes.
104
+ */
105
+ getOfferCatalogRateTable(lead: LeadCreateData): Promise<AsyncOfferCatalogRateTable>;
106
+ /**
107
+ * Create a new offer catalog rate table, immediately resolving it.
108
+ *
109
+ * @param lead - An object representing the lead information including offerCatalogProductTypes.
110
+ *
111
+ * @returns OfferCatalogRateTable
112
+ *
113
+ * @remarks
114
+ * This method will immediately resolve the final Offer Catalog Rate Table.
115
+ * This may mean waiting a significant amount of time before it is finalized.
116
+ * Only use this if you can handle waiting for that amount of time.
117
+ * The lead data should include offerCatalogProductTypes (e.g., ["DebtSettlement"]) instead of productTypes.
118
+ */
119
+ getOfferCatalogRateTableBlocking(lead: LeadCreateData): Promise<OfferCatalogRateTable>;
92
120
  }
package/dist/leads.js CHANGED
@@ -9,7 +9,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import { Client } from "./client.js";
11
11
  import { AsyncRateTable } from "./rate_tables.js";
12
- import { leadUuidDecoder, rateTableDecoder } from "./decoders.js";
12
+ import { AsyncOfferCatalogRateTable, } from "./offer_catalog_rate_tables.js";
13
+ import { leadUuidDecoder, rateTableDecoder, offerCatalogRateTableDecoder, } from "./decoders.js";
13
14
  /**
14
15
  * The class used to manage leads.
15
16
  * Both blocking and non-blocking methods are provided, depending on when you want to resolve the returned Rate Table.
@@ -143,4 +144,47 @@ export class Leads {
143
144
  return rateTable;
144
145
  });
145
146
  }
147
+ /**
148
+ * Create a new offer catalog rate table for a lead.
149
+ *
150
+ * @param lead - An object representing the lead information including offerCatalogProductTypes.
151
+ *
152
+ * @returns AsyncOfferCatalogRateTable
153
+ *
154
+ * @remarks
155
+ * This method returns an AsyncOfferCatalogRateTable.
156
+ * Use the resolve method on the returned object to retrieve the final Offer Catalog Rate Table.
157
+ * The lead data should include offerCatalogProductTypes (e.g., ["DebtSettlement"]) instead of productTypes.
158
+ */
159
+ getOfferCatalogRateTable(lead) {
160
+ return __awaiter(this, void 0, void 0, function* () {
161
+ const resp = yield this.client.post("originator/offerCatalogRateTables", lead);
162
+ const rateTable = offerCatalogRateTableDecoder.runWithException(resp);
163
+ const asyncRateTable = new AsyncOfferCatalogRateTable({
164
+ rateTable,
165
+ client: this.client,
166
+ });
167
+ return asyncRateTable;
168
+ });
169
+ }
170
+ /**
171
+ * Create a new offer catalog rate table, immediately resolving it.
172
+ *
173
+ * @param lead - An object representing the lead information including offerCatalogProductTypes.
174
+ *
175
+ * @returns OfferCatalogRateTable
176
+ *
177
+ * @remarks
178
+ * This method will immediately resolve the final Offer Catalog Rate Table.
179
+ * This may mean waiting a significant amount of time before it is finalized.
180
+ * Only use this if you can handle waiting for that amount of time.
181
+ * The lead data should include offerCatalogProductTypes (e.g., ["DebtSettlement"]) instead of productTypes.
182
+ */
183
+ getOfferCatalogRateTableBlocking(lead) {
184
+ return __awaiter(this, void 0, void 0, function* () {
185
+ const resp = yield this.client.post("blocking/originator/offerCatalogRateTables", lead);
186
+ const rateTable = offerCatalogRateTableDecoder.runWithException(resp);
187
+ return rateTable;
188
+ });
189
+ }
146
190
  }
@@ -12,6 +12,7 @@ import { Leads } from "./leads";
12
12
  import { setupServer } from "msw/node";
13
13
  import { http, HttpResponse } from "msw";
14
14
  import { AsyncRateTable } from "./rate_tables";
15
+ import { AsyncOfferCatalogRateTable } from "./offer_catalog_rate_tables";
15
16
  const testLeadData = {
16
17
  personalInformation: {
17
18
  firstName: "testFirst",
@@ -176,6 +177,56 @@ const pendingRateTable = {
176
177
  },
177
178
  ],
178
179
  };
180
+ const fullOfferCatalogRateTable = {
181
+ uuid: "full-offer-catalog-rate-table-uuid",
182
+ leadUuid: "full-lead-uuid",
183
+ offers: [
184
+ {
185
+ uuid: "full-special-offer-uuid",
186
+ productType: "CreditBuilder",
187
+ headline: "Mock Credit Builder Offer",
188
+ descriptionPoints: ["Description of the credit builder offer"],
189
+ url: "https://offers.engine.tech/ref/d6888b75-5454-498c-8710-e4c22daaf64e",
190
+ financialInstitutionDisplayName: "Engine Demo Loans Demand Sub Account 1",
191
+ financialInstitutionImageUrl: "https://s3.amazonaws.com/images.evenfinancial.com/logos/dev/engine_demo_loans_demand_sub_account-wjksncio.svg",
192
+ recommendationScore: 10,
193
+ financialInstitutionUuid: "financial-institution-uuid",
194
+ },
195
+ ],
196
+ pendingResponses: [],
197
+ };
198
+ const pendingOfferCatalogRateTable = {
199
+ uuid: "pending-offer-catalog-rate-table-uuid",
200
+ leadUuid: "pending-lead-uuid",
201
+ offers: [
202
+ {
203
+ uuid: "pending-special-offer-uuid",
204
+ productType: "DebtSettlement",
205
+ headline: "Mock Debt Settlement Offer",
206
+ descriptionPoints: ["Description of the debt settlement offer"],
207
+ url: "https://offers.engine.tech/ref/567beb02-9230-4bad-b60a-b2311bad400b",
208
+ financialInstitutionDisplayName: "Engine Demo Loans Demand Sub Account 2",
209
+ financialInstitutionImageUrl: "https://s3.amazonaws.com/images.evenfinancial.com/logos/dev/engine_demo_loans_demand_sub_account_2-wjkurpux.svg",
210
+ recommendationScore: 10,
211
+ financialInstitutionUuid: "financial-institution-uuid",
212
+ },
213
+ ],
214
+ pendingResponses: [
215
+ {
216
+ partner: {
217
+ uuid: "partner-uuid",
218
+ name: "partner",
219
+ description: "partner-description",
220
+ disclaimer: "partner-disclaimer",
221
+ supportsPreSelect: false,
222
+ shouldDisplayPreSelect: false,
223
+ supportsPersonalizedOffers: false,
224
+ imageUrl: "partner-image",
225
+ },
226
+ productTypes: ["other"],
227
+ },
228
+ ],
229
+ };
179
230
  const doublePollUuid = "double-poll-uuid";
180
231
  const testHost = "https://engine.com";
181
232
  const token = "good_auth_token";
@@ -223,6 +274,22 @@ const handlers = [
223
274
  status: 200,
224
275
  });
225
276
  }),
277
+ // Offer Catalog endpoints
278
+ http.post(`${testHost}/originator/offerCatalogRateTables`, () => {
279
+ return new HttpResponse(JSON.stringify(pendingOfferCatalogRateTable), {
280
+ status: 200,
281
+ });
282
+ }),
283
+ http.post(`${testHost}/blocking/originator/offerCatalogRateTables`, () => {
284
+ return new HttpResponse(JSON.stringify(fullOfferCatalogRateTable), {
285
+ status: 200,
286
+ });
287
+ }),
288
+ http.get(`${testHost}/originator/offerCatalogRateTables/${pendingOfferCatalogRateTable.uuid}`, () => {
289
+ return new HttpResponse(JSON.stringify(fullOfferCatalogRateTable), {
290
+ status: 200,
291
+ });
292
+ }),
226
293
  ];
227
294
  const server = setupServer(...handlers);
228
295
  describe("Leads", () => {
@@ -269,4 +336,16 @@ describe("Leads", () => {
269
336
  const resp = yield leads.getRateTableBlocking(getRateTableLeadUuidBlocking, testLeadData);
270
337
  expect(resp).toEqual(fullRateTable);
271
338
  }));
339
+ test("Get offer catalog rate table endpoint returns an async rate table", () => __awaiter(void 0, void 0, void 0, function* () {
340
+ const leads = new Leads(testHost, token);
341
+ const resp = yield leads.getOfferCatalogRateTable(testLeadData);
342
+ expect(resp).toBeInstanceOf(AsyncOfferCatalogRateTable);
343
+ const rateTable = yield resp.resolve();
344
+ expect(rateTable).toEqual(fullOfferCatalogRateTable);
345
+ }));
346
+ test("Get offer catalog rate table blocking endpoint returns a resolved rate table", () => __awaiter(void 0, void 0, void 0, function* () {
347
+ const leads = new Leads(testHost, token);
348
+ const resp = yield leads.getOfferCatalogRateTableBlocking(testLeadData);
349
+ expect(resp).toEqual(fullOfferCatalogRateTable);
350
+ }));
272
351
  });
@@ -0,0 +1,45 @@
1
+ import { Client } from "./client.js";
2
+ import { type FixedOfferCatalogRateTable } from "./decoders.js";
3
+ export type OfferCatalogRateTable = FixedOfferCatalogRateTable;
4
+ export interface AsyncOfferCatalogRateTableCtorArgs {
5
+ rateTable?: OfferCatalogRateTable;
6
+ client?: Client;
7
+ uuid?: string;
8
+ host?: string;
9
+ auth_token?: string;
10
+ }
11
+ /**
12
+ * The class used to fetch offer catalog rate tables from the Engine API.
13
+ * This class will handle polling the offer catalog rate tables endpoint until the pending responses are fulfilled.
14
+ */
15
+ export declare class AsyncOfferCatalogRateTable {
16
+ private rateTable?;
17
+ private client;
18
+ private uuid?;
19
+ /**
20
+ * Construct a new AsyncOfferCatalogRateTable instance.
21
+ * @param rateTable - An existing Offer Catalog Rate Table structure to start from.
22
+ * @param uuid - A UUID of an existing Offer Catalog Rate Table to fetch.
23
+ * @param client - A Client instance to use for fetching the data.
24
+ * @param host - A host used to construct a Client instance if none is provided.
25
+ * @param auth_token - An authentication token used to construct a Client instance if none is provided.
26
+ *
27
+ * @remarks
28
+ * Either one of rateTable or uuid is required, but providing both is an error.
29
+ * Similarly, provide either a pre-constructed Client instance or the host and auth_token parameters to construct one but not both.
30
+ */
31
+ constructor({ rateTable, uuid, client, host, auth_token, }: AsyncOfferCatalogRateTableCtorArgs);
32
+ /**
33
+ * Resolve the async Offer Catalog Rate Table into a real Offer Catalog Rate Table.
34
+ *
35
+ * @returns An Offer Catalog Rate Table with no pending responses.
36
+ *
37
+ * @remarks
38
+ *
39
+ * This will only make a network request if one is required.
40
+ * A network request is required if only a UUID was provided to the constructor, or if the provided Rate Table has pending responses.
41
+ * This method will also poll the API every second until the returned Rate Table has no more pending responses.
42
+ */
43
+ resolve(): Promise<OfferCatalogRateTable>;
44
+ private getRateTable;
45
+ }
@@ -0,0 +1,96 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { Client } from "./client.js";
11
+ import { offerCatalogRateTableDecoder, } from "./decoders.js";
12
+ const pollInterval = 1000; // 1 second
13
+ /**
14
+ * The class used to fetch offer catalog rate tables from the Engine API.
15
+ * This class will handle polling the offer catalog rate tables endpoint until the pending responses are fulfilled.
16
+ */
17
+ export class AsyncOfferCatalogRateTable {
18
+ /**
19
+ * Construct a new AsyncOfferCatalogRateTable instance.
20
+ * @param rateTable - An existing Offer Catalog Rate Table structure to start from.
21
+ * @param uuid - A UUID of an existing Offer Catalog Rate Table to fetch.
22
+ * @param client - A Client instance to use for fetching the data.
23
+ * @param host - A host used to construct a Client instance if none is provided.
24
+ * @param auth_token - An authentication token used to construct a Client instance if none is provided.
25
+ *
26
+ * @remarks
27
+ * Either one of rateTable or uuid is required, but providing both is an error.
28
+ * Similarly, provide either a pre-constructed Client instance or the host and auth_token parameters to construct one but not both.
29
+ */
30
+ constructor({ rateTable, uuid, client, host, auth_token, }) {
31
+ if (client && host && auth_token) {
32
+ throw new TypeError("Client cannot be provided at the same time as a host and auth_token.");
33
+ }
34
+ if (rateTable && uuid) {
35
+ throw new TypeError("Rate table and uuid cannot be provided at the same time.");
36
+ }
37
+ if (client) {
38
+ this.client = client;
39
+ }
40
+ else if (host && auth_token) {
41
+ this.client = new Client(host, auth_token);
42
+ }
43
+ else {
44
+ throw new TypeError("Either client must be provided or host and auth_token must be provided.");
45
+ }
46
+ this.rateTable = rateTable;
47
+ this.uuid = uuid;
48
+ if (!this.rateTable && !this.uuid) {
49
+ throw new TypeError("Either a rate table or a uuid must be provided.");
50
+ }
51
+ }
52
+ /**
53
+ * Resolve the async Offer Catalog Rate Table into a real Offer Catalog Rate Table.
54
+ *
55
+ * @returns An Offer Catalog Rate Table with no pending responses.
56
+ *
57
+ * @remarks
58
+ *
59
+ * This will only make a network request if one is required.
60
+ * A network request is required if only a UUID was provided to the constructor, or if the provided Rate Table has pending responses.
61
+ * This method will also poll the API every second until the returned Rate Table has no more pending responses.
62
+ */
63
+ resolve() {
64
+ return __awaiter(this, void 0, void 0, function* () {
65
+ if (this.rateTable &&
66
+ this.rateTable.pendingResponses &&
67
+ this.rateTable.pendingResponses.length > 0) {
68
+ const resolved = yield this.getRateTable(this.rateTable.uuid);
69
+ return new Promise((resolve) => {
70
+ setTimeout(() => {
71
+ resolve(resolved.resolve());
72
+ }, pollInterval);
73
+ });
74
+ }
75
+ if (this.uuid) {
76
+ const resolved = yield this.getRateTable(this.uuid);
77
+ return resolved.resolve();
78
+ }
79
+ if (this.rateTable) {
80
+ return this.rateTable;
81
+ }
82
+ throw new TypeError("No uuid or rate table was provided to resolve");
83
+ });
84
+ }
85
+ getRateTable(uuid) {
86
+ return __awaiter(this, void 0, void 0, function* () {
87
+ const endpoint = `originator/offerCatalogRateTables/${uuid}`;
88
+ const resp = yield this.client.get(endpoint);
89
+ const rateTable = offerCatalogRateTableDecoder.runWithException(resp);
90
+ return new AsyncOfferCatalogRateTable({
91
+ rateTable,
92
+ client: this.client,
93
+ });
94
+ });
95
+ }
96
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,215 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { describe, expect, test, beforeAll, afterEach, afterAll, } from "@jest/globals";
11
+ import { Client } from "./client";
12
+ import { setupServer } from "msw/node";
13
+ import { http, HttpResponse } from "msw";
14
+ import { AsyncOfferCatalogRateTable, } from "./offer_catalog_rate_tables";
15
+ const fullRateTable = {
16
+ uuid: "full-offer-catalog-rate-table-uuid",
17
+ leadUuid: "full-lead-uuid",
18
+ offers: [
19
+ {
20
+ uuid: "full-special-offer-uuid",
21
+ productType: "CreditBuilder",
22
+ headline: "Mock Credit Builder Offer",
23
+ descriptionPoints: ["Description of the credit builder offer"],
24
+ url: "https://offers.engine.tech/ref/d6888b75-5454-498c-8710-e4c22daaf64e",
25
+ financialInstitutionDisplayName: "Engine Demo Loans Demand Sub Account 1",
26
+ financialInstitutionImageUrl: "https://s3.amazonaws.com/images.evenfinancial.com/logos/dev/engine_demo_loans_demand_sub_account-wjksncio.svg",
27
+ recommendationScore: 10,
28
+ financialInstitutionUuid: "financial-institution-uuid",
29
+ },
30
+ {
31
+ uuid: "full-special-offer-uuid-2",
32
+ productType: "DebtSettlement",
33
+ headline: "Mock Debt Relief Offer",
34
+ descriptionPoints: ["Description of the debt relief offer"],
35
+ url: "https://offers.engine.tech/ref/567beb02-9230-4bad-b60a-b2311bad400b",
36
+ financialInstitutionDisplayName: "Engine Demo Loans Demand Sub Account 2",
37
+ financialInstitutionImageUrl: "https://s3.amazonaws.com/images.evenfinancial.com/logos/dev/engine_demo_loans_demand_sub_account_2-wjkurpux.svg",
38
+ recommendationScore: 10,
39
+ financialInstitutionUuid: "financial-institution-uuid",
40
+ },
41
+ {
42
+ uuid: "full-special-offer-uuid-3",
43
+ productType: "InstallmentLoans",
44
+ headline: "Mock Installment Loans Offer",
45
+ descriptionPoints: ["Description of the installment loans offer"],
46
+ url: "https://offers.engine.tech/ref/ec88908d-bdee-4b5d-8c49-2268167ea3c5",
47
+ financialInstitutionDisplayName: "Engine Demo Loans Demand Sub Account 3",
48
+ financialInstitutionImageUrl: "https://s3.amazonaws.com/images.evenfinancial.com/logos/dev/engine_demo_loans_demand_sub_account_3-wjkuspug.svg",
49
+ recommendationScore: 10,
50
+ financialInstitutionUuid: "financial-institution-uuid",
51
+ },
52
+ ],
53
+ pendingResponses: [],
54
+ };
55
+ const pendingRateTable = {
56
+ uuid: "pending-offer-catalog-rate-table-uuid",
57
+ leadUuid: "pending-lead-uuid",
58
+ offers: [
59
+ {
60
+ uuid: "pending-special-offer-uuid",
61
+ productType: "CreditBuilder",
62
+ headline: "Mock Credit Builder Offer",
63
+ descriptionPoints: ["Description of the credit builder offer"],
64
+ url: "https://offers.engine.tech/ref/d6888b75-5454-498c-8710-e4c22daaf64e",
65
+ financialInstitutionDisplayName: "Engine Demo Loans Demand Sub Account 1",
66
+ financialInstitutionImageUrl: "https://s3.amazonaws.com/images.evenfinancial.com/logos/dev/engine_demo_loans_demand_sub_account-wjksncio.svg",
67
+ recommendationScore: 10,
68
+ financialInstitutionUuid: "financial-institution-uuid",
69
+ },
70
+ {
71
+ uuid: "pending-special-offer-uuid-2",
72
+ productType: "DebtSettlement",
73
+ headline: "Mock Debt Relief Offer",
74
+ descriptionPoints: ["Description of the debt relief offer"],
75
+ url: "https://offers.engine.tech/ref/567beb02-9230-4bad-b60a-b2311bad400b",
76
+ financialInstitutionDisplayName: "Engine Demo Loans Demand Sub Account 2",
77
+ financialInstitutionImageUrl: "https://s3.amazonaws.com/images.evenfinancial.com/logos/dev/engine_demo_loans_demand_sub_account_2-wjkurpux.svg",
78
+ recommendationScore: 10,
79
+ financialInstitutionUuid: "financial-institution-uuid",
80
+ },
81
+ {
82
+ uuid: "pending-special-offer-uuid-3",
83
+ productType: "InstallmentLoans",
84
+ headline: "Mock Installment Loans Offer",
85
+ descriptionPoints: ["Description of the installment loans offer"],
86
+ url: "https://offers.engine.tech/ref/ec88908d-bdee-4b5d-8c49-2268167ea3c5",
87
+ financialInstitutionDisplayName: "Engine Demo Loans Demand Sub Account 3",
88
+ financialInstitutionImageUrl: "https://s3.amazonaws.com/images.evenfinancial.com/logos/dev/engine_demo_loans_demand_sub_account_3-wjkuspug.svg",
89
+ recommendationScore: 10,
90
+ financialInstitutionUuid: "financial-institution-uuid",
91
+ },
92
+ ],
93
+ pendingResponses: [
94
+ {
95
+ partner: {
96
+ uuid: "partner-uuid",
97
+ name: "partner",
98
+ description: "partner-description",
99
+ disclaimer: "partner-disclaimer",
100
+ supportsPreSelect: false,
101
+ shouldDisplayPreSelect: false,
102
+ supportsPersonalizedOffers: false,
103
+ imageUrl: "partner-image",
104
+ },
105
+ productTypes: ["credit_card"],
106
+ },
107
+ ],
108
+ };
109
+ const doublePollUuid = "double-poll-uuid";
110
+ const testHost = "https://engine.com";
111
+ const token = "good_auth_token";
112
+ const handlers = [
113
+ http.get(`${testHost}/originator/offerCatalogRateTables/${pendingRateTable.uuid}`, () => {
114
+ return new HttpResponse(JSON.stringify(fullRateTable), {
115
+ status: 200,
116
+ });
117
+ }),
118
+ http.get(`${testHost}/originator/offerCatalogRateTables/${doublePollUuid}`, () => {
119
+ return new HttpResponse(JSON.stringify(pendingRateTable), {
120
+ status: 200,
121
+ });
122
+ }),
123
+ ];
124
+ const server = setupServer(...handlers);
125
+ describe("OfferCatalogRateTables", () => {
126
+ beforeAll(() => server.listen({
127
+ onUnhandledRequest: "error",
128
+ }));
129
+ afterEach(() => server.resetHandlers());
130
+ afterAll(() => server.close());
131
+ test("Either client or host and auth_token must be provided to constructor", () => {
132
+ expect(() => new AsyncOfferCatalogRateTable({
133
+ host: testHost,
134
+ auth_token: token,
135
+ uuid: "test-uuid",
136
+ })).not.toThrowError();
137
+ expect(() => new AsyncOfferCatalogRateTable({
138
+ client: new Client(testHost, token),
139
+ uuid: "test-uuid",
140
+ })).not.toThrowError();
141
+ expect(() => new AsyncOfferCatalogRateTable({ uuid: "test-uuid" })).toThrowError(TypeError);
142
+ });
143
+ test("Either a rate table or a uuid must be provided to constructor", () => {
144
+ expect(() => new AsyncOfferCatalogRateTable({
145
+ host: testHost,
146
+ auth_token: token,
147
+ })).toThrowError(TypeError);
148
+ expect(() => new AsyncOfferCatalogRateTable({
149
+ host: testHost,
150
+ auth_token: token,
151
+ uuid: "test-uuid",
152
+ })).not.toThrowError();
153
+ expect(() => new AsyncOfferCatalogRateTable({
154
+ host: testHost,
155
+ auth_token: token,
156
+ rateTable: fullRateTable,
157
+ })).not.toThrowError();
158
+ });
159
+ test("Providing both a rate table and a uuid to constructor is an error", () => {
160
+ expect(() => new AsyncOfferCatalogRateTable({
161
+ host: testHost,
162
+ auth_token: token,
163
+ rateTable: fullRateTable,
164
+ uuid: "test-uuid",
165
+ })).toThrowError(TypeError);
166
+ });
167
+ test("Providing both a client instance and a host/auth_token pair is an error", () => {
168
+ expect(() => new AsyncOfferCatalogRateTable({
169
+ client: new Client(testHost, token),
170
+ host: testHost,
171
+ auth_token: token,
172
+ uuid: "test-uuid",
173
+ })).toThrowError(TypeError);
174
+ });
175
+ test("Providing a UUID resolves the rate table.", () => __awaiter(void 0, void 0, void 0, function* () {
176
+ const rateTables = new AsyncOfferCatalogRateTable({
177
+ host: testHost,
178
+ auth_token: token,
179
+ uuid: doublePollUuid,
180
+ });
181
+ const resp = yield rateTables.resolve();
182
+ expect(resp).toEqual(fullRateTable);
183
+ }));
184
+ test("Providing a rate table with pending responses resolves the rate table.", () => __awaiter(void 0, void 0, void 0, function* () {
185
+ const rateTables = new AsyncOfferCatalogRateTable({
186
+ host: testHost,
187
+ auth_token: token,
188
+ rateTable: pendingRateTable,
189
+ });
190
+ const resp = yield rateTables.resolve();
191
+ expect(resp).toEqual(fullRateTable);
192
+ }));
193
+ test("Providing a rate table with no pending responses resolves the rate table.", () => __awaiter(void 0, void 0, void 0, function* () {
194
+ const rateTables = new AsyncOfferCatalogRateTable({
195
+ host: testHost,
196
+ auth_token: token,
197
+ rateTable: fullRateTable,
198
+ });
199
+ const resp = yield rateTables.resolve();
200
+ expect(resp).toEqual(fullRateTable);
201
+ }));
202
+ test("If there are no pending responses no requests are made when resolving.", () => __awaiter(void 0, void 0, void 0, function* () {
203
+ const rateTables = new AsyncOfferCatalogRateTable({
204
+ host: testHost,
205
+ auth_token: token,
206
+ rateTable: fullRateTable,
207
+ });
208
+ let requestSent = false;
209
+ server.events.on("request:start", () => {
210
+ requestSent = true;
211
+ });
212
+ yield rateTables.resolve();
213
+ expect(requestSent).toBe(false);
214
+ }));
215
+ });
package/package.json CHANGED
@@ -1,48 +1,48 @@
1
1
  {
2
- "name": "@moneylion/engine-api",
3
- "version": "1.3.3",
4
- "description": "Interface to engine.tech API",
5
- "type": "module",
6
- "main": "dist/index.js",
7
- "files": [
8
- "dist"
9
- ],
10
- "scripts": {
11
- "build": "tsc",
12
- "lint": "prettier . --check && eslint src/",
13
- "lint:fix": "prettier . --write && eslint --fix src/",
14
- "test": "npm run build && NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" jest dist/",
15
- "generate:schema": "openapi-typescript https://even-api-reference.s3.amazonaws.com/releases/branches/public@1.49.0/latest/open-api/public/spec.json -o src/generated/schema.d.ts"
16
- },
17
- "author": "",
18
- "license": "MIT",
19
- "devDependencies": {
20
- "@jest/globals": "^29.7.0",
21
- "@tsconfig/node18": "^18.2.2",
22
- "@typescript-eslint/eslint-plugin": "^7.3.1",
23
- "@typescript-eslint/parser": "^7.3.1",
24
- "eslint": "^8.57.0",
25
- "eslint-config-prettier": "^9.1.0",
26
- "eslint-plugin-tsdoc": "^0.2.17",
27
- "jest": "^29.7.0",
28
- "msw": "^2.2.10",
29
- "openapi-typescript": "^6.7.5",
30
- "prettier": "3.2.5",
31
- "ts-jest": "^29.1.2",
32
- "typescript": "^5.2.2"
33
- },
34
- "engines": {
35
- "node": ">=18"
36
- },
37
- "dependencies": {
38
- "@mojotech/json-type-validation": "^3.1.0",
39
- "node-fetch": "^3.3.2"
40
- },
41
- "prettier": {
42
- "quoteProps": "consistent",
43
- "singleQuote": false,
44
- "tabWidth": 4,
45
- "trailingComma": "es5",
46
- "useTabs": true
47
- }
2
+ "name": "@moneylion/engine-api",
3
+ "version": "1.3.5",
4
+ "description": "Interface to engine.tech API",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "lint": "prettier . --check && eslint src/",
13
+ "lint:fix": "prettier . --write && eslint --fix src/",
14
+ "test": "npm run build && NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" jest dist/",
15
+ "generate:schema": "openapi-typescript https://even-api-reference.s3.amazonaws.com/releases/branches/public@1.49.0/latest/open-api/public/spec.json -o src/generated/schema.d.ts"
16
+ },
17
+ "author": "",
18
+ "license": "MIT",
19
+ "devDependencies": {
20
+ "@jest/globals": "^29.7.0",
21
+ "@tsconfig/node18": "^18.2.2",
22
+ "@typescript-eslint/eslint-plugin": "^7.3.1",
23
+ "@typescript-eslint/parser": "^7.3.1",
24
+ "eslint": "^8.57.0",
25
+ "eslint-config-prettier": "^9.1.0",
26
+ "eslint-plugin-tsdoc": "^0.2.17",
27
+ "jest": "^29.7.0",
28
+ "msw": "^2.2.10",
29
+ "openapi-typescript": "^6.7.5",
30
+ "prettier": "3.2.5",
31
+ "ts-jest": "^29.1.2",
32
+ "typescript": "^5.2.2"
33
+ },
34
+ "engines": {
35
+ "node": ">=18"
36
+ },
37
+ "dependencies": {
38
+ "@mojotech/json-type-validation": "^3.1.0",
39
+ "node-fetch": "^3.3.2"
40
+ },
41
+ "prettier": {
42
+ "quoteProps": "consistent",
43
+ "singleQuote": false,
44
+ "tabWidth": 4,
45
+ "trailingComma": "es5",
46
+ "useTabs": true
47
+ }
48
48
  }