@fluid-topics/public-api 1.0.49 → 1.0.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/build/cjs/index.js +373 -0
  2. package/build/cjs/preferences/unauthenticated-preferences.js +67 -0
  3. package/build/cjs/roles/roles.js +31 -0
  4. package/build/cjs/types/ft-common/public.js +743 -0
  5. package/build/cjs/types/ft-server/public.js +69 -0
  6. package/build/mjs/index.d.ts +168 -0
  7. package/build/mjs/index.js +358 -0
  8. package/build/mjs/preferences/unauthenticated-preferences.d.ts +9 -0
  9. package/build/mjs/preferences/unauthenticated-preferences.js +61 -0
  10. package/build/mjs/roles/roles.d.ts +2 -0
  11. package/build/mjs/roles/roles.js +25 -0
  12. package/build/mjs/types/ft-common/public.d.ts +580 -0
  13. package/build/mjs/types/ft-common/public.js +667 -0
  14. package/build/mjs/types/ft-server/public.d.ts +50 -0
  15. package/build/mjs/types/ft-server/public.js +59 -0
  16. package/dist/cjs/index.js +373 -0
  17. package/dist/cjs/package.json +3 -0
  18. package/dist/cjs/preferences/unauthenticated-preferences.js +67 -0
  19. package/dist/cjs/roles/roles.js +31 -0
  20. package/dist/cjs/types/ft-common/public.js +743 -0
  21. package/dist/cjs/types/ft-server/public.js +69 -0
  22. package/dist/fluidtopics.min.js +1 -0
  23. package/dist/mjs/index.d.ts +168 -0
  24. package/dist/mjs/index.js +358 -0
  25. package/dist/mjs/package.json +3 -0
  26. package/dist/mjs/preferences/unauthenticated-preferences.d.ts +9 -0
  27. package/dist/mjs/preferences/unauthenticated-preferences.js +61 -0
  28. package/dist/mjs/roles/roles.d.ts +2 -0
  29. package/dist/mjs/roles/roles.js +25 -0
  30. package/dist/mjs/types/ft-common/public.d.ts +580 -0
  31. package/dist/mjs/types/ft-common/public.js +667 -0
  32. package/dist/mjs/types/ft-server/public.d.ts +50 -0
  33. package/dist/mjs/types/ft-server/public.js +59 -0
  34. package/package.json +1 -1
@@ -0,0 +1,358 @@
1
+ import "cross-fetch/polyfill";
2
+ const wnd = (typeof window === "undefined" ? globalThis : window);
3
+ export * from "./types/ft-common/public";
4
+ export * from "./types/ft-server/public";
5
+ export * from "./roles/roles";
6
+ export * from "./preferences/unauthenticated-preferences";
7
+ function toBase64(s) {
8
+ return typeof Buffer !== "undefined" ? Buffer.from(s).toString("base64") : btoa(s);
9
+ }
10
+ export class HttpError extends Error {
11
+ status;
12
+ statusText;
13
+ body;
14
+ constructor(status, statusText, body) {
15
+ super(`${status} - ${statusText}: ${body}`);
16
+ this.status = status;
17
+ this.statusText = statusText;
18
+ this.body = body;
19
+ }
20
+ }
21
+ async function handleError(response) {
22
+ if (!response.ok) {
23
+ throw new HttpError(response.status, response.statusText, await response.text());
24
+ }
25
+ return response;
26
+ }
27
+ function getBody(response) {
28
+ return response.headers.get("Content-Type") === "application/json" ? response.json() : response.text();
29
+ }
30
+ export class FluidTopicsApi {
31
+ tenantBaseUrl;
32
+ ftCallingApp;
33
+ authorization;
34
+ searchLabel;
35
+ endpoints = {
36
+ authentication: {
37
+ login: `api/authentication/login`,
38
+ logout: `api/authentication/logout`,
39
+ currentSession: `api/authentication/current-session`,
40
+ },
41
+ khub: {
42
+ maps: {
43
+ mapId: (mapId) => ({
44
+ info: `api/khub/maps/${mapId}`,
45
+ toc: `api/khub/maps/${mapId}/toc`,
46
+ pages: `api/khub/maps/${mapId}/pages`,
47
+ feedback: `api/khub/maps/${mapId}/feedback`,
48
+ rating: `api/khub/maps/${mapId}/rating`,
49
+ attachments: {
50
+ list: `api/khub/maps/${mapId}/attachments`,
51
+ attachmentId: (attachmentId) => ({
52
+ content: `api/khub/maps/${mapId}/attachments/${attachmentId}/content`,
53
+ })
54
+ },
55
+ resources: {
56
+ list: `api/khub/maps/${mapId}/resources`,
57
+ resourceId: (resourceId) => ({
58
+ content: `api/khub/maps/${mapId}/resources/${resourceId}/content`,
59
+ })
60
+ },
61
+ topics: {
62
+ contentId: (contentId) => ({
63
+ info: `api/khub/maps/${mapId}/topics/${contentId}`,
64
+ content: `api/khub/maps/${mapId}/topics/${contentId}/content`,
65
+ }),
66
+ tocId: (tocId) => ({
67
+ feedback: `api/khub/maps/${mapId}/topics/${tocId}/feedback`,
68
+ rating: `api/khub/maps/${mapId}/topics/${tocId}/rating`,
69
+ })
70
+ },
71
+ })
72
+ },
73
+ documents: {
74
+ documentId: (documentId) => ({
75
+ info: `api/khub/documents/${documentId}`,
76
+ content: `api/khub/documents/${documentId}/content`,
77
+ text: `api/khub/documents/${documentId}/content/text`,
78
+ feedback: `api/khub/documents/${documentId}/feedback`,
79
+ rating: `api/khub/documents/${documentId}/rating`,
80
+ })
81
+ },
82
+ suggest: `api/khub/suggest`,
83
+ clusteredSearch: `api/khub/clustered-search`,
84
+ locales: `api/khub/locales`,
85
+ },
86
+ users: {
87
+ userId: (userId) => ({
88
+ collections: {
89
+ collectionId: (collectionId) => ({
90
+ documents: `api/users/${userId}/collections/${collectionId}/documents`,
91
+ })
92
+ },
93
+ searches: {
94
+ list: `api/users/${userId}/searches`
95
+ },
96
+ bookmarks: {
97
+ list: `api/users/${userId}/bookmarks`
98
+ }
99
+ }),
100
+ },
101
+ stylesheets: {
102
+ fonts: `api/stylesheets/fonts.css`,
103
+ theme: `api/stylesheets/theme.css`,
104
+ content: {
105
+ title: `api/stylesheets/content/title.css`,
106
+ topic: `api/stylesheets/content/topic.css`,
107
+ },
108
+ },
109
+ configuration: {
110
+ reader: `api/configuration/reader`
111
+ },
112
+ locales: {
113
+ ui: `api/locales/ui`
114
+ },
115
+ messages: {
116
+ locale: (locale) => ({
117
+ fluidTopics: {
118
+ contextName: (contextName) => ({
119
+ endpoint: `api/messages/${locale}/fluid-topics/${contextName}`,
120
+ })
121
+ },
122
+ custom: {
123
+ contextName: (contextName) => ({
124
+ endpoint: `api/messages/${locale}/custom/${contextName}`,
125
+ })
126
+ }
127
+ })
128
+ },
129
+ };
130
+ get defaultHeaders() {
131
+ return {
132
+ ...this.authorization,
133
+ ...this.searchLabel,
134
+ "Ft-Calling-App": this.ftCallingApp
135
+ };
136
+ }
137
+ constructor(tenantBaseUrl, integrationIdentifier, overrideIdentifierIfOnTenant) {
138
+ //@ts-ignore
139
+ tenantBaseUrl = (tenantBaseUrl ?? wnd.__gwt_ft_moduleBase ?? wnd.fluidtopicsclient?.__moduleBase ?? wnd.__gwt_activeModules?.fluidtopicsclient?.moduleBase ?? "").trim();
140
+ this.tenantBaseUrl = tenantBaseUrl.endsWith("/") ? tenantBaseUrl : tenantBaseUrl + "/";
141
+ if (overrideIdentifierIfOnTenant && typeof wnd.location !== "undefined" && wnd.location.href.startsWith(this.tenantBaseUrl)) {
142
+ this.ftCallingApp = integrationIdentifier;
143
+ }
144
+ else {
145
+ this.ftCallingApp = `ft-public-api/${integrationIdentifier}`;
146
+ }
147
+ }
148
+ setApiKey(apiKey) {
149
+ this.authorization = { "Authorization": "Bearer " + apiKey };
150
+ }
151
+ setCredentials(login, password) {
152
+ this.authorization = { "Authorization": "Basic " + toBase64(`${login}:${password}`) };
153
+ }
154
+ clearAuthentication() {
155
+ this.authorization = undefined;
156
+ }
157
+ setSearchLabel(searchLabel) {
158
+ this.searchLabel = { "FT-search-label": searchLabel };
159
+ }
160
+ clearSearchLabel() {
161
+ this.searchLabel = undefined;
162
+ }
163
+ login(login, password) {
164
+ let credentials = {
165
+ login: login,
166
+ password: password,
167
+ rememberMe: true
168
+ };
169
+ return this.post(this.endpoints.authentication.login, credentials)
170
+ .then(result => {
171
+ this.setCredentials(login, password);
172
+ return result;
173
+ });
174
+ }
175
+ logout() {
176
+ return this.post(this.endpoints.authentication.logout)
177
+ .then(() => this.clearAuthentication());
178
+ }
179
+ getCurrentSession() {
180
+ return this.get(this.endpoints.authentication.currentSession);
181
+ }
182
+ getReaderConfiguration() {
183
+ return this.get(this.endpoints.configuration.reader);
184
+ }
185
+ getMap(mapId, v) {
186
+ return this.get(this.endpoints.khub.maps.mapId(mapId).info, v);
187
+ }
188
+ getTableOfContent(mapId, v) {
189
+ return this.get(this.endpoints.khub.maps.mapId(mapId).toc, v);
190
+ }
191
+ getPages(mapId, v) {
192
+ return this.get(this.endpoints.khub.maps.mapId(mapId).pages, v);
193
+ }
194
+ getTopic(mapId, topicContentId, v) {
195
+ return this.get(this.endpoints.khub.maps.mapId(mapId).topics.contentId(topicContentId).info, v);
196
+ }
197
+ getTopicHTMLContent(mapId, topicContentId, target, v) {
198
+ return this.get(this.endpoints.khub.maps.mapId(mapId).topics.contentId(topicContentId).content + (target ? "?target=" + target : ""), v);
199
+ }
200
+ getMapAttachments(mapId, v) {
201
+ return this.get(this.endpoints.khub.maps.mapId(mapId).attachments.list, v);
202
+ }
203
+ getMapAttachmentContent(mapId, attachmentId, v) {
204
+ return this.fetchRawData(this.endpoints.khub.maps.mapId(mapId).attachments.attachmentId(attachmentId).content, v);
205
+ }
206
+ getMapResources(mapId, v) {
207
+ return this.get(this.endpoints.khub.maps.mapId(mapId).resources.list, v);
208
+ }
209
+ getMapResourceContent(mapId, resourceId, v) {
210
+ return this.fetchRawData(this.endpoints.khub.maps.mapId(mapId).resources.resourceId(resourceId).content, v);
211
+ }
212
+ getUnstructuredDocument(documentId, v) {
213
+ return this.get(this.endpoints.khub.documents.documentId(documentId).info, v);
214
+ }
215
+ getUnstructuredDocumentContent(documentId, v) {
216
+ return this.fetchRawData(this.endpoints.khub.documents.documentId(documentId).content, v);
217
+ }
218
+ getUnstructuredDocumentTextContent(documentId, v) {
219
+ return this.get(this.endpoints.khub.documents.documentId(documentId).text, v);
220
+ }
221
+ getCollectionDocuments(userId, collectionId) {
222
+ return this.get(this.endpoints.users.userId(userId).collections.collectionId(collectionId).documents);
223
+ }
224
+ getSuggestions(request) {
225
+ return this.post(this.endpoints.khub.suggest, request);
226
+ }
227
+ search(request) {
228
+ return this.post(this.endpoints.khub.clusteredSearch, request);
229
+ }
230
+ getAvailableSearchLocales() {
231
+ return this.get(this.endpoints.khub.locales);
232
+ }
233
+ getAvailableUiLocales() {
234
+ return this.get(this.endpoints.khub.locales);
235
+ }
236
+ getMapRating(mapId) {
237
+ return this.get(this.endpoints.khub.maps.mapId(mapId).rating);
238
+ }
239
+ rateMap(mapId, type, value) {
240
+ return this.post(this.endpoints.khub.maps.mapId(mapId).rating, { type, value });
241
+ }
242
+ unrateMap(mapId) {
243
+ return this.delete(this.endpoints.khub.maps.mapId(mapId).rating);
244
+ }
245
+ sendMapFeedback(mapId, message, from) {
246
+ return this.post(this.endpoints.khub.maps.mapId(mapId).feedback, { message, from });
247
+ }
248
+ rateTopic(mapId, tocId, type, value) {
249
+ return this.post(this.endpoints.khub.maps.mapId(mapId).topics.tocId(tocId).rating, {
250
+ type, value
251
+ });
252
+ }
253
+ unrateTopic(mapId, tocId) {
254
+ return this.delete(this.endpoints.khub.maps.mapId(mapId).topics.tocId(tocId).rating);
255
+ }
256
+ sendTopicFeedback(mapId, tocId, message, from) {
257
+ return this.post(this.endpoints.khub.maps.mapId(mapId).topics.tocId(tocId).feedback, { message, from });
258
+ }
259
+ getDocumentRating(docId) {
260
+ return this.get(this.endpoints.khub.documents.documentId(docId).rating);
261
+ }
262
+ rateDocument(docId, type, value) {
263
+ return this.post(this.endpoints.khub.documents.documentId(docId).rating, { type, value });
264
+ }
265
+ unrateDocument(docId) {
266
+ return this.delete(this.endpoints.khub.documents.documentId(docId).rating);
267
+ }
268
+ sendDocumentFeedback(docId, message, from) {
269
+ return this.post(this.endpoints.khub.documents.documentId(docId).feedback, { message, from });
270
+ }
271
+ getFluidTopicsMessageContext(locale, name) {
272
+ return this.get(this.endpoints.messages.locale(locale).fluidTopics.contextName(name).endpoint);
273
+ }
274
+ getCustomMessageContext(locale, name) {
275
+ return this.get(this.endpoints.messages.locale(locale).custom.contextName(name).endpoint);
276
+ }
277
+ listMySearches(userId) {
278
+ return this.get(this.endpoints.users.userId(userId).searches.list);
279
+ }
280
+ listMyBookmarks(userId) {
281
+ return this.get(this.endpoints.users.userId(userId).bookmarks.list);
282
+ }
283
+ get(endpoint, v) {
284
+ return this.makeRequest("GET", this.withVersion(endpoint, v));
285
+ }
286
+ post(endpoint, data) {
287
+ return this.makeRequest("POST", endpoint, data);
288
+ }
289
+ put(endpoint, data) {
290
+ return this.makeRequest("PUT", endpoint, data);
291
+ }
292
+ delete(endpoint) {
293
+ return this.makeRequest("DELETE", endpoint);
294
+ }
295
+ makeAbsolute(endpoint) {
296
+ return endpoint.startsWith(this.tenantBaseUrl) ? endpoint : (this.tenantBaseUrl + endpoint.replace(/^\//, ""));
297
+ }
298
+ async fetch(endpoint, init) {
299
+ const requestInit = init;
300
+ return await fetch(this.makeAbsolute(endpoint), {
301
+ ...(requestInit ?? {}),
302
+ headers: {
303
+ ...this.defaultHeaders,
304
+ ...(requestInit?.headers ?? {})
305
+ }
306
+ });
307
+ }
308
+ upload(method, endpoint, body, onProgress = () => undefined) {
309
+ if (typeof XMLHttpRequest !== "undefined") {
310
+ return new Promise((resolve, reject) => {
311
+ let xhr = new XMLHttpRequest();
312
+ xhr.onload = () => {
313
+ if (xhr.status >= 200 && xhr.status < 300) {
314
+ let data = xhr.getResponseHeader("Content-Type") === "application/json" ? JSON.parse(xhr.responseText) : xhr.responseText;
315
+ resolve(data);
316
+ }
317
+ else {
318
+ reject(new HttpError(xhr.status, xhr.statusText, xhr.responseText));
319
+ }
320
+ };
321
+ xhr.upload.onprogress = (e) => onProgress(e);
322
+ xhr.open(method, this.makeAbsolute(endpoint), true);
323
+ xhr.send(body);
324
+ });
325
+ }
326
+ else {
327
+ return this.fetch(endpoint, { method, body }).then(handleError).then(getBody);
328
+ }
329
+ }
330
+ makeRequest(method, endpoint, data) {
331
+ return this.fetch(endpoint, {
332
+ method: method,
333
+ headers: {
334
+ ...(data != null ? { "Content-Type": "application/json" } : {})
335
+ },
336
+ body: data != null ? JSON.stringify(data) : undefined,
337
+ credentials: this.authorization == null ? "include" : undefined
338
+ })
339
+ .then(handleError)
340
+ .then(getBody);
341
+ }
342
+ fetchRawData(endpoint, v) {
343
+ return fetch(this.withVersion(endpoint, v), {
344
+ headers: this.defaultHeaders,
345
+ credentials: this.authorization == null ? "include" : undefined
346
+ })
347
+ .then(handleError)
348
+ .then(response => response.arrayBuffer());
349
+ }
350
+ withVersion(endpoint, v) {
351
+ let url = new URL(this.makeAbsolute(endpoint));
352
+ if (v) {
353
+ url.searchParams.append("v", v);
354
+ }
355
+ return url.toString();
356
+ }
357
+ }
358
+ export default FluidTopicsApi;
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "module"
3
+ }
@@ -0,0 +1,9 @@
1
+ import { FtMetadataPreferenceConfiguration, FtSearchPreferencesConfiguration } from "../types/ft-common/public";
2
+ export declare function setUnauthenticatedUserSearchPreferences(tenantBaseUrl: string, input: FtSearchPreferencesConfiguration): {
3
+ metadata: Record<string, FtMetadataPreferenceConfiguration>;
4
+ };
5
+ export declare function getUnauthenticatedUserSearchPreferences(tenantBaseUrl: string): FtSearchPreferencesConfiguration;
6
+ export type HandlerRegistration = {
7
+ removeHandler: () => void;
8
+ };
9
+ export declare function addUnauthenticatedUserSearchPreferencesChangeHandler(tenantBaseUrl: string, handler: (newValue: FtSearchPreferencesConfiguration) => void): HandlerRegistration;
@@ -0,0 +1,61 @@
1
+ const wnd = (typeof window === "undefined" ? globalThis : window);
2
+ function normalizeMetadataPreferences(metadata) {
3
+ let normalized = {};
4
+ for (let key in metadata) {
5
+ let values = metadata[key];
6
+ if (typeof values !== "object" || Array.isArray(values)) {
7
+ values = { prior: values };
8
+ }
9
+ for (let property of ["prior", "filter"]) {
10
+ values[property] = Array.isArray(values[property]) ? values[property] : [values[property]];
11
+ values[property] = values[property]
12
+ .map(v => v != null ? "" + v : "")
13
+ .filter(v => v !== "");
14
+ }
15
+ normalized[key] = values;
16
+ }
17
+ return normalized;
18
+ }
19
+ function getStorageKey(tenantBaseUrl) {
20
+ return `${tenantBaseUrl}-FluidTopicsUnauthenticatedUserSearchPreferences`;
21
+ }
22
+ export function setUnauthenticatedUserSearchPreferences(tenantBaseUrl, input) {
23
+ if (wnd.localStorage) {
24
+ let preferences = {
25
+ ...input,
26
+ metadata: normalizeMetadataPreferences(input.metadata ?? {})
27
+ };
28
+ const key = getStorageKey(tenantBaseUrl);
29
+ const newValue = JSON.stringify(preferences);
30
+ wnd.localStorage.setItem(key, newValue);
31
+ wnd.dispatchEvent(new StorageEvent("storage", {
32
+ key,
33
+ newValue,
34
+ storageArea: wnd.localStorage,
35
+ url: wnd.location.href
36
+ }));
37
+ return preferences;
38
+ }
39
+ console.error("Cannot set unauthenticated preferences: local storage is unavailable.");
40
+ }
41
+ export function getUnauthenticatedUserSearchPreferences(tenantBaseUrl) {
42
+ if (wnd.localStorage) {
43
+ return JSON.parse(wnd.localStorage.getItem(getStorageKey(tenantBaseUrl)) ?? "{}");
44
+ }
45
+ console.error("Cannot get unauthenticated preferences: local storage is unavailable.");
46
+ }
47
+ export function addUnauthenticatedUserSearchPreferencesChangeHandler(tenantBaseUrl, handler) {
48
+ if (wnd.localStorage) {
49
+ const key = getStorageKey(tenantBaseUrl);
50
+ const eventListener = (event) => {
51
+ if (event.storageArea === wnd.localStorage && event.key === key) {
52
+ handler(JSON.parse(event.newValue ?? "{}"));
53
+ }
54
+ };
55
+ wnd.addEventListener("storage", eventListener);
56
+ return {
57
+ removeHandler: () => wnd.removeEventListener("storage", eventListener)
58
+ };
59
+ }
60
+ console.error("Cannot handle unauthenticated preferences: local storage is unavailable.");
61
+ }
@@ -0,0 +1,2 @@
1
+ import { FtSession, FtUserProfile, FtUserRole, FtUserRoleKeys } from "../types/ft-common/public";
2
+ export declare function userHasRole(sessionOrProfileOrRoles: FtSession | FtUserProfile | Array<FtUserRole | FtUserRoleKeys> | undefined, expectedRole: FtUserRole | FtUserRoleKeys): boolean;
@@ -0,0 +1,25 @@
1
+ import { FtUserRole } from "../types/ft-common/public";
2
+ const rolesInheritance = {
3
+ [FtUserRole.PERSONAL_BOOK_SHARE_USER]: [FtUserRole.PERSONAL_BOOK_USER],
4
+ [FtUserRole.HTML_EXPORT_USER]: [FtUserRole.PERSONAL_BOOK_USER],
5
+ [FtUserRole.PDF_EXPORT_USER]: [FtUserRole.PERSONAL_BOOK_USER],
6
+ [FtUserRole.KHUB_ADMIN]: [FtUserRole.CONTENT_PUBLISHER],
7
+ [FtUserRole.ADMIN]: [FtUserRole.KHUB_ADMIN, FtUserRole.USERS_ADMIN, FtUserRole.PORTAL_ADMIN],
8
+ [FtUserRole.DEVELOPER]: [FtUserRole.BETA_USER, FtUserRole.DEBUG_USER],
9
+ };
10
+ function roleMatches(actual, expected) {
11
+ return actual === expected || (rolesInheritance[actual] ?? []).some((inherited) => roleMatches(inherited, expected));
12
+ }
13
+ export function userHasRole(sessionOrProfileOrRoles, expectedRole) {
14
+ if (sessionOrProfileOrRoles == null) {
15
+ return false;
16
+ }
17
+ const roles = Array.isArray(sessionOrProfileOrRoles)
18
+ ? sessionOrProfileOrRoles
19
+ : Array.isArray(sessionOrProfileOrRoles.roles)
20
+ ? sessionOrProfileOrRoles.roles
21
+ : Array.isArray(sessionOrProfileOrRoles.profile?.roles)
22
+ ? sessionOrProfileOrRoles.profile.roles
23
+ : [];
24
+ return roles.some(role => roleMatches(role, expectedRole));
25
+ }