@webiny/website-builder-sdk 0.0.0-unstable.eb196ccd2f → 0.0.0-unstable.eb81deee7e

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.
Files changed (307) hide show
  1. package/BindingsApi.js +29 -36
  2. package/BindingsApi.js.map +1 -1
  3. package/BindingsProcessor.js +34 -43
  4. package/BindingsProcessor.js.map +1 -1
  5. package/BindingsProcessor.test.js +82 -77
  6. package/BindingsProcessor.test.js.map +1 -1
  7. package/BindingsResolver.d.ts +5 -2
  8. package/BindingsResolver.js +99 -122
  9. package/BindingsResolver.js.map +1 -1
  10. package/BindingsResolver.test.js +399 -362
  11. package/BindingsResolver.test.js.map +1 -1
  12. package/ComponentInputTraverser.js +32 -49
  13. package/ComponentInputTraverser.js.map +1 -1
  14. package/ComponentManifestToAstConverter.js +20 -21
  15. package/ComponentManifestToAstConverter.js.map +1 -1
  16. package/ComponentRegistry.d.ts +9 -0
  17. package/ComponentRegistry.js +38 -22
  18. package/ComponentRegistry.js.map +1 -1
  19. package/ComponentResolver.d.ts +3 -2
  20. package/ComponentResolver.js +39 -29
  21. package/ComponentResolver.js.map +1 -1
  22. package/ComponentResolver.test.d.ts +1 -0
  23. package/ComponentResolver.test.js +81 -0
  24. package/ComponentResolver.test.js.map +1 -0
  25. package/ConstraintEvaluator.d.ts +36 -0
  26. package/ConstraintEvaluator.js +288 -0
  27. package/ConstraintEvaluator.js.map +1 -0
  28. package/ConstraintEvaluator.test.d.ts +1 -0
  29. package/ConstraintEvaluator.test.js +1634 -0
  30. package/ConstraintEvaluator.test.js.map +1 -0
  31. package/ContentSdk.d.ts +17 -3
  32. package/ContentSdk.js +113 -90
  33. package/ContentSdk.js.map +1 -1
  34. package/DocumentStore.d.ts +1 -1
  35. package/DocumentStore.js +47 -59
  36. package/DocumentStore.js.map +1 -1
  37. package/DocumentStoreManager.js +17 -16
  38. package/DocumentStoreManager.js.map +1 -1
  39. package/EditingSdk.d.ts +2 -2
  40. package/EditingSdk.js +92 -124
  41. package/EditingSdk.js.map +1 -1
  42. package/ElementFactory.d.ts +2 -3
  43. package/ElementFactory.js +164 -163
  44. package/ElementFactory.js.map +1 -1
  45. package/ElementFactory.objectListDefaults.test.d.ts +1 -0
  46. package/ElementFactory.objectListDefaults.test.js +423 -0
  47. package/ElementFactory.objectListDefaults.test.js.map +1 -0
  48. package/ElementFactory.test.d.ts +1 -0
  49. package/ElementFactory.test.js +353 -0
  50. package/ElementFactory.test.js.map +1 -0
  51. package/Environment.js +18 -19
  52. package/Environment.js.map +1 -1
  53. package/FunctionConverter.js +8 -7
  54. package/FunctionConverter.js.map +1 -1
  55. package/HashObject.js +11 -12
  56. package/HashObject.js.map +1 -1
  57. package/HotkeyManager.js +41 -48
  58. package/HotkeyManager.js.map +1 -1
  59. package/IBindingsUpdater.js +0 -3
  60. package/IRedirects.js +0 -3
  61. package/InheritanceProcessor.d.ts +2 -2
  62. package/InheritanceProcessor.js +99 -139
  63. package/InheritanceProcessor.js.map +1 -1
  64. package/InheritanceProcessor.test.js +178 -178
  65. package/InheritanceProcessor.test.js.map +1 -1
  66. package/InheritedValueResolver.d.ts +18 -1
  67. package/InheritedValueResolver.js +18 -20
  68. package/InheritedValueResolver.js.map +1 -1
  69. package/InputBindingsProcessor.d.ts +23 -2
  70. package/InputBindingsProcessor.js +200 -289
  71. package/InputBindingsProcessor.js.map +1 -1
  72. package/InputBindingsProcessorTokens.test.d.ts +1 -0
  73. package/InputBindingsProcessorTokens.test.js +400 -0
  74. package/InputBindingsProcessorTokens.test.js.map +1 -0
  75. package/InputsBindingsProcessor.test.js +334 -313
  76. package/InputsBindingsProcessor.test.js.map +1 -1
  77. package/InputsUpdater.d.ts +1 -1
  78. package/InputsUpdater.js +23 -26
  79. package/InputsUpdater.js.map +1 -1
  80. package/LiveSdk.d.ts +2 -2
  81. package/LiveSdk.js +12 -13
  82. package/LiveSdk.js.map +1 -1
  83. package/Logger.d.ts +2 -1
  84. package/Logger.js +9 -8
  85. package/Logger.js.map +1 -1
  86. package/MouseTracker.js +77 -83
  87. package/MouseTracker.js.map +1 -1
  88. package/NullSdk.d.ts +4 -3
  89. package/NullSdk.js +22 -14
  90. package/NullSdk.js.map +1 -1
  91. package/PreviewDocument.d.ts +1 -0
  92. package/PreviewDocument.js +30 -30
  93. package/PreviewDocument.js.map +1 -1
  94. package/PreviewSdk.d.ts +4 -3
  95. package/PreviewSdk.js +19 -17
  96. package/PreviewSdk.js.map +1 -1
  97. package/PreviewViewport.d.ts +0 -1
  98. package/PreviewViewport.js +50 -82
  99. package/PreviewViewport.js.map +1 -1
  100. package/README.md +10 -2
  101. package/ResizeObserver.js +24 -31
  102. package/ResizeObserver.js.map +1 -1
  103. package/StylesBindingsProcessor.d.ts +12 -2
  104. package/StylesBindingsProcessor.js +62 -79
  105. package/StylesBindingsProcessor.js.map +1 -1
  106. package/StylesUpdater.d.ts +1 -1
  107. package/StylesUpdater.js +20 -25
  108. package/StylesUpdater.js.map +1 -1
  109. package/Theme.js +30 -32
  110. package/Theme.js.map +1 -1
  111. package/ViewportManager.d.ts +2 -0
  112. package/ViewportManager.js +89 -97
  113. package/ViewportManager.js.map +1 -1
  114. package/assertBindingShapes.d.ts +31 -0
  115. package/assertBindingShapes.js +64 -0
  116. package/assertBindingShapes.js.map +1 -0
  117. package/assertBindingShapes.test.d.ts +1 -0
  118. package/assertBindingShapes.test.js +131 -0
  119. package/assertBindingShapes.test.js.map +1 -0
  120. package/asset/deliveryUrl.d.ts +41 -0
  121. package/asset/deliveryUrl.js +34 -0
  122. package/asset/deliveryUrl.js.map +1 -0
  123. package/asset/deliveryUrl.test.d.ts +1 -0
  124. package/asset/deliveryUrl.test.js +127 -0
  125. package/asset/deliveryUrl.test.js.map +1 -0
  126. package/asset/geometry.d.ts +7 -0
  127. package/asset/geometry.js +10 -0
  128. package/asset/geometry.js.map +1 -0
  129. package/asset/imageSrcSet.d.ts +63 -0
  130. package/asset/imageSrcSet.js +98 -0
  131. package/asset/imageSrcSet.js.map +1 -0
  132. package/asset/imageSrcSet.test.d.ts +1 -0
  133. package/asset/imageSrcSet.test.js +103 -0
  134. package/asset/imageSrcSet.test.js.map +1 -0
  135. package/asset/index.d.ts +5 -0
  136. package/asset/index.js +5 -0
  137. package/asset/normalize.d.ts +24 -0
  138. package/asset/normalize.js +106 -0
  139. package/asset/normalize.js.map +1 -0
  140. package/asset/normalize.test.d.ts +1 -0
  141. package/asset/normalize.test.js +263 -0
  142. package/asset/normalize.test.js.map +1 -0
  143. package/asset/types.d.ts +2 -0
  144. package/asset/types.js +0 -0
  145. package/constants.d.ts +1 -0
  146. package/constants.js +7 -5
  147. package/constants.js.map +1 -1
  148. package/contentEntry/ContentEntryBindingsResolver.d.ts +30 -0
  149. package/contentEntry/ContentEntryBindingsResolver.js +45 -0
  150. package/contentEntry/ContentEntryBindingsResolver.js.map +1 -0
  151. package/contentEntry/ContentEntryCache.d.ts +46 -0
  152. package/contentEntry/ContentEntryCache.js +50 -0
  153. package/contentEntry/ContentEntryCache.js.map +1 -0
  154. package/contentEntry/resolveContentEntry.d.ts +74 -0
  155. package/contentEntry/resolveContentEntry.js +53 -0
  156. package/contentEntry/resolveContentEntry.js.map +1 -0
  157. package/contentEntry/resolveContentEntry.test.d.ts +1 -0
  158. package/contentEntry/resolveContentEntry.test.js +213 -0
  159. package/contentEntry/resolveContentEntry.test.js.map +1 -0
  160. package/createComponent.d.ts +5 -0
  161. package/createComponent.js +32 -0
  162. package/createComponent.js.map +1 -0
  163. package/createElement.js +5 -6
  164. package/createElement.js.map +1 -1
  165. package/createInput.d.ts +132 -16
  166. package/createInput.js +92 -111
  167. package/createInput.js.map +1 -1
  168. package/createTheme.js +2 -3
  169. package/createTheme.js.map +1 -1
  170. package/dataProviders/ApiClient.d.ts +10 -5
  171. package/dataProviders/ApiClient.js +40 -49
  172. package/dataProviders/ApiClient.js.map +1 -1
  173. package/dataProviders/DefaultDataProvider.d.ts +7 -3
  174. package/dataProviders/DefaultDataProvider.js +91 -45
  175. package/dataProviders/DefaultDataProvider.js.map +1 -1
  176. package/dataProviders/GET_EXPERIMENT_PAUSED.d.ts +1 -0
  177. package/dataProviders/GET_EXPERIMENT_PAUSED.js +17 -0
  178. package/dataProviders/GET_EXPERIMENT_PAUSED.js.map +1 -0
  179. package/dataProviders/GET_PAGE_BY_ID.d.ts +1 -1
  180. package/dataProviders/GET_PAGE_BY_ID.js +4 -1
  181. package/dataProviders/GET_PAGE_BY_ID.js.map +1 -1
  182. package/dataProviders/GET_PAGE_BY_PATH.d.ts +1 -1
  183. package/dataProviders/GET_PAGE_BY_PATH.js +4 -1
  184. package/dataProviders/GET_PAGE_BY_PATH.js.map +1 -1
  185. package/dataProviders/GET_PAGE_EXPERIMENT.d.ts +1 -0
  186. package/dataProviders/GET_PAGE_EXPERIMENT.js +32 -0
  187. package/dataProviders/GET_PAGE_EXPERIMENT.js.map +1 -0
  188. package/dataProviders/GET_VARIANT_CONTENT.d.ts +1 -0
  189. package/dataProviders/GET_VARIANT_CONTENT.js +24 -0
  190. package/dataProviders/GET_VARIANT_CONTENT.js.map +1 -0
  191. package/dataProviders/LIST_PUBLISHED_PAGES.d.ts +1 -1
  192. package/dataProviders/LIST_PUBLISHED_PAGES.js +17 -5
  193. package/dataProviders/LIST_PUBLISHED_PAGES.js.map +1 -1
  194. package/dataProviders/NullDataProvider.d.ts +16 -4
  195. package/dataProviders/NullDataProvider.js +30 -13
  196. package/dataProviders/NullDataProvider.js.map +1 -1
  197. package/dataProviders/RedirectsProvider.js +24 -27
  198. package/dataProviders/RedirectsProvider.js.map +1 -1
  199. package/defaultBreakpoints.js +43 -22
  200. package/defaultBreakpoints.js.map +1 -1
  201. package/documentOperations/$addElementReferenceToParent.d.ts +1 -1
  202. package/documentOperations/$addElementReferenceToParent.js +30 -26
  203. package/documentOperations/$addElementReferenceToParent.js.map +1 -1
  204. package/documentOperations/AddElement.js +8 -7
  205. package/documentOperations/AddElement.js.map +1 -1
  206. package/documentOperations/AddToParent.d.ts +2 -2
  207. package/documentOperations/AddToParent.js +14 -13
  208. package/documentOperations/AddToParent.js.map +1 -1
  209. package/documentOperations/IDocumentOperation.js +0 -3
  210. package/documentOperations/RemoveElement.js +10 -7
  211. package/documentOperations/RemoveElement.js.map +1 -1
  212. package/documentOperations/SetGlobalInputBinding.js +23 -22
  213. package/documentOperations/SetGlobalInputBinding.js.map +1 -1
  214. package/documentOperations/SetGlobalStyleBinding.js +23 -23
  215. package/documentOperations/SetGlobalStyleBinding.js.map +1 -1
  216. package/documentOperations/SetInputBindingOverride.js +30 -29
  217. package/documentOperations/SetInputBindingOverride.js.map +1 -1
  218. package/documentOperations/SetStyleBindingOverride.js +30 -31
  219. package/documentOperations/SetStyleBindingOverride.js.map +1 -1
  220. package/documentOperations/index.js +9 -8
  221. package/documentOperations/index.js.map +1 -1
  222. package/experiments/PostHogAnalyticsProvider.d.ts +31 -0
  223. package/experiments/PostHogAnalyticsProvider.js +28 -0
  224. package/experiments/PostHogAnalyticsProvider.js.map +1 -0
  225. package/experiments/analyticsProvider.d.ts +4 -0
  226. package/experiments/analyticsProvider.js +11 -0
  227. package/experiments/analyticsProvider.js.map +1 -0
  228. package/experiments/bucketing.d.ts +27 -0
  229. package/experiments/bucketing.js +91 -0
  230. package/experiments/bucketing.js.map +1 -0
  231. package/experiments/bucketing.test.d.ts +1 -0
  232. package/experiments/bucketing.test.js +183 -0
  233. package/experiments/bucketing.test.js.map +1 -0
  234. package/experiments/index.d.ts +5 -0
  235. package/experiments/index.js +5 -0
  236. package/experiments/render.d.ts +79 -0
  237. package/experiments/render.js +149 -0
  238. package/experiments/render.js.map +1 -0
  239. package/experiments/types.d.ts +108 -0
  240. package/experiments/types.js +4 -0
  241. package/experiments/types.js.map +1 -0
  242. package/findMatchingAstNode.js +11 -13
  243. package/findMatchingAstNode.js.map +1 -1
  244. package/generateElementId.d.ts +1 -1
  245. package/generateElementId.js +2 -2
  246. package/generateElementId.js.map +1 -1
  247. package/headersProvider.js +4 -3
  248. package/headersProvider.js.map +1 -1
  249. package/image/geometry.d.ts +54 -0
  250. package/image/geometry.js +112 -0
  251. package/image/geometry.js.map +1 -0
  252. package/image/geometry.test.d.ts +1 -0
  253. package/image/geometry.test.js +190 -0
  254. package/image/geometry.test.js.map +1 -0
  255. package/image/index.d.ts +3 -0
  256. package/image/index.js +3 -0
  257. package/image/presets.d.ts +6 -0
  258. package/image/presets.js +20 -0
  259. package/image/presets.js.map +1 -0
  260. package/image/types.d.ts +10 -0
  261. package/image/types.js +0 -0
  262. package/index.d.ts +12 -1
  263. package/index.js +11 -3
  264. package/jsonPatch.d.ts +1 -1
  265. package/jsonPatch.js +5 -9
  266. package/jsonPatch.js.map +1 -1
  267. package/messages.js +12 -11
  268. package/messages.js.map +1 -1
  269. package/messenger/MessageOrigin.js +12 -11
  270. package/messenger/MessageOrigin.js.map +1 -1
  271. package/messenger/Messenger.js +59 -70
  272. package/messenger/Messenger.js.map +1 -1
  273. package/messenger/index.js +0 -2
  274. package/package.json +19 -22
  275. package/registerComponentGroup.js +5 -6
  276. package/registerComponentGroup.js.map +1 -1
  277. package/tokenBinding.d.ts +26 -0
  278. package/tokenBinding.js +15 -0
  279. package/tokenBinding.js.map +1 -0
  280. package/tokenBinding.test.d.ts +1 -0
  281. package/tokenBinding.test.js +165 -0
  282. package/tokenBinding.test.js.map +1 -0
  283. package/types/ShorthandCssProperties.js +0 -3
  284. package/types/WebsiteBuilderTheme.d.ts +54 -45
  285. package/types/WebsiteBuilderTheme.js +0 -3
  286. package/types.d.ts +294 -13
  287. package/types.js +0 -3
  288. package/IBindingsUpdater.js.map +0 -1
  289. package/IRedirects.js.map +0 -1
  290. package/documentOperations/IDocumentOperation.js.map +0 -1
  291. package/index.js.map +0 -1
  292. package/lexical/createDefaultLexicalTheme.d.ts +0 -2
  293. package/lexical/createDefaultLexicalTheme.js +0 -84
  294. package/lexical/createDefaultLexicalTheme.js.map +0 -1
  295. package/lexical/createLexicalTheme.d.ts +0 -2
  296. package/lexical/createLexicalTheme.js +0 -7
  297. package/lexical/createLexicalTheme.js.map +0 -1
  298. package/lexical/deepMerge.d.ts +0 -1
  299. package/lexical/deepMerge.js +0 -23
  300. package/lexical/deepMerge.js.map +0 -1
  301. package/messenger/index.js.map +0 -1
  302. package/types/LexicalEditorTheme.d.ts +0 -2
  303. package/types/LexicalEditorTheme.js +0 -3
  304. package/types/LexicalEditorTheme.js.map +0 -1
  305. package/types/ShorthandCssProperties.js.map +0 -1
  306. package/types/WebsiteBuilderTheme.js.map +0 -1
  307. package/types.js.map +0 -1
@@ -0,0 +1,131 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { assertBindingShapes } from "./assertBindingShapes.js";
3
+ import { ComponentManifestToAstConverter } from "./ComponentManifestToAstConverter.js";
4
+ const ast = (inputs)=>ComponentManifestToAstConverter.convert(inputs);
5
+ const SCALAR_LIST = ast([
6
+ {
7
+ name: "features",
8
+ type: "text",
9
+ list: true
10
+ }
11
+ ]);
12
+ const SCALAR = ast([
13
+ {
14
+ name: "heading",
15
+ type: "text"
16
+ }
17
+ ]);
18
+ const OBJECT_LIST = ast([
19
+ {
20
+ name: "stats",
21
+ type: "object",
22
+ list: true,
23
+ fields: [
24
+ {
25
+ name: "value",
26
+ type: "text"
27
+ },
28
+ {
29
+ name: "label",
30
+ type: "text"
31
+ }
32
+ ]
33
+ }
34
+ ]);
35
+ const bindings = (inputs)=>({
36
+ inputs
37
+ });
38
+ describe("assertBindingShapes", ()=>{
39
+ it("reports a scalar written where a list is declared", ()=>{
40
+ const violations = assertBindingShapes(bindings({
41
+ features: {
42
+ static: "Dryer",
43
+ type: "text",
44
+ list: true
45
+ }
46
+ }), SCALAR_LIST);
47
+ expect(violations).toEqual([
48
+ {
49
+ path: "features",
50
+ declared: "list",
51
+ found: "scalar",
52
+ value: "Dryer"
53
+ }
54
+ ]);
55
+ });
56
+ it("accepts a scalar list stored element-wise", ()=>{
57
+ const violations = assertBindingShapes(bindings({
58
+ "features/0": {
59
+ static: "Floors"
60
+ },
61
+ "features/1": {
62
+ static: "Windows"
63
+ }
64
+ }), SCALAR_LIST);
65
+ expect(violations).toEqual([]);
66
+ });
67
+ it("accepts a scalar list stored as an array on one binding", ()=>{
68
+ const violations = assertBindingShapes(bindings({
69
+ features: {
70
+ static: [
71
+ "Floors",
72
+ "Windows"
73
+ ]
74
+ }
75
+ }), SCALAR_LIST);
76
+ expect(violations).toEqual([]);
77
+ });
78
+ it("accepts an empty list and an absent binding", ()=>{
79
+ expect(assertBindingShapes(bindings({
80
+ features: {
81
+ static: []
82
+ }
83
+ }), SCALAR_LIST)).toEqual([]);
84
+ expect(assertBindingShapes(bindings({}), SCALAR_LIST)).toEqual([]);
85
+ expect(assertBindingShapes(bindings({
86
+ features: {
87
+ static: null
88
+ }
89
+ }), SCALAR_LIST)).toEqual([]);
90
+ });
91
+ it("reports an array written where a scalar is declared", ()=>{
92
+ const violations = assertBindingShapes(bindings({
93
+ heading: {
94
+ static: [
95
+ "one",
96
+ "two"
97
+ ]
98
+ }
99
+ }), SCALAR);
100
+ expect(violations).toEqual([
101
+ {
102
+ path: "heading",
103
+ declared: "scalar",
104
+ found: "list",
105
+ value: [
106
+ "one",
107
+ "two"
108
+ ]
109
+ }
110
+ ]);
111
+ });
112
+ it("accepts an object list stored element-wise", ()=>{
113
+ const violations = assertBindingShapes(bindings({
114
+ "stats/0/value": {
115
+ static: "80"
116
+ },
117
+ "stats/0/label": {
118
+ static: "Walk Score"
119
+ },
120
+ "stats/1/value": {
121
+ static: "86"
122
+ },
123
+ "stats/1/label": {
124
+ static: "Bike Score"
125
+ }
126
+ }), OBJECT_LIST);
127
+ expect(violations).toEqual([]);
128
+ });
129
+ });
130
+
131
+ //# sourceMappingURL=assertBindingShapes.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assertBindingShapes.test.js","sources":["../src/assertBindingShapes.test.ts"],"sourcesContent":["import { describe, expect, it } from \"vitest\";\nimport { assertBindingShapes } from \"./assertBindingShapes.js\";\nimport { ComponentManifestToAstConverter } from \"./ComponentManifestToAstConverter.js\";\n\nconst ast = (inputs: unknown[]) => ComponentManifestToAstConverter.convert(inputs as never);\n\nconst SCALAR_LIST = ast([{ name: \"features\", type: \"text\", list: true }]);\nconst SCALAR = ast([{ name: \"heading\", type: \"text\" }]);\nconst OBJECT_LIST = ast([\n {\n name: \"stats\",\n type: \"object\",\n list: true,\n fields: [\n { name: \"value\", type: \"text\" },\n { name: \"label\", type: \"text\" }\n ]\n }\n]);\n\nconst bindings = (inputs: Record<string, unknown>) => ({ inputs }) as never;\n\ndescribe(\"assertBindingShapes\", () => {\n it(\"reports a scalar written where a list is declared\", () => {\n /*\n * The shape that made five pages return 500: a correct array arrived at the factory and the\n * traverser collapsed it to its last item while writing.\n */\n const violations = assertBindingShapes(\n bindings({ features: { static: \"Dryer\", type: \"text\", list: true } }),\n SCALAR_LIST\n );\n\n expect(violations).toEqual([\n { path: \"features\", declared: \"list\", found: \"scalar\", value: \"Dryer\" }\n ]);\n });\n\n it(\"accepts a scalar list stored element-wise\", () => {\n const violations = assertBindingShapes(\n bindings({\n \"features/0\": { static: \"Floors\" },\n \"features/1\": { static: \"Windows\" }\n }),\n SCALAR_LIST\n );\n\n expect(violations).toEqual([]);\n });\n\n it(\"accepts a scalar list stored as an array on one binding\", () => {\n const violations = assertBindingShapes(\n bindings({ features: { static: [\"Floors\", \"Windows\"] } }),\n SCALAR_LIST\n );\n\n expect(violations).toEqual([]);\n });\n\n it(\"accepts an empty list and an absent binding\", () => {\n expect(assertBindingShapes(bindings({ features: { static: [] } }), SCALAR_LIST)).toEqual(\n []\n );\n expect(assertBindingShapes(bindings({}), SCALAR_LIST)).toEqual([]);\n expect(assertBindingShapes(bindings({ features: { static: null } }), SCALAR_LIST)).toEqual(\n []\n );\n });\n\n it(\"reports an array written where a scalar is declared\", () => {\n // The inverse does not throw, so nothing else would ever notice it.\n const violations = assertBindingShapes(\n bindings({ heading: { static: [\"one\", \"two\"] } }),\n SCALAR\n );\n\n expect(violations).toEqual([\n { path: \"heading\", declared: \"scalar\", found: \"list\", value: [\"one\", \"two\"] }\n ]);\n });\n\n it(\"accepts an object list stored element-wise\", () => {\n const violations = assertBindingShapes(\n bindings({\n \"stats/0/value\": { static: \"80\" },\n \"stats/0/label\": { static: \"Walk Score\" },\n \"stats/1/value\": { static: \"86\" },\n \"stats/1/label\": { static: \"Bike Score\" }\n }),\n OBJECT_LIST\n );\n\n expect(violations).toEqual([]);\n });\n});\n"],"names":["ast","inputs","ComponentManifestToAstConverter","SCALAR_LIST","SCALAR","OBJECT_LIST","bindings","describe","it","violations","assertBindingShapes","expect"],"mappings":";;;AAIA,MAAMA,MAAM,CAACC,SAAsBC,gCAAgC,OAAO,CAACD;AAE3E,MAAME,cAAcH,IAAI;IAAC;QAAE,MAAM;QAAY,MAAM;QAAQ,MAAM;IAAK;CAAE;AACxE,MAAMI,SAASJ,IAAI;IAAC;QAAE,MAAM;QAAW,MAAM;IAAO;CAAE;AACtD,MAAMK,cAAcL,IAAI;IACpB;QACI,MAAM;QACN,MAAM;QACN,MAAM;QACN,QAAQ;YACJ;gBAAE,MAAM;gBAAS,MAAM;YAAO;YAC9B;gBAAE,MAAM;gBAAS,MAAM;YAAO;SACjC;IACL;CACH;AAED,MAAMM,WAAW,CAACL,SAAqC;QAAEA;IAAO;AAEhEM,SAAS,uBAAuB;IAC5BC,GAAG,qDAAqD;QAKpD,MAAMC,aAAaC,oBACfJ,SAAS;YAAE,UAAU;gBAAE,QAAQ;gBAAS,MAAM;gBAAQ,MAAM;YAAK;QAAE,IACnEH;QAGJQ,OAAOF,YAAY,OAAO,CAAC;YACvB;gBAAE,MAAM;gBAAY,UAAU;gBAAQ,OAAO;gBAAU,OAAO;YAAQ;SACzE;IACL;IAEAD,GAAG,6CAA6C;QAC5C,MAAMC,aAAaC,oBACfJ,SAAS;YACL,cAAc;gBAAE,QAAQ;YAAS;YACjC,cAAc;gBAAE,QAAQ;YAAU;QACtC,IACAH;QAGJQ,OAAOF,YAAY,OAAO,CAAC,EAAE;IACjC;IAEAD,GAAG,2DAA2D;QAC1D,MAAMC,aAAaC,oBACfJ,SAAS;YAAE,UAAU;gBAAE,QAAQ;oBAAC;oBAAU;iBAAU;YAAC;QAAE,IACvDH;QAGJQ,OAAOF,YAAY,OAAO,CAAC,EAAE;IACjC;IAEAD,GAAG,+CAA+C;QAC9CG,OAAOD,oBAAoBJ,SAAS;YAAE,UAAU;gBAAE,QAAQ,EAAE;YAAC;QAAE,IAAIH,cAAc,OAAO,CACpF,EAAE;QAENQ,OAAOD,oBAAoBJ,SAAS,CAAC,IAAIH,cAAc,OAAO,CAAC,EAAE;QACjEQ,OAAOD,oBAAoBJ,SAAS;YAAE,UAAU;gBAAE,QAAQ;YAAK;QAAE,IAAIH,cAAc,OAAO,CACtF,EAAE;IAEV;IAEAK,GAAG,uDAAuD;QAEtD,MAAMC,aAAaC,oBACfJ,SAAS;YAAE,SAAS;gBAAE,QAAQ;oBAAC;oBAAO;iBAAM;YAAC;QAAE,IAC/CF;QAGJO,OAAOF,YAAY,OAAO,CAAC;YACvB;gBAAE,MAAM;gBAAW,UAAU;gBAAU,OAAO;gBAAQ,OAAO;oBAAC;oBAAO;iBAAM;YAAC;SAC/E;IACL;IAEAD,GAAG,8CAA8C;QAC7C,MAAMC,aAAaC,oBACfJ,SAAS;YACL,iBAAiB;gBAAE,QAAQ;YAAK;YAChC,iBAAiB;gBAAE,QAAQ;YAAa;YACxC,iBAAiB;gBAAE,QAAQ;YAAK;YAChC,iBAAiB;gBAAE,QAAQ;YAAa;QAC5C,IACAD;QAGJM,OAAOF,YAAY,OAAO,CAAC,EAAE;IACjC;AACJ"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Build asset **delivery URLs** that frame the image server-side. The delivery
3
+ * pipeline applies the crop (`?crop`), an optional target aspect ratio + focal point
4
+ * (`?aspectRatio`, `?focal`), resizing (`?width`), and format (`?format`) — so the
5
+ * returned URL's pixels are already framed. Use with any renderer that loads a URL:
6
+ * `next/image`, a plain `<img>`, Angular, React Native, Open Graph tags, email, etc.
7
+ * Each distinct framing yields its own cacheable URL.
8
+ */
9
+ import type { Asset } from "./types.js";
10
+ export interface AssetUrlOptions {
11
+ /** Delivery width (snapped to the configured width ladder server-side). */
12
+ width?: number;
13
+ /** Output format, e.g. `"auto"` (negotiated via Accept), `"webp"`, `"avif"`. */
14
+ format?: string;
15
+ /** Encoder quality (1–100). */
16
+ quality?: number;
17
+ /** Include the per-usage crop (`image.crop`) as a server-side crop. Default `true`. */
18
+ crop?: boolean;
19
+ /**
20
+ * Frame to a target aspect ratio server-side (`"16:9"` or a `w/h` number),
21
+ * centered on the asset's focal point. Omit to deliver at the crop's own ratio.
22
+ */
23
+ aspectRatio?: number | string;
24
+ /**
25
+ * Include the asset's focal point (`image.focalPoint`) when `aspectRatio` is set.
26
+ * Default `true`.
27
+ */
28
+ focal?: boolean;
29
+ }
30
+ /**
31
+ * The `crop=top,left,bottom,right` query value for an asset's per-usage crop, or
32
+ * `undefined` when there is no crop (or a full-image, no-op crop).
33
+ */
34
+ export declare const getAssetCropParam: (asset: Pick<Asset, "image"> | null | undefined) => string | undefined;
35
+ /**
36
+ * Build a delivery URL for an asset, baking the per-usage crop into the delivered
37
+ * image (plus optional width/format/quality). Returns `""` for a missing asset.
38
+ */
39
+ export declare const getAssetUrl: (asset: (Pick<Asset, "src" | "image"> & {
40
+ src?: string;
41
+ }) | null | undefined, options?: AssetUrlOptions) => string;
@@ -0,0 +1,34 @@
1
+ const round = (n)=>Math.round(10000 * n) / 10000;
2
+ const getAssetCropParam = (asset)=>{
3
+ const c = asset?.image?.crop;
4
+ if (!c || 0 === c.top && 0 === c.left && 0 === c.bottom && 0 === c.right) return;
5
+ return [
6
+ c.top,
7
+ c.left,
8
+ c.bottom,
9
+ c.right
10
+ ].map(round).join(",");
11
+ };
12
+ const getAssetUrl = (asset, options = {})=>{
13
+ const src = asset?.src;
14
+ if (!src) return "";
15
+ const params = [];
16
+ if (false !== options.crop) {
17
+ const crop = getAssetCropParam(asset);
18
+ if (crop) params.push(`crop=${crop}`);
19
+ }
20
+ if (void 0 !== options.aspectRatio) {
21
+ params.push(`aspectRatio=${options.aspectRatio}`);
22
+ const fp = asset?.image?.focalPoint;
23
+ if (false !== options.focal && fp && !(0.5 === fp.x && 0.5 === fp.y)) params.push(`focal=${round(fp.x)},${round(fp.y)}`);
24
+ }
25
+ if (options.width) params.push(`width=${options.width}`);
26
+ if (options.format) params.push(`format=${options.format}`);
27
+ if (options.quality) params.push(`quality=${options.quality}`);
28
+ if (0 === params.length) return src;
29
+ const separator = src.includes("?") ? "&" : "?";
30
+ return `${src}${separator}${params.join("&")}`;
31
+ };
32
+ export { getAssetCropParam, getAssetUrl };
33
+
34
+ //# sourceMappingURL=deliveryUrl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asset/deliveryUrl.js","sources":["../../src/asset/deliveryUrl.ts"],"sourcesContent":["/**\n * Build asset **delivery URLs** that frame the image server-side. The delivery\n * pipeline applies the crop (`?crop`), an optional target aspect ratio + focal point\n * (`?aspectRatio`, `?focal`), resizing (`?width`), and format (`?format`) — so the\n * returned URL's pixels are already framed. Use with any renderer that loads a URL:\n * `next/image`, a plain `<img>`, Angular, React Native, Open Graph tags, email, etc.\n * Each distinct framing yields its own cacheable URL.\n */\nimport type { Asset } from \"./types.js\";\n\nexport interface AssetUrlOptions {\n /** Delivery width (snapped to the configured width ladder server-side). */\n width?: number;\n /** Output format, e.g. `\"auto\"` (negotiated via Accept), `\"webp\"`, `\"avif\"`. */\n format?: string;\n /** Encoder quality (1–100). */\n quality?: number;\n /** Include the per-usage crop (`image.crop`) as a server-side crop. Default `true`. */\n crop?: boolean;\n /**\n * Frame to a target aspect ratio server-side (`\"16:9\"` or a `w/h` number),\n * centered on the asset's focal point. Omit to deliver at the crop's own ratio.\n */\n aspectRatio?: number | string;\n /**\n * Include the asset's focal point (`image.focalPoint`) when `aspectRatio` is set.\n * Default `true`.\n */\n focal?: boolean;\n}\n\nconst round = (n: number): number => Math.round(n * 10000) / 10000;\n\n/**\n * The `crop=top,left,bottom,right` query value for an asset's per-usage crop, or\n * `undefined` when there is no crop (or a full-image, no-op crop).\n */\nexport const getAssetCropParam = (\n asset: Pick<Asset, \"image\"> | null | undefined\n): string | undefined => {\n const c = asset?.image?.crop;\n if (!c || (c.top === 0 && c.left === 0 && c.bottom === 0 && c.right === 0)) {\n return undefined;\n }\n return [c.top, c.left, c.bottom, c.right].map(round).join(\",\");\n};\n\n/**\n * Build a delivery URL for an asset, baking the per-usage crop into the delivered\n * image (plus optional width/format/quality). Returns `\"\"` for a missing asset.\n */\nexport const getAssetUrl = (\n asset: (Pick<Asset, \"src\" | \"image\"> & { src?: string }) | null | undefined,\n options: AssetUrlOptions = {}\n): string => {\n const src = asset?.src;\n if (!src) {\n return \"\";\n }\n\n const params: string[] = [];\n if (options.crop !== false) {\n const crop = getAssetCropParam(asset);\n if (crop) {\n params.push(`crop=${crop}`);\n }\n }\n if (options.aspectRatio !== undefined) {\n params.push(`aspectRatio=${options.aspectRatio}`);\n const fp = asset?.image?.focalPoint;\n if (options.focal !== false && fp && !(fp.x === 0.5 && fp.y === 0.5)) {\n params.push(`focal=${round(fp.x)},${round(fp.y)}`);\n }\n }\n if (options.width) {\n params.push(`width=${options.width}`);\n }\n if (options.format) {\n params.push(`format=${options.format}`);\n }\n if (options.quality) {\n params.push(`quality=${options.quality}`);\n }\n\n if (params.length === 0) {\n return src;\n }\n const separator = src.includes(\"?\") ? \"&\" : \"?\";\n return `${src}${separator}${params.join(\"&\")}`;\n};\n"],"names":["round","n","Math","getAssetCropParam","asset","c","getAssetUrl","options","src","params","crop","undefined","fp","separator"],"mappings":"AA+BA,MAAMA,QAAQ,CAACC,IAAsBC,KAAK,KAAK,CAACD,AAAI,QAAJA,KAAa;AAMtD,MAAME,oBAAoB,CAC7BC;IAEA,MAAMC,IAAID,OAAO,OAAO;IACxB,IAAI,CAACC,KAAMA,AAAU,MAAVA,EAAE,GAAG,IAAUA,AAAW,MAAXA,EAAE,IAAI,IAAUA,AAAa,MAAbA,EAAE,MAAM,IAAUA,AAAY,MAAZA,EAAE,KAAK,EAC/D;IAEJ,OAAO;QAACA,EAAE,GAAG;QAAEA,EAAE,IAAI;QAAEA,EAAE,MAAM;QAAEA,EAAE,KAAK;KAAC,CAAC,GAAG,CAACL,OAAO,IAAI,CAAC;AAC9D;AAMO,MAAMM,cAAc,CACvBF,OACAG,UAA2B,CAAC,CAAC;IAE7B,MAAMC,MAAMJ,OAAO;IACnB,IAAI,CAACI,KACD,OAAO;IAGX,MAAMC,SAAmB,EAAE;IAC3B,IAAIF,AAAiB,UAAjBA,QAAQ,IAAI,EAAY;QACxB,MAAMG,OAAOP,kBAAkBC;QAC/B,IAAIM,MACAD,OAAO,IAAI,CAAC,CAAC,KAAK,EAAEC,MAAM;IAElC;IACA,IAAIH,AAAwBI,WAAxBJ,QAAQ,WAAW,EAAgB;QACnCE,OAAO,IAAI,CAAC,CAAC,YAAY,EAAEF,QAAQ,WAAW,EAAE;QAChD,MAAMK,KAAKR,OAAO,OAAO;QACzB,IAAIG,AAAkB,UAAlBA,QAAQ,KAAK,IAAcK,MAAM,CAAEA,CAAAA,AAAS,QAATA,GAAG,CAAC,IAAYA,AAAS,QAATA,GAAG,CAAC,AAAO,GAC9DH,OAAO,IAAI,CAAC,CAAC,MAAM,EAAET,MAAMY,GAAG,CAAC,EAAE,CAAC,EAAEZ,MAAMY,GAAG,CAAC,GAAG;IAEzD;IACA,IAAIL,QAAQ,KAAK,EACbE,OAAO,IAAI,CAAC,CAAC,MAAM,EAAEF,QAAQ,KAAK,EAAE;IAExC,IAAIA,QAAQ,MAAM,EACdE,OAAO,IAAI,CAAC,CAAC,OAAO,EAAEF,QAAQ,MAAM,EAAE;IAE1C,IAAIA,QAAQ,OAAO,EACfE,OAAO,IAAI,CAAC,CAAC,QAAQ,EAAEF,QAAQ,OAAO,EAAE;IAG5C,IAAIE,AAAkB,MAAlBA,OAAO,MAAM,EACb,OAAOD;IAEX,MAAMK,YAAYL,IAAI,QAAQ,CAAC,OAAO,MAAM;IAC5C,OAAO,GAAGA,MAAMK,YAAYJ,OAAO,IAAI,CAAC,MAAM;AAClD"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,127 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { getAssetCropParam, getAssetUrl } from "./deliveryUrl.js";
3
+ const asset = (crop)=>({
4
+ id: "f",
5
+ src: "https://cdn/x/pic.jpg",
6
+ name: "pic.jpg",
7
+ mimeType: "image/jpeg",
8
+ size: 1,
9
+ image: {
10
+ width: 800,
11
+ height: 600,
12
+ ...crop ? {
13
+ crop
14
+ } : {}
15
+ }
16
+ });
17
+ describe("getAssetCropParam", ()=>{
18
+ it("serializes a crop as top,left,bottom,right", ()=>{
19
+ expect(getAssetCropParam(asset({
20
+ top: 0.1,
21
+ left: 0.2,
22
+ bottom: 0.1,
23
+ right: 0.05
24
+ }))).toBe("0.1,0.2,0.1,0.05");
25
+ });
26
+ it("is undefined for no crop or a full crop", ()=>{
27
+ expect(getAssetCropParam(asset())).toBeUndefined();
28
+ expect(getAssetCropParam(asset({
29
+ top: 0,
30
+ left: 0,
31
+ bottom: 0,
32
+ right: 0
33
+ }))).toBeUndefined();
34
+ expect(getAssetCropParam(null)).toBeUndefined();
35
+ });
36
+ });
37
+ describe("getAssetUrl", ()=>{
38
+ it("bakes the crop + width + format into the URL", ()=>{
39
+ const url = getAssetUrl(asset({
40
+ top: 0.1,
41
+ left: 0.2,
42
+ bottom: 0.1,
43
+ right: 0.05
44
+ }), {
45
+ width: 1200,
46
+ format: "auto"
47
+ });
48
+ expect(url).toBe("https://cdn/x/pic.jpg?crop=0.1,0.2,0.1,0.05&width=1200&format=auto");
49
+ });
50
+ it("omits the crop when there is none", ()=>{
51
+ expect(getAssetUrl(asset(), {
52
+ width: 640
53
+ })).toBe("https://cdn/x/pic.jpg?width=640");
54
+ });
55
+ it("can opt out of the crop", ()=>{
56
+ expect(getAssetUrl(asset({
57
+ top: 0.1,
58
+ left: 0,
59
+ bottom: 0,
60
+ right: 0
61
+ }), {
62
+ crop: false
63
+ })).toBe("https://cdn/x/pic.jpg");
64
+ });
65
+ it("returns the bare src when no options apply", ()=>{
66
+ expect(getAssetUrl(asset())).toBe("https://cdn/x/pic.jpg");
67
+ });
68
+ it("uses & when the src already has a query string", ()=>{
69
+ const url = getAssetUrl({
70
+ src: "https://cdn/x/pic.jpg?v=2",
71
+ image: {}
72
+ }, {
73
+ width: 640
74
+ });
75
+ expect(url).toBe("https://cdn/x/pic.jpg?v=2&width=640");
76
+ });
77
+ it("returns empty string for a missing asset", ()=>{
78
+ expect(getAssetUrl(null)).toBe("");
79
+ expect(getAssetUrl(void 0)).toBe("");
80
+ });
81
+ it("emits aspectRatio + focal (from the asset) when framing to a ratio", ()=>{
82
+ const a = {
83
+ ...asset(),
84
+ image: {
85
+ width: 800,
86
+ height: 600,
87
+ focalPoint: {
88
+ x: 0.7,
89
+ y: 0.4
90
+ }
91
+ }
92
+ };
93
+ expect(getAssetUrl(a, {
94
+ aspectRatio: "16:9",
95
+ width: 1200
96
+ })).toBe("https://cdn/x/pic.jpg?aspectRatio=16:9&focal=0.7,0.4&width=1200");
97
+ });
98
+ it("omits focal when it is centered or opted out", ()=>{
99
+ const centered = {
100
+ ...asset(),
101
+ image: {
102
+ focalPoint: {
103
+ x: 0.5,
104
+ y: 0.5
105
+ }
106
+ }
107
+ };
108
+ expect(getAssetUrl(centered, {
109
+ aspectRatio: 1
110
+ })).toBe("https://cdn/x/pic.jpg?aspectRatio=1");
111
+ const offCenter = {
112
+ ...asset(),
113
+ image: {
114
+ focalPoint: {
115
+ x: 0.7,
116
+ y: 0.4
117
+ }
118
+ }
119
+ };
120
+ expect(getAssetUrl(offCenter, {
121
+ aspectRatio: 1,
122
+ focal: false
123
+ })).toBe("https://cdn/x/pic.jpg?aspectRatio=1");
124
+ });
125
+ });
126
+
127
+ //# sourceMappingURL=deliveryUrl.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asset/deliveryUrl.test.js","sources":["../../src/asset/deliveryUrl.test.ts"],"sourcesContent":["import { describe, it, expect } from \"vitest\";\nimport { getAssetCropParam, getAssetUrl } from \"./deliveryUrl.js\";\n\nconst asset = (crop?: any) => ({\n id: \"f\",\n src: \"https://cdn/x/pic.jpg\",\n name: \"pic.jpg\",\n mimeType: \"image/jpeg\",\n size: 1,\n image: { width: 800, height: 600, ...(crop ? { crop } : {}) }\n});\n\ndescribe(\"getAssetCropParam\", () => {\n it(\"serializes a crop as top,left,bottom,right\", () => {\n expect(getAssetCropParam(asset({ top: 0.1, left: 0.2, bottom: 0.1, right: 0.05 }))).toBe(\n \"0.1,0.2,0.1,0.05\"\n );\n });\n\n it(\"is undefined for no crop or a full crop\", () => {\n expect(getAssetCropParam(asset())).toBeUndefined();\n expect(getAssetCropParam(asset({ top: 0, left: 0, bottom: 0, right: 0 }))).toBeUndefined();\n expect(getAssetCropParam(null)).toBeUndefined();\n });\n});\n\ndescribe(\"getAssetUrl\", () => {\n it(\"bakes the crop + width + format into the URL\", () => {\n const url = getAssetUrl(asset({ top: 0.1, left: 0.2, bottom: 0.1, right: 0.05 }), {\n width: 1200,\n format: \"auto\"\n });\n expect(url).toBe(\"https://cdn/x/pic.jpg?crop=0.1,0.2,0.1,0.05&width=1200&format=auto\");\n });\n\n it(\"omits the crop when there is none\", () => {\n expect(getAssetUrl(asset(), { width: 640 })).toBe(\"https://cdn/x/pic.jpg?width=640\");\n });\n\n it(\"can opt out of the crop\", () => {\n expect(\n getAssetUrl(asset({ top: 0.1, left: 0, bottom: 0, right: 0 }), { crop: false })\n ).toBe(\"https://cdn/x/pic.jpg\");\n });\n\n it(\"returns the bare src when no options apply\", () => {\n expect(getAssetUrl(asset())).toBe(\"https://cdn/x/pic.jpg\");\n });\n\n it(\"uses & when the src already has a query string\", () => {\n const url = getAssetUrl(\n { src: \"https://cdn/x/pic.jpg?v=2\", image: {} },\n {\n width: 640\n }\n );\n expect(url).toBe(\"https://cdn/x/pic.jpg?v=2&width=640\");\n });\n\n it(\"returns empty string for a missing asset\", () => {\n expect(getAssetUrl(null)).toBe(\"\");\n expect(getAssetUrl(undefined)).toBe(\"\");\n });\n\n it(\"emits aspectRatio + focal (from the asset) when framing to a ratio\", () => {\n const a = {\n ...asset(),\n image: { width: 800, height: 600, focalPoint: { x: 0.7, y: 0.4 } }\n };\n expect(getAssetUrl(a, { aspectRatio: \"16:9\", width: 1200 })).toBe(\n \"https://cdn/x/pic.jpg?aspectRatio=16:9&focal=0.7,0.4&width=1200\"\n );\n });\n\n it(\"omits focal when it is centered or opted out\", () => {\n const centered = { ...asset(), image: { focalPoint: { x: 0.5, y: 0.5 } } };\n expect(getAssetUrl(centered, { aspectRatio: 1 })).toBe(\n \"https://cdn/x/pic.jpg?aspectRatio=1\"\n );\n const offCenter = { ...asset(), image: { focalPoint: { x: 0.7, y: 0.4 } } };\n expect(getAssetUrl(offCenter, { aspectRatio: 1, focal: false })).toBe(\n \"https://cdn/x/pic.jpg?aspectRatio=1\"\n );\n });\n});\n"],"names":["asset","crop","describe","it","expect","getAssetCropParam","url","getAssetUrl","undefined","a","centered","offCenter"],"mappings":";;AAGA,MAAMA,QAAQ,CAACC,OAAgB;QAC3B,IAAI;QACJ,KAAK;QACL,MAAM;QACN,UAAU;QACV,MAAM;QACN,OAAO;YAAE,OAAO;YAAK,QAAQ;YAAK,GAAIA,OAAO;gBAAEA;YAAK,IAAI,CAAC,CAAC;QAAE;IAChE;AAEAC,SAAS,qBAAqB;IAC1BC,GAAG,8CAA8C;QAC7CC,OAAOC,kBAAkBL,MAAM;YAAE,KAAK;YAAK,MAAM;YAAK,QAAQ;YAAK,OAAO;QAAK,KAAK,IAAI,CACpF;IAER;IAEAG,GAAG,2CAA2C;QAC1CC,OAAOC,kBAAkBL,UAAU,aAAa;QAChDI,OAAOC,kBAAkBL,MAAM;YAAE,KAAK;YAAG,MAAM;YAAG,QAAQ;YAAG,OAAO;QAAE,KAAK,aAAa;QACxFI,OAAOC,kBAAkB,OAAO,aAAa;IACjD;AACJ;AAEAH,SAAS,eAAe;IACpBC,GAAG,gDAAgD;QAC/C,MAAMG,MAAMC,YAAYP,MAAM;YAAE,KAAK;YAAK,MAAM;YAAK,QAAQ;YAAK,OAAO;QAAK,IAAI;YAC9E,OAAO;YACP,QAAQ;QACZ;QACAI,OAAOE,KAAK,IAAI,CAAC;IACrB;IAEAH,GAAG,qCAAqC;QACpCC,OAAOG,YAAYP,SAAS;YAAE,OAAO;QAAI,IAAI,IAAI,CAAC;IACtD;IAEAG,GAAG,2BAA2B;QAC1BC,OACIG,YAAYP,MAAM;YAAE,KAAK;YAAK,MAAM;YAAG,QAAQ;YAAG,OAAO;QAAE,IAAI;YAAE,MAAM;QAAM,IAC/E,IAAI,CAAC;IACX;IAEAG,GAAG,8CAA8C;QAC7CC,OAAOG,YAAYP,UAAU,IAAI,CAAC;IACtC;IAEAG,GAAG,kDAAkD;QACjD,MAAMG,MAAMC,YACR;YAAE,KAAK;YAA6B,OAAO,CAAC;QAAE,GAC9C;YACI,OAAO;QACX;QAEJH,OAAOE,KAAK,IAAI,CAAC;IACrB;IAEAH,GAAG,4CAA4C;QAC3CC,OAAOG,YAAY,OAAO,IAAI,CAAC;QAC/BH,OAAOG,YAAYC,SAAY,IAAI,CAAC;IACxC;IAEAL,GAAG,sEAAsE;QACrE,MAAMM,IAAI;YACN,GAAGT,OAAO;YACV,OAAO;gBAAE,OAAO;gBAAK,QAAQ;gBAAK,YAAY;oBAAE,GAAG;oBAAK,GAAG;gBAAI;YAAE;QACrE;QACAI,OAAOG,YAAYE,GAAG;YAAE,aAAa;YAAQ,OAAO;QAAK,IAAI,IAAI,CAC7D;IAER;IAEAN,GAAG,gDAAgD;QAC/C,MAAMO,WAAW;YAAE,GAAGV,OAAO;YAAE,OAAO;gBAAE,YAAY;oBAAE,GAAG;oBAAK,GAAG;gBAAI;YAAE;QAAE;QACzEI,OAAOG,YAAYG,UAAU;YAAE,aAAa;QAAE,IAAI,IAAI,CAClD;QAEJ,MAAMC,YAAY;YAAE,GAAGX,OAAO;YAAE,OAAO;gBAAE,YAAY;oBAAE,GAAG;oBAAK,GAAG;gBAAI;YAAE;QAAE;QAC1EI,OAAOG,YAAYI,WAAW;YAAE,aAAa;YAAG,OAAO;QAAM,IAAI,IAAI,CACjE;IAER;AACJ"}
@@ -0,0 +1,7 @@
1
+ import { type ImageRenderData, type NormalizedRect } from "../image/geometry.js";
2
+ import type { AspectRatioInput } from "../image/types.js";
3
+ import type { Asset } from "./types.js";
4
+ type AssetLike = Pick<Asset, "image">;
5
+ export declare function getAssetVisibleRect(asset: AssetLike, aspectRatio?: AspectRatioInput): NormalizedRect;
6
+ export declare function getAssetImageRenderData(asset: AssetLike, aspectRatio?: AspectRatioInput): ImageRenderData;
7
+ export {};
@@ -0,0 +1,10 @@
1
+ import { getImageRenderData, getVisibleRect } from "../image/geometry.js";
2
+ function getAssetVisibleRect(asset, aspectRatio) {
3
+ return getVisibleRect(asset.image ?? {}, aspectRatio);
4
+ }
5
+ function getAssetImageRenderData(asset, aspectRatio) {
6
+ return getImageRenderData(asset.image ?? {}, aspectRatio);
7
+ }
8
+ export { getAssetImageRenderData, getAssetVisibleRect };
9
+
10
+ //# sourceMappingURL=geometry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asset/geometry.js","sources":["../../src/asset/geometry.ts"],"sourcesContent":["import {\n getImageRenderData,\n getVisibleRect,\n type ImageRenderData,\n type NormalizedRect\n} from \"../image/geometry.js\";\nimport type { AspectRatioInput } from \"../image/types.js\";\nimport type { Asset } from \"./types.js\";\n\ntype AssetLike = Pick<Asset, \"image\">;\n\nexport function getAssetVisibleRect(\n asset: AssetLike,\n aspectRatio?: AspectRatioInput\n): NormalizedRect {\n return getVisibleRect(asset.image ?? {}, aspectRatio);\n}\n\nexport function getAssetImageRenderData(\n asset: AssetLike,\n aspectRatio?: AspectRatioInput\n): ImageRenderData {\n return getImageRenderData(asset.image ?? {}, aspectRatio);\n}\n"],"names":["getAssetVisibleRect","asset","aspectRatio","getVisibleRect","getAssetImageRenderData","getImageRenderData"],"mappings":";AAWO,SAASA,oBACZC,KAAgB,EAChBC,WAA8B;IAE9B,OAAOC,eAAeF,MAAM,KAAK,IAAI,CAAC,GAAGC;AAC7C;AAEO,SAASE,wBACZH,KAAgB,EAChBC,WAA8B;IAE9B,OAAOG,mBAAmBJ,MAAM,KAAK,IAAI,CAAC,GAAGC;AACjD"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Framework-agnostic responsive-image helpers built on {@link getAssetUrl}.
3
+ *
4
+ * Every renderer (Next.js, React, Vue, Nuxt — and any future Angular / React Native
5
+ * / vanilla adapter) needs the same three things from a `Asset`: a width
6
+ * ladder, a `srcSet` with the per-usage crop/focal/format baked into each width, and
7
+ * the delivered image's intrinsic (cropped) dimensions for layout-shift-free
8
+ * rendering. Keeping that logic here — instead of re-deriving it per framework —
9
+ * makes each renderer a thin adapter over the one delivery-URL contract.
10
+ */
11
+ import type { Asset } from "./types.js";
12
+ import { type AssetUrlOptions } from "./deliveryUrl.js";
13
+ /**
14
+ * Canonical delivery-width ladder. Kept in lockstep with the server's resize ladder
15
+ * (`imageResizeWidths` in `@webiny/api-file-manager`) so every width a renderer
16
+ * requests snaps to a cached variant instead of forcing a fresh transform.
17
+ */
18
+ export declare const IMAGE_RESIZE_WIDTHS: readonly [128, 384, 640, 750, 828, 1080, 1200, 1920, 2048, 3840];
19
+ export interface ImageDimensions {
20
+ /** Delivered (cropped) width in pixels, or `0` when the intrinsic size is unknown. */
21
+ width: number;
22
+ /** Delivered (cropped) height in pixels, or `0` when the intrinsic size is unknown. */
23
+ height: number;
24
+ }
25
+ /**
26
+ * The intrinsic dimensions of the *delivered* image — i.e. after the per-usage crop
27
+ * (and an optional target aspect ratio) are applied. Renderers pass these to their
28
+ * layout primitive (e.g. `next/image`'s `width`/`height`) so the box reserves the
29
+ * right space and the page doesn't shift as the image loads. Returns `0`/`0` when the
30
+ * asset's intrinsic size is unknown.
31
+ */
32
+ export declare const getImageDimensions: (asset: Pick<Asset, "image"> | null | undefined, options?: {
33
+ aspectRatio?: number | string;
34
+ }) => ImageDimensions;
35
+ export interface ImageSrcSetOptions extends Omit<AssetUrlOptions, "width"> {
36
+ /** Widths to emit. Defaults to {@link IMAGE_RESIZE_WIDTHS}, trimmed by `cssWidth`. */
37
+ widths?: readonly number[];
38
+ /**
39
+ * A fixed CSS width for the rendered image (`"320px"` or `320`). When set, the
40
+ * ladder is trimmed to the smallest set that still covers it (incl. high-DPR);
41
+ * fluid widths (`%`, `vw`, unset) use the full ladder.
42
+ */
43
+ cssWidth?: number | string;
44
+ }
45
+ export interface ImageSrcSet {
46
+ /** Single-URL fallback for clients that ignore `srcSet` (the largest emitted width). */
47
+ src: string;
48
+ /** `"<url> 128w, <url> 384w, …"` — crop/focal/format baked into every width. */
49
+ srcSet: string;
50
+ /** Delivered (cropped) intrinsic dimensions; `0` when unknown. */
51
+ width: number;
52
+ height: number;
53
+ }
54
+ /**
55
+ * Build the responsive descriptor for an asset: a `srcSet` across the width ladder
56
+ * (each entry a delivery URL with the per-usage crop/focal/format baked in), a
57
+ * single-URL `src` fallback, and the delivered dimensions. Framework-agnostic — hand
58
+ * `src`/`srcSet` to any `<img>`-like primitive. Returns empty strings for a missing
59
+ * asset.
60
+ */
61
+ export declare const getImageSrcSet: (asset: (Pick<Asset, "src" | "image"> & {
62
+ src?: string;
63
+ }) | null | undefined, options?: ImageSrcSetOptions) => ImageSrcSet;
@@ -0,0 +1,98 @@
1
+ import { getAssetUrl } from "./deliveryUrl.js";
2
+ const IMAGE_RESIZE_WIDTHS = [
3
+ 128,
4
+ 384,
5
+ 640,
6
+ 750,
7
+ 828,
8
+ 1080,
9
+ 1200,
10
+ 1920,
11
+ 2048,
12
+ 3840
13
+ ];
14
+ const parseAspectRatio = (input)=>{
15
+ if (void 0 === input) return;
16
+ if ("number" == typeof input) return input > 0 ? input : void 0;
17
+ const trimmed = input.trim();
18
+ if (trimmed.includes(":")) {
19
+ const [w, h] = trimmed.split(":").map(Number);
20
+ return w > 0 && h > 0 ? w / h : void 0;
21
+ }
22
+ const n = Number(trimmed);
23
+ return n > 0 ? n : void 0;
24
+ };
25
+ const toPx = (cssWidth)=>{
26
+ if (void 0 === cssWidth) return;
27
+ if ("number" == typeof cssWidth) return cssWidth > 0 ? cssWidth : void 0;
28
+ const trimmed = cssWidth.trim();
29
+ if (trimmed.endsWith("px")) {
30
+ const n = parseInt(trimmed, 10);
31
+ return n > 0 ? n : void 0;
32
+ }
33
+ };
34
+ const resolveWidths = (widths, cssWidth)=>{
35
+ const px = toPx(cssWidth);
36
+ if (!px) return [
37
+ ...widths
38
+ ];
39
+ const result = [];
40
+ for (const w of widths){
41
+ result.push(w);
42
+ if (w >= 2 * px) break;
43
+ }
44
+ return result.length ? result : [
45
+ widths[widths.length - 1]
46
+ ];
47
+ };
48
+ const getImageDimensions = (asset, options = {})=>{
49
+ const img = asset?.image;
50
+ const iw = img?.width ?? 0;
51
+ const ih = img?.height ?? 0;
52
+ if (!iw || !ih) return {
53
+ width: 0,
54
+ height: 0
55
+ };
56
+ const crop = img?.crop;
57
+ const width = crop ? Math.round((1 - (crop.left ?? 0) - (crop.right ?? 0)) * iw) : iw;
58
+ const height = crop ? Math.round((1 - (crop.top ?? 0) - (crop.bottom ?? 0)) * ih) : ih;
59
+ const ar = parseAspectRatio(options.aspectRatio);
60
+ if (ar) return {
61
+ width,
62
+ height: Math.round(width / ar)
63
+ };
64
+ return {
65
+ width,
66
+ height
67
+ };
68
+ };
69
+ const getImageSrcSet = (asset, options = {})=>{
70
+ const { widths = IMAGE_RESIZE_WIDTHS, cssWidth, ...urlOptions } = options;
71
+ const dims = getImageDimensions(asset, {
72
+ aspectRatio: urlOptions.aspectRatio
73
+ });
74
+ if (!asset?.src) return {
75
+ src: "",
76
+ srcSet: "",
77
+ width: dims.width,
78
+ height: dims.height
79
+ };
80
+ const selected = resolveWidths(widths, cssWidth);
81
+ const srcSet = selected.map((w)=>`${getAssetUrl(asset, {
82
+ ...urlOptions,
83
+ width: w
84
+ })} ${w}w`).join(", ");
85
+ const src = getAssetUrl(asset, {
86
+ ...urlOptions,
87
+ width: selected[selected.length - 1]
88
+ });
89
+ return {
90
+ src,
91
+ srcSet,
92
+ width: dims.width,
93
+ height: dims.height
94
+ };
95
+ };
96
+ export { IMAGE_RESIZE_WIDTHS, getImageDimensions, getImageSrcSet };
97
+
98
+ //# sourceMappingURL=imageSrcSet.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asset/imageSrcSet.js","sources":["../../src/asset/imageSrcSet.ts"],"sourcesContent":["/**\n * Framework-agnostic responsive-image helpers built on {@link getAssetUrl}.\n *\n * Every renderer (Next.js, React, Vue, Nuxt — and any future Angular / React Native\n * / vanilla adapter) needs the same three things from a `Asset`: a width\n * ladder, a `srcSet` with the per-usage crop/focal/format baked into each width, and\n * the delivered image's intrinsic (cropped) dimensions for layout-shift-free\n * rendering. Keeping that logic here — instead of re-deriving it per framework —\n * makes each renderer a thin adapter over the one delivery-URL contract.\n */\nimport type { Asset } from \"./types.js\";\nimport { getAssetUrl, type AssetUrlOptions } from \"./deliveryUrl.js\";\n\n/**\n * Canonical delivery-width ladder. Kept in lockstep with the server's resize ladder\n * (`imageResizeWidths` in `@webiny/api-file-manager`) so every width a renderer\n * requests snaps to a cached variant instead of forcing a fresh transform.\n */\nexport const IMAGE_RESIZE_WIDTHS = [128, 384, 640, 750, 828, 1080, 1200, 1920, 2048, 3840] as const;\n\n/** Parse an aspect ratio given as a number, a `\"w:h\"` string, or a decimal string. */\nconst parseAspectRatio = (input: number | string | undefined): number | undefined => {\n if (input === undefined) {\n return undefined;\n }\n if (typeof input === \"number\") {\n return input > 0 ? input : undefined;\n }\n const trimmed = input.trim();\n if (trimmed.includes(\":\")) {\n const [w, h] = trimmed.split(\":\").map(Number);\n return w > 0 && h > 0 ? w / h : undefined;\n }\n const n = Number(trimmed);\n return n > 0 ? n : undefined;\n};\n\n/** Resolve a fixed CSS width to pixels, or `undefined` for fluid widths (`%`, `vw`, …). */\nconst toPx = (cssWidth: number | string | undefined): number | undefined => {\n if (cssWidth === undefined) {\n return undefined;\n }\n if (typeof cssWidth === \"number\") {\n return cssWidth > 0 ? cssWidth : undefined;\n }\n const trimmed = cssWidth.trim();\n if (trimmed.endsWith(\"px\")) {\n const n = parseInt(trimmed, 10);\n return n > 0 ? n : undefined;\n }\n return undefined;\n};\n\n/**\n * Trim the ladder to the smallest set that still covers a fixed CSS width, including\n * one step past `2×` for high-DPR screens. Fluid widths use the full ladder.\n */\nconst resolveWidths = (\n widths: readonly number[],\n cssWidth: number | string | undefined\n): number[] => {\n const px = toPx(cssWidth);\n if (!px) {\n return [...widths];\n }\n const result: number[] = [];\n for (const w of widths) {\n result.push(w);\n if (w >= px * 2) {\n break;\n }\n }\n return result.length ? result : [widths[widths.length - 1]];\n};\n\nexport interface ImageDimensions {\n /** Delivered (cropped) width in pixels, or `0` when the intrinsic size is unknown. */\n width: number;\n /** Delivered (cropped) height in pixels, or `0` when the intrinsic size is unknown. */\n height: number;\n}\n\n/**\n * The intrinsic dimensions of the *delivered* image — i.e. after the per-usage crop\n * (and an optional target aspect ratio) are applied. Renderers pass these to their\n * layout primitive (e.g. `next/image`'s `width`/`height`) so the box reserves the\n * right space and the page doesn't shift as the image loads. Returns `0`/`0` when the\n * asset's intrinsic size is unknown.\n */\nexport const getImageDimensions = (\n asset: Pick<Asset, \"image\"> | null | undefined,\n options: { aspectRatio?: number | string } = {}\n): ImageDimensions => {\n const img = asset?.image;\n const iw = img?.width ?? 0;\n const ih = img?.height ?? 0;\n if (!iw || !ih) {\n return { width: 0, height: 0 };\n }\n const crop = img?.crop;\n const width = crop ? Math.round((1 - (crop.left ?? 0) - (crop.right ?? 0)) * iw) : iw;\n const height = crop ? Math.round((1 - (crop.top ?? 0) - (crop.bottom ?? 0)) * ih) : ih;\n\n const ar = parseAspectRatio(options.aspectRatio);\n if (ar) {\n // Framed to a fixed ratio server-side: keep the cropped width, derive height.\n return { width, height: Math.round(width / ar) };\n }\n return { width, height };\n};\n\nexport interface ImageSrcSetOptions extends Omit<AssetUrlOptions, \"width\"> {\n /** Widths to emit. Defaults to {@link IMAGE_RESIZE_WIDTHS}, trimmed by `cssWidth`. */\n widths?: readonly number[];\n /**\n * A fixed CSS width for the rendered image (`\"320px\"` or `320`). When set, the\n * ladder is trimmed to the smallest set that still covers it (incl. high-DPR);\n * fluid widths (`%`, `vw`, unset) use the full ladder.\n */\n cssWidth?: number | string;\n}\n\nexport interface ImageSrcSet {\n /** Single-URL fallback for clients that ignore `srcSet` (the largest emitted width). */\n src: string;\n /** `\"<url> 128w, <url> 384w, …\"` — crop/focal/format baked into every width. */\n srcSet: string;\n /** Delivered (cropped) intrinsic dimensions; `0` when unknown. */\n width: number;\n height: number;\n}\n\n/**\n * Build the responsive descriptor for an asset: a `srcSet` across the width ladder\n * (each entry a delivery URL with the per-usage crop/focal/format baked in), a\n * single-URL `src` fallback, and the delivered dimensions. Framework-agnostic — hand\n * `src`/`srcSet` to any `<img>`-like primitive. Returns empty strings for a missing\n * asset.\n */\nexport const getImageSrcSet = (\n asset: (Pick<Asset, \"src\" | \"image\"> & { src?: string }) | null | undefined,\n options: ImageSrcSetOptions = {}\n): ImageSrcSet => {\n const { widths = IMAGE_RESIZE_WIDTHS, cssWidth, ...urlOptions } = options;\n const dims = getImageDimensions(asset, { aspectRatio: urlOptions.aspectRatio });\n\n if (!asset?.src) {\n return { src: \"\", srcSet: \"\", width: dims.width, height: dims.height };\n }\n\n const selected = resolveWidths(widths, cssWidth);\n const srcSet = selected\n .map(w => `${getAssetUrl(asset, { ...urlOptions, width: w })} ${w}w`)\n .join(\", \");\n const src = getAssetUrl(asset, { ...urlOptions, width: selected[selected.length - 1] });\n\n return { src, srcSet, width: dims.width, height: dims.height };\n};\n"],"names":["IMAGE_RESIZE_WIDTHS","parseAspectRatio","input","undefined","trimmed","w","h","Number","n","toPx","cssWidth","parseInt","resolveWidths","widths","px","result","getImageDimensions","asset","options","img","iw","ih","crop","width","Math","height","ar","getImageSrcSet","urlOptions","dims","selected","srcSet","getAssetUrl","src"],"mappings":";AAkBO,MAAMA,sBAAsB;IAAC;IAAK;IAAK;IAAK;IAAK;IAAK;IAAM;IAAM;IAAM;IAAM;CAAK;AAG1F,MAAMC,mBAAmB,CAACC;IACtB,IAAIA,AAAUC,WAAVD,OACA;IAEJ,IAAI,AAAiB,YAAjB,OAAOA,OACP,OAAOA,QAAQ,IAAIA,QAAQC;IAE/B,MAAMC,UAAUF,MAAM,IAAI;IAC1B,IAAIE,QAAQ,QAAQ,CAAC,MAAM;QACvB,MAAM,CAACC,GAAGC,EAAE,GAAGF,QAAQ,KAAK,CAAC,KAAK,GAAG,CAACG;QACtC,OAAOF,IAAI,KAAKC,IAAI,IAAID,IAAIC,IAAIH;IACpC;IACA,MAAMK,IAAID,OAAOH;IACjB,OAAOI,IAAI,IAAIA,IAAIL;AACvB;AAGA,MAAMM,OAAO,CAACC;IACV,IAAIA,AAAaP,WAAbO,UACA;IAEJ,IAAI,AAAoB,YAApB,OAAOA,UACP,OAAOA,WAAW,IAAIA,WAAWP;IAErC,MAAMC,UAAUM,SAAS,IAAI;IAC7B,IAAIN,QAAQ,QAAQ,CAAC,OAAO;QACxB,MAAMI,IAAIG,SAASP,SAAS;QAC5B,OAAOI,IAAI,IAAIA,IAAIL;IACvB;AAEJ;AAMA,MAAMS,gBAAgB,CAClBC,QACAH;IAEA,MAAMI,KAAKL,KAAKC;IAChB,IAAI,CAACI,IACD,OAAO;WAAID;KAAO;IAEtB,MAAME,SAAmB,EAAE;IAC3B,KAAK,MAAMV,KAAKQ,OAAQ;QACpBE,OAAO,IAAI,CAACV;QACZ,IAAIA,KAAKS,AAAK,IAALA,IACL;IAER;IACA,OAAOC,OAAO,MAAM,GAAGA,SAAS;QAACF,MAAM,CAACA,OAAO,MAAM,GAAG,EAAE;KAAC;AAC/D;AAgBO,MAAMG,qBAAqB,CAC9BC,OACAC,UAA6C,CAAC,CAAC;IAE/C,MAAMC,MAAMF,OAAO;IACnB,MAAMG,KAAKD,KAAK,SAAS;IACzB,MAAME,KAAKF,KAAK,UAAU;IAC1B,IAAI,CAACC,MAAM,CAACC,IACR,OAAO;QAAE,OAAO;QAAG,QAAQ;IAAE;IAEjC,MAAMC,OAAOH,KAAK;IAClB,MAAMI,QAAQD,OAAOE,KAAK,KAAK,CAAE,KAAKF,CAAAA,KAAK,IAAI,IAAI,KAAMA,CAAAA,KAAK,KAAK,IAAI,EAAC,IAAKF,MAAMA;IACnF,MAAMK,SAASH,OAAOE,KAAK,KAAK,CAAE,KAAKF,CAAAA,KAAK,GAAG,IAAI,KAAMA,CAAAA,KAAK,MAAM,IAAI,EAAC,IAAKD,MAAMA;IAEpF,MAAMK,KAAKzB,iBAAiBiB,QAAQ,WAAW;IAC/C,IAAIQ,IAEA,OAAO;QAAEH;QAAO,QAAQC,KAAK,KAAK,CAACD,QAAQG;IAAI;IAEnD,OAAO;QAAEH;QAAOE;IAAO;AAC3B;AA8BO,MAAME,iBAAiB,CAC1BV,OACAC,UAA8B,CAAC,CAAC;IAEhC,MAAM,EAAEL,SAASb,mBAAmB,EAAEU,QAAQ,EAAE,GAAGkB,YAAY,GAAGV;IAClE,MAAMW,OAAOb,mBAAmBC,OAAO;QAAE,aAAaW,WAAW,WAAW;IAAC;IAE7E,IAAI,CAACX,OAAO,KACR,OAAO;QAAE,KAAK;QAAI,QAAQ;QAAI,OAAOY,KAAK,KAAK;QAAE,QAAQA,KAAK,MAAM;IAAC;IAGzE,MAAMC,WAAWlB,cAAcC,QAAQH;IACvC,MAAMqB,SAASD,SACV,GAAG,CAACzB,CAAAA,IAAK,GAAG2B,YAAYf,OAAO;YAAE,GAAGW,UAAU;YAAE,OAAOvB;QAAE,GAAG,CAAC,EAAEA,EAAE,CAAC,CAAC,EACnE,IAAI,CAAC;IACV,MAAM4B,MAAMD,YAAYf,OAAO;QAAE,GAAGW,UAAU;QAAE,OAAOE,QAAQ,CAACA,SAAS,MAAM,GAAG,EAAE;IAAC;IAErF,OAAO;QAAEG;QAAKF;QAAQ,OAAOF,KAAK,KAAK;QAAE,QAAQA,KAAK,MAAM;IAAC;AACjE"}
@@ -0,0 +1 @@
1
+ export {};