@nuskin/contentstack-lib 2.1.0-pa-1117.1 → 2.1.0-pa-1117.3

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
@@ -7,6 +7,7 @@ This project extends the Contentstack delivery sdk, to be shared between the bac
7
7
  getSingletonEntries TAKES AN OPTION CALLED mergeWithFallback. IF THAT IS SET TO TRUE THEN IT WILL MERGE THE RESULTS
8
8
  FOR COMMON SPANISH AND MX-es FOR EXAMPLE.
9
9
  4. getSingletonEntries also allows you to convert the keys from snake case to camel case.
10
+ 5. It extends the stack with getAddressForms and getShippingAddressForms for address form content types.
10
11
 
11
12
  ## Installing
12
13
 
@@ -63,6 +64,33 @@ const [
63
64
  mergeWithFallback: true
64
65
  });
65
66
 
67
+ // Get address forms for a list of countries.
68
+ // By default the returned keys are snake_case.
69
+ const addressForms = await Stack.getAddressForms(['United States']);
70
+
71
+ // Example result:
72
+ // [
73
+ // {
74
+ // address_elements: [
75
+ // {
76
+ // field: 'address1',
77
+ // width: 'full',
78
+ // editable: true,
79
+ // max_length: 40
80
+ // }
81
+ // ],
82
+ // postal_code_regex: '^[0-9]{5}(?:-[0-9]{4})?$'
83
+ // }
84
+ // ]
85
+
86
+ // Pass true as the second parameter to camelCase the returned keys.
87
+ const camelizedAddressForms = await Stack.getAddressForms(['United States'], true);
88
+
89
+ // Get shipping address forms with referenced address form fields expanded.
90
+ // The second parameter works the same way here.
91
+ const shippingAddressForms = await Stack.getShippingAddressForms(['United States']);
92
+ const camelizedShippingAddressForms = await Stack.getShippingAddressForms(['United States'], true);
93
+
66
94
  // We could possibly add functionality to return the list of regions markets and languages in a single object structure
67
95
  ```
68
96
 
@@ -52,6 +52,13 @@ beforeEach(() => {
52
52
  findOne: mockSinglePromiseResult
53
53
  })
54
54
  })
55
+ }),
56
+ containedIn: () => ({
57
+ includeReference: () => ({
58
+ toJSON: () => ({
59
+ find: mockPromiseResult
60
+ })
61
+ })
55
62
  })
56
63
  })
57
64
  })
@@ -73,6 +80,23 @@ const mockResults = () => {
73
80
  mockSinglePromiseResult.mockResolvedValueOnce(singleCheckoutCartStrings);
74
81
  }
75
82
 
83
+ const addressFormFieldEntries = [
84
+ {
85
+ field: 'address1',
86
+ width: 'full',
87
+ editable: true,
88
+ max_length: '40',
89
+ required: true
90
+ },
91
+ {
92
+ field: 'postalCode',
93
+ width: 'half',
94
+ editable: false,
95
+ max_length: '10',
96
+ required: false
97
+ }
98
+ ];
99
+
76
100
  describe("ContentstackApi", () => {
77
101
  test("getSingletonEntries", async () => {
78
102
  mockResults();
@@ -136,5 +160,236 @@ describe("ContentstackApi", () => {
136
160
  getStack(env[index]);
137
161
  expect(mockStack).toHaveBeenCalledWith({api_key: csCfg.apiKey, delivery_token: csCfg.deliveryToken, environment: csCfg.environment});
138
162
  })
139
- })
163
+ });
164
+
165
+ test('extractAddressFormFields maps address form field entries', () => {
166
+ const {getStack} = require('../src/api');
167
+ const Stack = getStack('dev');
168
+ expect(Stack.extractAddressFormFields(addressFormFieldEntries)).toStrictEqual([
169
+ {
170
+ field: 'address1',
171
+ width: 'full',
172
+ editable: true,
173
+ max_length: 40,
174
+ required: true
175
+ },
176
+ {
177
+ field: 'postalCode',
178
+ width: 'half',
179
+ editable: false,
180
+ max_length: 10,
181
+ required: false
182
+ }
183
+ ]);
184
+ });
185
+
186
+ test('extractAddressFormFields camelcases address form field entries', () => {
187
+ const {getStack} = require('../src/api');
188
+ const Stack = getStack('dev');
189
+ expect(Stack.extractAddressFormFields(addressFormFieldEntries, true)).toStrictEqual([
190
+ {
191
+ field: 'address1',
192
+ width: 'full',
193
+ editable: true,
194
+ maxLength: 40,
195
+ required: true
196
+ },
197
+ {
198
+ field: 'postalCode',
199
+ width: 'half',
200
+ editable: false,
201
+ maxLength: 10,
202
+ required: false
203
+ }
204
+ ]);
205
+ });
206
+
207
+ test('getAddressForms maps address_elements', async () => {
208
+ mockPromiseResult.mockResolvedValueOnce([[
209
+ {
210
+ title: 'United States',
211
+ address_elements: addressFormFieldEntries,
212
+ postal_code_regex: '^[0-9]{5}(?:-[0-9]{4})?$',
213
+ verify_after_autocomplete: true,
214
+ wrap_address1_to_address2: false
215
+ }
216
+ ]]);
217
+ const {getStack} = require('../src/api');
218
+ const Stack = getStack('dev');
219
+ await expect(Stack.getAddressForms(['United States'])).resolves.toStrictEqual([
220
+ {
221
+ address_elements: [
222
+ {
223
+ field: 'address1',
224
+ width: 'full',
225
+ editable: true,
226
+ max_length: 40,
227
+ required: true
228
+ },
229
+ {
230
+ field: 'postalCode',
231
+ width: 'half',
232
+ editable: false,
233
+ max_length: 10,
234
+ required: false
235
+ }
236
+ ],
237
+ postal_code_regex: '^[0-9]{5}(?:-[0-9]{4})?$',
238
+ verify_after_autocomplete: true,
239
+ wrap_address1_to_address2: false
240
+ }
241
+ ]);
242
+ });
243
+
244
+ test('getAddressForms camelcases returned field names', async () => {
245
+ mockPromiseResult.mockResolvedValueOnce([[
246
+ {
247
+ address_elements: addressFormFieldEntries,
248
+ postal_code_regex: '^[0-9]{5}(?:-[0-9]{4})?$',
249
+ verify_after_autocomplete: true,
250
+ wrap_address1_to_address2: false
251
+ }
252
+ ]]);
253
+ const {getStack} = require('../src/api');
254
+ const Stack = getStack('dev');
255
+ await expect(Stack.getAddressForms(['United States'], true)).resolves.toStrictEqual([
256
+ {
257
+ addressElements: [
258
+ {
259
+ field: 'address1',
260
+ width: 'full',
261
+ editable: true,
262
+ maxLength: 40,
263
+ required: true
264
+ },
265
+ {
266
+ field: 'postalCode',
267
+ width: 'half',
268
+ editable: false,
269
+ maxLength: 10,
270
+ required: false
271
+ }
272
+ ],
273
+ postalCodeRegex: '^[0-9]{5}(?:-[0-9]{4})?$',
274
+ verifyAfterAutocomplete: true,
275
+ wrapAddress1ToAddress2: false
276
+ }
277
+ ]);
278
+ });
279
+
280
+ test('getShippingAddressForms maps nested address form fields', async () => {
281
+ mockPromiseResult.mockResolvedValueOnce([[
282
+ {
283
+ title: 'United States',
284
+ pre_address_fields: [addressFormFieldEntries[0]],
285
+ address_form: {
286
+ title: 'default',
287
+ address_elements: addressFormFieldEntries
288
+ },
289
+ post_address_fields: [addressFormFieldEntries[1]]
290
+ }
291
+ ]]);
292
+ const {getStack} = require('../src/api');
293
+ const Stack = getStack('dev');
294
+ await expect(Stack.getShippingAddressForms(['United States'])).resolves.toStrictEqual([
295
+ {
296
+ title: 'United States',
297
+ pre_address_fields: [
298
+ {
299
+ field: 'address1',
300
+ width: 'full',
301
+ editable: true,
302
+ max_length: 40,
303
+ required: true
304
+ }
305
+ ],
306
+ address_form: {
307
+ title: 'default',
308
+ address_elements: [
309
+ {
310
+ field: 'address1',
311
+ width: 'full',
312
+ editable: true,
313
+ max_length: 40,
314
+ required: true
315
+ },
316
+ {
317
+ field: 'postalCode',
318
+ width: 'half',
319
+ editable: false,
320
+ max_length: 10,
321
+ required: false
322
+ }
323
+ ]
324
+ },
325
+ post_address_fields: [
326
+ {
327
+ field: 'postalCode',
328
+ width: 'half',
329
+ editable: false,
330
+ max_length: 10,
331
+ required: false
332
+ }
333
+ ]
334
+ }
335
+ ]);
336
+ });
337
+
338
+ test('getShippingAddressForms camelcases returned field names', async () => {
339
+ mockPromiseResult.mockResolvedValueOnce([[
340
+ {
341
+ title: 'United States',
342
+ pre_address_fields: [addressFormFieldEntries[0]],
343
+ address_form: {
344
+ title: 'default',
345
+ address_elements: addressFormFieldEntries
346
+ },
347
+ post_address_fields: [addressFormFieldEntries[1]]
348
+ }
349
+ ]]);
350
+ const {getStack} = require('../src/api');
351
+ const Stack = getStack('dev');
352
+ await expect(Stack.getShippingAddressForms(['United States'], true)).resolves.toStrictEqual([
353
+ {
354
+ title: 'United States',
355
+ preAddressFields: [
356
+ {
357
+ field: 'address1',
358
+ width: 'full',
359
+ editable: true,
360
+ maxLength: 40,
361
+ required: true
362
+ }
363
+ ],
364
+ addressForm: {
365
+ title: 'default',
366
+ addressElements: [
367
+ {
368
+ field: 'address1',
369
+ width: 'full',
370
+ editable: true,
371
+ maxLength: 40,
372
+ required: true
373
+ },
374
+ {
375
+ field: 'postalCode',
376
+ width: 'half',
377
+ editable: false,
378
+ maxLength: 10,
379
+ required: false
380
+ }
381
+ ]
382
+ },
383
+ postAddressFields: [
384
+ {
385
+ field: 'postalCode',
386
+ width: 'half',
387
+ editable: false,
388
+ maxLength: 10,
389
+ required: false
390
+ }
391
+ ]
392
+ }
393
+ ]);
394
+ });
140
395
  });
package/docs/CHANGELOG.md CHANGED
@@ -1 +1 @@
1
- # [2.1.0-pa-1117.1](https://code.tls.nuskin.io/ns-am/utility/npm/contentstack-lib/compare/v2.0.0...v2.1.0-pa-1117.1) (2026-04-06)
1
+ # [2.1.0-pa-1117.3](https://code.tls.nuskin.io/ns-am/utility/npm/contentstack-lib/compare/v2.1.0-pa-1117.2...v2.1.0-pa-1117.3) (2026-04-06)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nuskin/contentstack-lib",
3
- "version": "2.1.0-pa-1117.1",
3
+ "version": "2.1.0-pa-1117.3",
4
4
  "description": "This project contains configuration and api code to access Contentstack, to be shared between the backend (AWS Lambda) and frontend (Vue, etc).",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
package/src/api.js CHANGED
@@ -179,13 +179,13 @@ async function getSingletonEntries(options) {
179
179
  * @param {string[]} values
180
180
  * @return {Promise<{Object}>} config
181
181
  */
182
- const _getMultiEntries = async (contentType, values) => {
182
+ const _getMultiEntries = async (contentType, includeRefs, values) => {
183
183
  try {
184
184
  const [results] = await Stack
185
185
  .ContentType(contentType)
186
186
  .Query()
187
187
  .containedIn('title', values)
188
- .includeReference(['pre_address_fields', 'address_form', 'post_address_fields'])
188
+ .includeReference(includeRefs)
189
189
  .toJSON()
190
190
  .find();
191
191
 
@@ -195,11 +195,54 @@ const _getMultiEntries = async (contentType, values) => {
195
195
  }
196
196
  }
197
197
 
198
+ /**
199
+ * Maps address form field entries into a small normalized dataset.
200
+ * @param {Object[]} addressFormFields
201
+ * @return {Object[]}
202
+ * @private
203
+ */
204
+ const _extractAddressFormFields = (addressFormFields = [], camelcase = false) => {
205
+ const mappedFields = addressFormFields.map(({field, width, editable, max_length, required}) => ({
206
+ field,
207
+ width,
208
+ editable,
209
+ max_length: Number(max_length),
210
+ required
211
+ }));
212
+
213
+ return camelcase ? _snakeObjectToCamel(mappedFields) : mappedFields;
214
+ }
198
215
 
199
- const getShippingAddressForms = async (countries) => {
200
- const results = await _getMultiEntries(countries);
201
- console.log(results);
216
+ const getShippingAddressForms = async (countries, camelcase = false) => {
217
+ const results = await _getMultiEntries('shipping_address_form', ['pre_address_fields', 'address_form', 'address_form.address_elements', 'post_address_fields'], countries);
218
+ const mappedResults = (results || []).map(result => ({
219
+ ...result,
220
+ pre_address_fields: _extractAddressFormFields(result.pre_address_fields, camelcase),
221
+ address_form: result.address_form ? {
222
+ ...result.address_form,
223
+ address_elements: _extractAddressFormFields(result.address_form.address_elements, camelcase)
224
+ } : result.address_form,
225
+ post_address_fields: _extractAddressFormFields(result.post_address_fields, camelcase)
226
+ }));
202
227
 
228
+ return camelcase ? _snakeObjectToCamel(mappedResults) : mappedResults;
229
+ }
230
+
231
+ const getAddressForms = async (countries, camelcase = false) => {
232
+ const results = await _getMultiEntries('address_form', 'address_elements', countries);
233
+ const mappedResults = (results || []).map(({
234
+ address_elements,
235
+ postal_code_regex,
236
+ verify_after_autocomplete,
237
+ wrap_address1_to_address2
238
+ }) => ({
239
+ address_elements: _extractAddressFormFields(address_elements, camelcase),
240
+ postal_code_regex,
241
+ verify_after_autocomplete,
242
+ wrap_address1_to_address2
243
+ }));
244
+
245
+ return camelcase ? _snakeObjectToCamel(mappedResults) : mappedResults;
203
246
  }
204
247
 
205
248
  /**
@@ -227,7 +270,10 @@ function getStack(envrnmnt) {
227
270
  // extend the Stack with a custom function to get translations
228
271
  Stack.getSingletonEntries = getSingletonEntries;
229
272
  // extend the Stack with a custom function to get ShippingAddressForms
273
+ Stack.getAddressForms = getAddressForms;
274
+ // extend the Stack with a custom function to get ShippingAddressForms
230
275
  Stack.getShippingAddressForms = getShippingAddressForms;
276
+ Stack.extractAddressFormFields = _extractAddressFormFields;
231
277
 
232
278
  return Stack;
233
279
  }
package/src/index.js CHANGED
@@ -5,9 +5,8 @@
5
5
 
6
6
  "use strict";
7
7
 
8
- const {getStack, init} = require("./api.js");
8
+ const {getStack} = require("./api.js");
9
9
 
10
10
  module.exports = {
11
- init,
12
11
  getStack
13
12
  };