@omerlo/omerlo-webkit 0.0.4 → 0.0.6
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/README.md +24 -24
- package/dist/components/OmerloWebkit.svelte +2 -3
- package/dist/components/OmerloWebkit.svelte.d.ts +1 -1
- package/dist/omerlo/index.d.ts +32 -4
- package/dist/omerlo/reader/endpoints/categories.d.ts +18 -0
- package/dist/omerlo/reader/endpoints/categories.js +39 -0
- package/dist/omerlo/reader/endpoints/content-templates.d.ts +23 -0
- package/dist/omerlo/reader/endpoints/content-templates.js +34 -0
- package/dist/omerlo/reader/endpoints/contents.d.ts +122 -0
- package/dist/omerlo/reader/endpoints/contents.js +187 -0
- package/dist/omerlo/reader/endpoints/device.js +1 -1
- package/dist/omerlo/reader/endpoints/events.d.ts +32 -0
- package/dist/omerlo/reader/endpoints/events.js +45 -0
- package/dist/omerlo/reader/endpoints/magazines.d.ts +104 -0
- package/dist/omerlo/reader/endpoints/magazines.js +135 -0
- package/dist/omerlo/reader/endpoints/media.d.ts +65 -0
- package/dist/omerlo/reader/endpoints/media.js +133 -0
- package/dist/omerlo/reader/endpoints/menu.d.ts +31 -0
- package/dist/omerlo/reader/endpoints/menu.js +49 -0
- package/dist/omerlo/reader/endpoints/notification.d.ts +5 -5
- package/dist/omerlo/reader/endpoints/notification.js +6 -8
- package/dist/omerlo/reader/endpoints/oauth.js +1 -1
- package/dist/omerlo/reader/endpoints/organizations.d.ts +40 -0
- package/dist/omerlo/reader/endpoints/organizations.js +72 -0
- package/dist/omerlo/reader/endpoints/person.d.ts +30 -0
- package/dist/omerlo/reader/endpoints/person.js +39 -0
- package/dist/omerlo/reader/endpoints/profileType.d.ts +27 -0
- package/dist/omerlo/reader/endpoints/profileType.js +28 -0
- package/dist/omerlo/reader/endpoints/profiles.d.ts +70 -0
- package/dist/omerlo/reader/endpoints/profiles.js +97 -0
- package/dist/omerlo/reader/endpoints/projects.d.ts +28 -0
- package/dist/omerlo/reader/endpoints/projects.js +37 -0
- package/dist/omerlo/reader/endpoints/visuals.d.ts +34 -0
- package/dist/omerlo/reader/endpoints/visuals.js +44 -0
- package/dist/omerlo/reader/endpoints/webpage.d.ts +20 -0
- package/dist/omerlo/reader/endpoints/webpage.js +21 -0
- package/dist/omerlo/reader/fetchers.d.ts +30 -2
- package/dist/omerlo/reader/fetchers.js +12 -0
- package/dist/omerlo/reader/index.d.ts +18 -1
- package/dist/omerlo/reader/index.js +18 -0
- package/dist/omerlo/reader/server/email.d.ts +12 -0
- package/dist/omerlo/reader/server/email.js +30 -0
- package/dist/omerlo/reader/server/hooks.d.ts +1 -1
- package/dist/omerlo/reader/server/hooks.js +39 -20
- package/dist/omerlo/reader/server/index.d.ts +1 -0
- package/dist/omerlo/reader/server/index.js +1 -0
- package/dist/omerlo/reader/server/token.d.ts +6 -6
- package/dist/omerlo/reader/server/token.js +7 -7
- package/dist/omerlo/reader/server/utils.d.ts +4 -4
- package/dist/omerlo/reader/server/utils.js +13 -7
- package/dist/omerlo/reader/stores/user_session.d.ts +2 -2
- package/dist/omerlo/reader/stores/user_session.js +11 -9
- package/dist/omerlo/reader/utils/api.d.ts +1 -1
- package/dist/omerlo/reader/utils/api.js +4 -3
- package/dist/omerlo/reader/utils/assocs.d.ts +5 -4
- package/dist/omerlo/reader/utils/assocs.js +23 -0
- package/dist/omerlo/reader/utils/parseHelpers.d.ts +7 -0
- package/dist/omerlo/reader/utils/parseHelpers.js +22 -0
- package/dist/omerlo/reader/utils/request.d.ts +10 -8
- package/dist/omerlo/reader/utils/request.js +39 -11
- package/dist/omerlo/reader/utils/response.d.ts +1 -1
- package/dist/omerlo/reader/utils/response.js +1 -1
- package/eslint.config.js +11 -2
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -7,8 +7,6 @@ over all window's tab, no need to refresh other tabs.
|
|
|
7
7
|
|
|
8
8
|
## Using the omerlo webkit
|
|
9
9
|
|
|
10
|
-
###
|
|
11
|
-
|
|
12
10
|
Install the package `omerlo-webkit`
|
|
13
11
|
|
|
14
12
|
```sh
|
|
@@ -24,17 +22,17 @@ Copy the `.env.dist` to `.env` then update its values to match your Omerlo's app
|
|
|
24
22
|
Create (or update) the file `src/hooks.server.ts` and add required hooks as follow
|
|
25
23
|
|
|
26
24
|
```ts
|
|
27
|
-
import type { Handle } from
|
|
25
|
+
import type { Handle } from '@sveltejs/kit';
|
|
28
26
|
|
|
29
27
|
import { handleUserToken, handleReaderApi } from 'omerlo-webkit/reader/server';
|
|
30
|
-
import { sequence } from
|
|
28
|
+
import { sequence } from '@sveltejs/kit/hooks';
|
|
31
29
|
|
|
32
30
|
// You can add custom hooks too
|
|
33
31
|
const handleLocale: Handle = async ({ event, resolve }) => {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
32
|
+
const userLocale = 'en'; // you can fetch this value from cookie or w.e
|
|
33
|
+
event.url.searchParams.append('locale', userLocale);
|
|
34
|
+
return resolve(event);
|
|
35
|
+
};
|
|
38
36
|
|
|
39
37
|
export const handle = sequence(handleLocale, handleUserToken, handleReaderApi);
|
|
40
38
|
```
|
|
@@ -92,7 +90,7 @@ You'll need to create a login endpoint to add some required params such as the `
|
|
|
92
90
|
|
|
93
91
|
```ts
|
|
94
92
|
// +server.ts
|
|
95
|
-
import { error, redirect, type RequestHandler } from
|
|
93
|
+
import { error, redirect, type RequestHandler } from '@sveltejs/kit';
|
|
96
94
|
import { env } from '$env/dynamic/private';
|
|
97
95
|
import jwt from 'jsonwebtoken';
|
|
98
96
|
|
|
@@ -104,39 +102,41 @@ export const GET: RequestHandler = ({ url }) => {
|
|
|
104
102
|
if (!oauthProviderId) error(400, 'Missing oauthProviderId query parameter');
|
|
105
103
|
|
|
106
104
|
const currentPath = url.searchParams.get('currentPath') || '/';
|
|
107
|
-
const state = jwt.sign({ currentPath, oauthProviderId }, env.PRIVATE_JWT_SECRET, {
|
|
105
|
+
const state = jwt.sign({ currentPath, oauthProviderId }, env.PRIVATE_JWT_SECRET, {
|
|
106
|
+
expiresIn: '1h'
|
|
107
|
+
});
|
|
108
108
|
|
|
109
109
|
const redirectUrl = new URL(oauthUrl);
|
|
110
110
|
redirectUrl.searchParams.set('state', state);
|
|
111
|
-
redirectUrl.searchParams.set('redirect_uri', url.origin +'/oauth/callback');
|
|
111
|
+
redirectUrl.searchParams.set('redirect_uri', url.origin + '/oauth/callback');
|
|
112
112
|
|
|
113
113
|
redirect(302, redirectUrl);
|
|
114
|
-
}
|
|
114
|
+
};
|
|
115
115
|
```
|
|
116
116
|
|
|
117
117
|
And then create a callback action.
|
|
118
118
|
|
|
119
119
|
```ts
|
|
120
|
-
import { error, redirect, type RequestHandler } from
|
|
120
|
+
import { error, redirect, type RequestHandler } from '@sveltejs/kit';
|
|
121
121
|
import { env } from '$env/dynamic/private';
|
|
122
122
|
import jwt from 'jsonwebtoken';
|
|
123
|
-
import { exchangeAuthorizationCode, setAuthorizationCookies } from
|
|
123
|
+
import { exchangeAuthorizationCode, setAuthorizationCookies } from 'omerlo-webkit/reader/server';
|
|
124
124
|
|
|
125
125
|
export const GET: RequestHandler = async ({ url, cookies }) => {
|
|
126
126
|
const redirectUri = url.origin + url.pathname;
|
|
127
127
|
const state = getRequiredQueryParams(url, 'state');
|
|
128
128
|
const code = getRequiredQueryParams(url, 'code');
|
|
129
|
-
const {oauthProviderId, currentPath} = parseJwt(state);
|
|
129
|
+
const { oauthProviderId, currentPath } = parseJwt(state);
|
|
130
130
|
|
|
131
131
|
try {
|
|
132
|
-
const token = await exchangeAuthorizationCode({code, redirectUri, oauthProviderId})
|
|
132
|
+
const token = await exchangeAuthorizationCode({ code, redirectUri, oauthProviderId });
|
|
133
133
|
setAuthorizationCookies(cookies, token);
|
|
134
|
-
} catch(_err) {
|
|
135
|
-
error(401,
|
|
134
|
+
} catch (_err) {
|
|
135
|
+
error(401, 'Could not authenticate from the provider');
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
redirect(303, currentPath);
|
|
139
|
-
}
|
|
139
|
+
};
|
|
140
140
|
|
|
141
141
|
function getRequiredQueryParams(url: URL, paramsName: string): string {
|
|
142
142
|
const value = url.searchParams.get(paramsName);
|
|
@@ -149,14 +149,14 @@ function getRequiredQueryParams(url: URL, paramsName: string): string {
|
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
interface State {
|
|
152
|
-
oauthProviderId: string
|
|
153
|
-
currentPath: string
|
|
152
|
+
oauthProviderId: string;
|
|
153
|
+
currentPath: string;
|
|
154
154
|
}
|
|
155
155
|
|
|
156
156
|
function parseJwt(state: string): State {
|
|
157
157
|
try {
|
|
158
158
|
return jwt.verify(state, env.PRIVATE_JWT_SECRET) as State;
|
|
159
|
-
} catch(_err) {
|
|
159
|
+
} catch (_err) {
|
|
160
160
|
error(400, 'Invalid state');
|
|
161
161
|
}
|
|
162
162
|
}
|
|
@@ -168,13 +168,13 @@ To logout your user you can create an endpoint that will drop cookies used for a
|
|
|
168
168
|
|
|
169
169
|
```ts
|
|
170
170
|
// +server.ts
|
|
171
|
-
import { json, type RequestHandler } from
|
|
171
|
+
import { json, type RequestHandler } from '@sveltejs/kit';
|
|
172
172
|
import { clearAuthorizationCookies } from 'omerlo-webkit/reader/server';
|
|
173
173
|
|
|
174
174
|
export const DELETE: RequestHandler = ({ cookies }) => {
|
|
175
175
|
clearAuthorizationCookies(cookies);
|
|
176
176
|
return json(201);
|
|
177
|
-
}
|
|
177
|
+
};
|
|
178
178
|
```
|
|
179
179
|
|
|
180
180
|
When a user is logout for any reason (401 or manually logout), the `invalidate('omerlo:user_session)` is triggered,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { initUserSession, type UserSession } from
|
|
3
|
-
import { onDestroy, onMount } from
|
|
2
|
+
import { initUserSession, type UserSession } from '../omerlo/reader/stores/user_session';
|
|
3
|
+
import { onDestroy, onMount } from 'svelte';
|
|
4
4
|
|
|
5
5
|
export let userSession: UserSession;
|
|
6
6
|
let selfComponent: HTMLDivElement;
|
|
@@ -23,4 +23,3 @@
|
|
|
23
23
|
<div id="omerlo-webkit" bind:this={selfComponent}>
|
|
24
24
|
<slot></slot>
|
|
25
25
|
</div>
|
|
26
|
-
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type UserSession } from
|
|
1
|
+
import { type UserSession } from '../omerlo/reader/stores/user_session';
|
|
2
2
|
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
3
3
|
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
4
4
|
$$bindings?: Bindings;
|
package/dist/omerlo/index.d.ts
CHANGED
|
@@ -1,12 +1,40 @@
|
|
|
1
1
|
export declare const useReader: (f: typeof fetch) => {
|
|
2
2
|
notifications: {
|
|
3
|
-
listTopics: (params?: Partial<import("./reader/utils/api").PagingParams>) => Promise<import("./reader/utils/api").ApiResponse<import("./reader
|
|
4
|
-
subscribeToTopic: (params: import("./reader
|
|
5
|
-
unsubscribeFromTopic: (params: import("./reader
|
|
3
|
+
listTopics: (params?: Partial<import("./reader/utils/api").PagingParams>) => Promise<import("./reader/utils/api").ApiResponse<import("./reader").TopicSummary[]>>;
|
|
4
|
+
subscribeToTopic: (params: import("./reader").SubscriptionParams) => Promise<import("./reader/utils/api").ApiResponse<unknown>>;
|
|
5
|
+
unsubscribeFromTopic: (params: import("./reader").SubscriptionParams) => Promise<import("./reader/utils/api").ApiResponse<unknown>>;
|
|
6
6
|
};
|
|
7
|
+
magazines: {
|
|
8
|
+
getIssue: (id: string) => Promise<import("./reader/utils/api").ApiResponse<import("./reader").Issue>>;
|
|
9
|
+
getBlocks: (sectionId: string) => Promise<import("./reader/utils/api").ApiResponse<import("./reader").IssueBlock[]>>;
|
|
10
|
+
searchContents: (issueId: string, q: string) => Promise<import("./reader/utils/api").ApiResponse<import("./reader").SectionContent[]>>;
|
|
11
|
+
getSectionContents: (sectionId: string) => Promise<import("./reader/utils/api").ApiResponse<import("./reader").Content[]>>;
|
|
12
|
+
};
|
|
13
|
+
getMenu: (key: string) => Promise<import("./reader/utils/api").ApiResponse<import("./reader").Menu>>;
|
|
14
|
+
listMenus: (params?: Partial<import("./reader/utils/api").PagingParams>) => Promise<import("./reader/utils/api").ApiResponse<import("./reader").MenuSummary[]>>;
|
|
15
|
+
listOrganizations: (params?: Partial<import("./reader/utils/api").PagingParams>) => Promise<import("./reader/utils/api").ApiResponse<import("./reader").OrganizationSummary[]>>;
|
|
16
|
+
getOrganization: () => Promise<import("./reader/utils/api").ApiResponse<import("./reader").Organization>>;
|
|
17
|
+
getOrgWebpage: (slug: string) => Promise<import("./reader/utils/api").ApiResponse<import("./reader").OrgWebpage>>;
|
|
18
|
+
listOrgWebpages: (params?: Partial<import("./reader/utils/api").PagingParams>) => Promise<import("./reader/utils/api").ApiResponse<import("./reader").WebpageSummary[]>>;
|
|
19
|
+
getMedia: () => Promise<import("./reader/utils/api").ApiResponse<import("./reader").Media>>;
|
|
20
|
+
getMediaOrganization: (id: string) => Promise<import("./reader/utils/api").ApiResponse<import("./reader").Organization>>;
|
|
21
|
+
listMediaOrganizations: (params?: Partial<import("./reader/utils/api").PagingParams>) => Promise<import("./reader/utils/api").ApiResponse<import("./reader").OrganizationSummary[]>>;
|
|
22
|
+
getMediaEvent: (id: string) => Promise<import("./reader/utils/api").ApiResponse<import("./reader").Event>>;
|
|
23
|
+
listMediaEvents: (params?: Partial<import("./reader/utils/api").PagingParams>) => Promise<import("./reader/utils/api").ApiResponse<import("./reader").EventSummary[]>>;
|
|
24
|
+
listMediaEventBlocks: (id: string, params?: Partial<import("./reader/utils/api").PagingParams>) => Promise<import("./reader/utils/api").ApiResponse<import("./reader").ProfileBlockKind[]>>;
|
|
25
|
+
getMediaPerson: (id: string) => Promise<import("./reader/utils/api").ApiResponse<import("./reader").Person>>;
|
|
26
|
+
listMediaPersons: (params?: Partial<import("./reader/utils/api").PagingParams>) => Promise<import("./reader/utils/api").ApiResponse<import("./reader").PersonSummary[]>>;
|
|
27
|
+
getMediaProject: (id: string) => Promise<import("./reader/utils/api").ApiResponse<import("./reader").Project>>;
|
|
28
|
+
listMediaProjects: (params?: Partial<import("./reader/utils/api").PagingParams>) => Promise<import("./reader/utils/api").ApiResponse<import("./reader").ProjectSummary[]>>;
|
|
29
|
+
getMediaProfileType: (id: string) => Promise<import("./reader/utils/api").ApiResponse<import("./reader").ProfileType>>;
|
|
30
|
+
listMediaProfileTypes: (params?: Partial<import("./reader/utils/api").PagingParams>) => Promise<import("./reader/utils/api").ApiResponse<import("./reader").ProfileTypeSummary[]>>;
|
|
31
|
+
getContent: (id: string) => Promise<import("./reader/utils/api").ApiResponse<import("./reader").Content>>;
|
|
32
|
+
listContents: (params?: Partial<import("./reader/utils/api").PagingParams>) => Promise<import("./reader/utils/api").ApiResponse<import("./reader").ContentSummary[]>>;
|
|
33
|
+
listCategories: (params?: Partial<import("./reader/utils/api").PagingParams>) => Promise<import("./reader/utils/api").ApiResponse<import("./reader").Category[]>>;
|
|
34
|
+
getCategory: (id: string) => Promise<import("./reader/utils/api").ApiResponse<import("./reader").Category>>;
|
|
7
35
|
listOauthProviders: (params?: Partial<import("./reader/utils/api").PagingParams>) => Promise<import("./reader/utils/api").ApiResponse<import("./reader").OauthProviderSummary[]>>;
|
|
8
36
|
getOauthUser: () => Promise<import("./reader/utils/api").ApiResponse<import("./reader").OauthUser>>;
|
|
9
|
-
registerDevice: (params: import("./reader
|
|
37
|
+
registerDevice: (params: import("./reader").DeviceParams) => Promise<import("./reader/utils/api").ApiResponse<unknown>>;
|
|
10
38
|
userInfo: () => Promise<import("./reader/utils/api").ApiResponse<import("./reader").UserInfo>>;
|
|
11
39
|
verifyAccount: (params: import("./reader").VerifyAccountParams) => void;
|
|
12
40
|
validateAccount: (params: import("./reader").ValidateAccountParams) => void;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type LocalesMetadata } from '../utils/response';
|
|
2
|
+
import { type ApiAssocs, type ApiData, type PagingParams } from '../utils/api';
|
|
3
|
+
export declare const categoriesFetchers: (f: typeof fetch) => {
|
|
4
|
+
listCategories: (params?: Partial<PagingParams>) => Promise<import("../utils/api").ApiResponse<Category[]>>;
|
|
5
|
+
getCategory: (id: string) => Promise<import("../utils/api").ApiResponse<Category>>;
|
|
6
|
+
};
|
|
7
|
+
export interface Category {
|
|
8
|
+
id: string;
|
|
9
|
+
svg: string;
|
|
10
|
+
name: string;
|
|
11
|
+
meta: {
|
|
12
|
+
locales: LocalesMetadata;
|
|
13
|
+
};
|
|
14
|
+
updatedAt: Date;
|
|
15
|
+
}
|
|
16
|
+
export declare function getCategory(f: typeof fetch): (id: string) => Promise<import("../utils/api").ApiResponse<Category>>;
|
|
17
|
+
export declare function listCategories(f: typeof fetch): (params?: Partial<PagingParams>) => Promise<import("../utils/api").ApiResponse<Category[]>>;
|
|
18
|
+
export declare function parseCategory(data: ApiData, _assoc: ApiAssocs): Category;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { parseLocalesMetadata } from '../utils/response';
|
|
2
|
+
import { parseMany } from '../utils/api';
|
|
3
|
+
import { requestPublisher } from '../utils/request';
|
|
4
|
+
import { buildMeta } from '../utils/parseHelpers';
|
|
5
|
+
export const categoriesFetchers = (f) => {
|
|
6
|
+
return {
|
|
7
|
+
listCategories: listCategories(f),
|
|
8
|
+
getCategory: getCategory(f)
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
export function getCategory(f) {
|
|
12
|
+
return async (id) => {
|
|
13
|
+
const opts = { parser: parseCategory };
|
|
14
|
+
return requestPublisher(f, `media/categories/${id}`, opts);
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export function listCategories(f) {
|
|
18
|
+
return async (params) => {
|
|
19
|
+
const opts = { parser: parseMany(parseCategory), queryParams: params };
|
|
20
|
+
return requestPublisher(f, `media/categories`, opts);
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export function parseCategory(data, _assoc) {
|
|
24
|
+
let meta;
|
|
25
|
+
// NOTE: this is to support publisher public api v2 but also reader api v1
|
|
26
|
+
if (data.meta) {
|
|
27
|
+
meta = { locales: parseLocalesMetadata(data.meta) };
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
meta = buildMeta(data.localized.locale);
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
id: data.id,
|
|
34
|
+
name: data.name,
|
|
35
|
+
svg: data.svg_icon,
|
|
36
|
+
meta,
|
|
37
|
+
updatedAt: data.updated_at
|
|
38
|
+
};
|
|
39
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type LocalesMetadata } from '../utils/response';
|
|
2
|
+
import type { ApiAssocs, ApiData } from '../utils/api';
|
|
3
|
+
export interface ContentTemplate {
|
|
4
|
+
id: string;
|
|
5
|
+
key: string;
|
|
6
|
+
name: string;
|
|
7
|
+
meta: {
|
|
8
|
+
locales: LocalesMetadata;
|
|
9
|
+
};
|
|
10
|
+
metadata: Record<string, string>;
|
|
11
|
+
enabledFields: string[];
|
|
12
|
+
updatedAt: Date;
|
|
13
|
+
}
|
|
14
|
+
export interface ContentBlockTemplate {
|
|
15
|
+
id: string;
|
|
16
|
+
key: string;
|
|
17
|
+
visual: {
|
|
18
|
+
allowedTypes: string[];
|
|
19
|
+
isEnabled: boolean;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export declare function parseContentBlockTemplate(data: ApiData, _assocs: ApiAssocs): ContentBlockTemplate;
|
|
23
|
+
export declare function parseContentTemplate(data: ApiData, _assocs: ApiAssocs): ContentTemplate;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { parseLocalesMetadata } from '../utils/response';
|
|
2
|
+
import { buildMeta } from '../utils/parseHelpers';
|
|
3
|
+
export function parseContentBlockTemplate(data, _assocs) {
|
|
4
|
+
return {
|
|
5
|
+
id: data.id,
|
|
6
|
+
key: data.key,
|
|
7
|
+
visual: {
|
|
8
|
+
allowedTypes: data.visual.allowed_types,
|
|
9
|
+
isEnabled: data.visual.is_enabled
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export function parseContentTemplate(data, _assocs) {
|
|
14
|
+
let name;
|
|
15
|
+
let meta;
|
|
16
|
+
if (data.localized) {
|
|
17
|
+
// NOTE: this is for retrocompatibility with public publisher api v2
|
|
18
|
+
name = data.localized.name;
|
|
19
|
+
meta = buildMeta(data.localized.locale);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
name = data.name;
|
|
23
|
+
meta = { locales: parseLocalesMetadata(data.meta) };
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
id: data.id,
|
|
27
|
+
key: data.key,
|
|
28
|
+
name,
|
|
29
|
+
meta,
|
|
30
|
+
metadata: data.metadata,
|
|
31
|
+
enabledFields: data.enabled_fields,
|
|
32
|
+
updatedAt: data.updated_at
|
|
33
|
+
};
|
|
34
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import type { Category } from './categories';
|
|
2
|
+
import type { ContentBlockTemplate, ContentTemplate } from './content-templates';
|
|
3
|
+
import { type Visual, type Slideshow, type Image, type Video } from './visuals';
|
|
4
|
+
import { type ApiAssocs, type ApiData, type PagingParams } from '../utils/api';
|
|
5
|
+
import { type LocalesMetadata } from '../utils/response';
|
|
6
|
+
import type { PersonSummary } from './person';
|
|
7
|
+
import type { OrganizationSummary } from './organizations';
|
|
8
|
+
export declare const contentsFetchers: (f: typeof fetch) => {
|
|
9
|
+
getContent: (id: string) => Promise<import("../utils/api").ApiResponse<Content>>;
|
|
10
|
+
listContents: (params?: Partial<PagingParams>) => Promise<import("../utils/api").ApiResponse<ContentSummary[]>>;
|
|
11
|
+
};
|
|
12
|
+
export interface ContentSeo {
|
|
13
|
+
title: string;
|
|
14
|
+
description: string;
|
|
15
|
+
}
|
|
16
|
+
export interface ContentSummary {
|
|
17
|
+
id: string;
|
|
18
|
+
template: ContentTemplate;
|
|
19
|
+
canonicalDomain: string | null;
|
|
20
|
+
canonicalUrl: string | null;
|
|
21
|
+
publishedAt: Date | null;
|
|
22
|
+
visibility: string | null;
|
|
23
|
+
categories: Category[];
|
|
24
|
+
showPublishedAt: boolean;
|
|
25
|
+
updatedAt: Date;
|
|
26
|
+
titleHtml: string;
|
|
27
|
+
titleText: string;
|
|
28
|
+
leadHtml: string | null;
|
|
29
|
+
leadText: string | null;
|
|
30
|
+
subtitleHtml: string | null;
|
|
31
|
+
subtitleText: string | null;
|
|
32
|
+
visual: Visual | null;
|
|
33
|
+
meta: {
|
|
34
|
+
locales: LocalesMetadata;
|
|
35
|
+
};
|
|
36
|
+
authors: (PersonSummary | OrganizationSummary)[];
|
|
37
|
+
}
|
|
38
|
+
export interface Content extends ContentSummary {
|
|
39
|
+
metadata: Record<string, string>;
|
|
40
|
+
blocks: ContentBlock[];
|
|
41
|
+
}
|
|
42
|
+
export type ContentBlockRichtext = {
|
|
43
|
+
id: string;
|
|
44
|
+
kind: 'richtext';
|
|
45
|
+
contentHtml: string;
|
|
46
|
+
visual: Visual | null;
|
|
47
|
+
template: ContentBlockTemplate | null;
|
|
48
|
+
};
|
|
49
|
+
export type ContentBlockData = {
|
|
50
|
+
id: string;
|
|
51
|
+
kind: 'data';
|
|
52
|
+
contentType: string;
|
|
53
|
+
data: string;
|
|
54
|
+
visual: Visual | null;
|
|
55
|
+
template: ContentBlockTemplate | null;
|
|
56
|
+
};
|
|
57
|
+
export type ContentBlockHTML = {
|
|
58
|
+
id: string;
|
|
59
|
+
kind: 'html';
|
|
60
|
+
contentHtml: string;
|
|
61
|
+
visual: Visual | null;
|
|
62
|
+
template: ContentBlockTemplate | null;
|
|
63
|
+
};
|
|
64
|
+
export type ContentBlockQuote = {
|
|
65
|
+
id: string;
|
|
66
|
+
kind: 'quote';
|
|
67
|
+
quoteHtml: string;
|
|
68
|
+
quoteText: string;
|
|
69
|
+
author: string;
|
|
70
|
+
visual: Visual | null;
|
|
71
|
+
template: ContentBlockTemplate | null;
|
|
72
|
+
};
|
|
73
|
+
export type ContentBlockRelatedContents = {
|
|
74
|
+
id: string;
|
|
75
|
+
kind: 'related-contents';
|
|
76
|
+
contents: Content[];
|
|
77
|
+
visual: Visual | null;
|
|
78
|
+
template: ContentBlockTemplate | null;
|
|
79
|
+
};
|
|
80
|
+
export type Answer = {
|
|
81
|
+
id: string;
|
|
82
|
+
contentHtml: string;
|
|
83
|
+
contentText: string;
|
|
84
|
+
};
|
|
85
|
+
export type ContentBlockQuestion = {
|
|
86
|
+
id: string;
|
|
87
|
+
kind: 'question';
|
|
88
|
+
questionHtml: string;
|
|
89
|
+
questionText: string;
|
|
90
|
+
acceptVoteUntil: Date;
|
|
91
|
+
answers: Answer[];
|
|
92
|
+
visual: Visual | null;
|
|
93
|
+
template: ContentBlockTemplate | null;
|
|
94
|
+
};
|
|
95
|
+
export type ContentBlockImage = {
|
|
96
|
+
id: string;
|
|
97
|
+
kind: 'image';
|
|
98
|
+
image: Image;
|
|
99
|
+
visual: Visual | null;
|
|
100
|
+
template: ContentBlockTemplate | null;
|
|
101
|
+
};
|
|
102
|
+
export type ContentBlockSlideshow = {
|
|
103
|
+
id: string;
|
|
104
|
+
kind: 'slideshow';
|
|
105
|
+
slideshow: Slideshow;
|
|
106
|
+
visual: Visual | null;
|
|
107
|
+
template: ContentBlockTemplate | null;
|
|
108
|
+
};
|
|
109
|
+
export type ContentBlockVideo = {
|
|
110
|
+
id: string;
|
|
111
|
+
kind: 'video';
|
|
112
|
+
video: Video;
|
|
113
|
+
visual: Visual | null;
|
|
114
|
+
template: ContentBlockTemplate | null;
|
|
115
|
+
};
|
|
116
|
+
export type ContentBlock = ContentBlockRichtext | ContentBlockData | ContentBlockHTML | ContentBlockQuote | ContentBlockRelatedContents | ContentBlockQuestion | ContentBlockImage | ContentBlockSlideshow | ContentBlockVideo;
|
|
117
|
+
export type ContentBlockType = 'richtext' | 'data' | 'html' | 'quote' | 'related-contents' | 'question' | 'image' | 'slideshow' | 'video';
|
|
118
|
+
export declare function getContent(f: typeof fetch): (id: string) => Promise<import("../utils/api").ApiResponse<Content>>;
|
|
119
|
+
export declare function listContents(f: typeof fetch): (params?: Partial<PagingParams>) => Promise<import("../utils/api").ApiResponse<ContentSummary[]>>;
|
|
120
|
+
export declare function parseContentSummary(data: ApiData, assocs: ApiAssocs): ContentSummary;
|
|
121
|
+
export declare function parseContent(data: ApiData, assocs: ApiAssocs): Content;
|
|
122
|
+
export declare function parseContentBlock(block: ApiData, assocs: ApiAssocs): ContentBlock | null;
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { parseVideo, parseImage, parseSlideshow, parseVisual } from './visuals';
|
|
2
|
+
import { requestPublisher } from '../utils/request';
|
|
3
|
+
import { parseMany } from '../utils/api';
|
|
4
|
+
import { getAssoc, getAssocs } from '../utils/assocs';
|
|
5
|
+
import { parseLocalesMetadata } from '../utils/response';
|
|
6
|
+
import { buildMeta, parseDate } from '../utils/parseHelpers';
|
|
7
|
+
export const contentsFetchers = (f) => {
|
|
8
|
+
return {
|
|
9
|
+
getContent: getContent(f),
|
|
10
|
+
listContents: listContents(f)
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
function baseBlock(data, assocs) {
|
|
14
|
+
return {
|
|
15
|
+
id: data.id,
|
|
16
|
+
kind: data.kind,
|
|
17
|
+
template: getBlockTemplate(data, assocs),
|
|
18
|
+
visual: parseVisual(data.visual, assocs)
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export function getContent(f) {
|
|
22
|
+
return async (id) => {
|
|
23
|
+
const opts = { parser: parseContent };
|
|
24
|
+
return requestPublisher(f, `media/contents/${id}`, opts);
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export function listContents(f) {
|
|
28
|
+
return async (params) => {
|
|
29
|
+
const opts = { parser: parseMany(parseContentSummary), queryParams: params };
|
|
30
|
+
return requestPublisher(f, `media/contents`, opts);
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export function parseContentSummary(data, assocs) {
|
|
34
|
+
if (data.localized) {
|
|
35
|
+
// NOTE: This is to support publisher public api v2
|
|
36
|
+
return {
|
|
37
|
+
id: data.id,
|
|
38
|
+
template: getAssoc(assocs, 'templates', data.template_id),
|
|
39
|
+
canonicalDomain: data.canonical_domain,
|
|
40
|
+
canonicalUrl: data.canonical_url,
|
|
41
|
+
publishedAt: parseDate(data.published_at),
|
|
42
|
+
visibility: data.visibility,
|
|
43
|
+
categories: getAssocs(assocs, 'categories', data.category_ids),
|
|
44
|
+
showPublishedAt: data.show_published_at,
|
|
45
|
+
updatedAt: new Date(data.updated_at),
|
|
46
|
+
titleHtml: data.localized.title_html,
|
|
47
|
+
titleText: data.localized.title_text,
|
|
48
|
+
leadHtml: data.localized.lead_html,
|
|
49
|
+
leadText: data.localized.lead_text,
|
|
50
|
+
subtitleHtml: data.localized.subtitle_html,
|
|
51
|
+
subtitleText: data.localized.subtitle_text,
|
|
52
|
+
visual: parseVisual(data.visual, assocs),
|
|
53
|
+
meta: buildMeta(data.localized.locale),
|
|
54
|
+
authors: getAssocs(assocs, 'profiles', data.localized.author_ids)
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
return {
|
|
59
|
+
id: data.id,
|
|
60
|
+
template: getAssoc(assocs, 'content_templates', data.template_id),
|
|
61
|
+
canonicalDomain: data.canonical_domain,
|
|
62
|
+
canonicalUrl: data.canonical_url,
|
|
63
|
+
publishedAt: parseDate(data.published_at),
|
|
64
|
+
visibility: data.visibility,
|
|
65
|
+
categories: getAssocs(assocs, 'categories', data.category_ids),
|
|
66
|
+
showPublishedAt: data.show_published_at,
|
|
67
|
+
updatedAt: new Date(data.updated_at),
|
|
68
|
+
titleHtml: data.title_html,
|
|
69
|
+
titleText: data.title_text,
|
|
70
|
+
leadHtml: data.lead_html,
|
|
71
|
+
leadText: data.lead_text,
|
|
72
|
+
subtitleHtml: data.subtitle_html,
|
|
73
|
+
subtitleText: data.subtitle_text,
|
|
74
|
+
visual: parseVisual(data.visual, assocs),
|
|
75
|
+
meta: { locales: parseLocalesMetadata(data.meta) },
|
|
76
|
+
authors: getAssocs(assocs, 'profiles', data.author_ids)
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
export function parseContent(data, assocs) {
|
|
81
|
+
let seo;
|
|
82
|
+
if (data.localized) {
|
|
83
|
+
seo = { title: data.localized.seo.title, description: data.localized.seo.description };
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
seo = { title: data.seo.title, description: data.seo.description };
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
...parseContentSummary(data, assocs),
|
|
90
|
+
metadata: data.metadata,
|
|
91
|
+
seo,
|
|
92
|
+
blocks: data.localized.blocks
|
|
93
|
+
.map((block) => parseContentBlock(block, assocs))
|
|
94
|
+
.filter(Boolean)
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
const ContentBlockParser = {
|
|
98
|
+
richtext: parseContentBlockRichtext,
|
|
99
|
+
data: parseContentBlockData,
|
|
100
|
+
html: parseContentBlockHTML,
|
|
101
|
+
quote: parseContentBlockQuote,
|
|
102
|
+
'related-contents': parseContentBlockRelatedContents,
|
|
103
|
+
question: parseContentBlockQuestion,
|
|
104
|
+
image: parseContentBlockImage,
|
|
105
|
+
slideshow: parseContentBlockSlideshow,
|
|
106
|
+
video: parseContentBlockVideo
|
|
107
|
+
};
|
|
108
|
+
export function parseContentBlock(block, assocs) {
|
|
109
|
+
const parser = ContentBlockParser[block.kind];
|
|
110
|
+
return parser ? parser(block, assocs) : null;
|
|
111
|
+
}
|
|
112
|
+
function getBlockTemplate(data, assocs) {
|
|
113
|
+
return data.template_id
|
|
114
|
+
? getAssoc(assocs, 'block_templates', data.template_id)
|
|
115
|
+
: null;
|
|
116
|
+
}
|
|
117
|
+
function getBlockContent(data, assocs) {
|
|
118
|
+
return data.related_contents ? getAssocs(assocs, 'contents', data.related_contents) : [];
|
|
119
|
+
}
|
|
120
|
+
function parseContentBlockRichtext(data, assocs) {
|
|
121
|
+
return {
|
|
122
|
+
...baseBlock(data, assocs),
|
|
123
|
+
contentHtml: data.content_html
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function parseContentBlockData(data, assocs) {
|
|
127
|
+
return {
|
|
128
|
+
...baseBlock(data, assocs),
|
|
129
|
+
contentType: data.content_type,
|
|
130
|
+
data: data.data
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
function parseContentBlockHTML(data, assocs) {
|
|
134
|
+
return {
|
|
135
|
+
...baseBlock(data, assocs),
|
|
136
|
+
contentHtml: data.content_html
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
function parseContentBlockQuote(data, assocs) {
|
|
140
|
+
return {
|
|
141
|
+
...baseBlock(data, assocs),
|
|
142
|
+
quoteHtml: data.quote_html,
|
|
143
|
+
quoteText: data.quote_text,
|
|
144
|
+
author: data.author
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
function parseContentBlockRelatedContents(data, assocs) {
|
|
148
|
+
const contents = getBlockContent(data, assocs);
|
|
149
|
+
return {
|
|
150
|
+
...baseBlock(data, assocs),
|
|
151
|
+
contents
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
function parseContentBlockQuestion(data, assocs) {
|
|
155
|
+
return {
|
|
156
|
+
...baseBlock(data, assocs),
|
|
157
|
+
questionHtml: data.question_html,
|
|
158
|
+
questionText: data.question_text,
|
|
159
|
+
acceptVoteUntil: new Date(data.accept_vote_until),
|
|
160
|
+
answers: data.answers?.map((answer) => parseAnswer(answer)) || []
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
function parseAnswer(data) {
|
|
164
|
+
return {
|
|
165
|
+
id: data.id,
|
|
166
|
+
contentHtml: data.content_html,
|
|
167
|
+
contentText: data.content_text
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
function parseContentBlockImage(data, assocs) {
|
|
171
|
+
return {
|
|
172
|
+
...baseBlock(data, assocs),
|
|
173
|
+
image: parseImage(data.image, assocs)
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
function parseContentBlockSlideshow(data, assocs) {
|
|
177
|
+
return {
|
|
178
|
+
...baseBlock(data, assocs),
|
|
179
|
+
slideshow: parseSlideshow(data.slideshow, assocs)
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
function parseContentBlockVideo(data, assocs) {
|
|
183
|
+
return {
|
|
184
|
+
...baseBlock(data, assocs),
|
|
185
|
+
video: parseVideo(data.video, assocs)
|
|
186
|
+
};
|
|
187
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Category } from './categories';
|
|
2
|
+
import { type ApiAssocs, type ApiData } from '../utils/api';
|
|
3
|
+
import type { LocalesMetadata } from '../utils/response';
|
|
4
|
+
import type { ProfileType } from './profileType';
|
|
5
|
+
import type { ProfileAddress, ProfileContact, ProfileDescription } from './profiles';
|
|
6
|
+
export interface EventSummary {
|
|
7
|
+
id: string;
|
|
8
|
+
profileType: ProfileType;
|
|
9
|
+
kind: string;
|
|
10
|
+
type: string;
|
|
11
|
+
isAllDay: boolean;
|
|
12
|
+
profileImageURL: string | null;
|
|
13
|
+
coverImageURL: string | null;
|
|
14
|
+
subscriptionURL: string | null;
|
|
15
|
+
meta: {
|
|
16
|
+
locales: LocalesMetadata;
|
|
17
|
+
};
|
|
18
|
+
name: string | null;
|
|
19
|
+
summaryHtml: string | null;
|
|
20
|
+
summaryText: string | null;
|
|
21
|
+
startsAt: Date | null;
|
|
22
|
+
endsAt: Date | null;
|
|
23
|
+
updatedAt: Date;
|
|
24
|
+
}
|
|
25
|
+
export interface Event extends EventSummary {
|
|
26
|
+
categories: Category[];
|
|
27
|
+
address: ProfileAddress | null;
|
|
28
|
+
contact: ProfileContact | null;
|
|
29
|
+
description: ProfileDescription | null;
|
|
30
|
+
}
|
|
31
|
+
export declare function parseEventSummary(data: ApiData, assocs: ApiAssocs): EventSummary;
|
|
32
|
+
export declare function parseEvent(data: ApiData, assocs: ApiAssocs): Event;
|