swell-js 5.2.0 → 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.
@@ -10119,6 +10119,17 @@
10119
10119
  connectionError.status = result?.$status;
10120
10120
 
10121
10121
  throw connectionError;
10122
+ } else if (result.$data.errors) {
10123
+ const param = Object.keys(result.$data.errors)[0];
10124
+ const err = new Error(
10125
+ result.$data.errors[param].message || 'Unknown error',
10126
+ );
10127
+
10128
+ err.code = 'vault_error';
10129
+ err.status = 402;
10130
+ err.param = param;
10131
+
10132
+ throw err;
10122
10133
  }
10123
10134
 
10124
10135
  return result.$data;
@@ -11320,6 +11331,295 @@
11320
11331
  };
11321
11332
  }
11322
11333
 
11334
+ class AppComponent {
11335
+ #preact = null;
11336
+ #preactComponent = null;
11337
+ #container = null;
11338
+
11339
+ constructor(app, component, api, options) {
11340
+ this.app = app;
11341
+ this.component = component;
11342
+ this.api = api;
11343
+ this.options = options;
11344
+ this.props = {};
11345
+ }
11346
+
11347
+ get id() {
11348
+ return this.component.id;
11349
+ }
11350
+
11351
+ get name() {
11352
+ return this.component.name;
11353
+ }
11354
+
11355
+ get extension() {
11356
+ return this.component.values.extension;
11357
+ }
11358
+
11359
+ get settings() {
11360
+ return this.app.settings[this.extension];
11361
+ }
11362
+
11363
+ get #fileData() {
11364
+ return this.component.build_file_data;
11365
+ }
11366
+
11367
+ render(containerId, props) {
11368
+ const container = document.getElementById(containerId);
11369
+
11370
+ if (!container) {
11371
+ throw new Error(`Container with ID "${containerId}" not found.`);
11372
+ }
11373
+
11374
+ const evalFn = new Function(`${this.#fileData}\nreturn { ...Component }`);
11375
+ const { preact, default: Component } = evalFn();
11376
+
11377
+ this.#preact = preact;
11378
+ this.#preactComponent = Component;
11379
+ this.#container = container;
11380
+
11381
+ return new Promise((resolve) => {
11382
+ this.#render({
11383
+ ...props,
11384
+ settings: this.settings,
11385
+ registerHandlers: this.#registerHandlers.bind(this),
11386
+ loadLib: this.#loadLib.bind(this),
11387
+ onReady: resolve,
11388
+ });
11389
+ });
11390
+ }
11391
+
11392
+ setProps(props) {
11393
+ this.#render(props);
11394
+ }
11395
+
11396
+ async updateCart(data) {
11397
+ const cart = await methods$a(this.api, this.options).update(data);
11398
+
11399
+ this.setProps({ cart });
11400
+ }
11401
+
11402
+ getHandler(name) {
11403
+ const handler = this.handlers?.[name];
11404
+
11405
+ return isFunction(handler) ? handler : null;
11406
+ }
11407
+
11408
+ #registerHandlers(handlers) {
11409
+ this.handlers = handlers;
11410
+ }
11411
+
11412
+ #loadLib(id, src, attributes = {}) {
11413
+ const scriptId = `${id}-${this.id}-component-lib`;
11414
+
11415
+ return loadScript(scriptId, src, attributes);
11416
+ }
11417
+
11418
+ #setProps(props) {
11419
+ if (!isObject(props)) {
11420
+ throw new Error('Props must be a plain object.');
11421
+ }
11422
+
11423
+ this.props = {
11424
+ ...this.props,
11425
+ ...props,
11426
+ };
11427
+ }
11428
+
11429
+ #render(props) {
11430
+ const { render, h } = this.#preact;
11431
+
11432
+ this.#setProps(props);
11433
+
11434
+ render(h(this.#preactComponent, this.props), this.#container);
11435
+ }
11436
+ }
11437
+
11438
+ class AppPaymentComponent extends AppComponent {
11439
+ constructor(app, component, api, options) {
11440
+ super(app, component, api, options);
11441
+ }
11442
+
11443
+ get #accountId() {
11444
+ return this.props.cart?.account_id;
11445
+ }
11446
+
11447
+ get #gateway() {
11448
+ return `app_${this.app.id}_${this.extension}`;
11449
+ }
11450
+
11451
+ render(containerId, props = {}) {
11452
+ return super.render(containerId, {
11453
+ ...props,
11454
+ updateCart: this.updateCart.bind(this),
11455
+ getIntent: this.#getIntent.bind(this),
11456
+ createIntent: this.#createIntent.bind(this),
11457
+ });
11458
+ }
11459
+
11460
+ #getIntent(data) {
11461
+ return vaultRequest('GET', '/intent', {
11462
+ gateway: this.#gateway,
11463
+ account_id: this.#accountId,
11464
+ intent: data,
11465
+ });
11466
+ }
11467
+
11468
+ #createIntent(data) {
11469
+ return vaultRequest('POST', '/intent', {
11470
+ gateway: this.#gateway,
11471
+ account_id: this.#accountId,
11472
+ intent: data,
11473
+ });
11474
+ }
11475
+ }
11476
+
11477
+ class App {
11478
+ constructor(app, api, options) {
11479
+ this.app = app;
11480
+ this.api = api;
11481
+ this.options = options;
11482
+ }
11483
+
11484
+ get #components() {
11485
+ return this.app.components?.results || [];
11486
+ }
11487
+
11488
+ getComponent(name) {
11489
+ if (!name) {
11490
+ throw new Error('Component name is not provided');
11491
+ }
11492
+
11493
+ const component = this.#components.find(
11494
+ (component) => component.name === name,
11495
+ );
11496
+
11497
+ if (!component) {
11498
+ throw new Error(`Component "${name}" not found`);
11499
+ }
11500
+
11501
+ return this.#createComponent(component);
11502
+ }
11503
+
11504
+ getComponents(params = {}) {
11505
+ const components = this.#filterComponents(params);
11506
+
11507
+ return components.reduce((acc, component) => {
11508
+ acc[component.name] = this.#createComponent(component);
11509
+
11510
+ return acc;
11511
+ }, {});
11512
+ }
11513
+
11514
+ #filterComponents(params) {
11515
+ if (!isObject(params) || isEmpty(params)) {
11516
+ return this.#components;
11517
+ }
11518
+
11519
+ const { extension, extensionType } = params;
11520
+
11521
+ if (extensionType) {
11522
+ return this.#filterByExtensionType(extensionType);
11523
+ }
11524
+
11525
+ if (extension) {
11526
+ return this.#filterByExtension(extension);
11527
+ }
11528
+
11529
+ return [];
11530
+ }
11531
+
11532
+ #filterByExtensionType(extensionType) {
11533
+ const extensions = this.app.extensions
11534
+ .filter((extension) => extension.type === extensionType)
11535
+ .map((extension) => extension.id);
11536
+
11537
+ return extensions
11538
+ .map((extension) => this.#filterByExtension(extension))
11539
+ .flat();
11540
+ }
11541
+
11542
+ #filterByExtension(extension) {
11543
+ return this.#components.filter(
11544
+ (component) => component.values.extension === extension,
11545
+ );
11546
+ }
11547
+
11548
+ #createComponent(component) {
11549
+ const { extensions } = this.app;
11550
+ const {
11551
+ name,
11552
+ values: { extension: componentExtension },
11553
+ } = component;
11554
+
11555
+ if (!componentExtension) {
11556
+ throw new Error(
11557
+ `The component "${name}" has no extension. Define the extension in the component's config.`,
11558
+ );
11559
+ }
11560
+
11561
+ const extension = extensions.find(
11562
+ (extension) => extension.id === componentExtension,
11563
+ );
11564
+
11565
+ if (!extension) {
11566
+ throw new Error(
11567
+ `The extension "${componentExtension}" of component "${name}" is not defined in "swell.json".`,
11568
+ );
11569
+ }
11570
+
11571
+ switch (extension.type) {
11572
+ case 'payment':
11573
+ return new AppPaymentComponent(
11574
+ this.app,
11575
+ component,
11576
+ this.api,
11577
+ this.options,
11578
+ );
11579
+ default:
11580
+ throw new Error(`Unknown extension type "${extension.type}".`);
11581
+ }
11582
+ }
11583
+ }
11584
+
11585
+ class AppController {
11586
+ #apps = new Map();
11587
+
11588
+ constructor(api, options) {
11589
+ this.api = api;
11590
+ this.options = options;
11591
+ }
11592
+
11593
+ async load(appId) {
11594
+ const loadedApp = this.#apps.get(appId);
11595
+
11596
+ if (loadedApp) {
11597
+ return loadedApp;
11598
+ }
11599
+
11600
+ const app = await this.#getApp(appId);
11601
+ const appInstance = new App(app, this.api, this.options);
11602
+
11603
+ this.#apps.set(appId, appInstance);
11604
+
11605
+ return appInstance;
11606
+ }
11607
+
11608
+ async #getApp(appId) {
11609
+ const app = await this.api.request('get', `/apps/${appId}`, undefined, {
11610
+ expand: 'components',
11611
+ });
11612
+
11613
+ if (isEmpty(app.extensions)) {
11614
+ throw new Error(
11615
+ `The app "${app.name}" has no extensions. Define the app extensions in "swell.json".`,
11616
+ );
11617
+ }
11618
+
11619
+ return app;
11620
+ }
11621
+ }
11622
+
11323
11623
  function methods$8(api) {
11324
11624
  const { get, list } = defaultMethods(api, '/categories', ['list', 'get']);
11325
11625
 
@@ -12153,7 +12453,7 @@
12153
12453
  * @returns {Promise<object>}
12154
12454
  */
12155
12455
  async createIntent(data) {
12156
- return this._vaultRequest('post', '/intent', data);
12456
+ return vaultRequest('post', '/intent', data);
12157
12457
  }
12158
12458
 
12159
12459
  /**
@@ -12163,7 +12463,7 @@
12163
12463
  * @returns {Promise<object>}
12164
12464
  */
12165
12465
  async updateIntent(data) {
12166
- return this._vaultRequest('put', '/intent', data);
12466
+ return vaultRequest('put', '/intent', data);
12167
12467
  }
12168
12468
 
12169
12469
  /**
@@ -12173,7 +12473,7 @@
12173
12473
  * @returns {Promise<object>}
12174
12474
  */
12175
12475
  async authorizeGateway(data) {
12176
- return this._vaultRequest('post', '/authorization', data);
12476
+ return vaultRequest('post', '/authorization', data);
12177
12477
  }
12178
12478
 
12179
12479
  /**
@@ -12257,29 +12557,6 @@
12257
12557
  return { ...cart, settings: { ...settings.store } };
12258
12558
  }
12259
12559
 
12260
- /**
12261
- * Sends a Vault request.
12262
- *
12263
- * @param {string} method
12264
- * @param {string} url
12265
- * @param {object} data
12266
- * @returns {Promise<object>}
12267
- */
12268
- async _vaultRequest(method, url, data) {
12269
- const response = await vaultRequest(method, url, data);
12270
-
12271
- if (response.errors) {
12272
- const param = Object.keys(response.errors)[0];
12273
- const err = new Error(response.errors[param].message || 'Unknown error');
12274
- err.code = 'vault_error';
12275
- err.status = 402;
12276
- err.param = param;
12277
- throw err;
12278
- }
12279
-
12280
- return response;
12281
- }
12282
-
12283
12560
  /**
12284
12561
  * Sets values for payment scripts.
12285
12562
  *
@@ -16794,15 +17071,6 @@
16794
17071
  async _vaultRequest(method, url, data) {
16795
17072
  const response = await vaultRequest(method, url, data);
16796
17073
 
16797
- if (response.errors) {
16798
- const param = Object.keys(response.errors)[0];
16799
- const err = new Error(response.errors[param].message || 'Unknown error');
16800
- err.code = 'vault_error';
16801
- err.status = 402;
16802
- err.param = param;
16803
- throw err;
16804
- }
16805
-
16806
17074
  if (this.options.useCamelCase) {
16807
17075
  return toCamel(response);
16808
17076
  }
@@ -17349,7 +17617,7 @@
17349
17617
  const api = {};
17350
17618
 
17351
17619
  Object.assign(api, {
17352
- version: '5.2.0',
17620
+ version: '5.3.0',
17353
17621
  options,
17354
17622
  request,
17355
17623
 
@@ -17412,6 +17680,8 @@
17412
17680
 
17413
17681
  account: methods$9(api),
17414
17682
 
17683
+ app: new AppController(api, options),
17684
+
17415
17685
  products: methods$b(api, options),
17416
17686
 
17417
17687
  categories: methods$8(api),