chayns-api 3.0.0-beta.4 → 3.1.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/README.md +4 -11
  2. package/dist/cjs/calls/index.js +4 -1
  3. package/dist/cjs/calls/visibilityChangeListener.js +4 -4
  4. package/dist/cjs/components/ChaynsProvider.js +34 -6
  5. package/dist/cjs/components/withHydrationBoundary.js +2 -2
  6. package/dist/cjs/constants/index.js +0 -22
  7. package/dist/cjs/contexts/HistoryLayerContext.js +89 -0
  8. package/dist/cjs/contexts/index.js +38 -0
  9. package/dist/cjs/handler/history/FrameHistoryLayer.js +100 -0
  10. package/dist/cjs/handler/history/HistoryLayer.js +321 -0
  11. package/dist/cjs/handler/history/index.js +19 -0
  12. package/dist/cjs/hooks/history.js +454 -0
  13. package/dist/cjs/hooks/index.js +62 -1
  14. package/dist/cjs/host/ChaynsHost.js +113 -54
  15. package/dist/cjs/host/iframe/HostIframe.js +70 -5
  16. package/dist/cjs/host/module/ModuleHost.js +50 -44
  17. package/dist/cjs/index.js +139 -6
  18. package/dist/cjs/types/history.js +1 -0
  19. package/dist/cjs/umd.index.js +2 -2
  20. package/dist/cjs/utils/EventBus.js +33 -0
  21. package/dist/cjs/{util → utils}/appStorage.js +2 -2
  22. package/dist/cjs/utils/equality.js +19 -0
  23. package/dist/cjs/utils/history/BlockRegistry.js +110 -0
  24. package/dist/cjs/utils/history/NavigationQueue.js +388 -0
  25. package/dist/cjs/utils/history/layerTree.js +32 -0
  26. package/dist/cjs/utils/history/navigationIndex.js +42 -0
  27. package/dist/cjs/utils/history/rootLayer.js +175 -0
  28. package/dist/cjs/utils/history/segments.js +15 -0
  29. package/dist/cjs/utils/history/stateProjector.js +156 -0
  30. package/dist/cjs/utils/history/url.js +47 -0
  31. package/dist/cjs/utils/history/window.js +9 -0
  32. package/dist/cjs/wrapper/AppWrapper.js +23 -23
  33. package/dist/cjs/wrapper/FrameWrapper.js +35 -2
  34. package/dist/cjs/wrapper/ModuleFederationWrapper.js +2 -0
  35. package/dist/cjs/wrapper/StaticChaynsApi.js +1 -1
  36. package/dist/esm/calls/index.js +2 -0
  37. package/dist/esm/calls/visibilityChangeListener.js +1 -1
  38. package/dist/esm/components/ChaynsProvider.js +34 -6
  39. package/dist/esm/components/withHydrationBoundary.js +1 -1
  40. package/dist/esm/constants/index.js +1 -3
  41. package/dist/esm/contexts/HistoryLayerContext.js +76 -0
  42. package/dist/esm/contexts/index.js +3 -0
  43. package/dist/esm/handler/history/FrameHistoryLayer.js +105 -0
  44. package/dist/esm/handler/history/HistoryLayer.js +321 -0
  45. package/dist/esm/handler/history/index.js +2 -0
  46. package/dist/esm/hooks/history.js +428 -0
  47. package/dist/esm/hooks/index.js +2 -1
  48. package/dist/esm/host/ChaynsHost.js +113 -54
  49. package/dist/esm/host/iframe/HostIframe.js +70 -5
  50. package/dist/esm/host/module/ModuleHost.js +50 -44
  51. package/dist/esm/index.js +15 -6
  52. package/dist/esm/types/history.js +1 -0
  53. package/dist/esm/umd.index.js +2 -2
  54. package/dist/esm/utils/EventBus.js +31 -0
  55. package/dist/esm/{util → utils}/appStorage.js +1 -1
  56. package/dist/esm/utils/equality.js +12 -0
  57. package/dist/esm/utils/history/BlockRegistry.js +108 -0
  58. package/dist/esm/utils/history/NavigationQueue.js +385 -0
  59. package/dist/esm/utils/history/layerTree.js +24 -0
  60. package/dist/esm/utils/history/navigationIndex.js +33 -0
  61. package/dist/esm/utils/history/rootLayer.js +167 -0
  62. package/dist/esm/utils/history/segments.js +7 -0
  63. package/dist/esm/utils/history/stateProjector.js +147 -0
  64. package/dist/esm/utils/history/url.js +40 -0
  65. package/dist/esm/utils/history/window.js +3 -0
  66. package/dist/esm/wrapper/AppWrapper.js +5 -5
  67. package/dist/esm/wrapper/FrameWrapper.js +35 -2
  68. package/dist/esm/wrapper/ModuleFederationWrapper.js +2 -0
  69. package/dist/esm/wrapper/StaticChaynsApi.js +2 -1
  70. package/dist/types/calls/index.d.ts +5 -0
  71. package/dist/types/components/ChaynsProvider.d.ts +21 -0
  72. package/dist/types/constants/index.d.ts +0 -2
  73. package/dist/types/contexts/HistoryLayerContext.d.ts +33 -0
  74. package/dist/types/contexts/index.d.ts +3 -0
  75. package/dist/types/handler/history/FrameHistoryLayer.d.ts +99 -0
  76. package/dist/types/handler/history/HistoryLayer.d.ts +117 -0
  77. package/dist/types/handler/history/index.d.ts +2 -0
  78. package/dist/types/hooks/history.d.ts +89 -0
  79. package/dist/types/hooks/index.d.ts +1 -0
  80. package/dist/types/host/ChaynsHost.d.ts +12 -0
  81. package/dist/types/host/iframe/HostIframe.d.ts +4 -0
  82. package/dist/types/host/module/ModuleHost.d.ts +4 -0
  83. package/dist/types/index.d.ts +15 -6
  84. package/dist/types/types/IChaynsReact.d.ts +3 -0
  85. package/dist/types/types/history.d.ts +74 -0
  86. package/dist/types/umd.index.d.ts +2 -2
  87. package/dist/types/utils/EventBus.d.ts +10 -0
  88. package/dist/types/{util → utils}/collectCssChunks.d.ts +1 -1
  89. package/dist/types/utils/equality.d.ts +2 -0
  90. package/dist/types/utils/history/BlockRegistry.d.ts +38 -0
  91. package/dist/types/utils/history/NavigationQueue.d.ts +109 -0
  92. package/dist/types/utils/history/layerTree.d.ts +10 -0
  93. package/dist/types/utils/history/navigationIndex.d.ts +14 -0
  94. package/dist/types/utils/history/rootLayer.d.ts +42 -0
  95. package/dist/types/utils/history/segments.d.ts +2 -0
  96. package/dist/types/utils/history/stateProjector.d.ts +24 -0
  97. package/dist/types/utils/history/url.d.ts +17 -0
  98. package/dist/types/utils/history/window.d.ts +1 -0
  99. package/dist/types/wrapper/FrameWrapper.d.ts +1 -0
  100. package/dist/types/wrapper/StaticChaynsApi.d.ts +1 -0
  101. package/package.json +2 -1
  102. /package/dist/cjs/{constants → contexts}/hydrationContext.js +0 -0
  103. /package/dist/cjs/{constants → contexts}/moduleContext.js +0 -0
  104. /package/dist/cjs/{helper/apiListenerHelper.js → utils/apiListener.js} +0 -0
  105. /package/dist/cjs/{util → utils}/appCall.js +0 -0
  106. /package/dist/cjs/{util → utils}/bindChaynsApi.js +0 -0
  107. /package/dist/cjs/{util → utils}/collectCssChunks.js +0 -0
  108. /package/dist/cjs/{util → utils}/deviceHelper.js +0 -0
  109. /package/dist/cjs/{util → utils}/heightHelper.js +0 -0
  110. /package/dist/cjs/{util → utils}/initModuleFederationSharing.js +0 -0
  111. /package/dist/cjs/{util → utils}/is.js +0 -0
  112. /package/dist/cjs/{util → utils}/postIframeForm.js +0 -0
  113. /package/dist/cjs/{util → utils}/transferNestedFunctions.js +0 -0
  114. /package/dist/cjs/{util → utils}/url.js +0 -0
  115. /package/dist/esm/{constants → contexts}/hydrationContext.js +0 -0
  116. /package/dist/esm/{constants → contexts}/moduleContext.js +0 -0
  117. /package/dist/esm/{helper/apiListenerHelper.js → utils/apiListener.js} +0 -0
  118. /package/dist/esm/{util → utils}/appCall.js +0 -0
  119. /package/dist/esm/{util → utils}/bindChaynsApi.js +0 -0
  120. /package/dist/esm/{util → utils}/collectCssChunks.js +0 -0
  121. /package/dist/esm/{util → utils}/deviceHelper.js +0 -0
  122. /package/dist/esm/{util → utils}/heightHelper.js +0 -0
  123. /package/dist/esm/{util → utils}/initModuleFederationSharing.js +0 -0
  124. /package/dist/esm/{util → utils}/is.js +0 -0
  125. /package/dist/esm/{util → utils}/postIframeForm.js +0 -0
  126. /package/dist/esm/{util → utils}/transferNestedFunctions.js +0 -0
  127. /package/dist/esm/{util → utils}/url.js +0 -0
  128. /package/dist/types/{constants → contexts}/hydrationContext.d.ts +0 -0
  129. /package/dist/types/{constants → contexts}/moduleContext.d.ts +0 -0
  130. /package/dist/types/{helper/apiListenerHelper.d.ts → utils/apiListener.d.ts} +0 -0
  131. /package/dist/types/{util → utils}/appCall.d.ts +0 -0
  132. /package/dist/types/{util → utils}/appStorage.d.ts +0 -0
  133. /package/dist/types/{util → utils}/bindChaynsApi.d.ts +0 -0
  134. /package/dist/types/{util → utils}/deviceHelper.d.ts +0 -0
  135. /package/dist/types/{util → utils}/heightHelper.d.ts +0 -0
  136. /package/dist/types/{util → utils}/initModuleFederationSharing.d.ts +0 -0
  137. /package/dist/types/{util → utils}/is.d.ts +0 -0
  138. /package/dist/types/{util → utils}/postIframeForm.d.ts +0 -0
  139. /package/dist/types/{util → utils}/transferNestedFunctions.d.ts +0 -0
  140. /package/dist/types/{util → utils}/url.d.ts +0 -0
@@ -0,0 +1,147 @@
1
+ import { shallowEqualObj } from '../equality';
2
+ const ROOT_KEY = '__chaynsHistory';
3
+ const SCHEMA_VERSION = 1;
4
+ function buildNode(layer) {
5
+ const node = {
6
+ ...layer._getOwnState()
7
+ };
8
+ const params = layer._getOwnParams();
9
+ if (Object.keys(params).length > 0) node.__params = {
10
+ ...params
11
+ };
12
+ const hash = layer._getOwnHash();
13
+ if (hash !== undefined) node.__hash = hash;
14
+ const activeChildId = layer.getActiveChildId();
15
+ if (activeChildId) {
16
+ node.activeChild = activeChildId;
17
+ const child = layer.getChildLayer(activeChildId);
18
+ if (child) {
19
+ node.childState = buildNode(child);
20
+ }
21
+ }
22
+ return node;
23
+ }
24
+ export function projectToState(root, existing = {}) {
25
+ const tree = buildNode(root);
26
+ return {
27
+ ...existing,
28
+ [ROOT_KEY]: {
29
+ v: SCHEMA_VERSION,
30
+ tree
31
+ }
32
+ };
33
+ }
34
+ function applyNode(layer, node) {
35
+ const {
36
+ activeChild,
37
+ childState,
38
+ __params,
39
+ __hash,
40
+ ...ownProps
41
+ } = node;
42
+ layer._setOwnStateSilent(ownProps);
43
+ layer._setOwnParamsSilent(__params !== null && __params !== void 0 ? __params : {});
44
+ layer._setOwnHashSilent('__hash' in node ? __hash : undefined);
45
+ if (activeChild !== undefined) {
46
+ layer._setActiveChildSilent(activeChild);
47
+ if (childState) {
48
+ const child = layer.getChildLayer(activeChild);
49
+ if (child) applyNode(child, childState);
50
+ }
51
+ } else {
52
+ layer._setActiveChildSilent(null);
53
+ }
54
+ }
55
+ export function applyStateToTree(root, raw) {
56
+ const node = extractNode(raw);
57
+ if (!node) return {
58
+ changedLayerIds: new Set()
59
+ };
60
+ const changedLayerIds = new Set();
61
+ applyNodeTracked(root, node, changedLayerIds);
62
+ return {
63
+ changedLayerIds
64
+ };
65
+ }
66
+ export function diffIncomingState(root, raw) {
67
+ const node = extractNode(raw);
68
+ if (!node) return {
69
+ changedLayerIds: new Set()
70
+ };
71
+ const changedLayerIds = new Set();
72
+ diffNodeTracked(root, node, changedLayerIds);
73
+ return {
74
+ changedLayerIds
75
+ };
76
+ }
77
+ function extractNode(raw) {
78
+ if (!raw || typeof raw !== 'object') return null;
79
+ const entry = raw[ROOT_KEY];
80
+ if (!entry || typeof entry !== 'object') return null;
81
+ const {
82
+ tree
83
+ } = entry;
84
+ return tree !== null && tree !== void 0 ? tree : null;
85
+ }
86
+ function applyNodeTracked(layer, node, changed) {
87
+ const {
88
+ activeChild,
89
+ childState,
90
+ __params,
91
+ __hash,
92
+ ...ownProps
93
+ } = node;
94
+ const prevState = layer._getOwnState();
95
+ const prevActiveChild = layer.getActiveChildId();
96
+ const prevParams = layer._getOwnParams();
97
+ const prevHash = layer._getOwnHash();
98
+ const incomingParams = __params !== null && __params !== void 0 ? __params : {};
99
+ const incomingHash = '__hash' in node ? __hash : undefined;
100
+ const ownPropsClean = ownProps;
101
+ const stateChanged = !shallowEqualObj(prevState, ownPropsClean);
102
+ const activeChildChanged = prevActiveChild !== (activeChild !== null && activeChild !== void 0 ? activeChild : null);
103
+ const paramsChanged = !shallowEqualObj(prevParams, incomingParams);
104
+ const hashChanged = prevHash !== incomingHash;
105
+ const child = activeChild ? layer.getChildLayer(activeChild) : undefined;
106
+ layer._setOwnStateSilent(ownPropsClean);
107
+ layer._setActiveChildSilent(activeChild !== null && activeChild !== void 0 ? activeChild : null);
108
+ layer._setOwnParamsSilent(incomingParams);
109
+ layer._setOwnHashSilent(incomingHash);
110
+ if (stateChanged || activeChildChanged || paramsChanged || hashChanged) {
111
+ changed.add(layer.id);
112
+ }
113
+ if (activeChild && childState) {
114
+ if (child) applyNodeTracked(child, childState, changed);
115
+ }
116
+ }
117
+ function diffNodeTracked(layer, node, changed) {
118
+ const {
119
+ activeChild,
120
+ childState,
121
+ __params,
122
+ __hash,
123
+ ...ownProps
124
+ } = node;
125
+ const prevState = layer._getOwnState();
126
+ const prevActiveChild = layer.getActiveChildId();
127
+ const prevParams = layer._getOwnParams();
128
+ const prevHash = layer._getOwnHash();
129
+ const incomingParams = __params !== null && __params !== void 0 ? __params : {};
130
+ const incomingHash = '__hash' in node ? __hash : undefined;
131
+ const ownPropsClean = ownProps;
132
+ const stateChanged = !shallowEqualObj(prevState, ownPropsClean);
133
+ const activeChildChanged = prevActiveChild !== (activeChild !== null && activeChild !== void 0 ? activeChild : null);
134
+ const paramsChanged = !shallowEqualObj(prevParams, incomingParams);
135
+ const hashChanged = prevHash !== incomingHash;
136
+ const child = activeChild ? layer.getChildLayer(activeChild) : undefined;
137
+ if (stateChanged || activeChildChanged || paramsChanged || hashChanged) {
138
+ changed.add(layer.id);
139
+ }
140
+ if (activeChild && childState) {
141
+ if (child) diffNodeTracked(child, childState, changed);
142
+ }
143
+ }
144
+ export { extractNode as _extractNode };
145
+ export function hasChaynsHistoryState(raw) {
146
+ return extractNode(raw) !== null;
147
+ }
@@ -0,0 +1,40 @@
1
+ import { getChaynsHistoryActiveChain } from './layerTree';
2
+ import { normalizeHistorySegments } from './segments';
3
+ export function projectToUrl(root) {
4
+ const chain = getChaynsHistoryActiveChain(root);
5
+ const parts = [];
6
+ const mergedParams = {};
7
+ let hash;
8
+ for (const layer of chain) {
9
+ for (const seg of normalizeHistorySegments(layer._getOwnSegments())) {
10
+ parts.push(seg);
11
+ }
12
+ Object.assign(mergedParams, layer._getOwnParams());
13
+ const layerHash = layer._getOwnHash();
14
+ if (layerHash !== undefined) hash = layerHash;
15
+ }
16
+ let url = '/' + parts.join('/');
17
+ const search = new URLSearchParams(mergedParams).toString();
18
+ if (search) url += '?' + search;
19
+ if (hash) url += '#' + hash;
20
+ return url;
21
+ }
22
+ export function parseFromUrl(url, root) {
23
+ const perLayerSegments = new Map();
24
+ const pathname = url.startsWith('/') ? url.slice(1) : url;
25
+ const all = pathname ? pathname.split('/') : [];
26
+ let offset = 0;
27
+ const chain = getChaynsHistoryActiveChain(root);
28
+ for (const layer of chain) {
29
+ const count = layer.getSegmentCount();
30
+ const slice = all.slice(offset, offset + count);
31
+ while (slice.length < count) slice.push('');
32
+ perLayerSegments.set(layer.id, slice);
33
+ offset += count;
34
+ }
35
+ const pendingSegments = offset < all.length ? all.slice(offset) : [];
36
+ return {
37
+ perLayerSegments,
38
+ pendingSegments
39
+ };
40
+ }
@@ -0,0 +1,3 @@
1
+ export function hasWindowHistory() {
2
+ return typeof window !== 'undefined' && typeof window.history !== 'undefined';
3
+ }
@@ -7,12 +7,12 @@ import { sendMessageToGroup, sendMessageToPage, sendMessageToUser } from '../cal
7
7
  import { DefaultLoginDialogOptions } from '../constants';
8
8
  import { DeviceLanguage } from '../constants/languages';
9
9
  import DialogHandler from '../handler/DialogHandler';
10
- import { addApiListener, dispatchApiEvent, removeApiListener } from '../helper/apiListenerHelper';
10
+ import { addApiListener, dispatchApiEvent, removeApiListener } from '../utils/apiListener';
11
11
  import { AppName, DialogButtonType, DialogType, Environment, Font, Gender, IconType, LoginState, RuntimeEnviroment, TappEvent } from '../types/IChaynsReact';
12
- import invokeAppCall from '../util/appCall';
13
- import { addAppStorageListener, clearAppStorage, isAppStorageAvailable, setAppStorageItem } from '../util/appStorage';
14
- import getDeviceInfo, { getScreenSize } from '../util/deviceHelper';
15
- import { isAppCallSupported } from '../util/is';
12
+ import invokeAppCall from '../utils/appCall';
13
+ import { addAppStorageListener, clearAppStorage, isAppStorageAvailable, setAppStorageItem } from '../utils/appStorage';
14
+ import getDeviceInfo, { getScreenSize } from '../utils/deviceHelper';
15
+ import { isAppCallSupported } from '../utils/is';
16
16
  export class AppWrapper {
17
17
  async loadStyleSettings(siteId) {
18
18
  try {
@@ -6,8 +6,9 @@ import getUserInfo from '../calls/getUserInfo';
6
6
  import { sendMessageToGroup, sendMessageToPage, sendMessageToUser } from '../calls/sendMessage';
7
7
  import { addVisibilityChangeListener, removeVisibilityChangeListener } from '../calls/visibilityChangeListener';
8
8
  import DialogHandler from '../handler/DialogHandler';
9
- import { setTappHeight } from '../util/heightHelper';
10
- import { initTransferNestedFunctions } from '../util/transferNestedFunctions';
9
+ import { FrameHistoryLayer } from '../handler/history/FrameHistoryLayer';
10
+ import { setTappHeight } from '../utils/heightHelper';
11
+ import { initTransferNestedFunctions } from '../utils/transferNestedFunctions';
11
12
  export class FrameWrapper {
12
13
  constructor() {
13
14
  _defineProperty(this, "resolve", null);
@@ -15,6 +16,7 @@ export class FrameWrapper {
15
16
  _defineProperty(this, "exposedCustomFunctions", {});
16
17
  _defineProperty(this, "exposedCustomFunctionNames", []);
17
18
  _defineProperty(this, "resizeListener", null);
19
+ _defineProperty(this, "_historyLayer", null);
18
20
  _defineProperty(this, "ready", new Promise(res => {
19
21
  this.resolve = res;
20
22
  }));
@@ -297,6 +299,12 @@ export class FrameWrapper {
297
299
  redirect: async options => {
298
300
  if (!this.initialized) await this.ready;
299
301
  return this.exposedFunctions.redirect(options);
302
+ },
303
+ getHistoryLayer: () => {
304
+ if (!this._historyLayer) {
305
+ throw new Error('[chaynsHistory] No history layer available. Ensure historyLayer prop is set on the parent HostIframe.');
306
+ }
307
+ return this._historyLayer;
300
308
  }
301
309
  });
302
310
  _defineProperty(this, "customFunctions", new Proxy({}, {
@@ -365,6 +373,31 @@ export class FrameWrapper {
365
373
  p[e] = (...args) => this.exposedCustomFunctions[e](...args.map(a => typeof a === 'function' ? comlink.proxy(a) : a));
366
374
  return p;
367
375
  }, {});
376
+ const exposedHistory = exposed.history;
377
+ if (exposedHistory) {
378
+ const initialState = await exposedHistory.getInitialState();
379
+ if (initialState) {
380
+ this._historyLayer = new FrameHistoryLayer({
381
+ setRoute: (route, opts) => exposedHistory.setRoute(route, opts),
382
+ setParams: (params, opts) => exposedHistory.setParams(params, opts),
383
+ setHash: (hash, opts) => exposedHistory.setHash(hash, opts),
384
+ setState: (state, opts) => exposedHistory.setState(state, opts),
385
+ navigate: opts => exposedHistory.navigate(opts),
386
+ setActiveChild: (id, init) => exposedHistory.setActiveChild(id, init),
387
+ setSegmentCount: n => exposedHistory.setSegmentCount(n),
388
+ addBlock: async (callback, opts) => {
389
+ const remoteUnsub = await exposedHistory.addBlock(comlink.proxy(callback), opts);
390
+ return () => void remoteUnsub();
391
+ }
392
+ }, initialState);
393
+ await exposedHistory.addChangeListener(comlink.proxy(e => {
394
+ this._historyLayer._applyAndEmit(e);
395
+ }));
396
+ await exposedHistory.addPopstateListener(comlink.proxy(e => {
397
+ this._historyLayer._applyAndEmit(e);
398
+ }));
399
+ }
400
+ }
368
401
  this.initialized = true;
369
402
  this.resolve(null);
370
403
  setTappHeight(this.functions.setHeight);
@@ -2,6 +2,7 @@ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object
2
2
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
3
3
  function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
4
4
  import DialogHandler from '../handler/DialogHandler';
5
+ import { getOrInitRootChaynsHistoryLayer } from '../utils/history/rootLayer';
5
6
  import { addVisibilityChangeListener, removeVisibilityChangeListener } from '../calls/visibilityChangeListener';
6
7
  import getUserInfo from '../calls/getUserInfo';
7
8
  import { sendMessageToGroup, sendMessageToPage, sendMessageToUser } from '../calls/sendMessage';
@@ -38,6 +39,7 @@ export class ModuleFederationWrapper {
38
39
  this.functions.createDialog = config => {
39
40
  return new DialogHandler(config, functions.openDialog, functions.closeDialog, functions.dispatchEventToDialogClient, functions.addDialogClientEventListener);
40
41
  };
42
+ this.functions.getHistoryLayer = () => getOrInitRootChaynsHistoryLayer().rootLayer;
41
43
  }
42
44
  async init() {
43
45
  return undefined;
@@ -3,7 +3,7 @@ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol"
3
3
  function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
4
4
  import { moduleWrapper } from '../components/moduleWrapper';
5
5
  import { AppFlavor } from '../types/IChaynsReact';
6
- import getDeviceInfo from '../util/deviceHelper';
6
+ import getDeviceInfo from '../utils/deviceHelper';
7
7
  import { AppWrapper } from './AppWrapper';
8
8
  import { FrameWrapper } from './FrameWrapper';
9
9
  import { ModuleFederationWrapper } from './ModuleFederationWrapper';
@@ -74,6 +74,7 @@ class StaticChaynsApi {
74
74
  _defineProperty(this, "addAccessTokenChangeListener", void 0);
75
75
  _defineProperty(this, "removeAccessTokenChangeListener", void 0);
76
76
  _defineProperty(this, "redirect", void 0);
77
+ _defineProperty(this, "getHistoryLayer", void 0);
77
78
  _defineProperty(this, "ready", void 0);
78
79
  _defineProperty(this, "addDataListener", void 0);
79
80
  _defineProperty(this, "_wrapper", void 0);
@@ -227,6 +227,11 @@ export declare const addAnonymousAccount: () => Promise<import("../types/IChayns
227
227
  * @category User functions
228
228
  */
229
229
  export declare const getUser: () => import("../types/IChaynsReact").ChaynsApiUser | undefined;
230
+ /**
231
+ * Returns the innermost currently mounted HistoryLayer. Falls back to the
232
+ * root layer when called outside any HistoryLayerProvider.
233
+ */
234
+ export declare const getChaynsHistoryLayer: () => import("..").ChaynsHistoryLayer | null;
230
235
  export declare const getSite: () => ChaynsApiSite;
231
236
  export declare const getCurrentPage: () => {
232
237
  id: number;
@@ -1,5 +1,6 @@
1
1
  import React, { ReactNode } from 'react';
2
2
  import { ChaynsReactFunctions, ChaynsReactValues, IChaynsReact } from '../types/IChaynsReact';
3
+ import type { ChaynsHistoryLayer } from '../types/history';
3
4
  export type ChaynsProviderProps = {
4
5
  data?: ChaynsReactValues;
5
6
  functions?: ChaynsReactFunctions;
@@ -8,6 +9,26 @@ export type ChaynsProviderProps = {
8
9
  isModule?: boolean;
9
10
  children?: ReactNode;
10
11
  chaynsApiId?: string;
12
+ /**
13
+ * Explicit history layer to provide to the React subtree.
14
+ * When set this layer is used directly and no root layer is auto-initialised.
15
+ * Use this when the parent already owns a layer and wants to scope children to it.
16
+ */
17
+ historyLayer?: ChaynsHistoryLayer;
18
+ /**
19
+ * Initial history configuration for the root layer.
20
+ * Ignored when `layer` is provided explicitly.
21
+ * - `url`: Current page URL — browser defaults to `window.location.pathname`;
22
+ * for SSR pass the request URL (e.g. `req.url` or `router.asPath`).
23
+ * - `segmentCount`: Number of URL path segments this application claims.
24
+ * E.g. `segmentCount: 2` on `/shop/products/detail` → `getLayer().getRoute()` → `['shop', 'products']`.
25
+ */
26
+ history?: {
27
+ url?: string;
28
+ segmentCount?: number;
29
+ };
30
+ segmentCount?: number;
31
+ isHistoryDisabled?: boolean;
11
32
  };
12
33
  declare const ChaynsProvider: React.FC<ChaynsProviderProps>;
13
34
  export default ChaynsProvider;
@@ -1,3 +1 @@
1
- export * from './hydrationContext';
2
1
  export * from './DefaultLoginDialogOptions';
3
- export * from './moduleContext';
@@ -0,0 +1,33 @@
1
+ import React, { type FC, type ReactNode } from 'react';
2
+ import type { ChaynsHistoryLayer } from '../types/history';
3
+ export declare function pushChaynsHistoryLayer(layer: ChaynsHistoryLayer): void;
4
+ export declare function popChaynsHistoryLayer(layer: ChaynsHistoryLayer): void;
5
+ /** Returns the innermost currently mounted ChaynsHistoryLayer, or the root layer as fallback. */
6
+ export declare function getCurrentChaynsHistoryLayer(): ChaynsHistoryLayer | null;
7
+ declare const ChaynsHistoryLayerContext: React.Context<ChaynsHistoryLayer | null>;
8
+ export interface ChaynsHistoryLayerProviderProps {
9
+ layer: ChaynsHistoryLayer;
10
+ children: ReactNode;
11
+ }
12
+ /**
13
+ * Provides a ChaynsHistoryLayer to the React subtree **and** registers it on the
14
+ * module-level layer stack so that `getCurrentChaynsHistoryLayer()` (static / non-React
15
+ * call sites) also sees this layer as the current one.
16
+ *
17
+ * Use `ChaynsHistoryLayerOverrideProvider` instead if you only want to override the
18
+ * React context without affecting static call sites.
19
+ */
20
+ export declare const ChaynsHistoryLayerProvider: FC<ChaynsHistoryLayerProviderProps>;
21
+ /**
22
+ * Overrides the ChaynsHistoryLayer for the React subtree **only** — hooks such as
23
+ * `useChaynsHistoryLayer`, `useChaynsHistoryRoute`, `useChaynsHistoryNavigate`, etc. will resolve to the
24
+ * provided `layer`, but `getCurrentChaynsHistoryLayer()` (the static / non-React accessor
25
+ * that reads from the module-level layer stack) is left unchanged.
26
+ *
27
+ * This is useful when you need to scope history to a specific layer inside a
28
+ * React tree without affecting imperative call sites outside that tree.
29
+ */
30
+ export declare const ChaynsHistoryLayerOverrideProvider: FC<ChaynsHistoryLayerProviderProps>;
31
+ /** Returns the nearest ChaynsHistoryLayer from context, or null if none. */
32
+ export declare function useChaynsHistoryLayerContext(): ChaynsHistoryLayer | null;
33
+ export default ChaynsHistoryLayerContext;
@@ -0,0 +1,3 @@
1
+ export * from './hydrationContext';
2
+ export * from './moduleContext';
3
+ export * from './HistoryLayerContext';
@@ -0,0 +1,99 @@
1
+ import type { ChaynsHistoryLayer, ChaynsHistoryNavigateOptions, ChaynsHistoryNavigationCommitOptions, ChaynsHistoryBlockOptions, ChaynsHistoryLayerEvent, ChaynsHistoryActionResult } from '../../types/history';
2
+ /**
3
+ * Async bridge functions forwarded via comlink from the iframe (FrameWrapper) to
4
+ * the parent window (HostIframe). All methods are async because they cross the
5
+ * comlink boundary.
6
+ *
7
+ * Callbacks that cross the boundary (addBlock) must be wrapped with
8
+ * `comlink.proxy()` by the caller (FrameWrapper.init) before being passed in.
9
+ */
10
+ export interface HistoryBridgeFunctions {
11
+ setRoute(route: string | string[], opts?: ChaynsHistoryNavigateOptions): Promise<void>;
12
+ setParams(params: Record<string, string>, opts?: ChaynsHistoryNavigationCommitOptions): Promise<void>;
13
+ setHash(hash: string, opts?: ChaynsHistoryNavigationCommitOptions): Promise<void>;
14
+ setState(state: Record<string, unknown>, opts?: ChaynsHistoryNavigateOptions): Promise<void>;
15
+ navigate(opts: {
16
+ route?: string | string[];
17
+ state?: Record<string, unknown>;
18
+ activeChild?: string | null;
19
+ activeChildInit?: {
20
+ route?: string | string[];
21
+ state?: Record<string, unknown>;
22
+ };
23
+ } & ChaynsHistoryNavigateOptions): Promise<ChaynsHistoryActionResult>;
24
+ setActiveChild(id: string | null, init?: {
25
+ route?: string | string[];
26
+ state?: Record<string, unknown>;
27
+ }): Promise<ChaynsHistoryActionResult>;
28
+ setSegmentCount(n: number): Promise<void>;
29
+ /** Callback must be wrapped with comlink.proxy by FrameWrapper. Returns an async unsubscribe fn. */
30
+ addBlock(callback: () => Promise<boolean>, opts?: ChaynsHistoryBlockOptions): Promise<() => void>;
31
+ }
32
+ /** Snapshot of the host layer's state transferred to the frame at init time. */
33
+ export interface HistoryInitialState {
34
+ id: string;
35
+ depth: number;
36
+ segments: string[];
37
+ params: Record<string, string>;
38
+ hash: string;
39
+ state: Record<string, unknown> | undefined;
40
+ activeChildId: string | null;
41
+ segmentCount: number;
42
+ }
43
+ /**
44
+ * A `ChaynsHistoryLayer` proxy that runs inside an iframe (FrameWrapper).
45
+ *
46
+ * - **Reads** are served from a local cache for synchronous access.
47
+ * - **Writes** are forwarded to the parent window via `bridge` functions.
48
+ * - The cache is kept in sync by `FrameWrapper.init()`, which sets up a single
49
+ * comlink listener and calls `_applyAndEmit()` on every navigation event.
50
+ * - **Child layers** are not supported in the frame context — manage sub-routing
51
+ * with a local `initRootChaynsHistoryLayer` inside the iframe instead.
52
+ */
53
+ export declare class FrameHistoryLayer implements ChaynsHistoryLayer {
54
+ readonly id: string;
55
+ readonly depth: number;
56
+ private _segments;
57
+ private _params;
58
+ private _hash;
59
+ private _state;
60
+ private _activeChildId;
61
+ private _segmentCount;
62
+ private readonly bus;
63
+ private readonly bridge;
64
+ constructor(bridge: HistoryBridgeFunctions, initial: HistoryInitialState);
65
+ getSegmentCount(): number;
66
+ setSegmentCount(n: number): void;
67
+ createChildLayer(_id: string): ChaynsHistoryLayer;
68
+ destroyChildLayer(_id: string): void;
69
+ setActiveChild(id: string | null, init?: {
70
+ route?: string | string[];
71
+ state?: Record<string, unknown>;
72
+ }): Promise<ChaynsHistoryActionResult>;
73
+ getActiveChildId(): string | null;
74
+ getChildLayer(_id: string): ChaynsHistoryLayer | undefined;
75
+ getRoute(): string[];
76
+ setRoute(route: string | string[], opts?: ChaynsHistoryNavigateOptions): void;
77
+ getParams(): Record<string, string>;
78
+ setParams(params: Record<string, string>, opts?: ChaynsHistoryNavigationCommitOptions): void;
79
+ getHash(): string;
80
+ setHash(hash: string, opts?: ChaynsHistoryNavigationCommitOptions): void;
81
+ getState<T extends object = Record<string, unknown>>(): T | undefined;
82
+ setState(state: object, opts?: ChaynsHistoryNavigateOptions): void;
83
+ navigate(opts: {
84
+ route?: string | string[];
85
+ state?: Record<string, unknown>;
86
+ activeChild?: string | null;
87
+ activeChildInit?: {
88
+ route?: string | string[];
89
+ state?: Record<string, unknown>;
90
+ };
91
+ } & ChaynsHistoryNavigateOptions): Promise<ChaynsHistoryActionResult>;
92
+ addBlock(callback: () => Promise<boolean>, opts?: ChaynsHistoryBlockOptions): () => void;
93
+ addEventListener(type: 'popstate' | 'change', handler: (e: ChaynsHistoryLayerEvent) => void): () => void;
94
+ /**
95
+ * @internal Called by `FrameWrapper` when a navigation event arrives from the host.
96
+ * Updates the local cache and re-emits the event to all registered listeners.
97
+ */
98
+ _applyAndEmit(e: ChaynsHistoryLayerEvent): void;
99
+ }
@@ -0,0 +1,117 @@
1
+ import type { ChaynsHistoryLayer as IChaynsHistoryLayer, ChaynsHistoryLayerEvent, ChaynsHistoryNavigateOptions, ChaynsHistoryNavigationCommitOptions, ChaynsHistoryBlockOptions, ChaynsHistoryActionResult } from '../../types/history';
2
+ import type { NavigationQueue } from '../../utils/history/NavigationQueue';
3
+ import type { BlockRegistry } from '../../utils/history/BlockRegistry';
4
+ export interface ChaynsHistoryLayerDeps {
5
+ /** Reference to the root layer for queue + block registry access. */
6
+ getRoot: () => ChaynsHistoryLayer;
7
+ /** Top-window navigation queue (singleton). */
8
+ getQueue: () => NavigationQueue;
9
+ /** Top-window block registry (singleton). */
10
+ getBlockRegistry: () => BlockRegistry;
11
+ }
12
+ export interface ChaynsHistoryLayerInit {
13
+ id: string;
14
+ parent: ChaynsHistoryLayer | null;
15
+ deps: ChaynsHistoryLayerDeps;
16
+ segmentCount?: number;
17
+ /** Initial URL segments for this layer (length must equal segmentCount). */
18
+ segments?: string[];
19
+ }
20
+ export declare class ChaynsHistoryLayer implements IChaynsHistoryLayer {
21
+ readonly id: string;
22
+ readonly depth: number;
23
+ readonly parent: ChaynsHistoryLayer | null;
24
+ /** Insertion-ordered map of children. */
25
+ private readonly children;
26
+ /** Currently active child id (null = no child active). */
27
+ private activeChildId;
28
+ /** Number of URL segments this layer owns. */
29
+ private segmentCount;
30
+ /** This layer's own URL segments (length must equal segmentCount when active). */
31
+ private segments;
32
+ /** This layer's own state slice (without reserved keys). */
33
+ private ownState;
34
+ /** This layer's own query params. Merged with other active-chain layers when projecting URL. */
35
+ private _params;
36
+ /**
37
+ * This layer's own hash fragment (without `#`).
38
+ * `undefined` = never explicitly set (unset/no opinion).
39
+ * `''` = explicitly cleared.
40
+ * `'foo'` = explicitly set to `'foo'`.
41
+ */
42
+ private _hash;
43
+ /** Pub/sub for change + popstate events scoped to this layer. */
44
+ private readonly bus;
45
+ private readonly deps;
46
+ /** Lazily-resolved bootstrap URL segments. Null = not yet initialised. */
47
+ private _bootstrapPool;
48
+ /** Resolver called once on first consume to build the pool. */
49
+ private _bootstrapUrlResolver;
50
+ private isDestroyed;
51
+ constructor(init: ChaynsHistoryLayerInit);
52
+ getSegmentCount(): number;
53
+ setSegmentCount(n: number): void;
54
+ createChildLayer(id: string): ChaynsHistoryLayer;
55
+ destroyChildLayer(id: string): void;
56
+ getChildLayer(id: string): ChaynsHistoryLayer | undefined;
57
+ getActiveChildId(): string | null;
58
+ setActiveChild(id: string | null, init?: {
59
+ route?: string | string[];
60
+ state?: Record<string, unknown>;
61
+ }): Promise<ChaynsHistoryActionResult>;
62
+ getRoute(): string[];
63
+ setRoute(route: string | string[], opts?: ChaynsHistoryNavigateOptions): void;
64
+ getParams(): Record<string, string>;
65
+ setParams(params: Record<string, string>, opts?: ChaynsHistoryNavigationCommitOptions): void;
66
+ getHash(): string;
67
+ setHash(hash: string, opts?: ChaynsHistoryNavigationCommitOptions): void;
68
+ getState<T extends object = Record<string, unknown>>(): T | undefined;
69
+ setState<T extends object>(state: T, opts?: ChaynsHistoryNavigateOptions): void;
70
+ navigate(opts: {
71
+ route?: string | string[];
72
+ state?: Record<string, unknown>;
73
+ activeChild?: string | null;
74
+ activeChildInit?: {
75
+ route?: string | string[];
76
+ state?: Record<string, unknown>;
77
+ };
78
+ } & ChaynsHistoryNavigateOptions): Promise<ChaynsHistoryActionResult>;
79
+ addBlock(callback: () => Promise<boolean>, opts?: ChaynsHistoryBlockOptions): () => void;
80
+ addEventListener(type: 'popstate' | 'change', handler: (e: ChaynsHistoryLayerEvent) => void): () => void;
81
+ /** @internal */
82
+ _getOwnState(): Record<string, unknown>;
83
+ /** @internal */
84
+ _getOwnSegments(): string[];
85
+ /** @internal */
86
+ _getChildren(): ReadonlyMap<string, ChaynsHistoryLayer>;
87
+ /** @internal Apply mutated own state without firing events (used by projectors). */
88
+ _setOwnStateSilent(next: Record<string, unknown>): void;
89
+ /** @internal Apply mutated segments without firing events. */
90
+ _setOwnSegmentsSilent(next: string[]): void;
91
+ /** @internal */
92
+ _getOwnParams(): Record<string, string>;
93
+ /** @internal */
94
+ _setOwnParamsSilent(params: Record<string, string>): void;
95
+ /** @internal Returns the raw hash value (`undefined` = never set). */
96
+ _getOwnHash(): string | undefined;
97
+ /** @internal */
98
+ _setOwnHashSilent(hash: string | undefined): void;
99
+ /** @internal Set active child without enqueueing (used by projectors / queue processor). */
100
+ _setActiveChildSilent(id: string | null): void;
101
+ /** @internal Emit a typed event. Called by queue after diff confirms relevance. */
102
+ _emit(type: 'change' | 'popstate'): void;
103
+ /** @internal True if this layer is reachable via active chain from root. */
104
+ _isInActiveChain(): boolean;
105
+ /** @internal Register a lazy URL resolver (called once on first bootstrap consume). */
106
+ _setBootstrapUrlResolver(resolver: () => string): void;
107
+ /** @internal Set the bootstrap pool directly (overrides the lazy resolver). */
108
+ _setBootstrapPool(segs: string[]): void;
109
+ /** @internal Consume the next `n` segments from the bootstrap pool. Returns null if pool is exhausted or unset. */
110
+ _consumeBootstrapSegments(n: number): string[] | null;
111
+ /** @internal */
112
+ _isDestroyed(): boolean;
113
+ private markDestroyed;
114
+ private getCumulativeSegmentCount;
115
+ private static normalizeRoute;
116
+ private static filterReservedKeys;
117
+ }
@@ -0,0 +1,2 @@
1
+ export { ChaynsHistoryLayer as ChaynsHistoryLayerClass } from './HistoryLayer';
2
+ export { FrameHistoryLayer, type HistoryBridgeFunctions, type HistoryInitialState } from './FrameHistoryLayer';