@fragmentsx/client-core 0.3.0 → 0.4.1

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 (49) hide show
  1. package/dist/createAreaManager.d.ts +18 -0
  2. package/dist/createAreaManager.d.ts.map +1 -0
  3. package/dist/fragmentsClient.d.ts +3 -2
  4. package/dist/fragmentsClient.d.ts.map +1 -1
  5. package/dist/index.cjs.js +254 -235
  6. package/dist/index.d.ts +3 -0
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.es.js +254 -235
  9. package/dist/plugins/fetch/areaQueries.test.d.ts +2 -0
  10. package/dist/plugins/fetch/areaQueries.test.d.ts.map +1 -0
  11. package/dist/plugins/fetch/index.d.ts +10 -7
  12. package/dist/plugins/fetch/index.d.ts.map +1 -1
  13. package/dist/plugins/fetch/restFetcher.d.ts +6 -0
  14. package/dist/plugins/fetch/restFetcher.d.ts.map +1 -0
  15. package/dist/plugins/fetch/restFetcher.test.d.ts +2 -0
  16. package/dist/plugins/fetch/restFetcher.test.d.ts.map +1 -0
  17. package/dist/plugins/filters/__tests__/filtersPlugin.test.d.ts +2 -0
  18. package/dist/plugins/filters/__tests__/filtersPlugin.test.d.ts.map +1 -0
  19. package/dist/plugins/filters/index.d.ts +9 -0
  20. package/dist/plugins/filters/index.d.ts.map +1 -0
  21. package/dist/plugins/fonts/index.d.ts.map +1 -1
  22. package/dist/plugins/fonts/index.test.d.ts +2 -0
  23. package/dist/plugins/fonts/index.test.d.ts.map +1 -0
  24. package/dist/plugins/fragments/index.d.ts.map +1 -1
  25. package/dist/plugins/load/index.d.ts +1 -1
  26. package/dist/plugins/load/index.d.ts.map +1 -1
  27. package/dist/plugins/metrics/globalMetrics.d.ts +8 -1
  28. package/dist/plugins/metrics/globalMetrics.d.ts.map +1 -1
  29. package/dist/plugins/metrics/index.d.ts.map +1 -1
  30. package/dist/plugins/properties/index.d.ts +17 -0
  31. package/dist/plugins/properties/index.d.ts.map +1 -0
  32. package/dist/plugins/properties/index.test.d.ts +2 -0
  33. package/dist/plugins/properties/index.test.d.ts.map +1 -0
  34. package/dist/plugins/styleSheet/utils/autoInjector.d.ts.map +1 -1
  35. package/dist/testing/createTestFragmentsClient.d.ts +4 -0
  36. package/dist/testing/createTestFragmentsClient.d.ts.map +1 -1
  37. package/package.json +3 -3
  38. package/dist/plugins/fetch/fetcher.d.ts +0 -8
  39. package/dist/plugins/fetch/fetcher.d.ts.map +0 -1
  40. package/dist/plugins/fetch/fetcher.test.d.ts +0 -2
  41. package/dist/plugins/fetch/fetcher.test.d.ts.map +0 -1
  42. package/dist/plugins/fetch/queries/AreaListQuery.d.ts +0 -43
  43. package/dist/plugins/fetch/queries/AreaListQuery.d.ts.map +0 -1
  44. package/dist/plugins/fetch/queries/AreaQuery.d.ts +0 -24
  45. package/dist/plugins/fetch/queries/AreaQuery.d.ts.map +0 -1
  46. package/dist/plugins/fetch/queries/FragmentQuery.d.ts +0 -31
  47. package/dist/plugins/fetch/queries/FragmentQuery.d.ts.map +0 -1
  48. package/dist/plugins/fetch/queries/parts.d.ts +0 -5
  49. package/dist/plugins/fetch/queries/parts.d.ts.map +0 -1
package/dist/index.cjs.js CHANGED
@@ -1690,100 +1690,48 @@ const CssOverrideSchema = /* @__PURE__ */ object({
1690
1690
  const BASE_HEADERS = {
1691
1691
  "Content-Type": "application/json"
1692
1692
  };
1693
- const createFetcher = (baseUrl, defaultHeaders = {}) => {
1693
+ const createRestFetcher = (baseUrl, defaultHeaders = {}) => {
1694
1694
  const cache = /* @__PURE__ */ new Map();
1695
1695
  const inflightRequests = /* @__PURE__ */ new Map();
1696
- const getCacheKey = (query2, variables, options) => JSON.stringify({ query: query2, variables, options });
1697
- const query = async (query2, variables = {}, options = {}) => {
1698
- const cacheKey = getCacheKey(query2, variables, options);
1699
- if (cache.has(cacheKey)) {
1700
- return cache.get(cacheKey);
1696
+ const get = (url) => {
1697
+ const fullUrl = `${baseUrl}${url}`;
1698
+ if (cache.has(fullUrl)) {
1699
+ return Promise.resolve(cache.get(fullUrl));
1701
1700
  }
1702
- if (inflightRequests.has(cacheKey)) {
1703
- return inflightRequests.get(cacheKey);
1701
+ if (inflightRequests.has(fullUrl)) {
1702
+ return inflightRequests.get(fullUrl);
1704
1703
  }
1705
- const request = fetch(baseUrl, {
1706
- ...options,
1707
- method: "POST",
1708
- body: JSON.stringify({ query: query2, variables }),
1709
- credentials: "include",
1704
+ const request = fetch(fullUrl, {
1705
+ method: "GET",
1710
1706
  headers: {
1711
1707
  ...BASE_HEADERS,
1712
- ...defaultHeaders,
1713
- ...options.headers
1708
+ ...defaultHeaders
1714
1709
  }
1715
1710
  }).then(async (res) => {
1716
1711
  if (!res.ok) {
1717
- if (process.env.NODE_ENV === "production") {
1718
- console.error(`Fetch error: ${res.status}`);
1719
- return null;
1720
- }
1721
- throw new Error(`Fetch error: ${res.status}`);
1712
+ throw new Error(`Fetch error: ${res.status} ${res.statusText}`);
1722
1713
  }
1723
- const data = await res.json();
1724
- if (!query2.includes("mutation")) {
1725
- cache.set(cacheKey, data);
1714
+ let data;
1715
+ try {
1716
+ data = await res.json();
1717
+ } catch {
1718
+ return null;
1726
1719
  }
1720
+ cache.set(fullUrl, data);
1727
1721
  return data;
1728
1722
  }).finally(() => {
1729
- inflightRequests.delete(cacheKey);
1723
+ inflightRequests.delete(fullUrl);
1730
1724
  });
1731
- inflightRequests.set(cacheKey, request);
1725
+ inflightRequests.set(fullUrl, request);
1732
1726
  return request;
1733
1727
  };
1734
- const invalidate = (endpoint, options) => {
1735
- cache.delete(getCacheKey(endpoint, options));
1728
+ const invalidate = (url) => {
1729
+ cache.delete(`${baseUrl}${url}`);
1736
1730
  };
1737
- const clearCache = () => cache.clear();
1738
- return { query, invalidate, clearCache };
1739
- };
1740
- const googleFonts = `googleFonts {
1741
- id
1742
- variants
1743
- subsets
1744
- family
1745
- version
1746
- files {
1747
- url
1748
- variant
1749
- }
1750
- category
1751
- }`;
1752
- const linkedCssChunk = `linkedCssChunk {
1753
- id
1754
- content
1755
- }`;
1756
- const linkedFragments = `{
1757
- id
1758
- document
1759
- ${googleFonts}
1760
- ${linkedCssChunk}
1761
- }`;
1762
- const fragment = `
1763
- {
1764
- id
1765
- document
1766
- linkedFragments ${linkedFragments}
1767
- ${googleFonts}
1768
- ${linkedCssChunk}
1769
- }
1770
- `;
1771
- const getFragmentQuery = (fragmentId, isSelf) => {
1772
- return {
1773
- query: isSelf ? `
1774
- query FragmentDocument($fragmentId: Int!) {
1775
- fragment(fragmentIds: [$fragmentId]) ${fragment}
1776
- }
1777
- ` : `
1778
- query FragmentDocument($fragmentId: Int!) {
1779
- clientFragment(fragmentId: $fragmentId) ${fragment}
1780
- }
1781
- }`,
1782
- variables: {
1783
- fragmentId
1784
- },
1785
- _type: null
1731
+ const clearCache = () => {
1732
+ cache.clear();
1786
1733
  };
1734
+ return { get, invalidate, clearCache };
1787
1735
  };
1788
1736
  var isObject = (input) => {
1789
1737
  return typeof input === "object" && input !== null && !Array.isArray(input);
@@ -1798,6 +1746,7 @@ var createConstants = (...constants) => {
1798
1746
  };
1799
1747
  var noop = () => void 0;
1800
1748
  var isBrowser_default = typeof window !== "undefined";
1749
+ var generateId = () => Math.random().toString(16).slice(2);
1801
1750
  var getKey = (v) => isKey(v) ? v.slice(1) : null;
1802
1751
  var isKey = (v) => typeof v === "string" && v.startsWith("$");
1803
1752
  function hashGenerator(layerKey) {
@@ -1955,159 +1904,104 @@ const fetchBeacon = (baseUrl) => {
1955
1904
  sendBeacon
1956
1905
  };
1957
1906
  };
1958
- const getAreaListQuery = (areaCodes) => {
1959
- return {
1960
- query: `query($areaCodes: [String!]!) {
1961
- clientAreas(areaCodes: $areaCodes) {
1962
- areaId
1963
- campaignId
1964
- areaProperties
1965
- projectProperties
1966
- font {
1967
- id
1968
- variants
1969
- subsets
1970
- family
1971
- version
1972
- files {
1973
- url
1974
- variant
1975
- }
1976
- category
1977
- }
1978
- variant {
1979
- id
1980
- fragment {
1981
- props
1982
- fragment ${fragment}
1983
- }
1984
- }
1985
- }
1986
- }`,
1987
- variables: {
1988
- areaCodes
1989
- }
1990
- };
1991
- };
1992
1907
  const fetchPlugin = (state) => {
1993
1908
  var _a, _b, _c, _d;
1994
- const isSelf = ((_a = state == null ? void 0 : state.env) == null ? void 0 : _a.isSelf) ?? false;
1995
- const url = (_b = state == null ? void 0 : state.env) == null ? void 0 : _b.backendEndpoint;
1996
- const apiToken = (_c = state == null ? void 0 : state.env) == null ? void 0 : _c.apiToken;
1997
- const referer = (_d = state == null ? void 0 : state.env) == null ? void 0 : _d.referer;
1909
+ const url = (_a = state == null ? void 0 : state.env) == null ? void 0 : _a.backendEndpoint;
1910
+ const apiToken = (_b = state == null ? void 0 : state.env) == null ? void 0 : _b.apiToken;
1911
+ const referer = (_c = state == null ? void 0 : state.env) == null ? void 0 : _c.referer;
1912
+ const filterOverrides = (_d = state == null ? void 0 : state.env) == null ? void 0 : _d.filterOverrides;
1998
1913
  let headers = {
1999
- Authorization: `Bearer ${apiToken}`
1914
+ "X-Api-Key": apiToken
2000
1915
  };
2001
1916
  if (referer) {
2002
1917
  headers.Referer = referer;
2003
1918
  }
2004
- const fetcher = createFetcher(url, headers);
1919
+ if (filterOverrides == null ? void 0 : filterOverrides.deviceType) {
1920
+ headers["X-Filter-Device-Type"] = filterOverrides.deviceType;
1921
+ }
1922
+ if (filterOverrides == null ? void 0 : filterOverrides.osType) {
1923
+ headers["X-Filter-OS-Type"] = filterOverrides.osType;
1924
+ }
1925
+ if (filterOverrides == null ? void 0 : filterOverrides.page) {
1926
+ headers["X-Filter-Page"] = filterOverrides.page;
1927
+ }
1928
+ if (filterOverrides == null ? void 0 : filterOverrides.ip) {
1929
+ headers["X-Filter-IP"] = filterOverrides.ip;
1930
+ }
1931
+ const restFetcher = createRestFetcher(url, headers);
2005
1932
  const beaconFetcher = fetchBeacon();
2006
- const registerFragmentDocument = (fragmentId, fragment2) => {
2007
- var _a2, _b2;
2008
- const fragmentDocument = fragment2 == null ? void 0 : fragment2.document;
1933
+ const registerFragmentDocument = (fragmentId, fragment) => {
1934
+ const fragmentDocument = fragment == null ? void 0 : fragment.document;
2009
1935
  if (!fragmentDocument) {
2010
1936
  console.error("Empty document");
2011
1937
  return null;
2012
1938
  }
2013
- if (fragment2) {
2014
- state.$fetch.cacheDocuments.set(fragmentId, fragmentDocument);
2015
- if (Array.isArray(fragment2.linkedFragments)) {
2016
- fragment2.linkedFragments.forEach(
2017
- (linkedFragment) => registerFragmentDocument(linkedFragment.id, linkedFragment)
2018
- );
2019
- }
2020
- if (Array.isArray(fragment2.linkedCssChunk)) {
2021
- fragment2.linkedCssChunk.forEach(
2022
- (linkedChunk) => state.$fetch.cacheCssChunks.set(linkedChunk.id, linkedChunk.content)
2023
- );
2024
- }
2025
- if ("$fonts" in state) {
2026
- (_b2 = fragment2 == null ? void 0 : fragment2.googleFonts) == null ? void 0 : _b2.forEach((_a2 = state.$fonts) == null ? void 0 : _a2.registerFont);
2027
- }
2028
- return fragmentDocument;
2029
- }
2030
- return null;
2031
- };
2032
- const queryFragment = async (fragmentId) => {
2033
- var _a2;
2034
- if (!apiToken || !fragmentId) return null;
2035
- if (state.$fetch.cacheDocuments.has(fragmentId)) {
2036
- return state.$fetch.cacheDocuments.get(fragmentId);
2037
- }
2038
- const fragmentQuery = getFragmentQuery(fragmentId, isSelf);
2039
- const response = await fetcher.query(
2040
- fragmentQuery.query,
2041
- fragmentQuery.variables,
2042
- { referrerPolicy: "unsafe-url" }
2043
- );
2044
- let fragment2 = null;
2045
- if (!!(response == null ? void 0 : response.data) && "clientFragment" in response.data) {
2046
- fragment2 = response.data.clientFragment;
1939
+ state.$fetch.cacheDocuments.set(fragmentId, fragmentDocument);
1940
+ if (fragment.linkedFragments !== void 0) {
1941
+ fragment.linkedFragments.forEach((linked) => {
1942
+ if ((linked == null ? void 0 : linked.id) && (linked == null ? void 0 : linked.document)) {
1943
+ registerFragmentDocument(linked.id, linked);
1944
+ }
1945
+ });
2047
1946
  }
2048
- if (!!(response == null ? void 0 : response.data) && "fragment" in response.data) {
2049
- fragment2 = (_a2 = response.data.fragment) == null ? void 0 : _a2.at(0);
1947
+ if (Array.isArray(fragment.linkedCssChunk)) {
1948
+ fragment.linkedCssChunk.forEach(({ id, content }) => {
1949
+ if (id != null && content != null) {
1950
+ state.$fetch.cacheCssChunks.set(id, content);
1951
+ }
1952
+ });
2050
1953
  }
2051
- return registerFragmentDocument(fragmentId, fragment2);
2052
- };
2053
- const queryArea = async (areaCode) => {
2054
- return queryAreaList([areaCode]).then((res) => res == null ? void 0 : res.at(0));
1954
+ return fragmentDocument;
2055
1955
  };
2056
- const queryAreaList = async (areaCodes2) => {
2057
- var _a2;
2058
- if (!apiToken || !areaCodes2) return null;
2059
- const nonLoadedAreas = areaCodes2.filter(
1956
+ const queryAreaList = async (areaCodes) => {
1957
+ if (!apiToken || !(areaCodes == null ? void 0 : areaCodes.length)) return [];
1958
+ const nonLoadedCodes = areaCodes.filter(
2060
1959
  (code) => !state.$fetch.cacheAreaDocuments.has(code)
2061
1960
  );
2062
- if (!nonLoadedAreas.length) {
2063
- return areaCodes2.map(state.$fetch.cacheAreaDocuments.get);
1961
+ if (nonLoadedCodes.length > 0) {
1962
+ await Promise.all(
1963
+ nonLoadedCodes.map(async (code) => {
1964
+ var _a2, _b2, _c2, _d2;
1965
+ const dto = await restFetcher.get(`/api/area/${code}`);
1966
+ if (!dto) {
1967
+ state.$fetch.cacheAreaDocuments.set(code, null);
1968
+ return;
1969
+ }
1970
+ const fragment = (_a2 = dto.variant) == null ? void 0 : _a2.fragment;
1971
+ if (fragment) {
1972
+ registerFragmentDocument(fragment.id, fragment);
1973
+ }
1974
+ if ("$fonts" in state && dto.font) {
1975
+ (_b2 = state.$fonts) == null ? void 0 : _b2.registerFont(dto.font);
1976
+ }
1977
+ const entity = {
1978
+ fragmentId: fragment == null ? void 0 : fragment.id,
1979
+ props: ((_c2 = dto.variant) == null ? void 0 : _c2.props) ?? {},
1980
+ font: dto.font,
1981
+ areaId: dto.areaId,
1982
+ campaignId: dto.campaignId,
1983
+ variantId: (_d2 = dto.variant) == null ? void 0 : _d2.id
1984
+ };
1985
+ state.$fetch.cacheAreaDocuments.set(code, entity);
1986
+ })
1987
+ );
2064
1988
  }
2065
- const areaQuery = getAreaListQuery(areaCodes2);
2066
- const response = await fetcher.query(
2067
- areaQuery.query,
2068
- areaQuery.variables,
2069
- { referrerPolicy: "unsafe-url" }
1989
+ return areaCodes.map(
1990
+ (code) => state.$fetch.cacheAreaDocuments.get(code) ?? null
2070
1991
  );
2071
- const areas = (_a2 = response == null ? void 0 : response.data) == null ? void 0 : _a2.clientAreas;
2072
- if (areas) {
2073
- areas.forEach((area, index2) => {
2074
- var _a3;
2075
- const areaCode = areaCodes2 == null ? void 0 : areaCodes2.at(index2);
2076
- const areaFragment = area.variant.fragment.fragment;
2077
- registerFragmentDocument(areaFragment.id, areaFragment);
2078
- const resultProps = [
2079
- ...area.projectProperties ?? [],
2080
- ...area.areaProperties ?? []
2081
- ].reduce((acc, prop) => {
2082
- acc[prop._id] = prop.defaultValue;
2083
- return acc;
2084
- }, area.variant.fragment.props);
2085
- const entity = {
2086
- areaId: area.areaId,
2087
- campaignId: area.campaignId,
2088
- variantId: area.variant.id,
2089
- fragmentId: area.variant.fragment.fragment.id,
2090
- font: area.font,
2091
- props: resultProps
2092
- };
2093
- if ("$fonts" in state) {
2094
- (_a3 = state.$fonts) == null ? void 0 : _a3.registerFont(area.font);
2095
- }
2096
- state.$fetch.cacheAreaDocuments.set(areaCode, entity);
2097
- });
2098
- return areaCodes2.map((code) => state.$fetch.cacheAreaDocuments.get(code));
2099
- }
2100
- return null;
1992
+ };
1993
+ const queryArea = async (areaCode) => {
1994
+ return queryAreaList([areaCode]).then((res) => (res == null ? void 0 : res.at(0)) ?? null);
2101
1995
  };
2102
1996
  state.$fetch = {
2103
1997
  cacheCssChunks: /* @__PURE__ */ new Map(),
2104
1998
  cacheDocuments: /* @__PURE__ */ new Map(),
2105
1999
  cacheAreaDocuments: /* @__PURE__ */ new Map(),
2106
- queryFragment,
2000
+ registerFragmentDocument,
2107
2001
  queryArea,
2108
2002
  queryAreaList,
2109
- query: fetcher.query,
2110
2003
  sendBeacon: beaconFetcher.sendBeacon,
2004
+ get: restFetcher.get,
2111
2005
  readCssChunk: (id) => state.$fetch.cacheCssChunks.get(id) ?? null,
2112
2006
  readFragment: (fragmentId) => state.$fetch.cacheDocuments.get(fragmentId) ?? null,
2113
2007
  readArea: (areaCode) => state.$fetch.cacheAreaDocuments.get(areaCode) ?? null
@@ -2324,22 +2218,12 @@ const fragmentStylesheetPlugin = (globalState) => (state) => {
2324
2218
  }
2325
2219
  return noop;
2326
2220
  };
2327
- const destroyStyles = () => {
2328
- state.mutate(
2329
- KEY,
2330
- {
2331
- styles: {}
2332
- },
2333
- { replace: true }
2334
- );
2335
- fragmentStyleInjector.unmount();
2336
- };
2337
2221
  state.$styleSheet = {
2338
2222
  key: KEY,
2339
2223
  addStyle,
2340
2224
  addCssChunk,
2341
2225
  mount: fragmentStyleInjector.mount,
2342
- unmount: destroyStyles,
2226
+ unmount: fragmentStyleInjector.unmount,
2343
2227
  extract: (withTag) => {
2344
2228
  var _a;
2345
2229
  const graph = state.resolve(KEY);
@@ -2410,6 +2294,84 @@ const scopesPlugin = (state) => {
2410
2294
  };
2411
2295
  return state;
2412
2296
  };
2297
+ const PROPERTIES_ROOT_KEY = "PropertiesRoot:root";
2298
+ const propertiesPlugin = (state) => {
2299
+ const hydrate = (properties) => {
2300
+ if (!Array.isArray(properties)) return;
2301
+ const keys = [];
2302
+ for (const prop of properties) {
2303
+ if (!prop || !prop._id) continue;
2304
+ const key = `${index.nodes.Variable}:${prop._id}`;
2305
+ state.mutate(
2306
+ { ...prop, _type: index.nodes.Variable, _id: String(prop._id) },
2307
+ { replace: true }
2308
+ );
2309
+ keys.push(key);
2310
+ }
2311
+ state.mutate(
2312
+ PROPERTIES_ROOT_KEY,
2313
+ { propertyKeys: keys },
2314
+ { replace: true }
2315
+ );
2316
+ };
2317
+ const addProperty = (type, initialData) => {
2318
+ const id = (initialData == null ? void 0 : initialData._id) || generateId();
2319
+ const key = `${index.nodes.Variable}:${id}`;
2320
+ state.mutate({
2321
+ _type: index.nodes.Variable,
2322
+ _id: String(id),
2323
+ type,
2324
+ name: `${type} property`,
2325
+ ...initialData
2326
+ });
2327
+ const root = state.resolve(PROPERTIES_ROOT_KEY);
2328
+ const currentKeys = (root == null ? void 0 : root.propertyKeys) ?? [];
2329
+ state.mutate(
2330
+ PROPERTIES_ROOT_KEY,
2331
+ { propertyKeys: [...currentKeys, key] },
2332
+ { replace: true }
2333
+ );
2334
+ return key;
2335
+ };
2336
+ const removeProperty = (key) => {
2337
+ state.invalidate(key);
2338
+ const root = state.resolve(PROPERTIES_ROOT_KEY);
2339
+ const currentKeys = (root == null ? void 0 : root.propertyKeys) ?? [];
2340
+ state.mutate(
2341
+ PROPERTIES_ROOT_KEY,
2342
+ { propertyKeys: currentKeys.filter((k) => k !== key) },
2343
+ { replace: true }
2344
+ );
2345
+ };
2346
+ const extractProperties = () => {
2347
+ const root = state.resolve(PROPERTIES_ROOT_KEY);
2348
+ const keys = (root == null ? void 0 : root.propertyKeys) ?? [];
2349
+ return keys.map((key) => state.resolve(key, { deep: true })).filter(Boolean);
2350
+ };
2351
+ const getPropertyKeys = () => {
2352
+ const root = state.resolve(PROPERTIES_ROOT_KEY);
2353
+ return (root == null ? void 0 : root.propertyKeys) ?? [];
2354
+ };
2355
+ state.addSkip((dataField) => {
2356
+ if (typeof dataField === "object" && dataField !== null && !Array.isArray(dataField)) {
2357
+ return dataField._type === index.nodes.Variable && (dataField._id === "replaceBeforeSave" || !dataField._id);
2358
+ }
2359
+ return false;
2360
+ });
2361
+ state.mutate({
2362
+ _type: "PropertiesRoot",
2363
+ _id: "root",
2364
+ propertyKeys: []
2365
+ });
2366
+ state.$properties = {
2367
+ key: PROPERTIES_ROOT_KEY,
2368
+ hydrate,
2369
+ addProperty,
2370
+ removeProperty,
2371
+ extractProperties,
2372
+ getPropertyKeys
2373
+ };
2374
+ };
2413
2375
  const fragmentsPlugin = (options) => (state) => {
2414
2376
  const plugins = (options == null ? void 0 : options.plugins) ?? [];
2415
2377
  const createFragmentManager = (fragmentId, initialDocument = {}) => {
@@ -2446,6 +2408,7 @@ const fragmentsPlugin = (options) => (state) => {
2446
2408
  // cssPlugin,
2447
2409
  fragmentStylesheetPlugin(state),
2448
2410
  scopesPlugin,
2411
+ propertiesPlugin,
2449
2412
  ...plugins
2450
2413
  ],
2451
2414
  skip: [
@@ -2456,12 +2419,19 @@ const fragmentsPlugin = (options) => (state) => {
2456
2419
  ...Object.keys(index.nodes),
2457
2420
  "Temp",
2458
2421
  "Spring",
2459
- PLUGIN_TYPES.FragmentStylesheet
2422
+ PLUGIN_TYPES.FragmentStylesheet,
2423
+ "PropertiesRoot"
2460
2424
  ])
2461
2425
  ]
2462
2426
  });
2463
2427
  manager.mutate(tempGraph);
2464
2428
  manager.mutate(springGraph);
2429
+ const fragmentRoot = manager.resolve(manager.$fragment.root);
2430
+ const propertyLinks = (fragmentRoot == null ? void 0 : fragmentRoot.properties) ?? [];
2431
+ const propertyEntities = propertyLinks.map((link) => manager.resolve(link)).filter(Boolean);
2432
+ if (propertyEntities.length > 0) {
2433
+ manager.$properties.hydrate(propertyEntities);
2434
+ }
2465
2435
  state.mutate(state.$fragments.key, {
2466
2436
  managers: {
2467
2437
  [fragmentId]: manager
@@ -2490,9 +2460,6 @@ const fragmentsPlugin = (options) => (state) => {
2490
2460
  });
2491
2461
  return state;
2492
2462
  };
2493
- const addClientMetric = `mutation AddClientMetric($type: ClientMetricType!, $value: GoalAchievementPost!) {
2494
- addClientMetric(metric: {metricType: $type, achievement: $value})
2495
- }`;
2496
2463
  const pendingPixels = /* @__PURE__ */ new Set();
2497
2464
  const sendWithImage = (url) => {
2498
2465
  try {
@@ -2566,10 +2533,16 @@ const types = createConstants(
2566
2533
  "REACH_PROJECT_GOAL"
2567
2534
  );
2568
2535
  const globalMetricsPlugin = (state) => {
2569
- const sendMetric = async (type, value) => {
2536
+ const sendMetric = (type, value) => {
2570
2537
  var _a;
2571
- const query = (_a = state == null ? void 0 : state.$fetch) == null ? void 0 : _a.query;
2572
- await query(addClientMetric, { type, value });
2538
+ if (type !== types.REACH_PROJECT_GOAL || !value) return;
2539
+ const params = new URLSearchParams({
2540
+ goal_id: String(value.goalId),
2541
+ variant_id: String(value.variantId),
2542
+ area_id: String(value.areaId),
2543
+ campaign_id: String(value.campaignId)
2544
+ });
2545
+ (_a = state.$fetch) == null ? void 0 : _a.get(`/api/metric/goal?${params}`).catch(() => void 0);
2573
2546
  };
2574
2547
  const reachGoal = (goal) => {
2575
2548
  sendMetric(types.REACH_PROJECT_GOAL, goal);
@@ -2593,23 +2566,17 @@ const loadPlugin = (state) => {
2593
2566
  const readFragment = (_a = state == null ? void 0 : state.$fetch) == null ? void 0 : _a.readFragment(fragmentId);
2594
2567
  const fragmentManager = (_b = state == null ? void 0 : state.$fragments) == null ? void 0 : _b.getManager(fragmentId);
2595
2568
  if (readFragment && !fragmentManager) {
2596
- const fragmentManager2 = state.$fragments.createFragmentManager(
2597
- fragmentId,
2598
- readFragment
2599
- );
2600
- return fragmentManager2;
2569
+ return state.$fragments.createFragmentManager(fragmentId, readFragment);
2601
2570
  }
2602
2571
  if (readFragment && fragmentManager) return fragmentManager;
2603
- return state.$fetch.queryFragment(fragmentId).then(
2604
- (fragmentDocument) => state.$fragments.createFragmentManager(fragmentId, fragmentDocument)
2605
- );
2572
+ return null;
2606
2573
  };
2607
2574
  const loadArea = (areaCode) => {
2608
2575
  var _a;
2609
2576
  const readArea2 = (_a = state == null ? void 0 : state.$fetch) == null ? void 0 : _a.readArea(areaCode);
2610
2577
  if (readArea2) return readArea2;
2611
- return state.$fetch.queryArea(areaCode).then(async (areaEntity) => {
2612
- await loadFragment(areaEntity == null ? void 0 : areaEntity.fragmentId);
2578
+ return state.$fetch.queryArea(areaCode).then((areaEntity) => {
2579
+ loadFragment(areaEntity == null ? void 0 : areaEntity.fragmentId);
2613
2580
  return areaEntity;
2614
2581
  });
2615
2582
  };
@@ -2626,6 +2593,7 @@ const fontsPlugin = (state) => {
2626
2593
  const fonts = /* @__PURE__ */ new Map();
2627
2594
  let defaultFontFamily = null;
2628
2595
  const registerFont = (font) => {
2596
+ if (!font) return;
2629
2597
  const fontFamily = font.family;
2630
2598
  if (!fonts.has(fontFamily)) {
2631
2599
  fonts.set(fontFamily, font);
@@ -2639,7 +2607,8 @@ const fontsPlugin = (state) => {
2639
2607
  const getStyles = () => {
2640
2608
  const styles = [];
2641
2609
  for (const [fontFamily, font] of fonts) {
2642
- const files = font.files ?? [];
2610
+ const rawFiles = font.files ?? [];
2611
+ const files = Array.isArray(rawFiles) ? rawFiles : Object.entries(rawFiles).map(([variant, url]) => ({ variant, url }));
2643
2612
  for (const file of files) {
2644
2613
  const [weightItem] = getFontWeights([file.variant]);
2645
2614
  styles.push(`@font-face {
@@ -2678,27 +2647,28 @@ const PLUGIN_TYPES = createConstants(
2678
2647
  "FragmentStylesheet"
2679
2648
  );
2680
2649
  const createFragmentsClient = (options) => {
2681
- const BACKEND_TARGET = (options == null ? void 0 : options.isSelf) ? "/graphql" : "http://85.192.29.65/graphql";
2682
2650
  return kt({
2683
2651
  _type: "GlobalManager",
2684
2652
  initialState: {},
2685
2653
  skip: [
2686
2654
  u([
2687
2655
  ...Object.keys(index.nodes),
2688
- ...Object.keys(PLUGIN_TYPES)
2656
+ ...Object.keys(PLUGIN_TYPES),
2657
+ "PropertiesRoot"
2689
2658
  ])
2690
2659
  ],
2691
2660
  plugins: [
2692
2661
  (state) => {
2693
2662
  state.env = {
2694
- isSelf: (options == null ? void 0 : options.isSelf) ?? false,
2695
- backendEndpoint: (options == null ? void 0 : options.backendEndpoint) ?? BACKEND_TARGET,
2663
+ backendEndpoint: (options == null ? void 0 : options.backendEndpoint) ?? "https://client-api.fragmentsx.com",
2696
2664
  apiToken: options == null ? void 0 : options.apiToken,
2697
2665
  referer: options == null ? void 0 : options.referer
2698
2666
  };
2699
2667
  },
2668
+ ...(options == null ? void 0 : options.plugins) ?? [],
2700
2669
  fetchPlugin,
2701
2670
  fontsPlugin,
2671
+ propertiesPlugin,
2702
2672
  fragmentsPlugin({
2703
2673
  plugins: options == null ? void 0 : options.fragmentPlugins
2704
2674
  }),
@@ -2709,6 +2679,39 @@ const createFragmentsClient = (options) => {
2709
2679
  ]
2710
2680
  });
2711
2681
  };
2682
+ const areaMetaPlugin = (options) => (state) => {
2683
+ state.$area = {
2684
+ areaId: options.areaId,
2685
+ campaignId: options.campaignId,
2686
+ variantId: options.variantId
2687
+ };
2688
+ };
2689
+ const createAreaManager = (options) => {
2690
+ var _a;
2691
+ const manager = kt({
2692
+ _type: "AreaManager",
2693
+ _id: String(options.areaId),
2694
+ initialState: {},
2695
+ skip: [
2696
+ u([
2697
+ ...Object.keys(index.nodes),
2698
+ "PropertiesRoot"
2699
+ ])
2700
+ ],
2701
+ plugins: [
2702
+ areaMetaPlugin({
2703
+ areaId: options.areaId,
2704
+ campaignId: options.campaignId,
2705
+ variantId: options.variantId
2706
+ }),
2707
+ propertiesPlugin
2708
+ ]
2709
+ });
2710
+ if ((_a = options.areaProperties) == null ? void 0 : _a.length) {
2711
+ manager.$properties.hydrate(options.areaProperties);
2712
+ }
2713
+ return manager;
2714
+ };
2712
2715
  const ssrPlugin = (state) => {
2713
2716
  var _a, _b, _c;
2714
2717
  if (!["$fragments"].every((field) => field in state)) {
@@ -2753,6 +2756,19 @@ const ssrPlugin = (state) => {
2753
2756
  };
2754
2757
  return state;
2755
2758
  };
2759
+ const VALID_DEVICE_TYPES = ["mobile", "tablet", "desktop"];
2760
+ const VALID_OS_TYPES = ["android", "ios", "windows", "macos", "linux"];
2761
+ const filtersPlugin = (overrides) => (state) => {
2762
+ if (overrides.deviceType && !VALID_DEVICE_TYPES.includes(overrides.deviceType)) {
2763
+ console.warn(
2764
+ `[filtersPlugin] Unknown deviceType: "${overrides.deviceType}"`
2765
+ );
2766
+ }
2767
+ if (overrides.osType && !VALID_OS_TYPES.includes(overrides.osType)) {
2768
+ console.warn(`[filtersPlugin] Unknown osType: "${overrides.osType}"`);
2769
+ }
2770
+ state.env.filterOverrides = overrides;
2771
+ };
2756
2772
  function createTestFragmentsClient(options) {
2757
2773
  const client = createFragmentsClient({
2758
2774
  apiToken: (options == null ? void 0 : options.apiToken) ?? "test-token"
@@ -2769,6 +2785,9 @@ function createTestFragmentsClient(options) {
2769
2785
  }
2770
2786
  return client;
2771
2787
  }
2788
+ exports.createAreaManager = createAreaManager;
2772
2789
  exports.createFragmentsClient = createFragmentsClient;
2773
2790
  exports.createTestFragmentsClient = createTestFragmentsClient;
2791
+ exports.filtersPlugin = filtersPlugin;
2792
+ exports.propertiesPlugin = propertiesPlugin;
2774
2793
  exports.ssrPlugin = ssrPlugin;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,7 @@
1
1
  export { createFragmentsClient } from './fragmentsClient';
2
+ export { createAreaManager } from './createAreaManager';
2
3
  export { ssrPlugin } from './plugins/ssr';
4
+ export { propertiesPlugin } from './plugins/properties';
5
+ export { filtersPlugin, type FilterOverrides } from './plugins/filters';
3
6
  export { createTestFragmentsClient, type TestFragmentsClientOptions, type FragmentDocument, type AreaCacheEntity, } from './testing/createTestFragmentsClient';
4
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE1C,OAAO,EACL,yBAAyB,EACzB,KAAK,0BAA0B,EAC/B,KAAK,gBAAgB,EACrB,KAAK,eAAe,GACrB,MAAM,qCAAqC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAExD,OAAO,EAAE,aAAa,EAAE,KAAK,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAExE,OAAO,EACL,yBAAyB,EACzB,KAAK,0BAA0B,EAC/B,KAAK,gBAAgB,EACrB,KAAK,eAAe,GACrB,MAAM,qCAAqC,CAAC"}