@fluid-app/rep-sdk 0.1.2 → 0.1.3
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/dist/ContactsScreen-33AJ5XUB.js +5 -0
- package/dist/{ContactsScreen-BYXF74BO.js.map → ContactsScreen-33AJ5XUB.js.map} +1 -1
- package/dist/ContactsScreen-ATASCZO2.cjs +18 -0
- package/dist/{ContactsScreen-XZOQJVFE.cjs.map → ContactsScreen-ATASCZO2.cjs.map} +1 -1
- package/dist/CustomersScreen-E4HXBKV7.js +5 -0
- package/dist/{CustomersScreen-VS6LGULO.js.map → CustomersScreen-E4HXBKV7.js.map} +1 -1
- package/dist/CustomersScreen-XMPMKSQA.cjs +18 -0
- package/dist/{CustomersScreen-53SXRDDK.cjs.map → CustomersScreen-XMPMKSQA.cjs.map} +1 -1
- package/dist/MessagingScreen-4H7ZBO3V.js +4 -0
- package/dist/{MessagingScreen-O42JEJMW.js.map → MessagingScreen-4H7ZBO3V.js.map} +1 -1
- package/dist/MessagingScreen-UPFXQZV3.cjs +17 -0
- package/dist/{MessagingScreen-UCVLYWZB.cjs.map → MessagingScreen-UPFXQZV3.cjs.map} +1 -1
- package/dist/OrdersScreen-IPPZLEYF.js +5 -0
- package/dist/{OrdersScreen-QQJFTTSS.js.map → OrdersScreen-IPPZLEYF.js.map} +1 -1
- package/dist/OrdersScreen-X7FYUROL.cjs +18 -0
- package/dist/{OrdersScreen-WNT2WDLI.cjs.map → OrdersScreen-X7FYUROL.cjs.map} +1 -1
- package/dist/ProductsScreen-4ZIUQNUU.cjs +18 -0
- package/dist/{ProductsScreen-CTIAKS3Z.cjs.map → ProductsScreen-4ZIUQNUU.cjs.map} +1 -1
- package/dist/ProductsScreen-YTSOZW7B.js +5 -0
- package/dist/{ProductsScreen-TRIT2FE3.js.map → ProductsScreen-YTSOZW7B.js.map} +1 -1
- package/dist/chunk-424PT5DM.js +21 -0
- package/dist/chunk-424PT5DM.js.map +1 -0
- package/dist/{chunk-QUVJ3R4T.cjs → chunk-5UBEM3AX.cjs} +4 -4
- package/dist/{chunk-QUVJ3R4T.cjs.map → chunk-5UBEM3AX.cjs.map} +1 -1
- package/dist/chunk-7JMNKWPN.js +1868 -0
- package/dist/chunk-7JMNKWPN.js.map +1 -0
- package/dist/chunk-B6S6BEPL.cjs +16 -0
- package/dist/chunk-B6S6BEPL.cjs.map +1 -0
- package/dist/{chunk-WH7WZXT6.js → chunk-CMF2FYTD.js} +3 -3
- package/dist/{chunk-WH7WZXT6.js.map → chunk-CMF2FYTD.js.map} +1 -1
- package/dist/{chunk-MEOOAMH2.cjs → chunk-EOXYOOWS.cjs} +4 -4
- package/dist/{chunk-MEOOAMH2.cjs.map → chunk-EOXYOOWS.cjs.map} +1 -1
- package/dist/{chunk-YII3IXF4.cjs → chunk-FG2CI6HA.cjs} +4 -4
- package/dist/{chunk-YII3IXF4.cjs.map → chunk-FG2CI6HA.cjs.map} +1 -1
- package/dist/chunk-HDQ2JUQT.cjs +24 -0
- package/dist/chunk-HDQ2JUQT.cjs.map +1 -0
- package/dist/{chunk-MBUCXIUN.cjs → chunk-MHPK7YQ2.cjs} +4 -4
- package/dist/{chunk-MBUCXIUN.cjs.map → chunk-MHPK7YQ2.cjs.map} +1 -1
- package/dist/{chunk-2AWTZV3T.js → chunk-QZMWG7EM.js} +3 -3
- package/dist/{chunk-2AWTZV3T.js.map → chunk-QZMWG7EM.js.map} +1 -1
- package/dist/chunk-RS4OSTES.js +14 -0
- package/dist/chunk-RS4OSTES.js.map +1 -0
- package/dist/chunk-V3IMQZIG.cjs +1942 -0
- package/dist/chunk-V3IMQZIG.cjs.map +1 -0
- package/dist/{chunk-PZIHCYDD.js → chunk-WFPYEYC7.js} +3 -3
- package/dist/{chunk-PZIHCYDD.js.map → chunk-WFPYEYC7.js.map} +1 -1
- package/dist/{chunk-CXRJSGO6.js → chunk-WMBD65GH.js} +3 -3
- package/dist/{chunk-CXRJSGO6.js.map → chunk-WMBD65GH.js.map} +1 -1
- package/dist/index.cjs +1596 -1212
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2596 -0
- package/dist/index.d.ts +2596 -0
- package/dist/index.js +1256 -1011
- package/dist/index.js.map +1 -1
- package/package.json +27 -8
- package/dist/ContactsScreen-BYXF74BO.js +0 -4
- package/dist/ContactsScreen-XZOQJVFE.cjs +0 -17
- package/dist/CustomersScreen-53SXRDDK.cjs +0 -17
- package/dist/CustomersScreen-VS6LGULO.js +0 -4
- package/dist/MessagingScreen-O42JEJMW.js +0 -4
- package/dist/MessagingScreen-UCVLYWZB.cjs +0 -17
- package/dist/OrdersScreen-QQJFTTSS.js +0 -4
- package/dist/OrdersScreen-WNT2WDLI.cjs +0 -17
- package/dist/ProductsScreen-CTIAKS3Z.cjs +0 -17
- package/dist/ProductsScreen-TRIT2FE3.js +0 -4
- package/dist/chunk-DEQ3PBVX.cjs +0 -29
- package/dist/chunk-DEQ3PBVX.cjs.map +0 -1
- package/dist/chunk-JZRNKSKT.cjs +0 -19
- package/dist/chunk-JZRNKSKT.cjs.map +0 -1
- package/dist/chunk-LO2HDG6C.js +0 -26
- package/dist/chunk-LO2HDG6C.js.map +0 -1
- package/dist/chunk-PJWPO4BJ.js +0 -16
- package/dist/chunk-PJWPO4BJ.js.map +0 -1
|
@@ -0,0 +1,1942 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkHDQ2JUQT_cjs = require('./chunk-HDQ2JUQT.cjs');
|
|
4
|
+
var react = require('react');
|
|
5
|
+
var app = require('@fluid-app/fluid-messaging-ui/app');
|
|
6
|
+
var fluidMessagingUi = require('@fluid-app/fluid-messaging-ui');
|
|
7
|
+
var fluidMessagingApiClient = require('@fluid-app/fluid-messaging-api-client');
|
|
8
|
+
var reactQuery = require('@tanstack/react-query');
|
|
9
|
+
var jose = require('jose');
|
|
10
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
11
|
+
var theme_star = require('@fluid-app/rep-core/theme');
|
|
12
|
+
var registryContext = require('@fluid-app/rep-core/data-sources/registry-context');
|
|
13
|
+
var contexts = require('@fluid-app/rep-widgets/contexts');
|
|
14
|
+
var widgetUtils = require('@fluid-app/rep-core/widget-utils');
|
|
15
|
+
var widgets = require('@fluid-app/rep-widgets/widgets');
|
|
16
|
+
var fluidMessagingCore = require('@fluid-app/fluid-messaging-core');
|
|
17
|
+
|
|
18
|
+
function _interopNamespace(e) {
|
|
19
|
+
if (e && e.__esModule) return e;
|
|
20
|
+
var n = Object.create(null);
|
|
21
|
+
if (e) {
|
|
22
|
+
Object.keys(e).forEach(function (k) {
|
|
23
|
+
if (k !== 'default') {
|
|
24
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
25
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
26
|
+
enumerable: true,
|
|
27
|
+
get: function () { return e[k]; }
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
n.default = e;
|
|
33
|
+
return Object.freeze(n);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
var theme_star__namespace = /*#__PURE__*/_interopNamespace(theme_star);
|
|
37
|
+
|
|
38
|
+
// src/auth/constants.ts
|
|
39
|
+
var AUTH_CONSTANTS = {
|
|
40
|
+
/**
|
|
41
|
+
* Grace period in milliseconds to account for clock skew
|
|
42
|
+
* when checking token expiration. Tokens are considered valid
|
|
43
|
+
* if they expire within this period.
|
|
44
|
+
*/
|
|
45
|
+
TOKEN_GRACE_PERIOD_MS: 30 * 1e3,
|
|
46
|
+
// 30 seconds
|
|
47
|
+
/**
|
|
48
|
+
* Default cookie max age in seconds (9 days).
|
|
49
|
+
* This matches the typical JWT token lifetime from the Fluid API.
|
|
50
|
+
*/
|
|
51
|
+
COOKIE_MAX_AGE: 9 * 24 * 60 * 60
|
|
52
|
+
// 9 days = 777600 seconds
|
|
53
|
+
};
|
|
54
|
+
var STORAGE_KEYS = {
|
|
55
|
+
/** localStorage key for user token */
|
|
56
|
+
USER_TOKEN: "fluidUserToken",
|
|
57
|
+
/** localStorage key for company token (legacy) */
|
|
58
|
+
COMPANY_TOKEN: "fluidCompanyToken",
|
|
59
|
+
/** Cookie name for auth token */
|
|
60
|
+
AUTH_COOKIE: "auth_token"
|
|
61
|
+
};
|
|
62
|
+
var URL_PARAMS = {
|
|
63
|
+
/** URL parameter name for user token */
|
|
64
|
+
USER_TOKEN: "fluidUserToken",
|
|
65
|
+
/** URL parameter name for company token (legacy) */
|
|
66
|
+
COMPANY_TOKEN: "fluidCompanyToken"
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// src/auth/browser-utils.ts
|
|
70
|
+
function isBrowser() {
|
|
71
|
+
return typeof window !== "undefined" && typeof document !== "undefined";
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// src/auth/url-token.ts
|
|
75
|
+
function extractTokenFromUrl(tokenKey = URL_PARAMS.USER_TOKEN) {
|
|
76
|
+
if (!isBrowser()) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
const searchParams = new URLSearchParams(window.location.search);
|
|
81
|
+
return searchParams.get(tokenKey);
|
|
82
|
+
} catch {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function extractCompanyTokenFromUrl(tokenKey = URL_PARAMS.COMPANY_TOKEN) {
|
|
87
|
+
if (!isBrowser()) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
const searchParams = new URLSearchParams(window.location.search);
|
|
92
|
+
return searchParams.get(tokenKey);
|
|
93
|
+
} catch {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function cleanTokenFromUrl(tokenKey = URL_PARAMS.USER_TOKEN) {
|
|
98
|
+
if (!isBrowser()) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
try {
|
|
102
|
+
const url = new URL(window.location.href);
|
|
103
|
+
const hadToken = url.searchParams.has(tokenKey);
|
|
104
|
+
const hadCompanyToken = url.searchParams.has(URL_PARAMS.COMPANY_TOKEN);
|
|
105
|
+
url.searchParams.delete(tokenKey);
|
|
106
|
+
url.searchParams.delete(URL_PARAMS.COMPANY_TOKEN);
|
|
107
|
+
if (hadToken || hadCompanyToken) {
|
|
108
|
+
window.history.replaceState(
|
|
109
|
+
window.history.state,
|
|
110
|
+
document.title,
|
|
111
|
+
url.toString()
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
} catch (error) {
|
|
115
|
+
console.warn("[FluidAuth] Failed to clean token from URL:", error);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function hasTokenInUrl(tokenKey = URL_PARAMS.USER_TOKEN) {
|
|
119
|
+
if (!isBrowser()) {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
try {
|
|
123
|
+
const searchParams = new URLSearchParams(window.location.search);
|
|
124
|
+
return searchParams.has(tokenKey);
|
|
125
|
+
} catch {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
function extractAllTokensFromUrl(userTokenKey = URL_PARAMS.USER_TOKEN, companyTokenKey = URL_PARAMS.COMPANY_TOKEN) {
|
|
130
|
+
if (!isBrowser()) {
|
|
131
|
+
return { userToken: null, companyToken: null };
|
|
132
|
+
}
|
|
133
|
+
try {
|
|
134
|
+
const searchParams = new URLSearchParams(window.location.search);
|
|
135
|
+
return {
|
|
136
|
+
userToken: searchParams.get(userTokenKey),
|
|
137
|
+
companyToken: searchParams.get(companyTokenKey)
|
|
138
|
+
};
|
|
139
|
+
} catch {
|
|
140
|
+
return { userToken: null, companyToken: null };
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// src/auth/token-storage.ts
|
|
145
|
+
function parseCookies() {
|
|
146
|
+
if (!isBrowser()) {
|
|
147
|
+
return {};
|
|
148
|
+
}
|
|
149
|
+
const cookies = {};
|
|
150
|
+
const cookieString = document.cookie;
|
|
151
|
+
if (!cookieString) {
|
|
152
|
+
return cookies;
|
|
153
|
+
}
|
|
154
|
+
cookieString.split(";").forEach((cookie) => {
|
|
155
|
+
const [name, ...valueParts] = cookie.trim().split("=");
|
|
156
|
+
if (name) {
|
|
157
|
+
cookies[name] = decodeURIComponent(valueParts.join("="));
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
return cookies;
|
|
161
|
+
}
|
|
162
|
+
function setCookie(name, value, options = {}) {
|
|
163
|
+
if (!isBrowser()) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
const {
|
|
167
|
+
maxAge = AUTH_CONSTANTS.COOKIE_MAX_AGE,
|
|
168
|
+
path = "/",
|
|
169
|
+
sameSite = "lax",
|
|
170
|
+
secure = window.location.protocol === "https:"
|
|
171
|
+
} = options;
|
|
172
|
+
let cookieString = `${name}=${encodeURIComponent(value)}`;
|
|
173
|
+
cookieString += `; path=${path}`;
|
|
174
|
+
cookieString += `; max-age=${maxAge}`;
|
|
175
|
+
cookieString += `; samesite=${sameSite}`;
|
|
176
|
+
if (secure) {
|
|
177
|
+
cookieString += "; secure";
|
|
178
|
+
}
|
|
179
|
+
document.cookie = cookieString;
|
|
180
|
+
}
|
|
181
|
+
function deleteCookie(name, path = "/") {
|
|
182
|
+
if (!isBrowser()) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
document.cookie = `${name}=; path=${path}; max-age=0`;
|
|
186
|
+
}
|
|
187
|
+
function getStoredToken(config) {
|
|
188
|
+
if (!isBrowser()) {
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
const cookieKey = config?.cookieKey ?? STORAGE_KEYS.AUTH_COOKIE;
|
|
192
|
+
const localStorageKey = STORAGE_KEYS.USER_TOKEN;
|
|
193
|
+
const cookies = parseCookies();
|
|
194
|
+
const cookieToken = cookies[cookieKey];
|
|
195
|
+
if (cookieToken) {
|
|
196
|
+
return cookieToken;
|
|
197
|
+
}
|
|
198
|
+
try {
|
|
199
|
+
return localStorage.getItem(localStorageKey);
|
|
200
|
+
} catch {
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
function storeToken(token, config) {
|
|
205
|
+
if (!isBrowser()) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
const cookieKey = config?.cookieKey ?? STORAGE_KEYS.AUTH_COOKIE;
|
|
209
|
+
const maxAge = config?.cookieMaxAge ?? AUTH_CONSTANTS.COOKIE_MAX_AGE;
|
|
210
|
+
try {
|
|
211
|
+
const inIframe = window.self !== window.top;
|
|
212
|
+
const sameSite = inIframe ? "none" : "lax";
|
|
213
|
+
setCookie(cookieKey, token, {
|
|
214
|
+
maxAge,
|
|
215
|
+
path: "/",
|
|
216
|
+
sameSite,
|
|
217
|
+
// SameSite=None requires Secure per RFC 6265bis; browsers silently
|
|
218
|
+
// reject the cookie otherwise (e.g. HTTP localhost in an iframe).
|
|
219
|
+
secure: sameSite === "none" || window.location.protocol === "https:"
|
|
220
|
+
});
|
|
221
|
+
} catch (error) {
|
|
222
|
+
console.warn("[FluidAuth] Failed to store token in cookie:", error);
|
|
223
|
+
}
|
|
224
|
+
try {
|
|
225
|
+
localStorage.setItem(STORAGE_KEYS.USER_TOKEN, token);
|
|
226
|
+
} catch (error) {
|
|
227
|
+
console.warn("[FluidAuth] Failed to store token in localStorage:", error);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
function clearTokens(config) {
|
|
231
|
+
if (!isBrowser()) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
const cookieKey = config?.cookieKey ?? STORAGE_KEYS.AUTH_COOKIE;
|
|
235
|
+
try {
|
|
236
|
+
deleteCookie(cookieKey);
|
|
237
|
+
} catch {
|
|
238
|
+
}
|
|
239
|
+
try {
|
|
240
|
+
localStorage.removeItem(STORAGE_KEYS.USER_TOKEN);
|
|
241
|
+
localStorage.removeItem(STORAGE_KEYS.COMPANY_TOKEN);
|
|
242
|
+
} catch {
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
function hasStoredToken(config) {
|
|
246
|
+
return getStoredToken(config) !== null;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// src/auth/types.ts
|
|
250
|
+
var USER_TYPES = {
|
|
251
|
+
admin: "admin",
|
|
252
|
+
rep: "rep",
|
|
253
|
+
root_admin: "root_admin",
|
|
254
|
+
customer: "customer"
|
|
255
|
+
};
|
|
256
|
+
function isUserType(value) {
|
|
257
|
+
return Object.values(USER_TYPES).includes(value);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// src/auth/token-utils.ts
|
|
261
|
+
function extractPayloadFromJose(decoded) {
|
|
262
|
+
const rawUserType = decoded.user_type;
|
|
263
|
+
const rawOgUserType = decoded.og_user_type;
|
|
264
|
+
return {
|
|
265
|
+
id: typeof decoded.id === "number" ? decoded.id : void 0,
|
|
266
|
+
email: typeof decoded.email === "string" ? decoded.email : void 0,
|
|
267
|
+
full_name: typeof decoded.full_name === "string" ? decoded.full_name : void 0,
|
|
268
|
+
user_type: typeof rawUserType === "string" && isUserType(rawUserType) ? rawUserType : "rep",
|
|
269
|
+
og_user_type: typeof rawOgUserType === "string" && isUserType(rawOgUserType) ? rawOgUserType : void 0,
|
|
270
|
+
company_id: typeof decoded.company_id === "number" ? decoded.company_id : void 0,
|
|
271
|
+
exp: decoded.exp,
|
|
272
|
+
auth_type: typeof decoded.auth_type === "string" ? decoded.auth_type : void 0
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
function decodeToken(token) {
|
|
276
|
+
try {
|
|
277
|
+
const decoded = jose.decodeJwt(token);
|
|
278
|
+
return extractPayloadFromJose(decoded);
|
|
279
|
+
} catch (error) {
|
|
280
|
+
console.error("[FluidAuth] Failed to decode JWT token:", error);
|
|
281
|
+
return null;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
function isTokenExpired(token, gracePeriodMs = AUTH_CONSTANTS.TOKEN_GRACE_PERIOD_MS) {
|
|
285
|
+
try {
|
|
286
|
+
const decoded = jose.decodeJwt(token);
|
|
287
|
+
if (!decoded.exp) {
|
|
288
|
+
return false;
|
|
289
|
+
}
|
|
290
|
+
const expirationTime = decoded.exp * 1e3;
|
|
291
|
+
const currentTime = Date.now();
|
|
292
|
+
return currentTime > expirationTime + gracePeriodMs;
|
|
293
|
+
} catch {
|
|
294
|
+
return true;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
function validateToken(token, gracePeriodMs = AUTH_CONSTANTS.TOKEN_GRACE_PERIOD_MS) {
|
|
298
|
+
if (!token || token.trim() === "") {
|
|
299
|
+
return {
|
|
300
|
+
isValid: false,
|
|
301
|
+
error: "Token is empty or not provided"
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
const payload = decodeToken(token);
|
|
305
|
+
if (!payload) {
|
|
306
|
+
return {
|
|
307
|
+
isValid: false,
|
|
308
|
+
error: "Token has invalid format"
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
if (isTokenExpired(token, gracePeriodMs)) {
|
|
312
|
+
return {
|
|
313
|
+
isValid: false,
|
|
314
|
+
payload,
|
|
315
|
+
error: "Token has expired"
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
return {
|
|
319
|
+
isValid: true,
|
|
320
|
+
payload
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
function isValidToken(result) {
|
|
324
|
+
return result.isValid === true;
|
|
325
|
+
}
|
|
326
|
+
function getTokenExpiration(token) {
|
|
327
|
+
try {
|
|
328
|
+
const decoded = jose.decodeJwt(token);
|
|
329
|
+
if (!decoded.exp) {
|
|
330
|
+
return null;
|
|
331
|
+
}
|
|
332
|
+
return new Date(decoded.exp * 1e3);
|
|
333
|
+
} catch {
|
|
334
|
+
return null;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
function getTokenTimeRemaining(token) {
|
|
338
|
+
try {
|
|
339
|
+
const decoded = jose.decodeJwt(token);
|
|
340
|
+
if (!decoded.exp) {
|
|
341
|
+
return Infinity;
|
|
342
|
+
}
|
|
343
|
+
const expirationTime = decoded.exp * 1e3;
|
|
344
|
+
const remaining = expirationTime - Date.now();
|
|
345
|
+
return Math.max(0, remaining);
|
|
346
|
+
} catch {
|
|
347
|
+
return 0;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
async function verifyToken(token, jwksUrl) {
|
|
351
|
+
try {
|
|
352
|
+
const JWKS = jose.createRemoteJWKSet(new URL(jwksUrl));
|
|
353
|
+
const { payload } = await jose.jwtVerify(token, JWKS);
|
|
354
|
+
const decoded = payload;
|
|
355
|
+
return extractPayloadFromJose(decoded);
|
|
356
|
+
} catch (error) {
|
|
357
|
+
console.error("[FluidAuth] JWT signature verification failed:", error);
|
|
358
|
+
return null;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// src/auth/dev-utils.ts
|
|
363
|
+
function isDevBypassActive(devBypass) {
|
|
364
|
+
if (!devBypass) return false;
|
|
365
|
+
try {
|
|
366
|
+
return undefined.DEV === true;
|
|
367
|
+
} catch {
|
|
368
|
+
return false;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
function createDevUser() {
|
|
372
|
+
return {
|
|
373
|
+
id: 99999,
|
|
374
|
+
// Dev placeholder — avoids falsy 0
|
|
375
|
+
email: "dev@localhost",
|
|
376
|
+
full_name: "Dev User",
|
|
377
|
+
user_type: USER_TYPES.rep,
|
|
378
|
+
og_user_type: void 0,
|
|
379
|
+
company_id: 99999,
|
|
380
|
+
// Dev placeholder — avoids falsy 0
|
|
381
|
+
exp: void 0,
|
|
382
|
+
// Never expires
|
|
383
|
+
auth_type: "dev_bypass"
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// src/auth/auth-redirect.ts
|
|
388
|
+
var DEFAULT_AUTH_URL = "https://auth.fluid.app";
|
|
389
|
+
var AUTH_REDIRECT_TOKEN_KEY = "jwt";
|
|
390
|
+
var REDIRECT_TIMESTAMP_KEY = "__fluid_auth_redirect_ts";
|
|
391
|
+
var REDIRECT_COOLDOWN_S = 10;
|
|
392
|
+
function isRedirectLoop() {
|
|
393
|
+
try {
|
|
394
|
+
const ts = sessionStorage.getItem(REDIRECT_TIMESTAMP_KEY);
|
|
395
|
+
if (!ts) return false;
|
|
396
|
+
const elapsed = (Date.now() - Number(ts)) / 1e3;
|
|
397
|
+
return elapsed < REDIRECT_COOLDOWN_S;
|
|
398
|
+
} catch {
|
|
399
|
+
return false;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
function markRedirect() {
|
|
403
|
+
try {
|
|
404
|
+
sessionStorage.setItem(REDIRECT_TIMESTAMP_KEY, String(Date.now()));
|
|
405
|
+
} catch {
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
function createDefaultAuthRedirect(authUrl) {
|
|
409
|
+
return () => {
|
|
410
|
+
if (isRedirectLoop()) {
|
|
411
|
+
console.warn(
|
|
412
|
+
"[FluidAuth] Auth redirect suppressed \u2014 possible redirect loop. Check that your auth server returns a token accepted by the API."
|
|
413
|
+
);
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
markRedirect();
|
|
417
|
+
const base = authUrl ?? DEFAULT_AUTH_URL;
|
|
418
|
+
const currentUrl = encodeURIComponent(window.location.href);
|
|
419
|
+
window.location.href = `${base}/?redirect_url=${currentUrl}`;
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
function resolveAuthFailureHandler(onAuthFailure, authUrl) {
|
|
423
|
+
return onAuthFailure ?? createDefaultAuthRedirect(authUrl);
|
|
424
|
+
}
|
|
425
|
+
var FluidAuthContext = react.createContext(null);
|
|
426
|
+
function FluidAuthProvider({
|
|
427
|
+
children,
|
|
428
|
+
config
|
|
429
|
+
}) {
|
|
430
|
+
const configRef = react.useRef(config);
|
|
431
|
+
configRef.current = config;
|
|
432
|
+
const [isLoading, setIsLoading] = react.useState(true);
|
|
433
|
+
const [token, setToken] = react.useState(null);
|
|
434
|
+
const [user, setUser] = react.useState(null);
|
|
435
|
+
const [error, setError] = react.useState(null);
|
|
436
|
+
react.useEffect(() => {
|
|
437
|
+
const initializeAuth = async () => {
|
|
438
|
+
const handleAuthFailure = () => {
|
|
439
|
+
const current = configRef.current;
|
|
440
|
+
const handler = resolveAuthFailureHandler(
|
|
441
|
+
current?.onAuthFailure,
|
|
442
|
+
current?.authUrl
|
|
443
|
+
);
|
|
444
|
+
handler();
|
|
445
|
+
};
|
|
446
|
+
try {
|
|
447
|
+
if (isDevBypassActive(config?.devBypass)) {
|
|
448
|
+
const envToken = undefined.VITE_DEV_TOKEN;
|
|
449
|
+
if (envToken) {
|
|
450
|
+
const validation = validateToken(envToken, config?.gracePeriodMs);
|
|
451
|
+
if (validation.isValid && validation.payload) {
|
|
452
|
+
storeToken(envToken, config);
|
|
453
|
+
setToken(envToken);
|
|
454
|
+
setUser(validation.payload);
|
|
455
|
+
setError(null);
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
console.warn(
|
|
459
|
+
"[FluidAuth] VITE_DEV_TOKEN is invalid or expired, falling back to mock user"
|
|
460
|
+
);
|
|
461
|
+
}
|
|
462
|
+
console.warn(
|
|
463
|
+
"[FluidAuth] Dev bypass active - using mock user. API calls will fail without a real token."
|
|
464
|
+
);
|
|
465
|
+
const devUser = createDevUser();
|
|
466
|
+
setToken(null);
|
|
467
|
+
setUser(devUser);
|
|
468
|
+
setError(null);
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
const tokenKey = config?.tokenKey ?? "fluidUserToken";
|
|
472
|
+
let candidateToken = extractTokenFromUrl(tokenKey);
|
|
473
|
+
if (!candidateToken && tokenKey !== AUTH_REDIRECT_TOKEN_KEY) {
|
|
474
|
+
candidateToken = extractTokenFromUrl(AUTH_REDIRECT_TOKEN_KEY);
|
|
475
|
+
}
|
|
476
|
+
cleanTokenFromUrl(tokenKey);
|
|
477
|
+
cleanTokenFromUrl(AUTH_REDIRECT_TOKEN_KEY);
|
|
478
|
+
if (!candidateToken) {
|
|
479
|
+
candidateToken = getStoredToken(config);
|
|
480
|
+
}
|
|
481
|
+
if (candidateToken) {
|
|
482
|
+
let payload = null;
|
|
483
|
+
if (config?.jwksUrl) {
|
|
484
|
+
payload = await verifyToken(candidateToken, config.jwksUrl);
|
|
485
|
+
if (!payload) {
|
|
486
|
+
clearTokens(config);
|
|
487
|
+
setToken(null);
|
|
488
|
+
setUser(null);
|
|
489
|
+
setError(new Error("JWT signature verification failed"));
|
|
490
|
+
handleAuthFailure();
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
if (isTokenExpired(candidateToken, config?.gracePeriodMs)) {
|
|
494
|
+
clearTokens(config);
|
|
495
|
+
setToken(null);
|
|
496
|
+
setUser(null);
|
|
497
|
+
setError(new Error("Token has expired"));
|
|
498
|
+
handleAuthFailure();
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
} else {
|
|
502
|
+
const validation = validateToken(
|
|
503
|
+
candidateToken,
|
|
504
|
+
config?.gracePeriodMs
|
|
505
|
+
);
|
|
506
|
+
if (validation.isValid && validation.payload) {
|
|
507
|
+
payload = validation.payload;
|
|
508
|
+
} else {
|
|
509
|
+
clearTokens(config);
|
|
510
|
+
setToken(null);
|
|
511
|
+
setUser(null);
|
|
512
|
+
setError(new Error(validation.error ?? "Invalid token"));
|
|
513
|
+
handleAuthFailure();
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
storeToken(candidateToken, config);
|
|
518
|
+
setToken(candidateToken);
|
|
519
|
+
setUser(payload);
|
|
520
|
+
setError(null);
|
|
521
|
+
} else {
|
|
522
|
+
setToken(null);
|
|
523
|
+
setUser(null);
|
|
524
|
+
setError(new Error("No authentication token found"));
|
|
525
|
+
handleAuthFailure();
|
|
526
|
+
}
|
|
527
|
+
} catch (err) {
|
|
528
|
+
const error2 = err instanceof Error ? err : new Error("Authentication error");
|
|
529
|
+
setError(error2);
|
|
530
|
+
setToken(null);
|
|
531
|
+
setUser(null);
|
|
532
|
+
handleAuthFailure();
|
|
533
|
+
} finally {
|
|
534
|
+
setIsLoading(false);
|
|
535
|
+
}
|
|
536
|
+
};
|
|
537
|
+
void initializeAuth();
|
|
538
|
+
}, []);
|
|
539
|
+
const clearAuth = react.useCallback(() => {
|
|
540
|
+
clearTokens(configRef.current);
|
|
541
|
+
setToken(null);
|
|
542
|
+
setUser(null);
|
|
543
|
+
setError(null);
|
|
544
|
+
}, []);
|
|
545
|
+
const contextValue = react.useMemo(
|
|
546
|
+
() => ({
|
|
547
|
+
isAuthenticated: user !== null,
|
|
548
|
+
isLoading,
|
|
549
|
+
user,
|
|
550
|
+
token,
|
|
551
|
+
clearAuth,
|
|
552
|
+
error
|
|
553
|
+
}),
|
|
554
|
+
[token, isLoading, user, clearAuth, error]
|
|
555
|
+
);
|
|
556
|
+
return /* @__PURE__ */ jsxRuntime.jsx(FluidAuthContext.Provider, { value: contextValue, children });
|
|
557
|
+
}
|
|
558
|
+
function useFluidAuthContext() {
|
|
559
|
+
const context = react.useContext(FluidAuthContext);
|
|
560
|
+
if (!context) {
|
|
561
|
+
throw new Error(
|
|
562
|
+
"useFluidAuthContext must be used within a FluidAuthProvider. Wrap your app with <FluidAuthProvider> to use authentication features."
|
|
563
|
+
);
|
|
564
|
+
}
|
|
565
|
+
return context;
|
|
566
|
+
}
|
|
567
|
+
function useFluidAuthOptional() {
|
|
568
|
+
return react.useContext(FluidAuthContext);
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
// ../../platform/api-client-core/src/fetch-client.ts
|
|
572
|
+
var ApiError = class _ApiError extends Error {
|
|
573
|
+
status;
|
|
574
|
+
data;
|
|
575
|
+
constructor(message, status, data) {
|
|
576
|
+
super(message);
|
|
577
|
+
this.name = "ApiError";
|
|
578
|
+
this.status = status;
|
|
579
|
+
this.data = data;
|
|
580
|
+
if ("captureStackTrace" in Error) {
|
|
581
|
+
Error.captureStackTrace(this, _ApiError);
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
toJSON() {
|
|
585
|
+
return {
|
|
586
|
+
name: this.name,
|
|
587
|
+
message: this.message,
|
|
588
|
+
status: this.status,
|
|
589
|
+
data: this.data
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
};
|
|
593
|
+
function createFetchClient(config) {
|
|
594
|
+
const { baseUrl, getAuthToken, onAuthError, defaultHeaders = {} } = config;
|
|
595
|
+
async function buildHeaders(customHeaders) {
|
|
596
|
+
const headers = {
|
|
597
|
+
"Content-Type": "application/json",
|
|
598
|
+
...defaultHeaders,
|
|
599
|
+
...customHeaders
|
|
600
|
+
};
|
|
601
|
+
if (getAuthToken) {
|
|
602
|
+
const token = await getAuthToken();
|
|
603
|
+
if (token) {
|
|
604
|
+
headers.Authorization = `Bearer ${token}`;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
return headers;
|
|
608
|
+
}
|
|
609
|
+
function joinUrl(endpoint) {
|
|
610
|
+
return `${baseUrl}${endpoint}`;
|
|
611
|
+
}
|
|
612
|
+
function buildUrl(endpoint, params) {
|
|
613
|
+
const fullUrl = joinUrl(endpoint);
|
|
614
|
+
if (!params || Object.keys(params).length === 0) {
|
|
615
|
+
return fullUrl;
|
|
616
|
+
}
|
|
617
|
+
const queryString = new URLSearchParams();
|
|
618
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
619
|
+
if (value === void 0 || value === null) {
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
if (Array.isArray(value)) {
|
|
623
|
+
value.forEach((item) => queryString.append(`${key}[]`, String(item)));
|
|
624
|
+
} else if (typeof value === "object") {
|
|
625
|
+
Object.entries(value).forEach(([subKey, subValue]) => {
|
|
626
|
+
if (subValue === void 0 || subValue === null) {
|
|
627
|
+
return;
|
|
628
|
+
}
|
|
629
|
+
if (Array.isArray(subValue)) {
|
|
630
|
+
subValue.forEach(
|
|
631
|
+
(item) => queryString.append(`${key}[${subKey}][]`, String(item))
|
|
632
|
+
);
|
|
633
|
+
} else {
|
|
634
|
+
queryString.append(`${key}[${subKey}]`, String(subValue));
|
|
635
|
+
}
|
|
636
|
+
});
|
|
637
|
+
} else {
|
|
638
|
+
queryString.append(key, String(value));
|
|
639
|
+
}
|
|
640
|
+
});
|
|
641
|
+
const qs = queryString.toString();
|
|
642
|
+
return qs ? `${fullUrl}?${qs}` : fullUrl;
|
|
643
|
+
}
|
|
644
|
+
async function handleResponse(response, method, _url) {
|
|
645
|
+
if (response.status === 401 && onAuthError) {
|
|
646
|
+
onAuthError();
|
|
647
|
+
}
|
|
648
|
+
if (!response.ok) {
|
|
649
|
+
try {
|
|
650
|
+
const contentType2 = response.headers.get("content-type");
|
|
651
|
+
if (contentType2?.includes("application/json")) {
|
|
652
|
+
const data = await response.json();
|
|
653
|
+
throw new ApiError(
|
|
654
|
+
data.message || data.error_message || `${method} request failed`,
|
|
655
|
+
response.status,
|
|
656
|
+
data.errors || data
|
|
657
|
+
);
|
|
658
|
+
} else {
|
|
659
|
+
throw new ApiError(
|
|
660
|
+
`${method} request failed with status ${response.status}`,
|
|
661
|
+
response.status,
|
|
662
|
+
null
|
|
663
|
+
);
|
|
664
|
+
}
|
|
665
|
+
} catch (error) {
|
|
666
|
+
if (error instanceof ApiError) {
|
|
667
|
+
throw error;
|
|
668
|
+
}
|
|
669
|
+
throw new ApiError(
|
|
670
|
+
`${method} request failed with status ${response.status}`,
|
|
671
|
+
response.status,
|
|
672
|
+
null
|
|
673
|
+
);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
if (response.status === 204 || response.headers.get("content-length") === "0") {
|
|
677
|
+
return null;
|
|
678
|
+
}
|
|
679
|
+
const contentType = response.headers.get("content-type");
|
|
680
|
+
if (contentType?.includes("application/json")) {
|
|
681
|
+
try {
|
|
682
|
+
const data = await response.json();
|
|
683
|
+
return data;
|
|
684
|
+
} catch {
|
|
685
|
+
try {
|
|
686
|
+
const text = await response.text();
|
|
687
|
+
return text;
|
|
688
|
+
} catch {
|
|
689
|
+
return null;
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
return null;
|
|
694
|
+
}
|
|
695
|
+
async function request(endpoint, options = {}) {
|
|
696
|
+
const {
|
|
697
|
+
method = "GET",
|
|
698
|
+
headers: customHeaders,
|
|
699
|
+
params,
|
|
700
|
+
body,
|
|
701
|
+
signal
|
|
702
|
+
} = options;
|
|
703
|
+
const url = params ? buildUrl(endpoint, params) : joinUrl(endpoint);
|
|
704
|
+
const headers = await buildHeaders(customHeaders);
|
|
705
|
+
let response;
|
|
706
|
+
try {
|
|
707
|
+
const fetchOptions = { method, headers };
|
|
708
|
+
const serializedBody = body && method !== "GET" ? JSON.stringify(body) : null;
|
|
709
|
+
if (serializedBody) fetchOptions.body = serializedBody;
|
|
710
|
+
if (signal) fetchOptions.signal = signal;
|
|
711
|
+
response = await fetch(url, fetchOptions);
|
|
712
|
+
} catch (networkError) {
|
|
713
|
+
throw new ApiError(
|
|
714
|
+
`Network error: ${networkError instanceof Error ? networkError.message : "Unknown network error"}`,
|
|
715
|
+
0,
|
|
716
|
+
null
|
|
717
|
+
);
|
|
718
|
+
}
|
|
719
|
+
return handleResponse(response, method);
|
|
720
|
+
}
|
|
721
|
+
async function requestWithFormData(endpoint, formData, options = {}) {
|
|
722
|
+
const { method = "POST", headers: customHeaders, signal } = options;
|
|
723
|
+
const url = joinUrl(endpoint);
|
|
724
|
+
const headers = await buildHeaders(customHeaders);
|
|
725
|
+
delete headers["Content-Type"];
|
|
726
|
+
let response;
|
|
727
|
+
try {
|
|
728
|
+
const fetchOptions = { method, headers, body: formData };
|
|
729
|
+
if (signal) fetchOptions.signal = signal;
|
|
730
|
+
response = await fetch(url, fetchOptions);
|
|
731
|
+
} catch (networkError) {
|
|
732
|
+
throw new ApiError(
|
|
733
|
+
`Network error: ${networkError instanceof Error ? networkError.message : "Unknown network error"}`,
|
|
734
|
+
0,
|
|
735
|
+
null
|
|
736
|
+
);
|
|
737
|
+
}
|
|
738
|
+
return handleResponse(response, method);
|
|
739
|
+
}
|
|
740
|
+
return {
|
|
741
|
+
request,
|
|
742
|
+
requestWithFormData,
|
|
743
|
+
// Convenience methods for common HTTP verbs
|
|
744
|
+
get: (endpoint, params, options) => request(endpoint, {
|
|
745
|
+
...options,
|
|
746
|
+
method: "GET",
|
|
747
|
+
...params && { params }
|
|
748
|
+
}),
|
|
749
|
+
post: (endpoint, body, options) => request(endpoint, {
|
|
750
|
+
...options,
|
|
751
|
+
method: "POST",
|
|
752
|
+
body
|
|
753
|
+
}),
|
|
754
|
+
put: (endpoint, body, options) => request(endpoint, {
|
|
755
|
+
...options,
|
|
756
|
+
method: "PUT",
|
|
757
|
+
body
|
|
758
|
+
}),
|
|
759
|
+
patch: (endpoint, body, options) => request(endpoint, {
|
|
760
|
+
...options,
|
|
761
|
+
method: "PATCH",
|
|
762
|
+
body
|
|
763
|
+
}),
|
|
764
|
+
delete: (endpoint, options) => request(endpoint, {
|
|
765
|
+
...options,
|
|
766
|
+
method: "DELETE"
|
|
767
|
+
})
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
// ../../fluidos/api-client/src/namespaces/fluid_os.ts
|
|
772
|
+
var fluid_os_exports = {};
|
|
773
|
+
chunkHDQ2JUQT_cjs.__export(fluid_os_exports, {
|
|
774
|
+
createFluidOSDefinition: () => createFluidOSDefinition,
|
|
775
|
+
createFluidOSNavigation: () => createFluidOSNavigation,
|
|
776
|
+
createFluidOSNavigationItem: () => createFluidOSNavigationItem,
|
|
777
|
+
createFluidOSProfile: () => createFluidOSProfile,
|
|
778
|
+
createFluidOSScreen: () => createFluidOSScreen,
|
|
779
|
+
createFluidOSTheme: () => createFluidOSTheme,
|
|
780
|
+
createFluidOSVersion: () => createFluidOSVersion,
|
|
781
|
+
deleteFluidOSDefinition: () => deleteFluidOSDefinition,
|
|
782
|
+
deleteFluidOSNavigation: () => deleteFluidOSNavigation,
|
|
783
|
+
deleteFluidOSNavigationItem: () => deleteFluidOSNavigationItem,
|
|
784
|
+
deleteFluidOSProfile: () => deleteFluidOSProfile,
|
|
785
|
+
deleteFluidOSScreen: () => deleteFluidOSScreen,
|
|
786
|
+
deleteFluidOSTheme: () => deleteFluidOSTheme,
|
|
787
|
+
getDefaultFluidOSProfile: () => getDefaultFluidOSProfile,
|
|
788
|
+
getFluidOSDefinition: () => getFluidOSDefinition,
|
|
789
|
+
getFluidOSManifest: () => getFluidOSManifest,
|
|
790
|
+
getFluidOSNavigation: () => getFluidOSNavigation,
|
|
791
|
+
getFluidOSNavigationItem: () => getFluidOSNavigationItem,
|
|
792
|
+
getFluidOSProfile: () => getFluidOSProfile,
|
|
793
|
+
getFluidOSScreen: () => getFluidOSScreen,
|
|
794
|
+
getFluidOSTheme: () => getFluidOSTheme,
|
|
795
|
+
getFluidOSVersion: () => getFluidOSVersion,
|
|
796
|
+
listFluidOSDefinitions: () => listFluidOSDefinitions,
|
|
797
|
+
listFluidOSNavigationItems: () => listFluidOSNavigationItems,
|
|
798
|
+
listFluidOSNavigations: () => listFluidOSNavigations,
|
|
799
|
+
listFluidOSProfiles: () => listFluidOSProfiles,
|
|
800
|
+
listFluidOSScreens: () => listFluidOSScreens,
|
|
801
|
+
listFluidOSThemes: () => listFluidOSThemes,
|
|
802
|
+
listFluidOSVersions: () => listFluidOSVersions,
|
|
803
|
+
updateFluidOSDefinition: () => updateFluidOSDefinition,
|
|
804
|
+
updateFluidOSNavigation: () => updateFluidOSNavigation,
|
|
805
|
+
updateFluidOSNavigationItem: () => updateFluidOSNavigationItem,
|
|
806
|
+
updateFluidOSProfile: () => updateFluidOSProfile,
|
|
807
|
+
updateFluidOSScreen: () => updateFluidOSScreen,
|
|
808
|
+
updateFluidOSTheme: () => updateFluidOSTheme,
|
|
809
|
+
updateFluidOSVersion: () => updateFluidOSVersion
|
|
810
|
+
});
|
|
811
|
+
async function listFluidOSDefinitions(client, params) {
|
|
812
|
+
return client.get(`/api/company/fluid_os/definitions`, params);
|
|
813
|
+
}
|
|
814
|
+
async function createFluidOSDefinition(client, body) {
|
|
815
|
+
return client.post(`/api/company/fluid_os/definitions`, body);
|
|
816
|
+
}
|
|
817
|
+
async function getFluidOSDefinition(client, id) {
|
|
818
|
+
return client.get(`/api/company/fluid_os/definitions/${id}`);
|
|
819
|
+
}
|
|
820
|
+
async function updateFluidOSDefinition(client, id, body) {
|
|
821
|
+
return client.put(`/api/company/fluid_os/definitions/${id}`, body);
|
|
822
|
+
}
|
|
823
|
+
async function deleteFluidOSDefinition(client, id) {
|
|
824
|
+
return client.delete(`/api/company/fluid_os/definitions/${id}`);
|
|
825
|
+
}
|
|
826
|
+
async function listFluidOSNavigationItems(client, definition_id, navigation_id) {
|
|
827
|
+
return client.get(
|
|
828
|
+
`/api/company/fluid_os/definitions/${definition_id}/navigations/${navigation_id}/navigation_items`
|
|
829
|
+
);
|
|
830
|
+
}
|
|
831
|
+
async function createFluidOSNavigationItem(client, definition_id, navigation_id, body) {
|
|
832
|
+
return client.post(
|
|
833
|
+
`/api/company/fluid_os/definitions/${definition_id}/navigations/${navigation_id}/navigation_items`,
|
|
834
|
+
body
|
|
835
|
+
);
|
|
836
|
+
}
|
|
837
|
+
async function getFluidOSNavigationItem(client, definition_id, navigation_id, id) {
|
|
838
|
+
return client.get(
|
|
839
|
+
`/api/company/fluid_os/definitions/${definition_id}/navigations/${navigation_id}/navigation_items/${id}`
|
|
840
|
+
);
|
|
841
|
+
}
|
|
842
|
+
async function updateFluidOSNavigationItem(client, definition_id, navigation_id, id, body) {
|
|
843
|
+
return client.put(
|
|
844
|
+
`/api/company/fluid_os/definitions/${definition_id}/navigations/${navigation_id}/navigation_items/${id}`,
|
|
845
|
+
body
|
|
846
|
+
);
|
|
847
|
+
}
|
|
848
|
+
async function deleteFluidOSNavigationItem(client, definition_id, navigation_id, id) {
|
|
849
|
+
return client.delete(
|
|
850
|
+
`/api/company/fluid_os/definitions/${definition_id}/navigations/${navigation_id}/navigation_items/${id}`
|
|
851
|
+
);
|
|
852
|
+
}
|
|
853
|
+
async function listFluidOSNavigations(client, definition_id, params) {
|
|
854
|
+
return client.get(
|
|
855
|
+
`/api/company/fluid_os/definitions/${definition_id}/navigations`,
|
|
856
|
+
params
|
|
857
|
+
);
|
|
858
|
+
}
|
|
859
|
+
async function createFluidOSNavigation(client, definition_id, body) {
|
|
860
|
+
return client.post(
|
|
861
|
+
`/api/company/fluid_os/definitions/${definition_id}/navigations`,
|
|
862
|
+
body
|
|
863
|
+
);
|
|
864
|
+
}
|
|
865
|
+
async function getFluidOSNavigation(client, definition_id, id) {
|
|
866
|
+
return client.get(
|
|
867
|
+
`/api/company/fluid_os/definitions/${definition_id}/navigations/${id}`
|
|
868
|
+
);
|
|
869
|
+
}
|
|
870
|
+
async function updateFluidOSNavigation(client, definition_id, id, body) {
|
|
871
|
+
return client.put(
|
|
872
|
+
`/api/company/fluid_os/definitions/${definition_id}/navigations/${id}`,
|
|
873
|
+
body
|
|
874
|
+
);
|
|
875
|
+
}
|
|
876
|
+
async function deleteFluidOSNavigation(client, definition_id, id) {
|
|
877
|
+
return client.delete(
|
|
878
|
+
`/api/company/fluid_os/definitions/${definition_id}/navigations/${id}`
|
|
879
|
+
);
|
|
880
|
+
}
|
|
881
|
+
async function listFluidOSProfiles(client, definition_id, params) {
|
|
882
|
+
return client.get(
|
|
883
|
+
`/api/company/fluid_os/definitions/${definition_id}/profiles`,
|
|
884
|
+
params
|
|
885
|
+
);
|
|
886
|
+
}
|
|
887
|
+
async function createFluidOSProfile(client, definition_id, body) {
|
|
888
|
+
return client.post(
|
|
889
|
+
`/api/company/fluid_os/definitions/${definition_id}/profiles`,
|
|
890
|
+
body
|
|
891
|
+
);
|
|
892
|
+
}
|
|
893
|
+
async function getDefaultFluidOSProfile(client, definition_id) {
|
|
894
|
+
return client.get(
|
|
895
|
+
`/api/company/fluid_os/definitions/${definition_id}/profiles/default`
|
|
896
|
+
);
|
|
897
|
+
}
|
|
898
|
+
async function getFluidOSProfile(client, definition_id, id) {
|
|
899
|
+
return client.get(
|
|
900
|
+
`/api/company/fluid_os/definitions/${definition_id}/profiles/${id}`
|
|
901
|
+
);
|
|
902
|
+
}
|
|
903
|
+
async function updateFluidOSProfile(client, definition_id, id, body) {
|
|
904
|
+
return client.put(
|
|
905
|
+
`/api/company/fluid_os/definitions/${definition_id}/profiles/${id}`,
|
|
906
|
+
body
|
|
907
|
+
);
|
|
908
|
+
}
|
|
909
|
+
async function deleteFluidOSProfile(client, definition_id, id) {
|
|
910
|
+
return client.delete(
|
|
911
|
+
`/api/company/fluid_os/definitions/${definition_id}/profiles/${id}`
|
|
912
|
+
);
|
|
913
|
+
}
|
|
914
|
+
async function getFluidOSManifest(client, params) {
|
|
915
|
+
return client.get(`/api/fluid_os/definitions/active`, params);
|
|
916
|
+
}
|
|
917
|
+
async function listFluidOSScreens(client, definition_id, params) {
|
|
918
|
+
return client.get(
|
|
919
|
+
`/api/company/fluid_os/definitions/${definition_id}/screens`,
|
|
920
|
+
params
|
|
921
|
+
);
|
|
922
|
+
}
|
|
923
|
+
async function createFluidOSScreen(client, definition_id, body) {
|
|
924
|
+
return client.post(
|
|
925
|
+
`/api/company/fluid_os/definitions/${definition_id}/screens`,
|
|
926
|
+
body
|
|
927
|
+
);
|
|
928
|
+
}
|
|
929
|
+
async function getFluidOSScreen(client, definition_id, id) {
|
|
930
|
+
return client.get(
|
|
931
|
+
`/api/company/fluid_os/definitions/${definition_id}/screens/${id}`
|
|
932
|
+
);
|
|
933
|
+
}
|
|
934
|
+
async function updateFluidOSScreen(client, definition_id, id, body) {
|
|
935
|
+
return client.put(
|
|
936
|
+
`/api/company/fluid_os/definitions/${definition_id}/screens/${id}`,
|
|
937
|
+
body
|
|
938
|
+
);
|
|
939
|
+
}
|
|
940
|
+
async function deleteFluidOSScreen(client, definition_id, id) {
|
|
941
|
+
return client.delete(
|
|
942
|
+
`/api/company/fluid_os/definitions/${definition_id}/screens/${id}`
|
|
943
|
+
);
|
|
944
|
+
}
|
|
945
|
+
async function listFluidOSThemes(client, definition_id, params) {
|
|
946
|
+
return client.get(
|
|
947
|
+
`/api/company/fluid_os/definitions/${definition_id}/themes`,
|
|
948
|
+
params
|
|
949
|
+
);
|
|
950
|
+
}
|
|
951
|
+
async function createFluidOSTheme(client, definition_id, body) {
|
|
952
|
+
return client.post(
|
|
953
|
+
`/api/company/fluid_os/definitions/${definition_id}/themes`,
|
|
954
|
+
body
|
|
955
|
+
);
|
|
956
|
+
}
|
|
957
|
+
async function getFluidOSTheme(client, definition_id, id) {
|
|
958
|
+
return client.get(
|
|
959
|
+
`/api/company/fluid_os/definitions/${definition_id}/themes/${id}`
|
|
960
|
+
);
|
|
961
|
+
}
|
|
962
|
+
async function updateFluidOSTheme(client, definition_id, id, body) {
|
|
963
|
+
return client.put(
|
|
964
|
+
`/api/company/fluid_os/definitions/${definition_id}/themes/${id}`,
|
|
965
|
+
body
|
|
966
|
+
);
|
|
967
|
+
}
|
|
968
|
+
async function deleteFluidOSTheme(client, definition_id, id) {
|
|
969
|
+
return client.delete(
|
|
970
|
+
`/api/company/fluid_os/definitions/${definition_id}/themes/${id}`
|
|
971
|
+
);
|
|
972
|
+
}
|
|
973
|
+
async function listFluidOSVersions(client, definition_id, params) {
|
|
974
|
+
return client.get(
|
|
975
|
+
`/api/company/fluid_os/definitions/${definition_id}/versions`,
|
|
976
|
+
params
|
|
977
|
+
);
|
|
978
|
+
}
|
|
979
|
+
async function createFluidOSVersion(client, definition_id) {
|
|
980
|
+
return client.post(
|
|
981
|
+
`/api/company/fluid_os/definitions/${definition_id}/versions`
|
|
982
|
+
);
|
|
983
|
+
}
|
|
984
|
+
async function getFluidOSVersion(client, definition_id, id) {
|
|
985
|
+
return client.get(
|
|
986
|
+
`/api/company/fluid_os/definitions/${definition_id}/versions/${id}`
|
|
987
|
+
);
|
|
988
|
+
}
|
|
989
|
+
async function updateFluidOSVersion(client, definition_id, id, body) {
|
|
990
|
+
return client.put(
|
|
991
|
+
`/api/company/fluid_os/definitions/${definition_id}/versions/${id}`,
|
|
992
|
+
body
|
|
993
|
+
);
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
// src/client/types.ts
|
|
997
|
+
var HTTP_METHODS = {
|
|
998
|
+
GET: "GET",
|
|
999
|
+
POST: "POST",
|
|
1000
|
+
PUT: "PUT",
|
|
1001
|
+
PATCH: "PATCH",
|
|
1002
|
+
DELETE: "DELETE"
|
|
1003
|
+
};
|
|
1004
|
+
|
|
1005
|
+
// src/transforms/screen-transforms.ts
|
|
1006
|
+
function normalizeComponentTree(componentTree) {
|
|
1007
|
+
if (!componentTree) return [];
|
|
1008
|
+
if (Array.isArray(componentTree)) return componentTree;
|
|
1009
|
+
if (typeof componentTree === "object") {
|
|
1010
|
+
return [componentTree];
|
|
1011
|
+
}
|
|
1012
|
+
return [];
|
|
1013
|
+
}
|
|
1014
|
+
function toScreenDefinition(screen) {
|
|
1015
|
+
return {
|
|
1016
|
+
id: Number(screen.id),
|
|
1017
|
+
slug: screen.slug ?? "",
|
|
1018
|
+
name: screen.name ?? "",
|
|
1019
|
+
component_tree: normalizeComponentTree(screen.component_tree)
|
|
1020
|
+
};
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
// src/transforms/navigation-transforms.ts
|
|
1024
|
+
function toNavigationItem(item) {
|
|
1025
|
+
const children = (item.children ?? []).map(toNavigationItem).sort((a, b) => (a.position ?? 0) - (b.position ?? 0));
|
|
1026
|
+
return {
|
|
1027
|
+
id: Number(item.id),
|
|
1028
|
+
label: item.label ?? "Untitled",
|
|
1029
|
+
// Use conditional spread for optional properties (exactOptionalPropertyTypes)
|
|
1030
|
+
...item.slug != null ? { slug: String(item.slug) } : {},
|
|
1031
|
+
...item.icon != null ? { icon: String(item.icon) } : {},
|
|
1032
|
+
...item.screen_id != null ? { screen_id: Number(item.screen_id) } : {},
|
|
1033
|
+
...item.parent_id != null ? { parent_id: Number(item.parent_id) } : {},
|
|
1034
|
+
position: item.position ?? 0,
|
|
1035
|
+
children
|
|
1036
|
+
};
|
|
1037
|
+
}
|
|
1038
|
+
function transformManifestToRepAppData(response) {
|
|
1039
|
+
const manifest = response.manifest;
|
|
1040
|
+
const rawProfile = manifest.profile;
|
|
1041
|
+
const rawThemes = Array.isArray(rawProfile?.themes) ? rawProfile.themes : [];
|
|
1042
|
+
const screens = (manifest.screens ?? []).map(
|
|
1043
|
+
(screen) => toScreenDefinition(screen)
|
|
1044
|
+
);
|
|
1045
|
+
const navigationItems = (rawProfile?.navigation?.navigation_items ?? []).map(
|
|
1046
|
+
toNavigationItem
|
|
1047
|
+
);
|
|
1048
|
+
const nav = rawProfile?.navigation;
|
|
1049
|
+
const activeThemeId = theme_star.getActiveThemeId(rawThemes);
|
|
1050
|
+
return {
|
|
1051
|
+
definition_id: manifest.definition_id,
|
|
1052
|
+
published_version: manifest.published_version ?? 0,
|
|
1053
|
+
screens,
|
|
1054
|
+
profile: {
|
|
1055
|
+
name: rawProfile?.name ?? "Default",
|
|
1056
|
+
definition_id: rawProfile?.definition_id ?? manifest.definition_id,
|
|
1057
|
+
themes: theme_star.transformThemes(rawThemes),
|
|
1058
|
+
// Conditional spread for exactOptionalPropertyTypes compliance
|
|
1059
|
+
...activeThemeId !== void 0 ? { activeThemeId } : {},
|
|
1060
|
+
navigation: {
|
|
1061
|
+
definition_id: nav?.definition_id ?? manifest.definition_id,
|
|
1062
|
+
id: nav?.id ?? 0,
|
|
1063
|
+
name: nav?.name ?? "Main Navigation",
|
|
1064
|
+
navigation_items: navigationItems,
|
|
1065
|
+
screens
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
};
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
// src/client/fluid-client.ts
|
|
1072
|
+
var ApiError2 = class _ApiError extends Error {
|
|
1073
|
+
status;
|
|
1074
|
+
data;
|
|
1075
|
+
constructor(message, status, data) {
|
|
1076
|
+
super(message);
|
|
1077
|
+
this.name = "ApiError";
|
|
1078
|
+
this.status = status;
|
|
1079
|
+
this.data = data;
|
|
1080
|
+
const errorWithCapture = Error;
|
|
1081
|
+
if (errorWithCapture.captureStackTrace) {
|
|
1082
|
+
errorWithCapture.captureStackTrace(this, _ApiError);
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
toJSON() {
|
|
1086
|
+
return {
|
|
1087
|
+
name: this.name,
|
|
1088
|
+
message: this.message,
|
|
1089
|
+
status: this.status,
|
|
1090
|
+
data: this.data
|
|
1091
|
+
};
|
|
1092
|
+
}
|
|
1093
|
+
};
|
|
1094
|
+
function isApiError2(error) {
|
|
1095
|
+
return error instanceof ApiError2;
|
|
1096
|
+
}
|
|
1097
|
+
function isString(value) {
|
|
1098
|
+
return typeof value === "string";
|
|
1099
|
+
}
|
|
1100
|
+
function extractErrorMessage(data, fallback) {
|
|
1101
|
+
if ("message" in data && isString(data.message)) {
|
|
1102
|
+
return data.message;
|
|
1103
|
+
}
|
|
1104
|
+
if ("error_message" in data && isString(data.error_message)) {
|
|
1105
|
+
return data.error_message;
|
|
1106
|
+
}
|
|
1107
|
+
if ("error" in data && isString(data.error)) {
|
|
1108
|
+
return data.error;
|
|
1109
|
+
}
|
|
1110
|
+
return fallback;
|
|
1111
|
+
}
|
|
1112
|
+
function createFluidClient(config) {
|
|
1113
|
+
const { baseUrl, getAuthToken, onAuthError, defaultHeaders = {} } = config;
|
|
1114
|
+
const effectiveOnAuthError = onAuthError ?? createDefaultAuthRedirect();
|
|
1115
|
+
const fetchClient = createFetchClient({
|
|
1116
|
+
baseUrl,
|
|
1117
|
+
...getAuthToken ? { getAuthToken } : {},
|
|
1118
|
+
onAuthError: effectiveOnAuthError,
|
|
1119
|
+
defaultHeaders
|
|
1120
|
+
});
|
|
1121
|
+
async function buildHeaders(customHeaders) {
|
|
1122
|
+
const headers = {
|
|
1123
|
+
"Content-Type": "application/json",
|
|
1124
|
+
...defaultHeaders,
|
|
1125
|
+
...customHeaders
|
|
1126
|
+
};
|
|
1127
|
+
if (getAuthToken) {
|
|
1128
|
+
const token = await getAuthToken();
|
|
1129
|
+
if (token) {
|
|
1130
|
+
headers.Authorization = `Bearer ${token}`;
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
return headers;
|
|
1134
|
+
}
|
|
1135
|
+
function buildUrl(endpoint, params) {
|
|
1136
|
+
const normalizedBase = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
|
|
1137
|
+
const normalizedEndpoint = endpoint.startsWith("/") ? endpoint : `/${endpoint}`;
|
|
1138
|
+
const url = new URL(normalizedBase + normalizedEndpoint);
|
|
1139
|
+
if (params) {
|
|
1140
|
+
for (const [key, value] of Object.entries(params)) {
|
|
1141
|
+
if (value === void 0 || value === null) {
|
|
1142
|
+
continue;
|
|
1143
|
+
}
|
|
1144
|
+
if (Array.isArray(value)) {
|
|
1145
|
+
for (const item of value) {
|
|
1146
|
+
url.searchParams.append(`${key}[]`, String(item));
|
|
1147
|
+
}
|
|
1148
|
+
} else if (typeof value === "object") {
|
|
1149
|
+
for (const [subKey, subValue] of Object.entries(
|
|
1150
|
+
value
|
|
1151
|
+
)) {
|
|
1152
|
+
if (subValue === void 0 || subValue === null) {
|
|
1153
|
+
continue;
|
|
1154
|
+
}
|
|
1155
|
+
if (Array.isArray(subValue)) {
|
|
1156
|
+
for (const item of subValue) {
|
|
1157
|
+
url.searchParams.append(`${key}[${subKey}][]`, String(item));
|
|
1158
|
+
}
|
|
1159
|
+
} else {
|
|
1160
|
+
url.searchParams.append(`${key}[${subKey}]`, String(subValue));
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
} else {
|
|
1164
|
+
url.searchParams.append(key, String(value));
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
return url.toString();
|
|
1169
|
+
}
|
|
1170
|
+
const defaultRequestOptions = {
|
|
1171
|
+
method: HTTP_METHODS.GET
|
|
1172
|
+
};
|
|
1173
|
+
async function request(endpoint, options = {}) {
|
|
1174
|
+
const {
|
|
1175
|
+
method = defaultRequestOptions.method,
|
|
1176
|
+
headers: customHeaders,
|
|
1177
|
+
params,
|
|
1178
|
+
body,
|
|
1179
|
+
signal
|
|
1180
|
+
} = options;
|
|
1181
|
+
const url = buildUrl(
|
|
1182
|
+
endpoint,
|
|
1183
|
+
method === HTTP_METHODS.GET ? params : void 0
|
|
1184
|
+
);
|
|
1185
|
+
const headers = await buildHeaders(customHeaders);
|
|
1186
|
+
let response;
|
|
1187
|
+
try {
|
|
1188
|
+
const fetchOptions = {
|
|
1189
|
+
method,
|
|
1190
|
+
headers
|
|
1191
|
+
};
|
|
1192
|
+
if (signal !== void 0) {
|
|
1193
|
+
fetchOptions.signal = signal;
|
|
1194
|
+
}
|
|
1195
|
+
if (body && method !== HTTP_METHODS.GET) {
|
|
1196
|
+
fetchOptions.body = JSON.stringify(body);
|
|
1197
|
+
}
|
|
1198
|
+
response = await fetch(url, fetchOptions);
|
|
1199
|
+
} catch (networkError) {
|
|
1200
|
+
throw new ApiError2(
|
|
1201
|
+
`Network error: ${networkError instanceof Error ? networkError.message : "Unknown network error"}`,
|
|
1202
|
+
0,
|
|
1203
|
+
null
|
|
1204
|
+
);
|
|
1205
|
+
}
|
|
1206
|
+
if (response.status === 401) {
|
|
1207
|
+
effectiveOnAuthError();
|
|
1208
|
+
throw new ApiError2("Authentication required", 401, null);
|
|
1209
|
+
}
|
|
1210
|
+
if (!response.ok) {
|
|
1211
|
+
try {
|
|
1212
|
+
const contentType = response.headers.get("content-type");
|
|
1213
|
+
if (contentType?.includes("application/json")) {
|
|
1214
|
+
const data = await response.json();
|
|
1215
|
+
const errorMessage = extractErrorMessage(
|
|
1216
|
+
data,
|
|
1217
|
+
`${method} request failed`
|
|
1218
|
+
);
|
|
1219
|
+
throw new ApiError2(
|
|
1220
|
+
errorMessage,
|
|
1221
|
+
response.status,
|
|
1222
|
+
"errors" in data ? data.errors : data
|
|
1223
|
+
);
|
|
1224
|
+
} else {
|
|
1225
|
+
throw new ApiError2(
|
|
1226
|
+
`${method} request failed with status ${response.status}`,
|
|
1227
|
+
response.status,
|
|
1228
|
+
null
|
|
1229
|
+
);
|
|
1230
|
+
}
|
|
1231
|
+
} catch (error) {
|
|
1232
|
+
if (isApiError2(error)) {
|
|
1233
|
+
throw error;
|
|
1234
|
+
}
|
|
1235
|
+
throw new ApiError2(
|
|
1236
|
+
`${method} request failed with status ${response.status}`,
|
|
1237
|
+
response.status,
|
|
1238
|
+
null
|
|
1239
|
+
);
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
if (response.status === 204 || response.headers.get("content-length") === "0") {
|
|
1243
|
+
return null;
|
|
1244
|
+
}
|
|
1245
|
+
try {
|
|
1246
|
+
const data = await response.json();
|
|
1247
|
+
if (data === null || data === void 0) {
|
|
1248
|
+
throw new ApiError2(
|
|
1249
|
+
"Unexpected null/undefined in JSON response",
|
|
1250
|
+
response.status,
|
|
1251
|
+
null
|
|
1252
|
+
);
|
|
1253
|
+
}
|
|
1254
|
+
return data;
|
|
1255
|
+
} catch (parseError) {
|
|
1256
|
+
if (isApiError2(parseError)) {
|
|
1257
|
+
throw parseError;
|
|
1258
|
+
}
|
|
1259
|
+
throw new ApiError2(
|
|
1260
|
+
"Failed to parse response as JSON",
|
|
1261
|
+
response.status,
|
|
1262
|
+
null
|
|
1263
|
+
);
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
async function requestNullable(endpoint, options = {}) {
|
|
1267
|
+
return request(endpoint, options);
|
|
1268
|
+
}
|
|
1269
|
+
async function safeRequest(endpoint, options = {}) {
|
|
1270
|
+
try {
|
|
1271
|
+
const data = await request(endpoint, options);
|
|
1272
|
+
return { success: true, data };
|
|
1273
|
+
} catch (error) {
|
|
1274
|
+
if (isApiError2(error)) {
|
|
1275
|
+
return { success: false, error };
|
|
1276
|
+
}
|
|
1277
|
+
return {
|
|
1278
|
+
success: false,
|
|
1279
|
+
error: new ApiError2(
|
|
1280
|
+
error instanceof Error ? error.message : "Unknown error",
|
|
1281
|
+
0,
|
|
1282
|
+
null
|
|
1283
|
+
)
|
|
1284
|
+
};
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
function toParams(params) {
|
|
1288
|
+
return params;
|
|
1289
|
+
}
|
|
1290
|
+
const get = (endpoint, params, options) => {
|
|
1291
|
+
const baseOptions = {
|
|
1292
|
+
...options,
|
|
1293
|
+
method: HTTP_METHODS.GET
|
|
1294
|
+
};
|
|
1295
|
+
const convertedParams = toParams(params);
|
|
1296
|
+
const requestOptions = convertedParams !== void 0 ? { ...baseOptions, params: convertedParams } : baseOptions;
|
|
1297
|
+
return request(endpoint, requestOptions);
|
|
1298
|
+
};
|
|
1299
|
+
const post = (endpoint, body, options) => request(endpoint, {
|
|
1300
|
+
...options,
|
|
1301
|
+
method: HTTP_METHODS.POST,
|
|
1302
|
+
body
|
|
1303
|
+
});
|
|
1304
|
+
const put = (endpoint, body, options) => request(endpoint, {
|
|
1305
|
+
...options,
|
|
1306
|
+
method: HTTP_METHODS.PUT,
|
|
1307
|
+
body
|
|
1308
|
+
});
|
|
1309
|
+
const patch = (endpoint, body, options) => request(endpoint, {
|
|
1310
|
+
...options,
|
|
1311
|
+
method: HTTP_METHODS.PATCH,
|
|
1312
|
+
body
|
|
1313
|
+
});
|
|
1314
|
+
const del = (endpoint, options) => request(endpoint, {
|
|
1315
|
+
...options,
|
|
1316
|
+
method: HTTP_METHODS.DELETE
|
|
1317
|
+
});
|
|
1318
|
+
return {
|
|
1319
|
+
// Fluidos FetchClient for structured API calls
|
|
1320
|
+
fetchClient,
|
|
1321
|
+
// Low-level methods for custom endpoints
|
|
1322
|
+
request,
|
|
1323
|
+
requestNullable,
|
|
1324
|
+
safeRequest,
|
|
1325
|
+
get,
|
|
1326
|
+
post,
|
|
1327
|
+
put,
|
|
1328
|
+
patch,
|
|
1329
|
+
delete: del,
|
|
1330
|
+
// Products API - matches fluid-admin's /company/v1/products
|
|
1331
|
+
products: {
|
|
1332
|
+
list: (params) => get(
|
|
1333
|
+
"/company/v1/products",
|
|
1334
|
+
params
|
|
1335
|
+
),
|
|
1336
|
+
get: (id) => get(`/company/v1/products/${id}`),
|
|
1337
|
+
search: (query, params) => get("/company/v1/products", {
|
|
1338
|
+
search_query: query,
|
|
1339
|
+
...params
|
|
1340
|
+
})
|
|
1341
|
+
},
|
|
1342
|
+
// Orders API
|
|
1343
|
+
orders: {
|
|
1344
|
+
list: (params) => get("/orders", params),
|
|
1345
|
+
get: (id) => get(`/orders/${id}`),
|
|
1346
|
+
create: (data) => post("/orders", data)
|
|
1347
|
+
},
|
|
1348
|
+
// Users API
|
|
1349
|
+
users: {
|
|
1350
|
+
me: () => get("/api/me")
|
|
1351
|
+
},
|
|
1352
|
+
// Reps API
|
|
1353
|
+
reps: {
|
|
1354
|
+
current: () => get("/reps/me"),
|
|
1355
|
+
updateProfile: (data) => patch("/reps/me", data)
|
|
1356
|
+
},
|
|
1357
|
+
// Profile API (themes, navigation, screens) — legacy endpoint
|
|
1358
|
+
profile: {
|
|
1359
|
+
get: () => get("/rep_app/manifest")
|
|
1360
|
+
},
|
|
1361
|
+
// App API — fluidos endpoint (full manifest with transforms)
|
|
1362
|
+
app: {
|
|
1363
|
+
/** Fetch the raw manifest (plain JSON, no Color objects). Cache-safe. */
|
|
1364
|
+
getRaw: async () => {
|
|
1365
|
+
const raw = await fluid_os_exports.getFluidOSManifest(fetchClient, {
|
|
1366
|
+
platform: "browser"
|
|
1367
|
+
});
|
|
1368
|
+
return raw;
|
|
1369
|
+
},
|
|
1370
|
+
/** Fetch the active app definition with full theme/screen/navigation transforms */
|
|
1371
|
+
get: async () => {
|
|
1372
|
+
const raw = await fluid_os_exports.getFluidOSManifest(fetchClient, {
|
|
1373
|
+
platform: "browser"
|
|
1374
|
+
});
|
|
1375
|
+
return transformManifestToRepAppData(
|
|
1376
|
+
raw
|
|
1377
|
+
);
|
|
1378
|
+
}
|
|
1379
|
+
},
|
|
1380
|
+
// Permissions API
|
|
1381
|
+
permissions: {
|
|
1382
|
+
get: () => get("/company/roles/my_permissions")
|
|
1383
|
+
},
|
|
1384
|
+
// Analytics API
|
|
1385
|
+
analytics: {
|
|
1386
|
+
dashboard: () => get("/analytics/dashboard"),
|
|
1387
|
+
sales: (params) => get("/analytics/sales", params)
|
|
1388
|
+
}
|
|
1389
|
+
};
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
// src/themes/index.ts
|
|
1393
|
+
var themes_exports = {};
|
|
1394
|
+
chunkHDQ2JUQT_cjs.__reExport(themes_exports, theme_star__namespace);
|
|
1395
|
+
var ThemeContext = react.createContext(null);
|
|
1396
|
+
function applyThemeToDOM(theme, mode, container) {
|
|
1397
|
+
const target = container ?? document.documentElement;
|
|
1398
|
+
const resolved = (0, themes_exports.resolveTheme)(theme);
|
|
1399
|
+
(0, themes_exports.applyTheme)(resolved);
|
|
1400
|
+
target.dataset.theme = theme.id;
|
|
1401
|
+
if (mode) {
|
|
1402
|
+
target.dataset.themeMode = mode;
|
|
1403
|
+
} else {
|
|
1404
|
+
delete target.dataset.themeMode;
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
function FluidThemeProvider({
|
|
1408
|
+
children,
|
|
1409
|
+
initialTheme,
|
|
1410
|
+
container
|
|
1411
|
+
}) {
|
|
1412
|
+
const [currentTheme, setCurrentTheme] = react.useState(
|
|
1413
|
+
initialTheme ?? null
|
|
1414
|
+
);
|
|
1415
|
+
const [mode, setMode] = react.useState(void 0);
|
|
1416
|
+
react.useEffect(() => {
|
|
1417
|
+
if (currentTheme) {
|
|
1418
|
+
applyThemeToDOM(currentTheme, mode, container ?? null);
|
|
1419
|
+
}
|
|
1420
|
+
return () => {
|
|
1421
|
+
(0, themes_exports.removeAllThemes)();
|
|
1422
|
+
};
|
|
1423
|
+
}, [currentTheme, mode, container]);
|
|
1424
|
+
const setTheme = react.useCallback((theme) => {
|
|
1425
|
+
setCurrentTheme(theme);
|
|
1426
|
+
}, []);
|
|
1427
|
+
const setThemeMode = react.useCallback((newMode) => {
|
|
1428
|
+
setMode(newMode);
|
|
1429
|
+
}, []);
|
|
1430
|
+
const value = react.useMemo(
|
|
1431
|
+
() => ({
|
|
1432
|
+
currentTheme,
|
|
1433
|
+
setTheme,
|
|
1434
|
+
setThemeMode,
|
|
1435
|
+
mode
|
|
1436
|
+
}),
|
|
1437
|
+
[currentTheme, setTheme, setThemeMode, mode]
|
|
1438
|
+
);
|
|
1439
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ThemeContext.Provider, { value, children });
|
|
1440
|
+
}
|
|
1441
|
+
function useThemeContext() {
|
|
1442
|
+
const context = react.useContext(ThemeContext);
|
|
1443
|
+
if (!context) {
|
|
1444
|
+
throw new Error("useThemeContext must be used within a FluidThemeProvider");
|
|
1445
|
+
}
|
|
1446
|
+
return context;
|
|
1447
|
+
}
|
|
1448
|
+
var DEFAULT_SDK_WIDGET_REGISTRY = widgetUtils.createWidgetRegistry({
|
|
1449
|
+
AlertWidget: widgets.AlertWidget,
|
|
1450
|
+
CalendarWidget: widgets.CalendarWidget,
|
|
1451
|
+
CarouselWidget: widgets.CarouselWidget,
|
|
1452
|
+
CatchUpWidget: widgets.CatchUpWidget,
|
|
1453
|
+
ChartWidget: widgets.ChartWidget,
|
|
1454
|
+
ContainerWidget: widgets.ContainerWidget,
|
|
1455
|
+
EmbedWidget: widgets.EmbedWidget,
|
|
1456
|
+
ImageWidget: widgets.ImageWidget,
|
|
1457
|
+
LayoutWidget: widgets.LayoutWidget,
|
|
1458
|
+
ListWidget: widgets.ListWidget,
|
|
1459
|
+
MySiteWidget: widgets.MySiteWidget,
|
|
1460
|
+
NestedWidget: widgets.NestedWidget,
|
|
1461
|
+
QuickShareWidget: widgets.QuickShareWidget,
|
|
1462
|
+
RecentActivityWidget: widgets.RecentActivityWidget,
|
|
1463
|
+
SpacerWidget: widgets.SpacerWidget,
|
|
1464
|
+
TableWidget: widgets.TableWidget,
|
|
1465
|
+
TextWidget: widgets.TextWidget,
|
|
1466
|
+
ToDoWidget: widgets.ToDoWidget,
|
|
1467
|
+
VideoWidget: widgets.VideoWidget
|
|
1468
|
+
});
|
|
1469
|
+
var FluidContext = react.createContext(null);
|
|
1470
|
+
function FluidProvider({
|
|
1471
|
+
config,
|
|
1472
|
+
children,
|
|
1473
|
+
queryClient,
|
|
1474
|
+
initialTheme,
|
|
1475
|
+
themeContainer,
|
|
1476
|
+
widgetRegistry,
|
|
1477
|
+
variables
|
|
1478
|
+
}) {
|
|
1479
|
+
const defaultQueryClient = react.useMemo(
|
|
1480
|
+
() => new reactQuery.QueryClient({
|
|
1481
|
+
defaultOptions: {
|
|
1482
|
+
queries: {
|
|
1483
|
+
staleTime: 1e3 * 60,
|
|
1484
|
+
// 1 minute
|
|
1485
|
+
retry: 1
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
}),
|
|
1489
|
+
[]
|
|
1490
|
+
);
|
|
1491
|
+
const configRef = react.useRef(config);
|
|
1492
|
+
configRef.current = config;
|
|
1493
|
+
const client = react.useMemo(
|
|
1494
|
+
() => createFluidClient({
|
|
1495
|
+
...configRef.current,
|
|
1496
|
+
getAuthToken: () => configRef.current.getAuthToken?.() ?? null,
|
|
1497
|
+
onAuthError: () => configRef.current.onAuthError?.()
|
|
1498
|
+
}),
|
|
1499
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1500
|
+
[config.baseUrl]
|
|
1501
|
+
);
|
|
1502
|
+
const contextValue = react.useMemo(
|
|
1503
|
+
() => ({ client, config: configRef.current }),
|
|
1504
|
+
[client]
|
|
1505
|
+
);
|
|
1506
|
+
const getApiHeaders = react.useCallback(() => {
|
|
1507
|
+
const headers = {
|
|
1508
|
+
"Content-Type": "application/json"
|
|
1509
|
+
};
|
|
1510
|
+
const getAuthToken = configRef.current.getAuthToken;
|
|
1511
|
+
if (typeof getAuthToken === "function") {
|
|
1512
|
+
const tokenOrPromise = getAuthToken();
|
|
1513
|
+
if (typeof tokenOrPromise === "string") {
|
|
1514
|
+
headers.Authorization = `Bearer ${tokenOrPromise}`;
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
return headers;
|
|
1518
|
+
}, []);
|
|
1519
|
+
const dataSourceBaseUrl = react.useMemo(() => {
|
|
1520
|
+
const base = config.baseUrl.replace(/\/+$/, "");
|
|
1521
|
+
return base.endsWith("/api") ? base : `${base}/api`;
|
|
1522
|
+
}, [config.baseUrl]);
|
|
1523
|
+
const authContext = useFluidAuthOptional();
|
|
1524
|
+
const autoVariables = react.useMemo(() => {
|
|
1525
|
+
if (authContext?.user?.id != null) {
|
|
1526
|
+
return { rep_id: String(authContext.user.id) };
|
|
1527
|
+
}
|
|
1528
|
+
return void 0;
|
|
1529
|
+
}, [authContext?.user?.id]);
|
|
1530
|
+
const effectiveVariables = variables ?? autoVariables;
|
|
1531
|
+
const themeProviderProps = {
|
|
1532
|
+
...initialTheme !== void 0 && { initialTheme },
|
|
1533
|
+
...themeContainer !== void 0 && { container: themeContainer }
|
|
1534
|
+
};
|
|
1535
|
+
const registry = widgetRegistry ?? DEFAULT_SDK_WIDGET_REGISTRY;
|
|
1536
|
+
return /* @__PURE__ */ jsxRuntime.jsx(reactQuery.QueryClientProvider, { client: queryClient ?? defaultQueryClient, children: /* @__PURE__ */ jsxRuntime.jsx(FluidContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1537
|
+
registryContext.DataSourceRegistryProvider,
|
|
1538
|
+
{
|
|
1539
|
+
baseUrl: dataSourceBaseUrl,
|
|
1540
|
+
getApiHeaders,
|
|
1541
|
+
variables: effectiveVariables,
|
|
1542
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(contexts.RegistryProvider, { registry, children: /* @__PURE__ */ jsxRuntime.jsx(FluidThemeProvider, { ...themeProviderProps, children }) })
|
|
1543
|
+
}
|
|
1544
|
+
) }) });
|
|
1545
|
+
}
|
|
1546
|
+
function useFluidContext() {
|
|
1547
|
+
const context = react.useContext(FluidContext);
|
|
1548
|
+
if (!context) {
|
|
1549
|
+
throw new Error("useFluidContext must be used within a FluidProvider");
|
|
1550
|
+
}
|
|
1551
|
+
return context;
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
// src/hooks/use-fluid-api.ts
|
|
1555
|
+
function useFluidApi() {
|
|
1556
|
+
const { client } = useFluidContext();
|
|
1557
|
+
return client;
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1560
|
+
// src/messaging/use-messaging-auth.ts
|
|
1561
|
+
var USERS_ME_QUERY_KEY = ["fluid", "users", "me"];
|
|
1562
|
+
function useMessagingAuth() {
|
|
1563
|
+
const auth = useFluidAuthContext();
|
|
1564
|
+
const api = useFluidApi();
|
|
1565
|
+
const {
|
|
1566
|
+
data: userMe,
|
|
1567
|
+
isLoading: isUserMeLoading,
|
|
1568
|
+
isError
|
|
1569
|
+
} = reactQuery.useQuery({
|
|
1570
|
+
queryKey: USERS_ME_QUERY_KEY,
|
|
1571
|
+
queryFn: () => api.users.me(),
|
|
1572
|
+
enabled: auth.isAuthenticated,
|
|
1573
|
+
staleTime: Infinity,
|
|
1574
|
+
retry: 1
|
|
1575
|
+
});
|
|
1576
|
+
if (auth.isLoading || auth.isAuthenticated && isUserMeLoading) {
|
|
1577
|
+
return {
|
|
1578
|
+
recipientId: null,
|
|
1579
|
+
companyId: null,
|
|
1580
|
+
currentUser: null,
|
|
1581
|
+
isLoading: true
|
|
1582
|
+
};
|
|
1583
|
+
}
|
|
1584
|
+
if (!auth.isAuthenticated || isError || !userMe) {
|
|
1585
|
+
return {
|
|
1586
|
+
recipientId: null,
|
|
1587
|
+
companyId: null,
|
|
1588
|
+
currentUser: null,
|
|
1589
|
+
isLoading: false
|
|
1590
|
+
};
|
|
1591
|
+
}
|
|
1592
|
+
const currentUser = userMe.recipient_id ? {
|
|
1593
|
+
id: userMe.id,
|
|
1594
|
+
recipientId: userMe.recipient_id,
|
|
1595
|
+
firstName: userMe.first_name ?? "",
|
|
1596
|
+
lastName: userMe.last_name ?? "",
|
|
1597
|
+
email: userMe.email,
|
|
1598
|
+
...userMe.image_url != null && { imageUrl: userMe.image_url },
|
|
1599
|
+
...userMe.affiliate_id != null && {
|
|
1600
|
+
affiliateId: userMe.affiliate_id
|
|
1601
|
+
}
|
|
1602
|
+
} : null;
|
|
1603
|
+
return {
|
|
1604
|
+
recipientId: userMe.recipient_id,
|
|
1605
|
+
companyId: userMe.company_id ?? null,
|
|
1606
|
+
currentUser,
|
|
1607
|
+
isLoading: false
|
|
1608
|
+
};
|
|
1609
|
+
}
|
|
1610
|
+
function deriveWebsocketUrl(baseUrl) {
|
|
1611
|
+
const base = baseUrl.replace(/\/+$/, "").replace(/\/api$/, "");
|
|
1612
|
+
return `${base}/cable`;
|
|
1613
|
+
}
|
|
1614
|
+
function useMessagingConfig() {
|
|
1615
|
+
const { config } = useFluidContext();
|
|
1616
|
+
const auth = useFluidAuthContext();
|
|
1617
|
+
const getHeaders = react.useCallback(async () => {
|
|
1618
|
+
const headers = {
|
|
1619
|
+
"Content-Type": "application/json",
|
|
1620
|
+
...config.defaultHeaders
|
|
1621
|
+
};
|
|
1622
|
+
if (config.getAuthToken) {
|
|
1623
|
+
const token = await config.getAuthToken();
|
|
1624
|
+
if (token) {
|
|
1625
|
+
headers.Authorization = `Bearer ${token}`;
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
return headers;
|
|
1629
|
+
}, [config]);
|
|
1630
|
+
const apiBaseUrl = react.useMemo(() => {
|
|
1631
|
+
const base = config.baseUrl.replace(/\/+$/, "");
|
|
1632
|
+
return base.endsWith("/api") ? base : `${base}/api`;
|
|
1633
|
+
}, [config.baseUrl]);
|
|
1634
|
+
const apiConfig = react.useMemo(
|
|
1635
|
+
() => ({
|
|
1636
|
+
baseUrl: apiBaseUrl,
|
|
1637
|
+
getHeaders,
|
|
1638
|
+
...config.onAuthError != null && { onAuthError: config.onAuthError }
|
|
1639
|
+
}),
|
|
1640
|
+
[apiBaseUrl, config.onAuthError, getHeaders]
|
|
1641
|
+
);
|
|
1642
|
+
const websocketUrl = react.useMemo(
|
|
1643
|
+
() => config.websocketUrl ?? deriveWebsocketUrl(config.baseUrl),
|
|
1644
|
+
[config.websocketUrl, config.baseUrl]
|
|
1645
|
+
);
|
|
1646
|
+
return {
|
|
1647
|
+
apiConfig,
|
|
1648
|
+
websocketUrl,
|
|
1649
|
+
token: auth.token
|
|
1650
|
+
};
|
|
1651
|
+
}
|
|
1652
|
+
var FILESTACK_UPLOAD_URL = "https://www.filestackapi.com/api/store/S3";
|
|
1653
|
+
function getImageDimensions(file) {
|
|
1654
|
+
if (!file.type.startsWith("image/")) return Promise.resolve(null);
|
|
1655
|
+
return new Promise((resolve) => {
|
|
1656
|
+
const img = new Image();
|
|
1657
|
+
const url = URL.createObjectURL(file);
|
|
1658
|
+
img.onload = () => {
|
|
1659
|
+
URL.revokeObjectURL(url);
|
|
1660
|
+
resolve({ width: img.naturalWidth, height: img.naturalHeight });
|
|
1661
|
+
};
|
|
1662
|
+
img.onerror = () => {
|
|
1663
|
+
URL.revokeObjectURL(url);
|
|
1664
|
+
resolve(null);
|
|
1665
|
+
};
|
|
1666
|
+
img.src = url;
|
|
1667
|
+
});
|
|
1668
|
+
}
|
|
1669
|
+
function uploadToFilestack(file, apiKey, callbacks) {
|
|
1670
|
+
const xhr = new XMLHttpRequest();
|
|
1671
|
+
let aborted = false;
|
|
1672
|
+
getImageDimensions(file).then((metadata) => {
|
|
1673
|
+
if (aborted) return;
|
|
1674
|
+
const url = `${FILESTACK_UPLOAD_URL}?key=${encodeURIComponent(apiKey)}`;
|
|
1675
|
+
xhr.open("POST", url);
|
|
1676
|
+
xhr.setRequestHeader("Content-Type", file.type);
|
|
1677
|
+
xhr.upload.onprogress = (event) => {
|
|
1678
|
+
if (event.lengthComputable) {
|
|
1679
|
+
const progress = Math.round(event.loaded / event.total * 100);
|
|
1680
|
+
callbacks.onProgress(progress);
|
|
1681
|
+
}
|
|
1682
|
+
};
|
|
1683
|
+
xhr.onload = () => {
|
|
1684
|
+
if (xhr.status >= 200 && xhr.status < 300) {
|
|
1685
|
+
try {
|
|
1686
|
+
const response = JSON.parse(xhr.responseText);
|
|
1687
|
+
const result = {
|
|
1688
|
+
url: response.url,
|
|
1689
|
+
size: file.size,
|
|
1690
|
+
mimetype: file.type,
|
|
1691
|
+
kind: fluidMessagingCore.getFileTypeFromMimetype(file.type),
|
|
1692
|
+
metadata
|
|
1693
|
+
};
|
|
1694
|
+
callbacks.onSuccess(result);
|
|
1695
|
+
} catch {
|
|
1696
|
+
callbacks.onError(new Error("Failed to parse upload response"));
|
|
1697
|
+
}
|
|
1698
|
+
} else {
|
|
1699
|
+
callbacks.onError(
|
|
1700
|
+
new Error(`Upload failed with status ${xhr.status}`)
|
|
1701
|
+
);
|
|
1702
|
+
}
|
|
1703
|
+
};
|
|
1704
|
+
xhr.onerror = () => {
|
|
1705
|
+
if (!aborted) {
|
|
1706
|
+
callbacks.onError(new Error("Upload failed due to a network error"));
|
|
1707
|
+
}
|
|
1708
|
+
};
|
|
1709
|
+
xhr.onabort = () => {
|
|
1710
|
+
};
|
|
1711
|
+
xhr.send(file);
|
|
1712
|
+
}).catch((error) => {
|
|
1713
|
+
if (!aborted) {
|
|
1714
|
+
callbacks.onError(
|
|
1715
|
+
error instanceof Error ? error : new Error("Upload preparation failed")
|
|
1716
|
+
);
|
|
1717
|
+
}
|
|
1718
|
+
});
|
|
1719
|
+
return {
|
|
1720
|
+
abort: () => {
|
|
1721
|
+
aborted = true;
|
|
1722
|
+
xhr.abort();
|
|
1723
|
+
}
|
|
1724
|
+
};
|
|
1725
|
+
}
|
|
1726
|
+
function createFluidFileUploader(apiKey) {
|
|
1727
|
+
if (!apiKey) {
|
|
1728
|
+
return {
|
|
1729
|
+
uploadFile: (_file, callbacks) => {
|
|
1730
|
+
callbacks.onError(
|
|
1731
|
+
new Error(
|
|
1732
|
+
"File uploads are not configured. Set filestackApiKey in your SDK config to enable attachments."
|
|
1733
|
+
)
|
|
1734
|
+
);
|
|
1735
|
+
return { abort: () => {
|
|
1736
|
+
} };
|
|
1737
|
+
}
|
|
1738
|
+
};
|
|
1739
|
+
}
|
|
1740
|
+
return {
|
|
1741
|
+
uploadFile: (file, callbacks) => uploadToFilestack(file, apiKey, callbacks)
|
|
1742
|
+
};
|
|
1743
|
+
}
|
|
1744
|
+
function renderImage(props) {
|
|
1745
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1746
|
+
"img",
|
|
1747
|
+
{
|
|
1748
|
+
src: props.src,
|
|
1749
|
+
alt: props.alt,
|
|
1750
|
+
width: props.width,
|
|
1751
|
+
height: props.height,
|
|
1752
|
+
className: props.className
|
|
1753
|
+
}
|
|
1754
|
+
);
|
|
1755
|
+
}
|
|
1756
|
+
function defaultToast(message, type) {
|
|
1757
|
+
if (type === "error") {
|
|
1758
|
+
console.warn("[Messaging]", message);
|
|
1759
|
+
}
|
|
1760
|
+
}
|
|
1761
|
+
function MessagingScreen({
|
|
1762
|
+
onToast,
|
|
1763
|
+
filestackApiKey,
|
|
1764
|
+
websocketUrl: websocketUrlOverride,
|
|
1765
|
+
/* eslint-disable @typescript-eslint/no-unused-vars -- destructured to exclude from divProps spread */
|
|
1766
|
+
background,
|
|
1767
|
+
textColor,
|
|
1768
|
+
accentColor,
|
|
1769
|
+
padding,
|
|
1770
|
+
borderRadius,
|
|
1771
|
+
/* eslint-enable @typescript-eslint/no-unused-vars */
|
|
1772
|
+
...divProps
|
|
1773
|
+
}) {
|
|
1774
|
+
const { config } = useFluidContext();
|
|
1775
|
+
const { apiConfig, websocketUrl, token } = useMessagingConfig();
|
|
1776
|
+
const messagingAuth = useMessagingAuth();
|
|
1777
|
+
const effectiveApiKey = filestackApiKey ?? config.filestackApiKey;
|
|
1778
|
+
const uploader = react.useMemo(
|
|
1779
|
+
() => createFluidFileUploader(effectiveApiKey),
|
|
1780
|
+
[effectiveApiKey]
|
|
1781
|
+
);
|
|
1782
|
+
const effectiveWsUrl = websocketUrlOverride ?? websocketUrl;
|
|
1783
|
+
const effectiveToast = onToast ?? defaultToast;
|
|
1784
|
+
const searchUsers = react.useCallback(
|
|
1785
|
+
async (query) => {
|
|
1786
|
+
const result = await fluidMessagingApiClient.listConnectedRecipients(apiConfig, {
|
|
1787
|
+
filterrific: { search_query: query },
|
|
1788
|
+
per_page: 10,
|
|
1789
|
+
page: 1
|
|
1790
|
+
});
|
|
1791
|
+
const recipients = result?.[1]?.items ?? [];
|
|
1792
|
+
return recipients.map((user) => {
|
|
1793
|
+
const hasName = [user.first_name, user.last_name].filter(Boolean).length > 0;
|
|
1794
|
+
const name = hasName ? [user.first_name, user.last_name].filter(Boolean).join(" ") : `User ${user.id}`;
|
|
1795
|
+
return {
|
|
1796
|
+
id: String(user.id),
|
|
1797
|
+
label: name,
|
|
1798
|
+
imageType: "user",
|
|
1799
|
+
userData: {
|
|
1800
|
+
first_name: user.first_name,
|
|
1801
|
+
last_name: user.last_name,
|
|
1802
|
+
image_url: user.avatar_url,
|
|
1803
|
+
phone: user.phone || void 0,
|
|
1804
|
+
email: user.email || void 0
|
|
1805
|
+
},
|
|
1806
|
+
conversationName: name
|
|
1807
|
+
};
|
|
1808
|
+
});
|
|
1809
|
+
},
|
|
1810
|
+
[apiConfig]
|
|
1811
|
+
);
|
|
1812
|
+
const searchChannels = react.useCallback(
|
|
1813
|
+
async (query) => {
|
|
1814
|
+
const channels = await fluidMessagingApiClient.searchConversations(apiConfig, {
|
|
1815
|
+
filterrific: { search_query: query }
|
|
1816
|
+
}) ?? [];
|
|
1817
|
+
return channels.map((channel) => {
|
|
1818
|
+
const { text: nameWithoutEmoji } = fluidMessagingUi.extractEmoji(channel.name);
|
|
1819
|
+
return {
|
|
1820
|
+
id: `channel-${channel.id}`,
|
|
1821
|
+
label: fluidMessagingUi.formatMessageChannelName(nameWithoutEmoji),
|
|
1822
|
+
imageType: "channel",
|
|
1823
|
+
userData: {
|
|
1824
|
+
first_name: channel.name,
|
|
1825
|
+
last_name: null,
|
|
1826
|
+
image_url: channel.avatar_url
|
|
1827
|
+
},
|
|
1828
|
+
conversationName: channel.name
|
|
1829
|
+
};
|
|
1830
|
+
});
|
|
1831
|
+
},
|
|
1832
|
+
[apiConfig]
|
|
1833
|
+
);
|
|
1834
|
+
if (messagingAuth.isLoading) {
|
|
1835
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1836
|
+
"div",
|
|
1837
|
+
{
|
|
1838
|
+
...divProps,
|
|
1839
|
+
className: `flex h-full items-center justify-center ${divProps.className ?? ""}`,
|
|
1840
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-muted-foreground", children: "Loading messaging..." })
|
|
1841
|
+
}
|
|
1842
|
+
);
|
|
1843
|
+
}
|
|
1844
|
+
if (!messagingAuth.recipientId) {
|
|
1845
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1846
|
+
"div",
|
|
1847
|
+
{
|
|
1848
|
+
...divProps,
|
|
1849
|
+
className: `flex h-full items-center justify-center ${divProps.className ?? ""}`,
|
|
1850
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-sm rounded-lg border border-dashed border-border p-8 text-center", children: [
|
|
1851
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-xl font-semibold text-foreground", children: "Messaging" }),
|
|
1852
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-muted-foreground", children: "Messaging is not available for your account" })
|
|
1853
|
+
] })
|
|
1854
|
+
}
|
|
1855
|
+
);
|
|
1856
|
+
}
|
|
1857
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { ...divProps, className: `h-full ${divProps.className ?? ""}`, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1858
|
+
app.MessagingApp,
|
|
1859
|
+
{
|
|
1860
|
+
config: apiConfig,
|
|
1861
|
+
auth: messagingAuth,
|
|
1862
|
+
websocketUrl: effectiveWsUrl,
|
|
1863
|
+
token,
|
|
1864
|
+
renderImage,
|
|
1865
|
+
showAdminFeatures: false,
|
|
1866
|
+
onToast: effectiveToast,
|
|
1867
|
+
messagesViewProps: {
|
|
1868
|
+
uploader,
|
|
1869
|
+
saveDrafts: true,
|
|
1870
|
+
onToast: effectiveToast
|
|
1871
|
+
},
|
|
1872
|
+
newMessageViewProps: {
|
|
1873
|
+
searchUsers,
|
|
1874
|
+
searchChannels
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
) });
|
|
1878
|
+
}
|
|
1879
|
+
var messagingScreenPropertySchema = {
|
|
1880
|
+
widgetType: "MessagingScreen",
|
|
1881
|
+
displayName: "Messaging Screen",
|
|
1882
|
+
tabsConfig: [{ id: "styling", label: "Styling" }],
|
|
1883
|
+
fields: []
|
|
1884
|
+
};
|
|
1885
|
+
|
|
1886
|
+
Object.defineProperty(exports, "buildThemeDefinition", {
|
|
1887
|
+
enumerable: true,
|
|
1888
|
+
get: function () { return theme_star.buildThemeDefinition; }
|
|
1889
|
+
});
|
|
1890
|
+
Object.defineProperty(exports, "getActiveThemeId", {
|
|
1891
|
+
enumerable: true,
|
|
1892
|
+
get: function () { return theme_star.getActiveThemeId; }
|
|
1893
|
+
});
|
|
1894
|
+
Object.defineProperty(exports, "transformThemes", {
|
|
1895
|
+
enumerable: true,
|
|
1896
|
+
get: function () { return theme_star.transformThemes; }
|
|
1897
|
+
});
|
|
1898
|
+
exports.AUTH_CONSTANTS = AUTH_CONSTANTS;
|
|
1899
|
+
exports.ApiError = ApiError2;
|
|
1900
|
+
exports.DEFAULT_AUTH_URL = DEFAULT_AUTH_URL;
|
|
1901
|
+
exports.DEFAULT_SDK_WIDGET_REGISTRY = DEFAULT_SDK_WIDGET_REGISTRY;
|
|
1902
|
+
exports.FluidAuthProvider = FluidAuthProvider;
|
|
1903
|
+
exports.FluidProvider = FluidProvider;
|
|
1904
|
+
exports.FluidThemeProvider = FluidThemeProvider;
|
|
1905
|
+
exports.MessagingScreen = MessagingScreen;
|
|
1906
|
+
exports.STORAGE_KEYS = STORAGE_KEYS;
|
|
1907
|
+
exports.URL_PARAMS = URL_PARAMS;
|
|
1908
|
+
exports.USER_TYPES = USER_TYPES;
|
|
1909
|
+
exports.cleanTokenFromUrl = cleanTokenFromUrl;
|
|
1910
|
+
exports.clearTokens = clearTokens;
|
|
1911
|
+
exports.createDefaultAuthRedirect = createDefaultAuthRedirect;
|
|
1912
|
+
exports.createFluidClient = createFluidClient;
|
|
1913
|
+
exports.createFluidFileUploader = createFluidFileUploader;
|
|
1914
|
+
exports.decodeToken = decodeToken;
|
|
1915
|
+
exports.extractAllTokensFromUrl = extractAllTokensFromUrl;
|
|
1916
|
+
exports.extractCompanyTokenFromUrl = extractCompanyTokenFromUrl;
|
|
1917
|
+
exports.extractTokenFromUrl = extractTokenFromUrl;
|
|
1918
|
+
exports.getStoredToken = getStoredToken;
|
|
1919
|
+
exports.getTokenExpiration = getTokenExpiration;
|
|
1920
|
+
exports.getTokenTimeRemaining = getTokenTimeRemaining;
|
|
1921
|
+
exports.hasStoredToken = hasStoredToken;
|
|
1922
|
+
exports.hasTokenInUrl = hasTokenInUrl;
|
|
1923
|
+
exports.isApiError = isApiError2;
|
|
1924
|
+
exports.isTokenExpired = isTokenExpired;
|
|
1925
|
+
exports.isUserType = isUserType;
|
|
1926
|
+
exports.isValidToken = isValidToken;
|
|
1927
|
+
exports.messagingScreenPropertySchema = messagingScreenPropertySchema;
|
|
1928
|
+
exports.normalizeComponentTree = normalizeComponentTree;
|
|
1929
|
+
exports.storeToken = storeToken;
|
|
1930
|
+
exports.themes_exports = themes_exports;
|
|
1931
|
+
exports.toNavigationItem = toNavigationItem;
|
|
1932
|
+
exports.toScreenDefinition = toScreenDefinition;
|
|
1933
|
+
exports.transformManifestToRepAppData = transformManifestToRepAppData;
|
|
1934
|
+
exports.useFluidApi = useFluidApi;
|
|
1935
|
+
exports.useFluidAuthContext = useFluidAuthContext;
|
|
1936
|
+
exports.useFluidContext = useFluidContext;
|
|
1937
|
+
exports.useMessagingAuth = useMessagingAuth;
|
|
1938
|
+
exports.useMessagingConfig = useMessagingConfig;
|
|
1939
|
+
exports.useThemeContext = useThemeContext;
|
|
1940
|
+
exports.validateToken = validateToken;
|
|
1941
|
+
//# sourceMappingURL=chunk-V3IMQZIG.cjs.map
|
|
1942
|
+
//# sourceMappingURL=chunk-V3IMQZIG.cjs.map
|