swell-js 5.1.3 → 5.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/api.mjs CHANGED
@@ -3,21 +3,310 @@ import { getCookie, setCookie } from './cookie.mjs';
3
3
  import cacheApi from './cache.mjs';
4
4
  import methods$3 from './cart.mjs';
5
5
  import methods$4 from './account.mjs';
6
+ import { k as isFunction, l as loadScript, b as isObject, v as vaultRequest, n as isEmpty, d as defaultMethods, z as trimEnd, A as setOptions, B as utils, C as trimStart, D as trimBoth, t as toSnake, E as stringifyQuery, q as base64Encode, i as isServer, a as toCamel } from './index.a227b03d.mjs';
7
+ import 'qs';
8
+ import 'deepmerge';
9
+ import 'fast-case';
6
10
  import methods$5 from './products.mjs';
7
11
  import methods$6 from './categories.mjs';
8
12
  import methods$7 from './attributes.mjs';
9
13
  import methods$8 from './subscriptions.mjs';
10
- import { d as defaultMethods, z as trimEnd, A as setOptions, B as utils, C as trimStart, D as trimBoth, t as toSnake, E as stringifyQuery, q as base64Encode, i as isServer, a as toCamel } from './index.3c15c4d3.mjs';
11
14
  import methods$9 from './content.mjs';
12
15
  import methods$a from './settings.mjs';
13
16
  import PaymentController from './payment.mjs';
14
17
  import methods$b from './locale.mjs';
15
18
  import methods$c from './currency.mjs';
16
- import 'qs';
17
19
  import './find.18f1ac6d.mjs';
18
20
  import './round.577a8441.mjs';
19
- import 'deepmerge';
20
- import 'fast-case';
21
+
22
+ class AppComponent {
23
+ #preact = null;
24
+ #preactComponent = null;
25
+ #container = null;
26
+
27
+ constructor(app, component, api, options) {
28
+ this.app = app;
29
+ this.component = component;
30
+ this.api = api;
31
+ this.options = options;
32
+ this.props = {};
33
+ }
34
+
35
+ get id() {
36
+ return this.component.id;
37
+ }
38
+
39
+ get name() {
40
+ return this.component.name;
41
+ }
42
+
43
+ get extension() {
44
+ return this.component.values.extension;
45
+ }
46
+
47
+ get settings() {
48
+ return this.app.settings[this.extension];
49
+ }
50
+
51
+ get #fileData() {
52
+ return this.component.build_file_data;
53
+ }
54
+
55
+ render(containerId, props) {
56
+ const container = document.getElementById(containerId);
57
+
58
+ if (!container) {
59
+ throw new Error(`Container with ID "${containerId}" not found.`);
60
+ }
61
+
62
+ const evalFn = new Function(`${this.#fileData}\nreturn { ...Component }`);
63
+ const { preact, default: Component } = evalFn();
64
+
65
+ this.#preact = preact;
66
+ this.#preactComponent = Component;
67
+ this.#container = container;
68
+
69
+ return new Promise((resolve) => {
70
+ this.#render({
71
+ ...props,
72
+ settings: this.settings,
73
+ registerHandlers: this.#registerHandlers.bind(this),
74
+ loadLib: this.#loadLib.bind(this),
75
+ onReady: resolve,
76
+ });
77
+ });
78
+ }
79
+
80
+ setProps(props) {
81
+ this.#render(props);
82
+ }
83
+
84
+ async updateCart(data) {
85
+ const cart = await methods$3(this.api, this.options).update(data);
86
+
87
+ this.setProps({ cart });
88
+ }
89
+
90
+ getHandler(name) {
91
+ const handler = this.handlers?.[name];
92
+
93
+ return isFunction(handler) ? handler : null;
94
+ }
95
+
96
+ #registerHandlers(handlers) {
97
+ this.handlers = handlers;
98
+ }
99
+
100
+ #loadLib(id, src, attributes = {}) {
101
+ const scriptId = `${id}-${this.id}-component-lib`;
102
+
103
+ return loadScript(scriptId, src, attributes);
104
+ }
105
+
106
+ #setProps(props) {
107
+ if (!isObject(props)) {
108
+ throw new Error('Props must be a plain object.');
109
+ }
110
+
111
+ this.props = {
112
+ ...this.props,
113
+ ...props,
114
+ };
115
+ }
116
+
117
+ #render(props) {
118
+ const { render, h } = this.#preact;
119
+
120
+ this.#setProps(props);
121
+
122
+ render(h(this.#preactComponent, this.props), this.#container);
123
+ }
124
+ }
125
+
126
+ class AppPaymentComponent extends AppComponent {
127
+ constructor(app, component, api, options) {
128
+ super(app, component, api, options);
129
+ }
130
+
131
+ get #accountId() {
132
+ return this.props.cart?.account_id;
133
+ }
134
+
135
+ get #gateway() {
136
+ return `app_${this.app.id}_${this.extension}`;
137
+ }
138
+
139
+ render(containerId, props = {}) {
140
+ return super.render(containerId, {
141
+ ...props,
142
+ updateCart: this.updateCart.bind(this),
143
+ getIntent: this.#getIntent.bind(this),
144
+ createIntent: this.#createIntent.bind(this),
145
+ });
146
+ }
147
+
148
+ #getIntent(data) {
149
+ return vaultRequest('GET', '/intent', {
150
+ gateway: this.#gateway,
151
+ account_id: this.#accountId,
152
+ intent: data,
153
+ });
154
+ }
155
+
156
+ #createIntent(data) {
157
+ return vaultRequest('POST', '/intent', {
158
+ gateway: this.#gateway,
159
+ account_id: this.#accountId,
160
+ intent: data,
161
+ });
162
+ }
163
+ }
164
+
165
+ class App {
166
+ constructor(app, api, options) {
167
+ this.app = app;
168
+ this.api = api;
169
+ this.options = options;
170
+ }
171
+
172
+ get #components() {
173
+ return this.app.components?.results || [];
174
+ }
175
+
176
+ getComponent(name) {
177
+ if (!name) {
178
+ throw new Error('Component name is not provided');
179
+ }
180
+
181
+ const component = this.#components.find(
182
+ (component) => component.name === name,
183
+ );
184
+
185
+ if (!component) {
186
+ throw new Error(`Component "${name}" not found`);
187
+ }
188
+
189
+ return this.#createComponent(component);
190
+ }
191
+
192
+ getComponents(params = {}) {
193
+ const components = this.#filterComponents(params);
194
+
195
+ return components.reduce((acc, component) => {
196
+ acc[component.name] = this.#createComponent(component);
197
+
198
+ return acc;
199
+ }, {});
200
+ }
201
+
202
+ #filterComponents(params) {
203
+ if (!isObject(params) || isEmpty(params)) {
204
+ return this.#components;
205
+ }
206
+
207
+ const { extension, extensionType } = params;
208
+
209
+ if (extensionType) {
210
+ return this.#filterByExtensionType(extensionType);
211
+ }
212
+
213
+ if (extension) {
214
+ return this.#filterByExtension(extension);
215
+ }
216
+
217
+ return [];
218
+ }
219
+
220
+ #filterByExtensionType(extensionType) {
221
+ const extensions = this.app.extensions
222
+ .filter((extension) => extension.type === extensionType)
223
+ .map((extension) => extension.id);
224
+
225
+ return extensions
226
+ .map((extension) => this.#filterByExtension(extension))
227
+ .flat();
228
+ }
229
+
230
+ #filterByExtension(extension) {
231
+ return this.#components.filter(
232
+ (component) => component.values.extension === extension,
233
+ );
234
+ }
235
+
236
+ #createComponent(component) {
237
+ const { extensions } = this.app;
238
+ const {
239
+ name,
240
+ values: { extension: componentExtension },
241
+ } = component;
242
+
243
+ if (!componentExtension) {
244
+ throw new Error(
245
+ `The component "${name}" has no extension. Define the extension in the component's config.`,
246
+ );
247
+ }
248
+
249
+ const extension = extensions.find(
250
+ (extension) => extension.id === componentExtension,
251
+ );
252
+
253
+ if (!extension) {
254
+ throw new Error(
255
+ `The extension "${componentExtension}" of component "${name}" is not defined in "swell.json".`,
256
+ );
257
+ }
258
+
259
+ switch (extension.type) {
260
+ case 'payment':
261
+ return new AppPaymentComponent(
262
+ this.app,
263
+ component,
264
+ this.api,
265
+ this.options,
266
+ );
267
+ default:
268
+ throw new Error(`Unknown extension type "${extension.type}".`);
269
+ }
270
+ }
271
+ }
272
+
273
+ class AppController {
274
+ #apps = new Map();
275
+
276
+ constructor(api, options) {
277
+ this.api = api;
278
+ this.options = options;
279
+ }
280
+
281
+ async load(appId) {
282
+ const loadedApp = this.#apps.get(appId);
283
+
284
+ if (loadedApp) {
285
+ return loadedApp;
286
+ }
287
+
288
+ const app = await this.#getApp(appId);
289
+ const appInstance = new App(app, this.api, this.options);
290
+
291
+ this.#apps.set(appId, appInstance);
292
+
293
+ return appInstance;
294
+ }
295
+
296
+ async #getApp(appId) {
297
+ const app = await this.api.request('get', `/apps/${appId}`, undefined, {
298
+ expand: 'components',
299
+ });
300
+
301
+ if (isEmpty(app.extensions)) {
302
+ throw new Error(
303
+ `The app "${app.name}" has no extensions. Define the app extensions in "swell.json".`,
304
+ );
305
+ }
306
+
307
+ return app;
308
+ }
309
+ }
21
310
 
22
311
  function methods$2(api) {
23
312
  const { get, list } = defaultMethods(api, '/invoices', ['list', 'get']);
@@ -157,7 +446,7 @@ function swell(initStore = undefined, initKey, initOptions = {}) {
157
446
  const api = {};
158
447
 
159
448
  Object.assign(api, {
160
- version: '5.1.3',
449
+ version: '5.3.0',
161
450
  options,
162
451
  request,
163
452
 
@@ -220,6 +509,8 @@ function swell(initStore = undefined, initKey, initOptions = {}) {
220
509
 
221
510
  account: methods$4(api),
222
511
 
512
+ app: new AppController(api, options),
513
+
223
514
  products: methods$5(api, options),
224
515
 
225
516
  categories: methods$6(api),
@@ -1,4 +1,4 @@
1
- import { d as defaultMethods } from './index.3c15c4d3.mjs';
1
+ import { d as defaultMethods } from './index.a227b03d.mjs';
2
2
  import cacheApi from './cache.mjs';
3
3
  import 'qs';
4
4
  import './find.18f1ac6d.mjs';
package/dist/cache.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { s as set, m as merge, a as toCamel, h as toCamelPath, j as getOptions } from './index.3c15c4d3.mjs';
1
+ import { s as set, m as merge, a as toCamel, h as toCamelPath, j as getOptions } from './index.a227b03d.mjs';
2
2
  import { g as get } from './find.18f1ac6d.mjs';
3
3
  import 'qs';
4
4
  import './round.577a8441.mjs';
package/dist/card.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { t as toSnake, v as vaultRequest } from './index.3c15c4d3.mjs';
1
+ import { t as toSnake, v as vaultRequest } from './index.a227b03d.mjs';
2
2
  import 'qs';
3
3
  import './find.18f1ac6d.mjs';
4
4
  import './round.577a8441.mjs';
package/dist/cart.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import 'qs';
2
- import { c as cloneDeep } from './index.3c15c4d3.mjs';
2
+ import { c as cloneDeep } from './index.a227b03d.mjs';
3
3
  import 'deepmerge';
4
4
  import 'fast-case';
5
5
  import { cleanProductOptions } from './products.mjs';
@@ -1,4 +1,4 @@
1
- import { d as defaultMethods } from './index.3c15c4d3.mjs';
1
+ import { d as defaultMethods } from './index.a227b03d.mjs';
2
2
  import cacheApi from './cache.mjs';
3
3
  import 'qs';
4
4
  import './find.18f1ac6d.mjs';
package/dist/content.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import cacheApi from './cache.mjs';
2
- import './index.3c15c4d3.mjs';
2
+ import './index.a227b03d.mjs';
3
3
  import 'qs';
4
4
  import './find.18f1ac6d.mjs';
5
5
  import './round.577a8441.mjs';
package/dist/cookie.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { i as isServer } from './index.3c15c4d3.mjs';
1
+ import { i as isServer } from './index.a227b03d.mjs';
2
2
  import 'qs';
3
3
  import './find.18f1ac6d.mjs';
4
4
  import './round.577a8441.mjs';
@@ -1654,6 +1654,17 @@ async function vaultRequest(method, url, data) {
1654
1654
  connectionError.status = result?.$status;
1655
1655
 
1656
1656
  throw connectionError;
1657
+ } else if (result.$data.errors) {
1658
+ const param = Object.keys(result.$data.errors)[0];
1659
+ const err = new Error(
1660
+ result.$data.errors[param].message || 'Unknown error',
1661
+ );
1662
+
1663
+ err.code = 'vault_error';
1664
+ err.status = 402;
1665
+ err.param = param;
1666
+
1667
+ throw err;
1657
1668
  }
1658
1669
 
1659
1670
  return result.$data;
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  export { default } from './api.mjs';
2
2
  import './card.mjs';
3
- import './index.3c15c4d3.mjs';
3
+ import './index.a227b03d.mjs';
4
4
  import 'qs';
5
5
  import './find.18f1ac6d.mjs';
6
6
  import './round.577a8441.mjs';