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.
package/dist/swell.cjs CHANGED
@@ -4674,6 +4674,17 @@ async function vaultRequest(method, url, data) {
4674
4674
  connectionError.status = result?.$status;
4675
4675
 
4676
4676
  throw connectionError;
4677
+ } else if (result.$data.errors) {
4678
+ const param = Object.keys(result.$data.errors)[0];
4679
+ const err = new Error(
4680
+ result.$data.errors[param].message || 'Unknown error',
4681
+ );
4682
+
4683
+ err.code = 'vault_error';
4684
+ err.status = 402;
4685
+ err.param = param;
4686
+
4687
+ throw err;
4677
4688
  }
4678
4689
 
4679
4690
  return result.$data;
@@ -5875,6 +5886,295 @@ function methods$9(api) {
5875
5886
  };
5876
5887
  }
5877
5888
 
5889
+ class AppComponent {
5890
+ #preact = null;
5891
+ #preactComponent = null;
5892
+ #container = null;
5893
+
5894
+ constructor(app, component, api, options) {
5895
+ this.app = app;
5896
+ this.component = component;
5897
+ this.api = api;
5898
+ this.options = options;
5899
+ this.props = {};
5900
+ }
5901
+
5902
+ get id() {
5903
+ return this.component.id;
5904
+ }
5905
+
5906
+ get name() {
5907
+ return this.component.name;
5908
+ }
5909
+
5910
+ get extension() {
5911
+ return this.component.values.extension;
5912
+ }
5913
+
5914
+ get settings() {
5915
+ return this.app.settings[this.extension];
5916
+ }
5917
+
5918
+ get #fileData() {
5919
+ return this.component.build_file_data;
5920
+ }
5921
+
5922
+ render(containerId, props) {
5923
+ const container = document.getElementById(containerId);
5924
+
5925
+ if (!container) {
5926
+ throw new Error(`Container with ID "${containerId}" not found.`);
5927
+ }
5928
+
5929
+ const evalFn = new Function(`${this.#fileData}\nreturn { ...Component }`);
5930
+ const { preact, default: Component } = evalFn();
5931
+
5932
+ this.#preact = preact;
5933
+ this.#preactComponent = Component;
5934
+ this.#container = container;
5935
+
5936
+ return new Promise((resolve) => {
5937
+ this.#render({
5938
+ ...props,
5939
+ settings: this.settings,
5940
+ registerHandlers: this.#registerHandlers.bind(this),
5941
+ loadLib: this.#loadLib.bind(this),
5942
+ onReady: resolve,
5943
+ });
5944
+ });
5945
+ }
5946
+
5947
+ setProps(props) {
5948
+ this.#render(props);
5949
+ }
5950
+
5951
+ async updateCart(data) {
5952
+ const cart = await methods$a(this.api, this.options).update(data);
5953
+
5954
+ this.setProps({ cart });
5955
+ }
5956
+
5957
+ getHandler(name) {
5958
+ const handler = this.handlers?.[name];
5959
+
5960
+ return isFunction(handler) ? handler : null;
5961
+ }
5962
+
5963
+ #registerHandlers(handlers) {
5964
+ this.handlers = handlers;
5965
+ }
5966
+
5967
+ #loadLib(id, src, attributes = {}) {
5968
+ const scriptId = `${id}-${this.id}-component-lib`;
5969
+
5970
+ return loadScript(scriptId, src, attributes);
5971
+ }
5972
+
5973
+ #setProps(props) {
5974
+ if (!isObject(props)) {
5975
+ throw new Error('Props must be a plain object.');
5976
+ }
5977
+
5978
+ this.props = {
5979
+ ...this.props,
5980
+ ...props,
5981
+ };
5982
+ }
5983
+
5984
+ #render(props) {
5985
+ const { render, h } = this.#preact;
5986
+
5987
+ this.#setProps(props);
5988
+
5989
+ render(h(this.#preactComponent, this.props), this.#container);
5990
+ }
5991
+ }
5992
+
5993
+ class AppPaymentComponent extends AppComponent {
5994
+ constructor(app, component, api, options) {
5995
+ super(app, component, api, options);
5996
+ }
5997
+
5998
+ get #accountId() {
5999
+ return this.props.cart?.account_id;
6000
+ }
6001
+
6002
+ get #gateway() {
6003
+ return `app_${this.app.id}_${this.extension}`;
6004
+ }
6005
+
6006
+ render(containerId, props = {}) {
6007
+ return super.render(containerId, {
6008
+ ...props,
6009
+ updateCart: this.updateCart.bind(this),
6010
+ getIntent: this.#getIntent.bind(this),
6011
+ createIntent: this.#createIntent.bind(this),
6012
+ });
6013
+ }
6014
+
6015
+ #getIntent(data) {
6016
+ return vaultRequest('GET', '/intent', {
6017
+ gateway: this.#gateway,
6018
+ account_id: this.#accountId,
6019
+ intent: data,
6020
+ });
6021
+ }
6022
+
6023
+ #createIntent(data) {
6024
+ return vaultRequest('POST', '/intent', {
6025
+ gateway: this.#gateway,
6026
+ account_id: this.#accountId,
6027
+ intent: data,
6028
+ });
6029
+ }
6030
+ }
6031
+
6032
+ class App {
6033
+ constructor(app, api, options) {
6034
+ this.app = app;
6035
+ this.api = api;
6036
+ this.options = options;
6037
+ }
6038
+
6039
+ get #components() {
6040
+ return this.app.components?.results || [];
6041
+ }
6042
+
6043
+ getComponent(name) {
6044
+ if (!name) {
6045
+ throw new Error('Component name is not provided');
6046
+ }
6047
+
6048
+ const component = this.#components.find(
6049
+ (component) => component.name === name,
6050
+ );
6051
+
6052
+ if (!component) {
6053
+ throw new Error(`Component "${name}" not found`);
6054
+ }
6055
+
6056
+ return this.#createComponent(component);
6057
+ }
6058
+
6059
+ getComponents(params = {}) {
6060
+ const components = this.#filterComponents(params);
6061
+
6062
+ return components.reduce((acc, component) => {
6063
+ acc[component.name] = this.#createComponent(component);
6064
+
6065
+ return acc;
6066
+ }, {});
6067
+ }
6068
+
6069
+ #filterComponents(params) {
6070
+ if (!isObject(params) || isEmpty(params)) {
6071
+ return this.#components;
6072
+ }
6073
+
6074
+ const { extension, extensionType } = params;
6075
+
6076
+ if (extensionType) {
6077
+ return this.#filterByExtensionType(extensionType);
6078
+ }
6079
+
6080
+ if (extension) {
6081
+ return this.#filterByExtension(extension);
6082
+ }
6083
+
6084
+ return [];
6085
+ }
6086
+
6087
+ #filterByExtensionType(extensionType) {
6088
+ const extensions = this.app.extensions
6089
+ .filter((extension) => extension.type === extensionType)
6090
+ .map((extension) => extension.id);
6091
+
6092
+ return extensions
6093
+ .map((extension) => this.#filterByExtension(extension))
6094
+ .flat();
6095
+ }
6096
+
6097
+ #filterByExtension(extension) {
6098
+ return this.#components.filter(
6099
+ (component) => component.values.extension === extension,
6100
+ );
6101
+ }
6102
+
6103
+ #createComponent(component) {
6104
+ const { extensions } = this.app;
6105
+ const {
6106
+ name,
6107
+ values: { extension: componentExtension },
6108
+ } = component;
6109
+
6110
+ if (!componentExtension) {
6111
+ throw new Error(
6112
+ `The component "${name}" has no extension. Define the extension in the component's config.`,
6113
+ );
6114
+ }
6115
+
6116
+ const extension = extensions.find(
6117
+ (extension) => extension.id === componentExtension,
6118
+ );
6119
+
6120
+ if (!extension) {
6121
+ throw new Error(
6122
+ `The extension "${componentExtension}" of component "${name}" is not defined in "swell.json".`,
6123
+ );
6124
+ }
6125
+
6126
+ switch (extension.type) {
6127
+ case 'payment':
6128
+ return new AppPaymentComponent(
6129
+ this.app,
6130
+ component,
6131
+ this.api,
6132
+ this.options,
6133
+ );
6134
+ default:
6135
+ throw new Error(`Unknown extension type "${extension.type}".`);
6136
+ }
6137
+ }
6138
+ }
6139
+
6140
+ class AppController {
6141
+ #apps = new Map();
6142
+
6143
+ constructor(api, options) {
6144
+ this.api = api;
6145
+ this.options = options;
6146
+ }
6147
+
6148
+ async load(appId) {
6149
+ const loadedApp = this.#apps.get(appId);
6150
+
6151
+ if (loadedApp) {
6152
+ return loadedApp;
6153
+ }
6154
+
6155
+ const app = await this.#getApp(appId);
6156
+ const appInstance = new App(app, this.api, this.options);
6157
+
6158
+ this.#apps.set(appId, appInstance);
6159
+
6160
+ return appInstance;
6161
+ }
6162
+
6163
+ async #getApp(appId) {
6164
+ const app = await this.api.request('get', `/apps/${appId}`, undefined, {
6165
+ expand: 'components',
6166
+ });
6167
+
6168
+ if (isEmpty(app.extensions)) {
6169
+ throw new Error(
6170
+ `The app "${app.name}" has no extensions. Define the app extensions in "swell.json".`,
6171
+ );
6172
+ }
6173
+
6174
+ return app;
6175
+ }
6176
+ }
6177
+
5878
6178
  function methods$8(api) {
5879
6179
  const { get, list } = defaultMethods(api, '/categories', ['list', 'get']);
5880
6180
 
@@ -6708,7 +7008,7 @@ class Payment {
6708
7008
  * @returns {Promise<object>}
6709
7009
  */
6710
7010
  async createIntent(data) {
6711
- return this._vaultRequest('post', '/intent', data);
7011
+ return vaultRequest('post', '/intent', data);
6712
7012
  }
6713
7013
 
6714
7014
  /**
@@ -6718,7 +7018,7 @@ class Payment {
6718
7018
  * @returns {Promise<object>}
6719
7019
  */
6720
7020
  async updateIntent(data) {
6721
- return this._vaultRequest('put', '/intent', data);
7021
+ return vaultRequest('put', '/intent', data);
6722
7022
  }
6723
7023
 
6724
7024
  /**
@@ -6728,7 +7028,7 @@ class Payment {
6728
7028
  * @returns {Promise<object>}
6729
7029
  */
6730
7030
  async authorizeGateway(data) {
6731
- return this._vaultRequest('post', '/authorization', data);
7031
+ return vaultRequest('post', '/authorization', data);
6732
7032
  }
6733
7033
 
6734
7034
  /**
@@ -6812,29 +7112,6 @@ class Payment {
6812
7112
  return { ...cart, settings: { ...settings.store } };
6813
7113
  }
6814
7114
 
6815
- /**
6816
- * Sends a Vault request.
6817
- *
6818
- * @param {string} method
6819
- * @param {string} url
6820
- * @param {object} data
6821
- * @returns {Promise<object>}
6822
- */
6823
- async _vaultRequest(method, url, data) {
6824
- const response = await vaultRequest(method, url, data);
6825
-
6826
- if (response.errors) {
6827
- const param = Object.keys(response.errors)[0];
6828
- const err = new Error(response.errors[param].message || 'Unknown error');
6829
- err.code = 'vault_error';
6830
- err.status = 402;
6831
- err.param = param;
6832
- throw err;
6833
- }
6834
-
6835
- return response;
6836
- }
6837
-
6838
7115
  /**
6839
7116
  * Sets values for payment scripts.
6840
7117
  *
@@ -11349,15 +11626,6 @@ class PaymentController {
11349
11626
  async _vaultRequest(method, url, data) {
11350
11627
  const response = await vaultRequest(method, url, data);
11351
11628
 
11352
- if (response.errors) {
11353
- const param = Object.keys(response.errors)[0];
11354
- const err = new Error(response.errors[param].message || 'Unknown error');
11355
- err.code = 'vault_error';
11356
- err.status = 402;
11357
- err.param = param;
11358
- throw err;
11359
- }
11360
-
11361
11629
  if (this.options.useCamelCase) {
11362
11630
  return toCamel(response);
11363
11631
  }
@@ -11904,7 +12172,7 @@ function swell(initStore = undefined, initKey, initOptions = {}) {
11904
12172
  const api = {};
11905
12173
 
11906
12174
  Object.assign(api, {
11907
- version: '5.2.0',
12175
+ version: '5.3.0',
11908
12176
  options,
11909
12177
  request,
11910
12178
 
@@ -11967,6 +12235,8 @@ function swell(initStore = undefined, initKey, initOptions = {}) {
11967
12235
 
11968
12236
  account: methods$9(api),
11969
12237
 
12238
+ app: new AppController(api, options),
12239
+
11970
12240
  products: methods$b(api, options),
11971
12241
 
11972
12242
  categories: methods$8(api),