@akinon/next 1.126.15 → 1.126.16

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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @akinon/next
2
2
 
3
+ ## 1.126.16
4
+
5
+ ### Patch Changes
6
+
7
+ - 032b418: ZERO-5194: add getWidgetSchemaData to the v1 server data layer, as on main
8
+
3
9
  ## 1.126.15
4
10
 
5
11
  ### Patch Changes
@@ -0,0 +1,121 @@
1
+ jest.mock('server-only', () => ({}), { virtual: true });
2
+
3
+ const appFetch = jest.fn();
4
+
5
+ jest.mock('../utils/app-fetch', () => ({
6
+ __esModule: true,
7
+ default: (...args: unknown[]) => appFetch(...args)
8
+ }));
9
+
10
+ jest.mock('../utils/server-variables', () => ({
11
+ ServerVariables: { locale: 'tr', currency: 'try' }
12
+ }));
13
+
14
+ import { getWidgetData, getWidgetSchemaData } from '../data/server/widget';
15
+ import { Cache, CacheKey } from '../lib/cache';
16
+
17
+ const SLUG = 'section-hero';
18
+
19
+ const SCHEMA = {
20
+ pk: 12,
21
+ name: SLUG,
22
+ schema: {
23
+ [SLUG]: { metadata: { blocks: [{ id: 'block-banner', type: 'image' }] } }
24
+ }
25
+ };
26
+
27
+ describe('getWidgetSchemaData', () => {
28
+ let wrap: jest.SpyInstance;
29
+
30
+ beforeEach(() => {
31
+ appFetch.mockReset().mockResolvedValue(SCHEMA);
32
+ wrap = jest
33
+ .spyOn(Cache, 'wrap')
34
+ .mockImplementation(async (_key, _locale, handler) => handler());
35
+ });
36
+
37
+ afterEach(() => {
38
+ wrap.mockRestore();
39
+ });
40
+
41
+ it('reads the schema endpoint for the request locale and currency', async () => {
42
+ await expect(getWidgetSchemaData({ widgetSlug: SLUG })).resolves.toEqual(
43
+ SCHEMA
44
+ );
45
+
46
+ expect(appFetch).toHaveBeenCalledTimes(1);
47
+ expect(appFetch).toHaveBeenCalledWith({
48
+ url: `/widgets/${SLUG}/schema/`,
49
+ locale: 'tr',
50
+ currency: 'try',
51
+ init: {}
52
+ });
53
+ });
54
+
55
+ it('caches under its own key, per locale', async () => {
56
+ await getWidgetSchemaData({ widgetSlug: SLUG });
57
+
58
+ expect(wrap).toHaveBeenCalledWith(
59
+ `widget_schema_${SLUG}`,
60
+ 'tr',
61
+ expect.any(Function),
62
+ undefined
63
+ );
64
+ });
65
+
66
+ it('never shares a cache entry with the widget answer', () => {
67
+ expect(CacheKey.WidgetSchema(SLUG)).not.toBe(CacheKey.Widget(SLUG));
68
+ });
69
+
70
+ it('honours an explicit locale, currency and cache options', async () => {
71
+ const cacheOptions = { expire: 30 };
72
+
73
+ await getWidgetSchemaData({
74
+ widgetSlug: SLUG,
75
+ locale: 'en',
76
+ currency: 'usd',
77
+ cacheOptions
78
+ });
79
+
80
+ expect(wrap).toHaveBeenCalledWith(
81
+ `widget_schema_${SLUG}`,
82
+ 'en',
83
+ expect.any(Function),
84
+ cacheOptions
85
+ );
86
+ expect(appFetch).toHaveBeenCalledWith({
87
+ url: `/widgets/${SLUG}/schema/`,
88
+ locale: 'en',
89
+ currency: 'usd',
90
+ init: {}
91
+ });
92
+ });
93
+
94
+ it('serves a cached schema without calling the api', async () => {
95
+ wrap.mockResolvedValue(SCHEMA);
96
+
97
+ await expect(getWidgetSchemaData({ widgetSlug: SLUG })).resolves.toEqual(
98
+ SCHEMA
99
+ );
100
+ expect(appFetch).not.toHaveBeenCalled();
101
+ });
102
+
103
+ it('answers null for an empty slug without calling the api', async () => {
104
+ await expect(getWidgetSchemaData({ widgetSlug: '' })).resolves.toBeNull();
105
+ expect(appFetch).not.toHaveBeenCalled();
106
+ });
107
+
108
+ it('lives exactly as long as the widget answer it is paired with', async () => {
109
+ await getWidgetData({ slug: SLUG });
110
+ await getWidgetSchemaData({ widgetSlug: SLUG });
111
+
112
+ const [dataOptions, schemaOptions] = wrap.mock.calls.map((call) => call[3]);
113
+
114
+ expect(wrap.mock.calls.map((call) => call[0])).toEqual([
115
+ `widget_${SLUG}`,
116
+ `widget_schema_${SLUG}`
117
+ ]);
118
+ expect(dataOptions?.expire).toBeUndefined();
119
+ expect(schemaOptions?.expire).toBeUndefined();
120
+ });
121
+ });
@@ -1,6 +1,6 @@
1
1
  import { Cache, CacheKey } from '../../lib/cache';
2
2
  import 'server-only';
3
- import { CacheOptions, WidgetResultType } from '../../types';
3
+ import { CacheOptions, WidgetResultType, WidgetSchemaType } from '../../types';
4
4
  import appFetch from '../../utils/app-fetch';
5
5
  import { widgets } from '../urls';
6
6
  import { ServerVariables } from '../../utils/server-variables';
@@ -264,3 +264,42 @@ export const getWidgetData = async <T>({
264
264
  }
265
265
  );
266
266
  };
267
+
268
+ const getWidgetSchemaDataHandler =
269
+ (
270
+ widgetSlug: string,
271
+ locale: string,
272
+ currency: string,
273
+ next?: { revalidate: number }
274
+ ) =>
275
+ async () => {
276
+ if (!widgetSlug) {
277
+ return null;
278
+ }
279
+
280
+ return await appFetch({
281
+ url: widgets.getWidgetSchema(widgetSlug),
282
+ locale,
283
+ currency,
284
+ init: next ? { next } : {}
285
+ });
286
+ };
287
+
288
+ export const getWidgetSchemaData = async <T>({
289
+ widgetSlug,
290
+ locale = ServerVariables.locale,
291
+ currency = ServerVariables.currency,
292
+ cacheOptions
293
+ }: {
294
+ widgetSlug: string;
295
+ locale?: string;
296
+ currency?: string;
297
+ cacheOptions?: CacheOptions;
298
+ }): Promise<WidgetSchemaType<T>> => {
299
+ return Cache.wrap(
300
+ CacheKey.WidgetSchema(widgetSlug),
301
+ locale,
302
+ getWidgetSchemaDataHandler(widgetSlug, locale, currency),
303
+ cacheOptions
304
+ );
305
+ };
package/lib/cache.ts CHANGED
@@ -108,6 +108,7 @@ export const CacheKey = {
108
108
  FlatPage: (pk: number) => `flat_page_${pk}`,
109
109
  LandingPage: (pk: number) => `landing_page_${pk}`,
110
110
  Widget: (slug: string) => `widget_${slug}`,
111
+ WidgetSchema: (widgetSlug: string) => `widget_schema_${widgetSlug}`,
111
112
  PrettyUrl: (pathname: string) => `pretty_url_${pathname}`,
112
113
  Menu: (depth: number, parent?: string) =>
113
114
  `menu_${depth}${parent ? `_${parent}` : ''}`,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@akinon/next",
3
3
  "description": "Core package for Project Zero Next",
4
- "version": "1.126.15",
4
+ "version": "1.126.16",
5
5
  "private": false,
6
6
  "license": "MIT",
7
7
  "bin": {
@@ -35,7 +35,7 @@
35
35
  "set-cookie-parser": "2.6.0"
36
36
  },
37
37
  "devDependencies": {
38
- "@akinon/eslint-plugin-projectzero": "1.126.15",
38
+ "@akinon/eslint-plugin-projectzero": "1.126.16",
39
39
  "@babel/core": "7.26.10",
40
40
  "@babel/preset-env": "7.26.9",
41
41
  "@babel/preset-typescript": "7.27.0",
@@ -26,3 +26,9 @@ export type WidgetResultType<T> = {
26
26
  slug?: string;
27
27
  template?: string;
28
28
  };
29
+
30
+ export type WidgetSchemaType<T> = {
31
+ pk?: number;
32
+ name?: string;
33
+ schema?: T;
34
+ };