@froomle/frontend-sdk 0.0.17 → 0.0.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +5 -396
- package/dist/froomle.global.js +5 -5
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +18 -152
- package/dist/index.js +1 -1
- package/dist/js-FtOpub-e.js +5 -0
- package/dist/react.cjs +1 -0
- package/dist/react.d.ts +45 -27
- package/dist/react.js +1 -1
- package/dist/src-6IU8XQgM.js +1 -0
- package/dist/src-CAyj-n-g.cjs +5 -0
- package/package.json +7 -7
- package/dist/Recommendations.d-HGeAMYU5.d.ts +0 -49
- package/dist/chunk-R3QWQW4H.js +0 -5
package/LICENSE
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or Derivative
|
|
95
|
+
Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
177
|
+
|
|
178
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
179
|
+
|
|
180
|
+
To apply the Apache License to your work, attach the following
|
|
181
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
182
|
+
replaced with your own identifying information. (Don't include
|
|
183
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
184
|
+
comment syntax for the file format. We also recommend that a
|
|
185
|
+
file or class name and description of purpose be included on the
|
|
186
|
+
same "printed page" as the copyright notice for easier
|
|
187
|
+
identification within third-party archives.
|
|
188
|
+
|
|
189
|
+
Copyright [yyyy] [name of copyright owner]
|
|
190
|
+
|
|
191
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
|
+
you may not use this file except in compliance with the License.
|
|
193
|
+
You may obtain a copy of the License at
|
|
194
|
+
|
|
195
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
196
|
+
|
|
197
|
+
Unless required by applicable law or agreed to in writing, software
|
|
198
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
200
|
+
See the License for the specific language governing permissions and
|
|
201
|
+
limitations under the License.
|
package/README.md
CHANGED
|
@@ -1,399 +1,8 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Froomle Frontend SDK
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
3. [JavaScript Modules](#javascript-modules)
|
|
6
|
-
4. [Supporting a New Framework](#supporting-a-new-framework)
|
|
3
|
+
[](https://www.npmjs.com/package/@froomle/frontend-sdk)
|
|
4
|
+
[](https://www.npmjs.com/package/@froomle/frontend-sdk)
|
|
7
5
|
|
|
8
|
-
|
|
6
|
+
Public documentation is located at:
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
This mechanism allows recommendation items to be **used immediately**, even though the underlying data may not yet be available.
|
|
13
|
-
|
|
14
|
-
---
|
|
15
|
-
|
|
16
|
-
### Problem Being Solved
|
|
17
|
-
|
|
18
|
-
Frameworks like React expect values to be:
|
|
19
|
-
|
|
20
|
-
- referentially stable
|
|
21
|
-
- accessible during render
|
|
22
|
-
- optionally async-aware
|
|
23
|
-
|
|
24
|
-
At the same time, the SDK:
|
|
25
|
-
|
|
26
|
-
- batches recommendation requests
|
|
27
|
-
- resolves them later via a single backend call
|
|
28
|
-
- relies on shared static state
|
|
29
|
-
- cannot expose all internal APIs directly
|
|
30
|
-
|
|
31
|
-
Returning a raw `Promise<RecommendationItem>` would not work, because components often need to **read fields synchronously**.
|
|
32
|
-
|
|
33
|
-
---
|
|
34
|
-
|
|
35
|
-
### High-Level Idea
|
|
36
|
-
|
|
37
|
-
The solution is to return a **Proxy object** that behaves as both:
|
|
38
|
-
|
|
39
|
-
- a `RecommendationItem`
|
|
40
|
-
- a `PromiseLike<RecommendationItem>`
|
|
41
|
-
|
|
42
|
-
This proxy:
|
|
43
|
-
|
|
44
|
-
- intercepts property access
|
|
45
|
-
- defers resolution until recommendations are fulfilled
|
|
46
|
-
- transparently switches to real data once available
|
|
47
|
-
|
|
48
|
-
From the consumer’s point of view, it behaves like a normal recommendation object that “fills itself in later”.
|
|
49
|
-
|
|
50
|
-
---
|
|
51
|
-
|
|
52
|
-
### Deferred Request Queue
|
|
53
|
-
|
|
54
|
-
When a recommendation is requested:
|
|
55
|
-
|
|
56
|
-
- a deferred promise is created
|
|
57
|
-
- the request is added to a shared queue
|
|
58
|
-
- no backend call is executed immediately
|
|
59
|
-
|
|
60
|
-
All pending requests are stored in a global request list until they are explicitly fulfilled.
|
|
61
|
-
|
|
62
|
-
This allows:
|
|
63
|
-
|
|
64
|
-
- batching multiple requests into one backend call
|
|
65
|
-
- predictable request ordering
|
|
66
|
-
- shared static backend state
|
|
67
|
-
|
|
68
|
-
---
|
|
69
|
-
|
|
70
|
-
### Fulfilling Recommendations
|
|
71
|
-
|
|
72
|
-
`fulfillRecommendations()`:
|
|
73
|
-
|
|
74
|
-
- executes a single backend request for all queued recommendations
|
|
75
|
-
- receives a list of recommendation items
|
|
76
|
-
- resolves each deferred promise with its corresponding item
|
|
77
|
-
- clears the request queue
|
|
78
|
-
|
|
79
|
-
This function is typically called once per render cycle (for example on application mount in React).
|
|
80
|
-
|
|
81
|
-
---
|
|
82
|
-
|
|
83
|
-
### Proxy-Based Recommendation Item
|
|
84
|
-
|
|
85
|
-
The returned object is a JavaScript `Proxy` wrapping an internal recommendation item.
|
|
86
|
-
|
|
87
|
-
The proxy provides three key behaviors:
|
|
88
|
-
|
|
89
|
-
- **Property access interception**
|
|
90
|
-
When a field is accessed, the proxy either:
|
|
91
|
-
- returns the real value (once resolved)
|
|
92
|
-
- returns a safe placeholder value
|
|
93
|
-
|
|
94
|
-
- **Promise compatibility**
|
|
95
|
-
Accessing `.then(...)` forwards to the underlying deferred promise, allowing async usage.
|
|
96
|
-
|
|
97
|
-
- **Late data injection**
|
|
98
|
-
Once the real recommendation item is available, its data is copied into the proxy target object.
|
|
99
|
-
|
|
100
|
-
This makes the transition from “unresolved” to “resolved” completely transparent.
|
|
101
|
-
|
|
102
|
-
---
|
|
103
|
-
|
|
104
|
-
### Why This Works Across Frameworks
|
|
105
|
-
|
|
106
|
-
This approach ensures that:
|
|
107
|
-
|
|
108
|
-
- the same core logic works for React and non-React frameworks
|
|
109
|
-
- recommendation items can be read synchronously
|
|
110
|
-
- async resolution integrates naturally with effects and lifecycle hooks
|
|
111
|
-
- internal SDK boundaries remain intact
|
|
112
|
-
- static backend state is shared correctly
|
|
113
|
-
|
|
114
|
-
No framework-specific logic is required in the core SDK.
|
|
115
|
-
|
|
116
|
-
---
|
|
117
|
-
|
|
118
|
-
## React Integration Helpers
|
|
119
|
-
|
|
120
|
-
The SDK provides a small React-specific helper layer to integrate recommendations into React applications while preserving the SDK’s internal async model and shared state.
|
|
121
|
-
|
|
122
|
-
This layer is intentionally thin and does **not** reimplement SDK logic. It only adapts existing SDK primitives to React’s rendering and lifecycle model.
|
|
123
|
-
|
|
124
|
-
---
|
|
125
|
-
|
|
126
|
-
### `FroomleSdkInit`
|
|
127
|
-
|
|
128
|
-
`FroomleSdkInit` is a lightweight initialization component.
|
|
129
|
-
|
|
130
|
-
Its responsibility is to trigger the resolution of pending recommendation requests once the React application is mounted.
|
|
131
|
-
|
|
132
|
-
Key characteristics:
|
|
133
|
-
|
|
134
|
-
- Calls `fulfillRecommendations()` exactly once on mount
|
|
135
|
-
- Ensures all queued recommendation requests are executed
|
|
136
|
-
- Does not render anything itself
|
|
137
|
-
- Acts purely as a lifecycle hook
|
|
138
|
-
|
|
139
|
-
This component should be mounted near the root of the React tree.
|
|
140
|
-
|
|
141
|
-
---
|
|
142
|
-
|
|
143
|
-
### `useNewCreateReco`
|
|
144
|
-
|
|
145
|
-
`useNewCreateReco` is a React hook that requests a single recommendation and binds it to component state.
|
|
146
|
-
|
|
147
|
-
It bridges three concerns:
|
|
148
|
-
|
|
149
|
-
- the SDK’s promise-like recommendation model
|
|
150
|
-
- React’s render cycle
|
|
151
|
-
- referential stability across renders
|
|
152
|
-
|
|
153
|
-
---
|
|
154
|
-
|
|
155
|
-
### Hook Behavior
|
|
156
|
-
|
|
157
|
-
The hook works as follows:
|
|
158
|
-
|
|
159
|
-
1. A recommendation request is created once using `proxyReco(req)`
|
|
160
|
-
2. The result is stored in a `ref` to ensure it is not recreated on re-renders
|
|
161
|
-
3. A `then(...)` callback is registered to detect when the recommendation resolves
|
|
162
|
-
4. When resolved, the hook forces a component update
|
|
163
|
-
5. The resolved `RecommendationItem` is returned
|
|
164
|
-
|
|
165
|
-
This allows React components to render immediately and update automatically once recommendation data becomes available.
|
|
166
|
-
|
|
167
|
-
---
|
|
168
|
-
|
|
169
|
-
### Why `useRef` Is Used
|
|
170
|
-
|
|
171
|
-
`useRef` is used instead of `useState` to ensure that:
|
|
172
|
-
|
|
173
|
-
- the recommendation request is created only once
|
|
174
|
-
- no duplicate requests are triggered
|
|
175
|
-
- static SDK state remains consistent
|
|
176
|
-
- React re-renders do not affect request identity
|
|
177
|
-
|
|
178
|
-
This is critical because the SDK relies on shared internal state.
|
|
179
|
-
|
|
180
|
-
---
|
|
181
|
-
|
|
182
|
-
If you want next, I can:
|
|
183
|
-
- add a **usage example** section
|
|
184
|
-
- document `proxyReco` explicitly
|
|
185
|
-
- or explain how multiple hooks coordinate through `fulfillRecommendations()`
|
|
186
|
-
|
|
187
|
-
## JavaScript Modules
|
|
188
|
-
|
|
189
|
-
The SDK ships multiple JavaScript modules, including:
|
|
190
|
-
|
|
191
|
-
- a **default JavaScript module**
|
|
192
|
-
- a **React-specific module**
|
|
193
|
-
- **( potentially more modules in the future )**
|
|
194
|
-
|
|
195
|
-
Both modules are distributed together but serve different integration use cases.
|
|
196
|
-
|
|
197
|
-
---
|
|
198
|
-
|
|
199
|
-
### Background Problem
|
|
200
|
-
|
|
201
|
-
Originally, the default JavaScript module and the React module were **compiled separately**.
|
|
202
|
-
|
|
203
|
-
However, the React module depended on internal logic that was also used by the default module. Because both modules were built independently, this resulted in:
|
|
204
|
-
|
|
205
|
-
- the **same internal code being compiled twice**
|
|
206
|
-
- **separate static instances** of internal classes
|
|
207
|
-
- shared state (for example backend state or configuration) no longer being shared
|
|
208
|
-
|
|
209
|
-
This caused incorrect behavior, as the SDK relies on **single, shared static state** across the entire runtime.
|
|
210
|
-
|
|
211
|
-
---
|
|
212
|
-
|
|
213
|
-
### Why Not Just Re-Export Everything
|
|
214
|
-
|
|
215
|
-
Exposing all internal logic from the default module was not an option because:
|
|
216
|
-
|
|
217
|
-
- not all internal classes are part of the public API
|
|
218
|
-
- many classes must remain hidden to prevent incorrect usage
|
|
219
|
-
- exposing everything would break the SDK’s API boundaries
|
|
220
|
-
|
|
221
|
-
The React module needed access to internal functionality **without making that functionality public**.
|
|
222
|
-
|
|
223
|
-
---
|
|
224
|
-
|
|
225
|
-
### Solution: Shared Module Chunk
|
|
226
|
-
|
|
227
|
-
To solve this, the JavaScript builds are structured so that:
|
|
228
|
-
|
|
229
|
-
- shared internal code is compiled **once**
|
|
230
|
-
- both the default module and the React module depend on the **same compiled chunk**
|
|
231
|
-
- static state is shared correctly at runtime
|
|
232
|
-
|
|
233
|
-
This is achieved by compiling the modules together and extracting shared code into a **common chunk**, which both modules import.
|
|
234
|
-
|
|
235
|
-
---
|
|
236
|
-
|
|
237
|
-
### Resulting Behavior
|
|
238
|
-
|
|
239
|
-
With this setup:
|
|
240
|
-
|
|
241
|
-
- internal singletons and static state exist only once
|
|
242
|
-
- the default module and React module remain logically separate
|
|
243
|
-
- API boundaries are preserved
|
|
244
|
-
- users can import only what is intended to be public
|
|
245
|
-
- internal code reuse is safe and consistent
|
|
246
|
-
|
|
247
|
-
From the user’s perspective, the modules behave independently, while internally they share the same core implementation.
|
|
248
|
-
|
|
249
|
-
---
|
|
250
|
-
|
|
251
|
-
## Supporting a New Framework
|
|
252
|
-
|
|
253
|
-
The SDK is designed so that **adding support for a new frontend framework does not require changes to the core logic**. Instead, framework support is implemented as a thin adaptation layer on top of the existing primitives.
|
|
254
|
-
|
|
255
|
-
This section describes what is required to integrate a new framework.
|
|
256
|
-
|
|
257
|
-
---
|
|
258
|
-
|
|
259
|
-
### Core Principles
|
|
260
|
-
|
|
261
|
-
When adding a new framework integration, the following principles must be preserved:
|
|
262
|
-
|
|
263
|
-
- **Single shared SDK state**
|
|
264
|
-
All framework integrations must share the same internal static state (backend, requests, configuration).
|
|
265
|
-
|
|
266
|
-
- **Deferred recommendation resolution**
|
|
267
|
-
Recommendation requests are created early and resolved later in a batched backend call.
|
|
268
|
-
|
|
269
|
-
- **No direct backend access**
|
|
270
|
-
Framework layers must never call backend logic directly. They rely on existing SDK functions.
|
|
271
|
-
|
|
272
|
-
- **No expansion of the public API**
|
|
273
|
-
Internal classes remain internal; the framework layer adapts behavior, not visibility.
|
|
274
|
-
|
|
275
|
-
---
|
|
276
|
-
|
|
277
|
-
### Required Building Blocks
|
|
278
|
-
|
|
279
|
-
A framework integration typically needs the following pieces.
|
|
280
|
-
|
|
281
|
-
#### 1. A Stable Recommendation Handle
|
|
282
|
-
|
|
283
|
-
The framework must receive a value that:
|
|
284
|
-
|
|
285
|
-
- can be accessed synchronously during render
|
|
286
|
-
- is referentially stable across renders
|
|
287
|
-
- updates automatically once data becomes available
|
|
288
|
-
|
|
289
|
-
This is achieved by using the existing **proxy-based recommendation item**, which behaves as both:
|
|
290
|
-
|
|
291
|
-
- a `RecommendationItem`
|
|
292
|
-
- a `PromiseLike<RecommendationItem>`
|
|
293
|
-
|
|
294
|
-
New frameworks should reuse this mechanism rather than reimplementing it.
|
|
295
|
-
|
|
296
|
-
---
|
|
297
|
-
|
|
298
|
-
#### 2. Deferred Request Registration
|
|
299
|
-
|
|
300
|
-
The framework layer must:
|
|
301
|
-
|
|
302
|
-
- create recommendation requests using the shared request queue
|
|
303
|
-
- avoid triggering backend requests immediately
|
|
304
|
-
- rely on deferred resolution
|
|
305
|
-
|
|
306
|
-
This ensures that:
|
|
307
|
-
|
|
308
|
-
- requests can be batched
|
|
309
|
-
- ordering is preserved
|
|
310
|
-
- backend calls remain predictable
|
|
311
|
-
|
|
312
|
-
---
|
|
313
|
-
#### 3. A Lifecycle Hook to Fulfill Requests
|
|
314
|
-
|
|
315
|
-
Every framework must provide **one well-defined moment** where pending recommendation requests are fulfilled.
|
|
316
|
-
|
|
317
|
-
This usually maps to:
|
|
318
|
-
|
|
319
|
-
- an application mount hook
|
|
320
|
-
- a root-level lifecycle event
|
|
321
|
-
- a global effect or initialization step
|
|
322
|
-
|
|
323
|
-
At this point, the framework integration must call:
|
|
324
|
-
|
|
325
|
-
- `fulfillRecommendations()`
|
|
326
|
-
|
|
327
|
-
This triggers the backend request and resolves all pending recommendation proxies.
|
|
328
|
-
|
|
329
|
-
---
|
|
330
|
-
|
|
331
|
-
##### How This SDK Does It
|
|
332
|
-
|
|
333
|
-
In this SDK, recommendation requests are **created lazily** during component or template execution, but they are **not fulfilled immediately**.
|
|
334
|
-
|
|
335
|
-
Instead:
|
|
336
|
-
|
|
337
|
-
- all recommendation requests are collected in a shared queue
|
|
338
|
-
- the framework integration defines a single initialization point
|
|
339
|
-
- at that point, `fulfillRecommendations()` is called once
|
|
340
|
-
|
|
341
|
-
For example:
|
|
342
|
-
|
|
343
|
-
- in React, this is done via a small root-level initialization component
|
|
344
|
-
- the call is placed inside a mount effect
|
|
345
|
-
- this ensures all components have had a chance to register their requests first
|
|
346
|
-
|
|
347
|
-
This approach guarantees that:
|
|
348
|
-
|
|
349
|
-
- all requests are batched into a single backend call
|
|
350
|
-
- request order is preserved
|
|
351
|
-
- static SDK state is shared correctly
|
|
352
|
-
- framework rendering remains predictable
|
|
353
|
-
|
|
354
|
-
The same pattern can be applied to any other framework by choosing an appropriate lifecycle boundary and invoking `fulfillRecommendations()` exactly once per render cycle or application start.
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
#### 4. Controlled Re-render or Update Trigger
|
|
358
|
-
|
|
359
|
-
Once a recommendation resolves, the framework must:
|
|
360
|
-
|
|
361
|
-
- trigger a re-render
|
|
362
|
-
- or notify the framework’s change detection system
|
|
363
|
-
|
|
364
|
-
How this is done depends on the framework:
|
|
365
|
-
|
|
366
|
-
- React: `useEffect` + state update
|
|
367
|
-
- Vue: reactive ref update
|
|
368
|
-
- Svelte: store or reactive assignment
|
|
369
|
-
- Others: equivalent lifecycle or observer mechanism
|
|
370
|
-
|
|
371
|
-
The SDK itself does **not** trigger renders; this is the responsibility of the framework adapter.
|
|
372
|
-
|
|
373
|
-
---
|
|
374
|
-
|
|
375
|
-
### What You Do *Not* Need
|
|
376
|
-
|
|
377
|
-
When supporting a new framework, you do **not** need to:
|
|
378
|
-
|
|
379
|
-
- modify `RecoBackendV2`
|
|
380
|
-
- modify DOM logic (`DomDomDom`, `FroomleDomTree`, `DomNode`)
|
|
381
|
-
- introduce framework-specific logic into the core SDK
|
|
382
|
-
- expose additional internal classes
|
|
383
|
-
|
|
384
|
-
The framework layer is purely an adapter.
|
|
385
|
-
|
|
386
|
-
---
|
|
387
|
-
|
|
388
|
-
### Minimal Integration Checklist
|
|
389
|
-
|
|
390
|
-
To support a new framework, you need:
|
|
391
|
-
|
|
392
|
-
- a wrapper that calls `proxyReco(...)`
|
|
393
|
-
- a place to call `fulfillRecommendations()`
|
|
394
|
-
- a mechanism to trigger framework updates on resolution
|
|
395
|
-
- no changes to core SDK internals
|
|
396
|
-
|
|
397
|
-
If these conditions are met, the framework will integrate correctly.
|
|
398
|
-
|
|
399
|
-
---
|
|
8
|
+
https://docs.froomle.ai/froomle-doc-main/v2/js_lib/jslib.html
|