@blotoutio/providers-blotout-wallet-sdk 0.40.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/README.md ADDED
@@ -0,0 +1,11 @@
1
+ # providers-blotout-wallet-sdk
2
+
3
+ This library was generated with [Nx](https://nx.dev).
4
+
5
+ ## Building
6
+
7
+ Run `nx build providers-blotout-wallet-sdk` to build the library.
8
+
9
+ ## Running unit tests
10
+
11
+ Run `nx test providers-blotout-wallet-sdk` to execute the unit tests via [Jest](https://jestjs.io).
package/index.cjs.js ADDED
@@ -0,0 +1,295 @@
1
+ 'use strict';
2
+
3
+ const packageName = 'blotoutWallet';
4
+
5
+ const canLog = () => {
6
+ try {
7
+ return localStorage.getItem('edgeTagDebug') === '1';
8
+ }
9
+ catch {
10
+ return false;
11
+ }
12
+ };
13
+ const logger = {
14
+ log: (...args) => {
15
+ if (canLog()) {
16
+ console.log(...args);
17
+ }
18
+ },
19
+ error: (...args) => {
20
+ if (canLog()) {
21
+ console.error(...args);
22
+ }
23
+ },
24
+ info: (...args) => {
25
+ if (canLog()) {
26
+ console.info(...args);
27
+ }
28
+ },
29
+ trace: (...args) => {
30
+ if (canLog()) {
31
+ console.trace(...args);
32
+ }
33
+ },
34
+ table: (...args) => {
35
+ if (canLog()) {
36
+ console.table(...args);
37
+ }
38
+ },
39
+ dir: (...args) => {
40
+ if (canLog()) {
41
+ console.dir(...args);
42
+ }
43
+ },
44
+ };
45
+
46
+ class APIError extends Error {
47
+ constructor(...args) {
48
+ super(...args);
49
+ }
50
+ }
51
+ class WalletAPI {
52
+ constructor({ baseUrl, userId }) {
53
+ this.listeners = new Set();
54
+ this._cart = null;
55
+ this.baseUrl = baseUrl;
56
+ this.userId = userId;
57
+ }
58
+ getHeaders(json = false) {
59
+ const headers = new Headers({
60
+ EdgeTagUserId: this.userId,
61
+ });
62
+ if (json) {
63
+ headers.set('Content-type', 'application/json; charset=utf-8');
64
+ }
65
+ return headers;
66
+ }
67
+ getUrl(path) {
68
+ return `${this.baseUrl}/providers/blotoutWallet${path}`;
69
+ }
70
+ notify() {
71
+ for (const listener of this.listeners) {
72
+ try {
73
+ listener(this.cart);
74
+ }
75
+ catch (err) {
76
+ console.error(err);
77
+ }
78
+ }
79
+ }
80
+ get cart() {
81
+ return this._cart;
82
+ }
83
+ set cart(value) {
84
+ if (this._cart !== value) {
85
+ this._cart = value;
86
+ this.notify();
87
+ }
88
+ }
89
+ subscribe(listener) {
90
+ this.listeners.add(listener);
91
+ return () => {
92
+ this.listeners.delete(listener);
93
+ };
94
+ }
95
+ getCart() {
96
+ return fetch(this.getUrl('/cart'), {
97
+ method: 'GET',
98
+ headers: this.getHeaders(),
99
+ }).then(async (response) => {
100
+ if (!response.ok) {
101
+ if (response.status == 404) {
102
+ return (this.cart = null);
103
+ }
104
+ throw new APIError(`Could not fetch cart contents`, {
105
+ cause: response,
106
+ });
107
+ }
108
+ return (this.cart = await response.json());
109
+ });
110
+ }
111
+ addItems(items) {
112
+ return fetch(this.getUrl('/items'), {
113
+ method: 'POST',
114
+ headers: this.getHeaders(true),
115
+ body: JSON.stringify(items),
116
+ }).then(async (response) => {
117
+ if (!response.ok) {
118
+ throw new APIError(`Could not add items`, { cause: response });
119
+ }
120
+ return (this.cart = await response.json());
121
+ });
122
+ }
123
+ setItems(items) {
124
+ return fetch(this.getUrl('/items'), {
125
+ method: 'PUT',
126
+ headers: this.getHeaders(true),
127
+ body: JSON.stringify(items),
128
+ }).then(async (response) => {
129
+ if (!response.ok) {
130
+ throw new APIError(`Could not set items`, { cause: response });
131
+ }
132
+ return (this.cart = await response.json());
133
+ });
134
+ }
135
+ updateItem(item) {
136
+ fetch(this.getUrl(`/items/${item.itemId}`), {
137
+ method: 'PUT',
138
+ headers: this.getHeaders(true),
139
+ body: JSON.stringify({
140
+ name: item.name,
141
+ productId: item.productId,
142
+ amount: item.amount,
143
+ value: item.value,
144
+ }),
145
+ }).then(async (response) => {
146
+ if (!response.ok) {
147
+ throw new APIError(`Could not update item`, { cause: response });
148
+ }
149
+ return (this.cart = await response.json());
150
+ });
151
+ }
152
+ removeItem(itemId) {
153
+ fetch(this.getUrl(`/items/${itemId}`), {
154
+ method: 'DELETE',
155
+ headers: this.getHeaders(),
156
+ }).then(async (response) => {
157
+ if (!response.ok) {
158
+ throw new APIError(`Could not remove item`, { cause: response });
159
+ }
160
+ return (this.cart = await response.json());
161
+ });
162
+ }
163
+ purchase(orderId) {
164
+ return fetch(this.getUrl('/cart/purchase'), {
165
+ method: 'POST',
166
+ body: JSON.stringify({ orderId }),
167
+ headers: this.getHeaders(true),
168
+ }).then((response) => {
169
+ if (!response.ok) {
170
+ throw new APIError(`Could not mark purchase`, { cause: response });
171
+ }
172
+ });
173
+ }
174
+ }
175
+
176
+ let api;
177
+ let component;
178
+ const setComponent = (_component) => {
179
+ component = _component;
180
+ };
181
+ const setAPI = (_api) => {
182
+ api = _api;
183
+ };
184
+ const getAPI = () => api;
185
+ const getComponent = () => component;
186
+
187
+ const symbol = Symbol.for('blotout-store-implementation');
188
+
189
+ const getItemKey = (item) => `${item.productId}-${item.variantId}`;
190
+ const syncCartItems = async (api, storeApi) => {
191
+ try {
192
+ const [wallet, shopItems] = await Promise.all([
193
+ api.getCart(),
194
+ storeApi.getCart(),
195
+ ]);
196
+ const lookup = new Map(wallet === null || wallet === void 0 ? void 0 : wallet.items.map((item) => [getItemKey(item), item]));
197
+ const missingItems = [];
198
+ for (const item of shopItems) {
199
+ const walletItem = lookup.get(getItemKey(item));
200
+ if (!walletItem) {
201
+ missingItems.push(item);
202
+ }
203
+ else if (walletItem.amount < item.amount) {
204
+ missingItems.push({
205
+ ...item,
206
+ amount: item.amount - walletItem.amount,
207
+ });
208
+ }
209
+ }
210
+ if (missingItems.length > 0) {
211
+ await api.addItems(missingItems);
212
+ }
213
+ }
214
+ catch (err) {
215
+ logger.error(err);
216
+ }
217
+ };
218
+ const init = (params) => {
219
+ var _a;
220
+ if (window && document && !getComponent()) {
221
+ const element = document.createElement('blotout-wallet');
222
+ element.setAttribute('tag-name', params.manifest.tagName);
223
+ setComponent(element);
224
+ const api = new WalletAPI({
225
+ baseUrl: params.baseUrl,
226
+ userId: params.userId,
227
+ });
228
+ setAPI(api);
229
+ const store = (_a = window[symbol]) === null || _a === void 0 ? void 0 : _a.call(window);
230
+ if (!store) {
231
+ throw new Error('Implementation for store API missing!');
232
+ }
233
+ document.body.append(element);
234
+ syncCartItems(api, store);
235
+ }
236
+ };
237
+
238
+ const transformItems = (data) => {
239
+ var _a;
240
+ return (_a = data.contents) === null || _a === void 0 ? void 0 : _a.map((item) => ({
241
+ productId: item.id,
242
+ variantId: item.variantId || null,
243
+ name: item.description || '',
244
+ amount: parseInt(item.quantity.toString()),
245
+ value: parseFloat(item.item_price.toString()),
246
+ }));
247
+ };
248
+ const tag = (params) => {
249
+ const api = getAPI();
250
+ switch (params.eventName) {
251
+ case 'AddToCart': {
252
+ const items = transformItems(params.data);
253
+ if (items) {
254
+ api.addItems(items).catch(logger.error);
255
+ }
256
+ return;
257
+ }
258
+ case 'InitiateCheckout': {
259
+ const items = transformItems(params.data);
260
+ if (items) {
261
+ api.setItems(items).catch(logger.error);
262
+ }
263
+ return;
264
+ }
265
+ case 'Purchase': {
266
+ const { orderId } = params.data;
267
+ api.purchase(orderId).catch(logger.error);
268
+ return;
269
+ }
270
+ }
271
+ };
272
+
273
+ // eslint-disable-next-line @nx/enforce-module-boundaries
274
+ const user = (params) => {
275
+ console.log(`[${packageName}]: user`, params);
276
+ };
277
+
278
+ // eslint-disable-next-line @nx/enforce-module-boundaries
279
+ const data = {
280
+ name: packageName,
281
+ init,
282
+ tag,
283
+ user,
284
+ };
285
+ try {
286
+ if (window) {
287
+ window.edgetagProviders = window.edgetagProviders || [];
288
+ window.edgetagProviders.push(data);
289
+ }
290
+ }
291
+ catch {
292
+ // no window
293
+ }
294
+
295
+ module.exports = data;
package/index.js ADDED
@@ -0,0 +1,298 @@
1
+ var ProvidersBlotoutWalletSdk = (function () {
2
+ 'use strict';
3
+
4
+ const packageName = 'blotoutWallet';
5
+
6
+ const canLog = () => {
7
+ try {
8
+ return localStorage.getItem('edgeTagDebug') === '1';
9
+ }
10
+ catch {
11
+ return false;
12
+ }
13
+ };
14
+ const logger = {
15
+ log: (...args) => {
16
+ if (canLog()) {
17
+ console.log(...args);
18
+ }
19
+ },
20
+ error: (...args) => {
21
+ if (canLog()) {
22
+ console.error(...args);
23
+ }
24
+ },
25
+ info: (...args) => {
26
+ if (canLog()) {
27
+ console.info(...args);
28
+ }
29
+ },
30
+ trace: (...args) => {
31
+ if (canLog()) {
32
+ console.trace(...args);
33
+ }
34
+ },
35
+ table: (...args) => {
36
+ if (canLog()) {
37
+ console.table(...args);
38
+ }
39
+ },
40
+ dir: (...args) => {
41
+ if (canLog()) {
42
+ console.dir(...args);
43
+ }
44
+ },
45
+ };
46
+
47
+ class APIError extends Error {
48
+ constructor(...args) {
49
+ super(...args);
50
+ }
51
+ }
52
+ class WalletAPI {
53
+ constructor({ baseUrl, userId }) {
54
+ this.listeners = new Set();
55
+ this._cart = null;
56
+ this.baseUrl = baseUrl;
57
+ this.userId = userId;
58
+ }
59
+ getHeaders(json = false) {
60
+ const headers = new Headers({
61
+ EdgeTagUserId: this.userId,
62
+ });
63
+ if (json) {
64
+ headers.set('Content-type', 'application/json; charset=utf-8');
65
+ }
66
+ return headers;
67
+ }
68
+ getUrl(path) {
69
+ return `${this.baseUrl}/providers/blotoutWallet${path}`;
70
+ }
71
+ notify() {
72
+ for (const listener of this.listeners) {
73
+ try {
74
+ listener(this.cart);
75
+ }
76
+ catch (err) {
77
+ console.error(err);
78
+ }
79
+ }
80
+ }
81
+ get cart() {
82
+ return this._cart;
83
+ }
84
+ set cart(value) {
85
+ if (this._cart !== value) {
86
+ this._cart = value;
87
+ this.notify();
88
+ }
89
+ }
90
+ subscribe(listener) {
91
+ this.listeners.add(listener);
92
+ return () => {
93
+ this.listeners.delete(listener);
94
+ };
95
+ }
96
+ getCart() {
97
+ return fetch(this.getUrl('/cart'), {
98
+ method: 'GET',
99
+ headers: this.getHeaders(),
100
+ }).then(async (response) => {
101
+ if (!response.ok) {
102
+ if (response.status == 404) {
103
+ return (this.cart = null);
104
+ }
105
+ throw new APIError(`Could not fetch cart contents`, {
106
+ cause: response,
107
+ });
108
+ }
109
+ return (this.cart = await response.json());
110
+ });
111
+ }
112
+ addItems(items) {
113
+ return fetch(this.getUrl('/items'), {
114
+ method: 'POST',
115
+ headers: this.getHeaders(true),
116
+ body: JSON.stringify(items),
117
+ }).then(async (response) => {
118
+ if (!response.ok) {
119
+ throw new APIError(`Could not add items`, { cause: response });
120
+ }
121
+ return (this.cart = await response.json());
122
+ });
123
+ }
124
+ setItems(items) {
125
+ return fetch(this.getUrl('/items'), {
126
+ method: 'PUT',
127
+ headers: this.getHeaders(true),
128
+ body: JSON.stringify(items),
129
+ }).then(async (response) => {
130
+ if (!response.ok) {
131
+ throw new APIError(`Could not set items`, { cause: response });
132
+ }
133
+ return (this.cart = await response.json());
134
+ });
135
+ }
136
+ updateItem(item) {
137
+ fetch(this.getUrl(`/items/${item.itemId}`), {
138
+ method: 'PUT',
139
+ headers: this.getHeaders(true),
140
+ body: JSON.stringify({
141
+ name: item.name,
142
+ productId: item.productId,
143
+ amount: item.amount,
144
+ value: item.value,
145
+ }),
146
+ }).then(async (response) => {
147
+ if (!response.ok) {
148
+ throw new APIError(`Could not update item`, { cause: response });
149
+ }
150
+ return (this.cart = await response.json());
151
+ });
152
+ }
153
+ removeItem(itemId) {
154
+ fetch(this.getUrl(`/items/${itemId}`), {
155
+ method: 'DELETE',
156
+ headers: this.getHeaders(),
157
+ }).then(async (response) => {
158
+ if (!response.ok) {
159
+ throw new APIError(`Could not remove item`, { cause: response });
160
+ }
161
+ return (this.cart = await response.json());
162
+ });
163
+ }
164
+ purchase(orderId) {
165
+ return fetch(this.getUrl('/cart/purchase'), {
166
+ method: 'POST',
167
+ body: JSON.stringify({ orderId }),
168
+ headers: this.getHeaders(true),
169
+ }).then((response) => {
170
+ if (!response.ok) {
171
+ throw new APIError(`Could not mark purchase`, { cause: response });
172
+ }
173
+ });
174
+ }
175
+ }
176
+
177
+ let api;
178
+ let component;
179
+ const setComponent = (_component) => {
180
+ component = _component;
181
+ };
182
+ const setAPI = (_api) => {
183
+ api = _api;
184
+ };
185
+ const getAPI = () => api;
186
+ const getComponent = () => component;
187
+
188
+ const symbol = Symbol.for('blotout-store-implementation');
189
+
190
+ const getItemKey = (item) => `${item.productId}-${item.variantId}`;
191
+ const syncCartItems = async (api, storeApi) => {
192
+ try {
193
+ const [wallet, shopItems] = await Promise.all([
194
+ api.getCart(),
195
+ storeApi.getCart(),
196
+ ]);
197
+ const lookup = new Map(wallet === null || wallet === void 0 ? void 0 : wallet.items.map((item) => [getItemKey(item), item]));
198
+ const missingItems = [];
199
+ for (const item of shopItems) {
200
+ const walletItem = lookup.get(getItemKey(item));
201
+ if (!walletItem) {
202
+ missingItems.push(item);
203
+ }
204
+ else if (walletItem.amount < item.amount) {
205
+ missingItems.push({
206
+ ...item,
207
+ amount: item.amount - walletItem.amount,
208
+ });
209
+ }
210
+ }
211
+ if (missingItems.length > 0) {
212
+ await api.addItems(missingItems);
213
+ }
214
+ }
215
+ catch (err) {
216
+ logger.error(err);
217
+ }
218
+ };
219
+ const init = (params) => {
220
+ var _a;
221
+ if (window && document && !getComponent()) {
222
+ const element = document.createElement('blotout-wallet');
223
+ element.setAttribute('tag-name', params.manifest.tagName);
224
+ setComponent(element);
225
+ const api = new WalletAPI({
226
+ baseUrl: params.baseUrl,
227
+ userId: params.userId,
228
+ });
229
+ setAPI(api);
230
+ const store = (_a = window[symbol]) === null || _a === void 0 ? void 0 : _a.call(window);
231
+ if (!store) {
232
+ throw new Error('Implementation for store API missing!');
233
+ }
234
+ document.body.append(element);
235
+ syncCartItems(api, store);
236
+ }
237
+ };
238
+
239
+ const transformItems = (data) => {
240
+ var _a;
241
+ return (_a = data.contents) === null || _a === void 0 ? void 0 : _a.map((item) => ({
242
+ productId: item.id,
243
+ variantId: item.variantId || null,
244
+ name: item.description || '',
245
+ amount: parseInt(item.quantity.toString()),
246
+ value: parseFloat(item.item_price.toString()),
247
+ }));
248
+ };
249
+ const tag = (params) => {
250
+ const api = getAPI();
251
+ switch (params.eventName) {
252
+ case 'AddToCart': {
253
+ const items = transformItems(params.data);
254
+ if (items) {
255
+ api.addItems(items).catch(logger.error);
256
+ }
257
+ return;
258
+ }
259
+ case 'InitiateCheckout': {
260
+ const items = transformItems(params.data);
261
+ if (items) {
262
+ api.setItems(items).catch(logger.error);
263
+ }
264
+ return;
265
+ }
266
+ case 'Purchase': {
267
+ const { orderId } = params.data;
268
+ api.purchase(orderId).catch(logger.error);
269
+ return;
270
+ }
271
+ }
272
+ };
273
+
274
+ // eslint-disable-next-line @nx/enforce-module-boundaries
275
+ const user = (params) => {
276
+ console.log(`[${packageName}]: user`, params);
277
+ };
278
+
279
+ // eslint-disable-next-line @nx/enforce-module-boundaries
280
+ const data = {
281
+ name: packageName,
282
+ init,
283
+ tag,
284
+ user,
285
+ };
286
+ try {
287
+ if (window) {
288
+ window.edgetagProviders = window.edgetagProviders || [];
289
+ window.edgetagProviders.push(data);
290
+ }
291
+ }
292
+ catch {
293
+ // no window
294
+ }
295
+
296
+ return data;
297
+
298
+ })();
package/index.mjs ADDED
@@ -0,0 +1,293 @@
1
+ const packageName = 'blotoutWallet';
2
+
3
+ const canLog = () => {
4
+ try {
5
+ return localStorage.getItem('edgeTagDebug') === '1';
6
+ }
7
+ catch {
8
+ return false;
9
+ }
10
+ };
11
+ const logger = {
12
+ log: (...args) => {
13
+ if (canLog()) {
14
+ console.log(...args);
15
+ }
16
+ },
17
+ error: (...args) => {
18
+ if (canLog()) {
19
+ console.error(...args);
20
+ }
21
+ },
22
+ info: (...args) => {
23
+ if (canLog()) {
24
+ console.info(...args);
25
+ }
26
+ },
27
+ trace: (...args) => {
28
+ if (canLog()) {
29
+ console.trace(...args);
30
+ }
31
+ },
32
+ table: (...args) => {
33
+ if (canLog()) {
34
+ console.table(...args);
35
+ }
36
+ },
37
+ dir: (...args) => {
38
+ if (canLog()) {
39
+ console.dir(...args);
40
+ }
41
+ },
42
+ };
43
+
44
+ class APIError extends Error {
45
+ constructor(...args) {
46
+ super(...args);
47
+ }
48
+ }
49
+ class WalletAPI {
50
+ constructor({ baseUrl, userId }) {
51
+ this.listeners = new Set();
52
+ this._cart = null;
53
+ this.baseUrl = baseUrl;
54
+ this.userId = userId;
55
+ }
56
+ getHeaders(json = false) {
57
+ const headers = new Headers({
58
+ EdgeTagUserId: this.userId,
59
+ });
60
+ if (json) {
61
+ headers.set('Content-type', 'application/json; charset=utf-8');
62
+ }
63
+ return headers;
64
+ }
65
+ getUrl(path) {
66
+ return `${this.baseUrl}/providers/blotoutWallet${path}`;
67
+ }
68
+ notify() {
69
+ for (const listener of this.listeners) {
70
+ try {
71
+ listener(this.cart);
72
+ }
73
+ catch (err) {
74
+ console.error(err);
75
+ }
76
+ }
77
+ }
78
+ get cart() {
79
+ return this._cart;
80
+ }
81
+ set cart(value) {
82
+ if (this._cart !== value) {
83
+ this._cart = value;
84
+ this.notify();
85
+ }
86
+ }
87
+ subscribe(listener) {
88
+ this.listeners.add(listener);
89
+ return () => {
90
+ this.listeners.delete(listener);
91
+ };
92
+ }
93
+ getCart() {
94
+ return fetch(this.getUrl('/cart'), {
95
+ method: 'GET',
96
+ headers: this.getHeaders(),
97
+ }).then(async (response) => {
98
+ if (!response.ok) {
99
+ if (response.status == 404) {
100
+ return (this.cart = null);
101
+ }
102
+ throw new APIError(`Could not fetch cart contents`, {
103
+ cause: response,
104
+ });
105
+ }
106
+ return (this.cart = await response.json());
107
+ });
108
+ }
109
+ addItems(items) {
110
+ return fetch(this.getUrl('/items'), {
111
+ method: 'POST',
112
+ headers: this.getHeaders(true),
113
+ body: JSON.stringify(items),
114
+ }).then(async (response) => {
115
+ if (!response.ok) {
116
+ throw new APIError(`Could not add items`, { cause: response });
117
+ }
118
+ return (this.cart = await response.json());
119
+ });
120
+ }
121
+ setItems(items) {
122
+ return fetch(this.getUrl('/items'), {
123
+ method: 'PUT',
124
+ headers: this.getHeaders(true),
125
+ body: JSON.stringify(items),
126
+ }).then(async (response) => {
127
+ if (!response.ok) {
128
+ throw new APIError(`Could not set items`, { cause: response });
129
+ }
130
+ return (this.cart = await response.json());
131
+ });
132
+ }
133
+ updateItem(item) {
134
+ fetch(this.getUrl(`/items/${item.itemId}`), {
135
+ method: 'PUT',
136
+ headers: this.getHeaders(true),
137
+ body: JSON.stringify({
138
+ name: item.name,
139
+ productId: item.productId,
140
+ amount: item.amount,
141
+ value: item.value,
142
+ }),
143
+ }).then(async (response) => {
144
+ if (!response.ok) {
145
+ throw new APIError(`Could not update item`, { cause: response });
146
+ }
147
+ return (this.cart = await response.json());
148
+ });
149
+ }
150
+ removeItem(itemId) {
151
+ fetch(this.getUrl(`/items/${itemId}`), {
152
+ method: 'DELETE',
153
+ headers: this.getHeaders(),
154
+ }).then(async (response) => {
155
+ if (!response.ok) {
156
+ throw new APIError(`Could not remove item`, { cause: response });
157
+ }
158
+ return (this.cart = await response.json());
159
+ });
160
+ }
161
+ purchase(orderId) {
162
+ return fetch(this.getUrl('/cart/purchase'), {
163
+ method: 'POST',
164
+ body: JSON.stringify({ orderId }),
165
+ headers: this.getHeaders(true),
166
+ }).then((response) => {
167
+ if (!response.ok) {
168
+ throw new APIError(`Could not mark purchase`, { cause: response });
169
+ }
170
+ });
171
+ }
172
+ }
173
+
174
+ let api;
175
+ let component;
176
+ const setComponent = (_component) => {
177
+ component = _component;
178
+ };
179
+ const setAPI = (_api) => {
180
+ api = _api;
181
+ };
182
+ const getAPI = () => api;
183
+ const getComponent = () => component;
184
+
185
+ const symbol = Symbol.for('blotout-store-implementation');
186
+
187
+ const getItemKey = (item) => `${item.productId}-${item.variantId}`;
188
+ const syncCartItems = async (api, storeApi) => {
189
+ try {
190
+ const [wallet, shopItems] = await Promise.all([
191
+ api.getCart(),
192
+ storeApi.getCart(),
193
+ ]);
194
+ const lookup = new Map(wallet === null || wallet === void 0 ? void 0 : wallet.items.map((item) => [getItemKey(item), item]));
195
+ const missingItems = [];
196
+ for (const item of shopItems) {
197
+ const walletItem = lookup.get(getItemKey(item));
198
+ if (!walletItem) {
199
+ missingItems.push(item);
200
+ }
201
+ else if (walletItem.amount < item.amount) {
202
+ missingItems.push({
203
+ ...item,
204
+ amount: item.amount - walletItem.amount,
205
+ });
206
+ }
207
+ }
208
+ if (missingItems.length > 0) {
209
+ await api.addItems(missingItems);
210
+ }
211
+ }
212
+ catch (err) {
213
+ logger.error(err);
214
+ }
215
+ };
216
+ const init = (params) => {
217
+ var _a;
218
+ if (window && document && !getComponent()) {
219
+ const element = document.createElement('blotout-wallet');
220
+ element.setAttribute('tag-name', params.manifest.tagName);
221
+ setComponent(element);
222
+ const api = new WalletAPI({
223
+ baseUrl: params.baseUrl,
224
+ userId: params.userId,
225
+ });
226
+ setAPI(api);
227
+ const store = (_a = window[symbol]) === null || _a === void 0 ? void 0 : _a.call(window);
228
+ if (!store) {
229
+ throw new Error('Implementation for store API missing!');
230
+ }
231
+ document.body.append(element);
232
+ syncCartItems(api, store);
233
+ }
234
+ };
235
+
236
+ const transformItems = (data) => {
237
+ var _a;
238
+ return (_a = data.contents) === null || _a === void 0 ? void 0 : _a.map((item) => ({
239
+ productId: item.id,
240
+ variantId: item.variantId || null,
241
+ name: item.description || '',
242
+ amount: parseInt(item.quantity.toString()),
243
+ value: parseFloat(item.item_price.toString()),
244
+ }));
245
+ };
246
+ const tag = (params) => {
247
+ const api = getAPI();
248
+ switch (params.eventName) {
249
+ case 'AddToCart': {
250
+ const items = transformItems(params.data);
251
+ if (items) {
252
+ api.addItems(items).catch(logger.error);
253
+ }
254
+ return;
255
+ }
256
+ case 'InitiateCheckout': {
257
+ const items = transformItems(params.data);
258
+ if (items) {
259
+ api.setItems(items).catch(logger.error);
260
+ }
261
+ return;
262
+ }
263
+ case 'Purchase': {
264
+ const { orderId } = params.data;
265
+ api.purchase(orderId).catch(logger.error);
266
+ return;
267
+ }
268
+ }
269
+ };
270
+
271
+ // eslint-disable-next-line @nx/enforce-module-boundaries
272
+ const user = (params) => {
273
+ console.log(`[${packageName}]: user`, params);
274
+ };
275
+
276
+ // eslint-disable-next-line @nx/enforce-module-boundaries
277
+ const data = {
278
+ name: packageName,
279
+ init,
280
+ tag,
281
+ user,
282
+ };
283
+ try {
284
+ if (window) {
285
+ window.edgetagProviders = window.edgetagProviders || [];
286
+ window.edgetagProviders.push(data);
287
+ }
288
+ }
289
+ catch {
290
+ // no window
291
+ }
292
+
293
+ export { data as default };
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@blotoutio/providers-blotout-wallet-sdk",
3
+ "version": "0.40.0",
4
+ "description": "Blotout Wallet SDK for EdgeTag",
5
+ "author": "Blotout",
6
+ "license": "MIT",
7
+ "homepage": "https://github.com/blotoutio/edgetag-sdk",
8
+ "publishConfig": {
9
+ "access": "public"
10
+ },
11
+ "main": "./index.cjs.js",
12
+ "module": "./index.mjs",
13
+ "exports": {
14
+ ".": {
15
+ "require": "./index.cjs.js",
16
+ "import": "./index.mjs",
17
+ "default": "./index.js"
18
+ },
19
+ "./stores/shopify.js": {
20
+ "require": "./stores/shopify/index.cjs.js",
21
+ "import": "./stores/shopify/index.mjs",
22
+ "default": "./stores/shopify/index.js"
23
+ }
24
+ },
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git+https://github.com/blotoutio/edgetag-sdk.git"
28
+ },
29
+ "files": [
30
+ "index.js",
31
+ "index.cjs.js",
32
+ "index.mjs",
33
+ "package.json",
34
+ "README.md",
35
+ "stores/shopify/index.js",
36
+ "stores/shopify/index.cjs.js",
37
+ "stores/shopify/index.mjs"
38
+ ]
39
+ }
@@ -0,0 +1,58 @@
1
+ 'use strict';
2
+
3
+ const symbol = Symbol.for('blotout-store-implementation');
4
+
5
+ const createShopApi = (fetchOverride = window.fetch) => ({
6
+ addItems(items) {
7
+ return fetchOverride(`${window.Shopify.routes.root}cart/add.js`, {
8
+ method: 'POST',
9
+ body: JSON.stringify({
10
+ items: items.map((item) => ({
11
+ id: item.productId,
12
+ variant_id: item.variantId,
13
+ quantity: item.amount,
14
+ })),
15
+ }),
16
+ headers: { 'Content-type': 'application/json' },
17
+ }).then(async (response) => {
18
+ if (!response.ok) {
19
+ throw new Error('Could not add items', { cause: await response.text() });
20
+ }
21
+ return this.getCart();
22
+ });
23
+ },
24
+ clearCart() {
25
+ return fetchOverride(`${window.Shopify.routes.root}cart/clear.js`, {
26
+ method: 'POST',
27
+ }).then(async (response) => {
28
+ if (!response.ok) {
29
+ throw new Error('Could not clear cart', {
30
+ cause: await response.text(),
31
+ });
32
+ }
33
+ });
34
+ },
35
+ getCart() {
36
+ return fetchOverride(`${window.Shopify.routes.root}cart.js`, {
37
+ method: 'GET',
38
+ headers: { Accept: 'application/json' },
39
+ })
40
+ .then(async (response) => {
41
+ if (!response.ok) {
42
+ throw new Error('Could not fetch cart', {
43
+ cause: await response.text(),
44
+ });
45
+ }
46
+ return response.json();
47
+ })
48
+ .then((cart) => cart.items.map(({ id, variant_id, title, quantity, price }) => ({
49
+ productId: id.toString(),
50
+ variantId: (variant_id === null || variant_id === void 0 ? void 0 : variant_id.toString()) || null,
51
+ name: title,
52
+ amount: quantity,
53
+ // TODO: should this be `final_price`, `discounted_price` or just `price`?
54
+ value: price,
55
+ })));
56
+ },
57
+ });
58
+ window[symbol] = createShopApi;
@@ -0,0 +1,61 @@
1
+ (function () {
2
+ 'use strict';
3
+
4
+ const symbol = Symbol.for('blotout-store-implementation');
5
+
6
+ const createShopApi = (fetchOverride = window.fetch) => ({
7
+ addItems(items) {
8
+ return fetchOverride(`${window.Shopify.routes.root}cart/add.js`, {
9
+ method: 'POST',
10
+ body: JSON.stringify({
11
+ items: items.map((item) => ({
12
+ id: item.productId,
13
+ variant_id: item.variantId,
14
+ quantity: item.amount,
15
+ })),
16
+ }),
17
+ headers: { 'Content-type': 'application/json' },
18
+ }).then(async (response) => {
19
+ if (!response.ok) {
20
+ throw new Error('Could not add items', { cause: await response.text() });
21
+ }
22
+ return this.getCart();
23
+ });
24
+ },
25
+ clearCart() {
26
+ return fetchOverride(`${window.Shopify.routes.root}cart/clear.js`, {
27
+ method: 'POST',
28
+ }).then(async (response) => {
29
+ if (!response.ok) {
30
+ throw new Error('Could not clear cart', {
31
+ cause: await response.text(),
32
+ });
33
+ }
34
+ });
35
+ },
36
+ getCart() {
37
+ return fetchOverride(`${window.Shopify.routes.root}cart.js`, {
38
+ method: 'GET',
39
+ headers: { Accept: 'application/json' },
40
+ })
41
+ .then(async (response) => {
42
+ if (!response.ok) {
43
+ throw new Error('Could not fetch cart', {
44
+ cause: await response.text(),
45
+ });
46
+ }
47
+ return response.json();
48
+ })
49
+ .then((cart) => cart.items.map(({ id, variant_id, title, quantity, price }) => ({
50
+ productId: id.toString(),
51
+ variantId: (variant_id === null || variant_id === void 0 ? void 0 : variant_id.toString()) || null,
52
+ name: title,
53
+ amount: quantity,
54
+ // TODO: should this be `final_price`, `discounted_price` or just `price`?
55
+ value: price,
56
+ })));
57
+ },
58
+ });
59
+ window[symbol] = createShopApi;
60
+
61
+ })();
@@ -0,0 +1,56 @@
1
+ const symbol = Symbol.for('blotout-store-implementation');
2
+
3
+ const createShopApi = (fetchOverride = window.fetch) => ({
4
+ addItems(items) {
5
+ return fetchOverride(`${window.Shopify.routes.root}cart/add.js`, {
6
+ method: 'POST',
7
+ body: JSON.stringify({
8
+ items: items.map((item) => ({
9
+ id: item.productId,
10
+ variant_id: item.variantId,
11
+ quantity: item.amount,
12
+ })),
13
+ }),
14
+ headers: { 'Content-type': 'application/json' },
15
+ }).then(async (response) => {
16
+ if (!response.ok) {
17
+ throw new Error('Could not add items', { cause: await response.text() });
18
+ }
19
+ return this.getCart();
20
+ });
21
+ },
22
+ clearCart() {
23
+ return fetchOverride(`${window.Shopify.routes.root}cart/clear.js`, {
24
+ method: 'POST',
25
+ }).then(async (response) => {
26
+ if (!response.ok) {
27
+ throw new Error('Could not clear cart', {
28
+ cause: await response.text(),
29
+ });
30
+ }
31
+ });
32
+ },
33
+ getCart() {
34
+ return fetchOverride(`${window.Shopify.routes.root}cart.js`, {
35
+ method: 'GET',
36
+ headers: { Accept: 'application/json' },
37
+ })
38
+ .then(async (response) => {
39
+ if (!response.ok) {
40
+ throw new Error('Could not fetch cart', {
41
+ cause: await response.text(),
42
+ });
43
+ }
44
+ return response.json();
45
+ })
46
+ .then((cart) => cart.items.map(({ id, variant_id, title, quantity, price }) => ({
47
+ productId: id.toString(),
48
+ variantId: (variant_id === null || variant_id === void 0 ? void 0 : variant_id.toString()) || null,
49
+ name: title,
50
+ amount: quantity,
51
+ // TODO: should this be `final_price`, `discounted_price` or just `price`?
52
+ value: price,
53
+ })));
54
+ },
55
+ });
56
+ window[symbol] = createShopApi;