@intlayer/api 9.5.12 → 9.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/distantDictionary/fetchDistantDictionaries.cjs.map +1 -1
- package/dist/cjs/distantDictionary/fetchDistantDictionary.cjs.map +1 -1
- package/dist/cjs/fetcher.cjs.map +1 -1
- package/dist/cjs/getIntlayerAPI/ai.cjs +76 -22
- package/dist/cjs/getIntlayerAPI/ai.cjs.map +1 -1
- package/dist/cjs/getIntlayerAPI/analytics.cjs +44 -10
- package/dist/cjs/getIntlayerAPI/analytics.cjs.map +1 -1
- package/dist/cjs/getIntlayerAPI/asset.cjs +38 -8
- package/dist/cjs/getIntlayerAPI/asset.cjs.map +1 -1
- package/dist/cjs/getIntlayerAPI/audit.cjs +70 -16
- package/dist/cjs/getIntlayerAPI/audit.cjs.map +1 -1
- package/dist/cjs/getIntlayerAPI/bitbucket.cjs +39 -9
- package/dist/cjs/getIntlayerAPI/bitbucket.cjs.map +1 -1
- package/dist/cjs/getIntlayerAPI/codeberg.cjs +21 -0
- package/dist/cjs/getIntlayerAPI/codeberg.cjs.map +1 -0
- package/dist/cjs/getIntlayerAPI/dictionary.cjs +59 -13
- package/dist/cjs/getIntlayerAPI/dictionary.cjs.map +1 -1
- package/dist/cjs/getIntlayerAPI/editor.cjs.map +1 -1
- package/dist/cjs/getIntlayerAPI/environment.cjs +44 -10
- package/dist/cjs/getIntlayerAPI/environment.cjs.map +1 -1
- package/dist/cjs/getIntlayerAPI/forge.cjs +64 -0
- package/dist/cjs/getIntlayerAPI/forge.cjs.map +1 -0
- package/dist/cjs/getIntlayerAPI/gitee.cjs +21 -0
- package/dist/cjs/getIntlayerAPI/gitee.cjs.map +1 -0
- package/dist/cjs/getIntlayerAPI/github.cjs +44 -10
- package/dist/cjs/getIntlayerAPI/github.cjs.map +1 -1
- package/dist/cjs/getIntlayerAPI/gitlab.cjs +39 -9
- package/dist/cjs/getIntlayerAPI/gitlab.cjs.map +1 -1
- package/dist/cjs/getIntlayerAPI/index.cjs +4 -0
- package/dist/cjs/getIntlayerAPI/index.cjs.map +1 -1
- package/dist/cjs/getIntlayerAPI/newsletter.cjs +28 -6
- package/dist/cjs/getIntlayerAPI/newsletter.cjs.map +1 -1
- package/dist/cjs/getIntlayerAPI/oAuth.cjs +31 -5
- package/dist/cjs/getIntlayerAPI/oAuth.cjs.map +1 -1
- package/dist/cjs/getIntlayerAPI/organization.cjs +72 -20
- package/dist/cjs/getIntlayerAPI/organization.cjs.map +1 -1
- package/dist/cjs/getIntlayerAPI/project.cjs +112 -29
- package/dist/cjs/getIntlayerAPI/project.cjs.map +1 -1
- package/dist/cjs/getIntlayerAPI/reviewer.cjs +142 -31
- package/dist/cjs/getIntlayerAPI/reviewer.cjs.map +1 -1
- package/dist/cjs/getIntlayerAPI/search.cjs +15 -3
- package/dist/cjs/getIntlayerAPI/search.cjs.map +1 -1
- package/dist/cjs/getIntlayerAPI/showcaseProject.cjs +61 -15
- package/dist/cjs/getIntlayerAPI/showcaseProject.cjs.map +1 -1
- package/dist/cjs/getIntlayerAPI/status.cjs +16 -3
- package/dist/cjs/getIntlayerAPI/status.cjs.map +1 -1
- package/dist/cjs/getIntlayerAPI/stripe.cjs +141 -35
- package/dist/cjs/getIntlayerAPI/stripe.cjs.map +1 -1
- package/dist/cjs/getIntlayerAPI/tag.cjs +33 -7
- package/dist/cjs/getIntlayerAPI/tag.cjs.map +1 -1
- package/dist/cjs/getIntlayerAPI/translate.cjs +46 -8
- package/dist/cjs/getIntlayerAPI/translate.cjs.map +1 -1
- package/dist/cjs/getIntlayerAPI/user.cjs +58 -14
- package/dist/cjs/getIntlayerAPI/user.cjs.map +1 -1
- package/dist/cjs/index.cjs +8 -0
- package/dist/cjs/proxy.cjs +4 -0
- package/dist/cjs/proxy.cjs.map +1 -1
- package/dist/cjs/public/createPublicClient.cjs +25 -5
- package/dist/cjs/public/createPublicClient.cjs.map +1 -1
- package/dist/esm/distantDictionary/fetchDistantDictionaries.mjs.map +1 -1
- package/dist/esm/distantDictionary/fetchDistantDictionary.mjs.map +1 -1
- package/dist/esm/fetcher.mjs.map +1 -1
- package/dist/esm/getIntlayerAPI/ai.mjs +76 -22
- package/dist/esm/getIntlayerAPI/ai.mjs.map +1 -1
- package/dist/esm/getIntlayerAPI/analytics.mjs +44 -10
- package/dist/esm/getIntlayerAPI/analytics.mjs.map +1 -1
- package/dist/esm/getIntlayerAPI/asset.mjs +38 -8
- package/dist/esm/getIntlayerAPI/asset.mjs.map +1 -1
- package/dist/esm/getIntlayerAPI/audit.mjs +70 -16
- package/dist/esm/getIntlayerAPI/audit.mjs.map +1 -1
- package/dist/esm/getIntlayerAPI/bitbucket.mjs +39 -9
- package/dist/esm/getIntlayerAPI/bitbucket.mjs.map +1 -1
- package/dist/esm/getIntlayerAPI/codeberg.mjs +19 -0
- package/dist/esm/getIntlayerAPI/codeberg.mjs.map +1 -0
- package/dist/esm/getIntlayerAPI/dictionary.mjs +59 -13
- package/dist/esm/getIntlayerAPI/dictionary.mjs.map +1 -1
- package/dist/esm/getIntlayerAPI/editor.mjs.map +1 -1
- package/dist/esm/getIntlayerAPI/environment.mjs +44 -10
- package/dist/esm/getIntlayerAPI/environment.mjs.map +1 -1
- package/dist/esm/getIntlayerAPI/forge.mjs +63 -0
- package/dist/esm/getIntlayerAPI/forge.mjs.map +1 -0
- package/dist/esm/getIntlayerAPI/gitee.mjs +19 -0
- package/dist/esm/getIntlayerAPI/gitee.mjs.map +1 -0
- package/dist/esm/getIntlayerAPI/github.mjs +44 -10
- package/dist/esm/getIntlayerAPI/github.mjs.map +1 -1
- package/dist/esm/getIntlayerAPI/gitlab.mjs +39 -9
- package/dist/esm/getIntlayerAPI/gitlab.mjs.map +1 -1
- package/dist/esm/getIntlayerAPI/index.mjs +4 -0
- package/dist/esm/getIntlayerAPI/index.mjs.map +1 -1
- package/dist/esm/getIntlayerAPI/newsletter.mjs +28 -6
- package/dist/esm/getIntlayerAPI/newsletter.mjs.map +1 -1
- package/dist/esm/getIntlayerAPI/oAuth.mjs +31 -5
- package/dist/esm/getIntlayerAPI/oAuth.mjs.map +1 -1
- package/dist/esm/getIntlayerAPI/organization.mjs +72 -20
- package/dist/esm/getIntlayerAPI/organization.mjs.map +1 -1
- package/dist/esm/getIntlayerAPI/project.mjs +112 -29
- package/dist/esm/getIntlayerAPI/project.mjs.map +1 -1
- package/dist/esm/getIntlayerAPI/reviewer.mjs +142 -31
- package/dist/esm/getIntlayerAPI/reviewer.mjs.map +1 -1
- package/dist/esm/getIntlayerAPI/search.mjs +15 -3
- package/dist/esm/getIntlayerAPI/search.mjs.map +1 -1
- package/dist/esm/getIntlayerAPI/showcaseProject.mjs +61 -15
- package/dist/esm/getIntlayerAPI/showcaseProject.mjs.map +1 -1
- package/dist/esm/getIntlayerAPI/status.mjs +16 -3
- package/dist/esm/getIntlayerAPI/status.mjs.map +1 -1
- package/dist/esm/getIntlayerAPI/stripe.mjs +141 -35
- package/dist/esm/getIntlayerAPI/stripe.mjs.map +1 -1
- package/dist/esm/getIntlayerAPI/tag.mjs +33 -7
- package/dist/esm/getIntlayerAPI/tag.mjs.map +1 -1
- package/dist/esm/getIntlayerAPI/translate.mjs +46 -8
- package/dist/esm/getIntlayerAPI/translate.mjs.map +1 -1
- package/dist/esm/getIntlayerAPI/user.mjs +58 -14
- package/dist/esm/getIntlayerAPI/user.mjs.map +1 -1
- package/dist/esm/index.mjs +4 -1
- package/dist/esm/proxy.mjs +4 -0
- package/dist/esm/proxy.mjs.map +1 -1
- package/dist/esm/public/createPublicClient.mjs +25 -5
- package/dist/esm/public/createPublicClient.mjs.map +1 -1
- package/dist/types/distantDictionary/fetchDistantDictionaries.d.ts +1 -1
- package/dist/types/distantDictionary/fetchDistantDictionary.d.ts +1 -1
- package/dist/types/fetcher.d.ts +1 -1
- package/dist/types/fetcher.d.ts.map +1 -1
- package/dist/types/getIntlayerAPI/ai.d.ts +1 -1
- package/dist/types/getIntlayerAPI/ai.d.ts.map +1 -1
- package/dist/types/getIntlayerAPI/analytics.d.ts +1 -1
- package/dist/types/getIntlayerAPI/analytics.d.ts.map +1 -1
- package/dist/types/getIntlayerAPI/asset.d.ts +1 -0
- package/dist/types/getIntlayerAPI/asset.d.ts.map +1 -1
- package/dist/types/getIntlayerAPI/audit.d.ts +47 -3
- package/dist/types/getIntlayerAPI/audit.d.ts.map +1 -1
- package/dist/types/getIntlayerAPI/bitbucket.d.ts.map +1 -1
- package/dist/types/getIntlayerAPI/codeberg.d.ts +23 -0
- package/dist/types/getIntlayerAPI/codeberg.d.ts.map +1 -0
- package/dist/types/getIntlayerAPI/dictionary.d.ts +1 -1
- package/dist/types/getIntlayerAPI/dictionary.d.ts.map +1 -1
- package/dist/types/getIntlayerAPI/editor.d.ts +2 -1
- package/dist/types/getIntlayerAPI/editor.d.ts.map +1 -1
- package/dist/types/getIntlayerAPI/environment.d.ts +1 -1
- package/dist/types/getIntlayerAPI/environment.d.ts.map +1 -1
- package/dist/types/getIntlayerAPI/forge.d.ts +17 -0
- package/dist/types/getIntlayerAPI/forge.d.ts.map +1 -0
- package/dist/types/getIntlayerAPI/gitee.d.ts +23 -0
- package/dist/types/getIntlayerAPI/gitee.d.ts.map +1 -0
- package/dist/types/getIntlayerAPI/github.d.ts.map +1 -1
- package/dist/types/getIntlayerAPI/gitlab.d.ts.map +1 -1
- package/dist/types/getIntlayerAPI/index.d.ts +4 -0
- package/dist/types/getIntlayerAPI/index.d.ts.map +1 -1
- package/dist/types/getIntlayerAPI/newsletter.d.ts +1 -1
- package/dist/types/getIntlayerAPI/newsletter.d.ts.map +1 -1
- package/dist/types/getIntlayerAPI/oAuth.d.ts +2 -0
- package/dist/types/getIntlayerAPI/oAuth.d.ts.map +1 -1
- package/dist/types/getIntlayerAPI/organization.d.ts +1 -3
- package/dist/types/getIntlayerAPI/organization.d.ts.map +1 -1
- package/dist/types/getIntlayerAPI/project.d.ts +2 -1
- package/dist/types/getIntlayerAPI/project.d.ts.map +1 -1
- package/dist/types/getIntlayerAPI/reviewer.d.ts +680 -35
- package/dist/types/getIntlayerAPI/reviewer.d.ts.map +1 -1
- package/dist/types/getIntlayerAPI/search.d.ts +1 -1
- package/dist/types/getIntlayerAPI/search.d.ts.map +1 -1
- package/dist/types/getIntlayerAPI/showcaseProject.d.ts +1 -1
- package/dist/types/getIntlayerAPI/showcaseProject.d.ts.map +1 -1
- package/dist/types/getIntlayerAPI/status.d.ts +3 -4
- package/dist/types/getIntlayerAPI/status.d.ts.map +1 -1
- package/dist/types/getIntlayerAPI/stripe.d.ts +1 -1
- package/dist/types/getIntlayerAPI/stripe.d.ts.map +1 -1
- package/dist/types/getIntlayerAPI/tag.d.ts +1 -1
- package/dist/types/getIntlayerAPI/tag.d.ts.map +1 -1
- package/dist/types/getIntlayerAPI/translate.d.ts +1 -1
- package/dist/types/getIntlayerAPI/translate.d.ts.map +1 -1
- package/dist/types/getIntlayerAPI/user.d.ts +4 -4
- package/dist/types/getIntlayerAPI/user.d.ts.map +1 -1
- package/dist/types/index.d.ts +7 -4
- package/dist/types/proxy.d.ts.map +1 -1
- package/dist/types/public/createPublicClient.d.ts +1 -7
- package/dist/types/public/createPublicClient.d.ts.map +1 -1
- package/dist/types/types.d.ts +5 -2
- package/package.json +22 -5
|
@@ -2,16 +2,62 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
2
2
|
const require_fetcher = require('../fetcher.cjs');
|
|
3
3
|
const require_cms_createIntlayerCMS = require('../cms/createIntlayerCMS.cjs');
|
|
4
4
|
let _intlayer_config_built = require("@intlayer/config/built");
|
|
5
|
+
let _intlayer_backend_contract_defineRoute = require("@intlayer/backend-contract/defineRoute");
|
|
6
|
+
let _intlayer_config_defaultValues = require("@intlayer/config/defaultValues");
|
|
5
7
|
|
|
6
8
|
//#region src/getIntlayerAPI/user.ts
|
|
9
|
+
/** Prefix of the routes, checked against the backend contract. */
|
|
10
|
+
const userGroup = { prefix: "/api/user" };
|
|
11
|
+
/**
|
|
12
|
+
* Method and path of every route, checked against the backend contract at
|
|
13
|
+
* compile time (the contract's zod schemas are never loaded).
|
|
14
|
+
*/
|
|
15
|
+
const userEndpoints = {
|
|
16
|
+
getSetupStatus: {
|
|
17
|
+
method: "GET",
|
|
18
|
+
path: "/setup"
|
|
19
|
+
},
|
|
20
|
+
getUsers: {
|
|
21
|
+
method: "GET",
|
|
22
|
+
path: "/"
|
|
23
|
+
},
|
|
24
|
+
updateUser: {
|
|
25
|
+
method: "PUT",
|
|
26
|
+
path: "/"
|
|
27
|
+
},
|
|
28
|
+
createUser: {
|
|
29
|
+
method: "POST",
|
|
30
|
+
path: "/"
|
|
31
|
+
},
|
|
32
|
+
getUserById: {
|
|
33
|
+
method: "GET",
|
|
34
|
+
path: "/:userId"
|
|
35
|
+
},
|
|
36
|
+
getUserByEmail: {
|
|
37
|
+
method: "GET",
|
|
38
|
+
path: "/email/:email"
|
|
39
|
+
},
|
|
40
|
+
deleteUser: {
|
|
41
|
+
method: "DELETE",
|
|
42
|
+
path: "/:userId"
|
|
43
|
+
},
|
|
44
|
+
verifyEmailStatusSSE: {
|
|
45
|
+
method: "GET",
|
|
46
|
+
path: "/verify-email-status/:userId"
|
|
47
|
+
},
|
|
48
|
+
uploadAvatar: {
|
|
49
|
+
method: "POST",
|
|
50
|
+
path: "/avatar"
|
|
51
|
+
}
|
|
52
|
+
};
|
|
7
53
|
const getUserAPI = (authAPIOptions = {}, intlayerConfig) => {
|
|
8
|
-
const
|
|
54
|
+
const backendURL = intlayerConfig?.editor?.backendURL ?? _intlayer_config_built.editor.backendURL ?? _intlayer_config_defaultValues.BACKEND_URL;
|
|
9
55
|
/**
|
|
10
56
|
* Retrieves a list of users based on filters and pagination.
|
|
11
57
|
* @param filters - Filters and pagination options.
|
|
12
58
|
* @returns List of users.
|
|
13
59
|
*/
|
|
14
|
-
const getUsers = async (filters, otherOptions = {}) => await require_fetcher.fetcher(
|
|
60
|
+
const getUsers = async (filters, otherOptions = {}) => await require_fetcher.fetcher((0, _intlayer_backend_contract_defineRoute.buildRouteURL)(backendURL, userGroup, userEndpoints.getUsers), authAPIOptions, otherOptions, {
|
|
15
61
|
cache: "no-store",
|
|
16
62
|
params: filters
|
|
17
63
|
});
|
|
@@ -20,26 +66,25 @@ const getUserAPI = (authAPIOptions = {}, intlayerConfig) => {
|
|
|
20
66
|
* @param userId - User ID.
|
|
21
67
|
* @returns User object.
|
|
22
68
|
*/
|
|
23
|
-
const getUserById = async (userId, otherOptions = {}) => await require_fetcher.fetcher(
|
|
69
|
+
const getUserById = async (userId, otherOptions = {}) => await require_fetcher.fetcher((0, _intlayer_backend_contract_defineRoute.buildRouteURL)(backendURL, userGroup, userEndpoints.getUserById, { userId: String(userId) }), authAPIOptions, otherOptions, { cache: "no-store" });
|
|
24
70
|
/**
|
|
25
71
|
* Retrieves a user by email.
|
|
26
72
|
* @param email - User email.
|
|
27
73
|
* @returns User object.
|
|
28
74
|
*/
|
|
29
|
-
const getUserByEmail = async (email, otherOptions = {}) => await require_fetcher.fetcher(
|
|
75
|
+
const getUserByEmail = async (email, otherOptions = {}) => await require_fetcher.fetcher((0, _intlayer_backend_contract_defineRoute.buildRouteURL)(backendURL, userGroup, userEndpoints.getUserByEmail, { email }), authAPIOptions, otherOptions, { cache: "no-store" });
|
|
30
76
|
/**
|
|
31
77
|
* Retrieves a user by account.
|
|
32
78
|
* @param providerAccountId - The provider account ID.
|
|
33
79
|
* @param provider - The provider of the account.
|
|
34
80
|
*/
|
|
35
|
-
const getUserByAccount = async (providerAccountId, provider, otherOptions = {}) => await require_fetcher.fetcher(`${USER_API_ROUTE}/account/${provider}/${providerAccountId}`, authAPIOptions, otherOptions, { cache: "no-store" });
|
|
36
81
|
/**
|
|
37
82
|
* Creates a new user.
|
|
38
83
|
* @param user - User credentials.
|
|
39
84
|
* @returns User object.
|
|
40
85
|
*/
|
|
41
|
-
const createUser = async (user, otherOptions = {}) => await require_fetcher.fetcher(
|
|
42
|
-
method:
|
|
86
|
+
const createUser = async (user, otherOptions = {}) => await require_fetcher.fetcher((0, _intlayer_backend_contract_defineRoute.buildRouteURL)(backendURL, userGroup, userEndpoints.createUser), authAPIOptions, otherOptions, {
|
|
87
|
+
method: userEndpoints.createUser.method,
|
|
43
88
|
body: user
|
|
44
89
|
});
|
|
45
90
|
/**
|
|
@@ -47,8 +92,8 @@ const getUserAPI = (authAPIOptions = {}, intlayerConfig) => {
|
|
|
47
92
|
* @param user - Updated user data.
|
|
48
93
|
* @returns User object.
|
|
49
94
|
*/
|
|
50
|
-
const updateUser = async (user, otherOptions = {}) => await require_fetcher.fetcher(
|
|
51
|
-
method:
|
|
95
|
+
const updateUser = async (user, otherOptions = {}) => await require_fetcher.fetcher((0, _intlayer_backend_contract_defineRoute.buildRouteURL)(backendURL, userGroup, userEndpoints.updateUser), authAPIOptions, otherOptions, {
|
|
96
|
+
method: userEndpoints.updateUser.method,
|
|
52
97
|
body: user
|
|
53
98
|
});
|
|
54
99
|
/**
|
|
@@ -56,7 +101,7 @@ const getUserAPI = (authAPIOptions = {}, intlayerConfig) => {
|
|
|
56
101
|
* @param userId - User ID.
|
|
57
102
|
* @returns User object.
|
|
58
103
|
*/
|
|
59
|
-
const deleteUser = async (userId, otherOptions = {}) => await require_fetcher.fetcher(
|
|
104
|
+
const deleteUser = async (userId, otherOptions = {}) => await require_fetcher.fetcher((0, _intlayer_backend_contract_defineRoute.buildRouteURL)(backendURL, userGroup, userEndpoints.deleteUser, { userId: String(userId) }), authAPIOptions, otherOptions, { method: userEndpoints.deleteUser.method });
|
|
60
105
|
/**
|
|
61
106
|
* Uploads a new avatar for the authenticated user.
|
|
62
107
|
* @param file - The image File object to upload.
|
|
@@ -66,8 +111,8 @@ const getUserAPI = (authAPIOptions = {}, intlayerConfig) => {
|
|
|
66
111
|
const buffer = await file.arrayBuffer();
|
|
67
112
|
const baseHeaders = { "Content-Type": file.type || "image/jpeg" };
|
|
68
113
|
const authHeaders = authAPIOptions.headers ?? {};
|
|
69
|
-
const response = await fetch(
|
|
70
|
-
method:
|
|
114
|
+
const response = await fetch((0, _intlayer_backend_contract_defineRoute.buildRouteURL)(backendURL, userGroup, userEndpoints.uploadAvatar), {
|
|
115
|
+
method: userEndpoints.uploadAvatar.method,
|
|
71
116
|
credentials: "include",
|
|
72
117
|
headers: {
|
|
73
118
|
...authHeaders,
|
|
@@ -87,12 +132,11 @@ const getUserAPI = (authAPIOptions = {}, intlayerConfig) => {
|
|
|
87
132
|
* @param userId - User ID.
|
|
88
133
|
* @returns The verify email status URL.
|
|
89
134
|
*/
|
|
90
|
-
const getVerifyEmailStatusURL = (userId) =>
|
|
135
|
+
const getVerifyEmailStatusURL = (userId) => (0, _intlayer_backend_contract_defineRoute.buildRouteURL)(backendURL, userGroup, userEndpoints.verifyEmailStatusSSE, { userId: String(userId) });
|
|
91
136
|
return {
|
|
92
137
|
createUser,
|
|
93
138
|
getUsers,
|
|
94
139
|
getUserById,
|
|
95
|
-
getUserByAccount,
|
|
96
140
|
getUserByEmail,
|
|
97
141
|
updateUser,
|
|
98
142
|
deleteUser,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user.cjs","names":["editor","fetcher","createEndpoint"],"sources":["../../../src/getIntlayerAPI/user.ts"],"sourcesContent":["import type {\n CreateUserBody,\n CreateUserResult,\n GetUserByEmailParams,\n GetUserByEmailResult,\n GetUserByIdParams,\n GetUserByIdResult,\n GetUsersParams,\n GetUsersResult,\n
|
|
1
|
+
{"version":3,"file":"user.cjs","names":["editor","BACKEND_URL","fetcher","buildRouteURL","createEndpoint"],"sources":["../../../src/getIntlayerAPI/user.ts"],"sourcesContent":["import type { RouteEndpoints } from '@intlayer/backend-contract/defineRoute';\nimport { buildRouteURL } from '@intlayer/backend-contract/defineRoute';\nimport type { ResponseData } from '@intlayer/backend-contract/responseData';\nimport type {\n CreateUserBody,\n CreateUserResult,\n GetUserByEmailParams,\n GetUserByEmailResult,\n GetUserByIdParams,\n GetUserByIdResult,\n GetUsersParams,\n GetUsersResult,\n UpdateUserBody,\n UpdateUserResult,\n UploadUserAvatarResult,\n UserAPI,\n UserRoutes,\n userContract,\n} from '@intlayer/backend-contract/user';\nimport { editor } from '@intlayer/config/built';\nimport { BACKEND_URL } from '@intlayer/config/defaultValues';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { createEndpoint } from '../cms/createIntlayerCMS';\nimport { type FetcherOptions, fetcher } from '../fetcher';\n\nexport type GetUserByAccountParams = {\n providerAccountId: string;\n provider: string;\n};\nexport type GetUserByAccountResult = ResponseData<UserAPI>;\n\n/** Prefix of the routes, checked against the backend contract. */\nconst userGroup = {\n prefix: '/api/user',\n} as const satisfies Pick<typeof userContract, 'prefix'>;\n\n/**\n * Method and path of every route, checked against the backend contract at\n * compile time (the contract's zod schemas are never loaded).\n */\nconst userEndpoints = {\n getSetupStatus: { method: 'GET', path: '/setup' },\n getUsers: { method: 'GET', path: '/' },\n updateUser: { method: 'PUT', path: '/' },\n createUser: { method: 'POST', path: '/' },\n getUserById: { method: 'GET', path: '/:userId' },\n getUserByEmail: { method: 'GET', path: '/email/:email' },\n deleteUser: { method: 'DELETE', path: '/:userId' },\n verifyEmailStatusSSE: { method: 'GET', path: '/verify-email-status/:userId' },\n uploadAvatar: { method: 'POST', path: '/avatar' },\n} as const satisfies RouteEndpoints<UserRoutes>;\n\nexport const getUserAPI = (\n authAPIOptions: FetcherOptions = {},\n intlayerConfig?: IntlayerConfig\n) => {\n const backendURL =\n intlayerConfig?.editor?.backendURL ?? editor.backendURL ?? BACKEND_URL;\n\n /**\n * Retrieves a list of users based on filters and pagination.\n * @param filters - Filters and pagination options.\n * @returns List of users.\n */\n const getUsers = async (\n filters?: GetUsersParams,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetUsersResult>(\n buildRouteURL(backendURL, userGroup, userEndpoints.getUsers),\n authAPIOptions,\n otherOptions,\n {\n cache: 'no-store',\n // @ts-ignore Number of parameter will be stringified by the fetcher\n params: filters,\n }\n );\n\n /**\n * Retrieves a user by ID.\n * @param userId - User ID.\n * @returns User object.\n */\n const getUserById = async (\n userId: GetUserByIdParams['userId'],\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetUserByIdResult>(\n buildRouteURL(backendURL, userGroup, userEndpoints.getUserById, {\n userId: String(userId),\n }),\n authAPIOptions,\n otherOptions,\n {\n cache: 'no-store',\n }\n );\n\n /**\n * Retrieves a user by email.\n * @param email - User email.\n * @returns User object.\n */\n const getUserByEmail = async (\n email: GetUserByEmailParams['email'],\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetUserByEmailResult>(\n buildRouteURL(backendURL, userGroup, userEndpoints.getUserByEmail, {\n email,\n }),\n authAPIOptions,\n otherOptions,\n {\n cache: 'no-store',\n }\n );\n\n /**\n * Retrieves a user by account.\n * @param providerAccountId - The provider account ID.\n * @param provider - The provider of the account.\n */\n /**\n * Creates a new user.\n * @param user - User credentials.\n * @returns User object.\n */\n const createUser = async (\n user: CreateUserBody,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<CreateUserResult>(\n buildRouteURL(backendURL, userGroup, userEndpoints.createUser),\n authAPIOptions,\n otherOptions,\n {\n method: userEndpoints.createUser.method,\n body: user,\n }\n );\n\n /**\n * Updates the user with the provided data.\n * @param user - Updated user data.\n * @returns User object.\n */\n const updateUser = async (\n user: UpdateUserBody,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<UpdateUserResult>(\n buildRouteURL(backendURL, userGroup, userEndpoints.updateUser),\n authAPIOptions,\n otherOptions,\n {\n method: userEndpoints.updateUser.method,\n body: user,\n }\n );\n\n /**\n * Deletes a user with the provided ID.\n * @param userId - User ID.\n * @returns User object.\n */\n const deleteUser = async (\n userId: string,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<UpdateUserResult>(\n buildRouteURL(backendURL, userGroup, userEndpoints.deleteUser, {\n userId: String(userId),\n }),\n authAPIOptions,\n otherOptions,\n {\n method: userEndpoints.deleteUser.method,\n }\n );\n\n /**\n * Uploads a new avatar for the authenticated user.\n * @param file - The image File object to upload.\n * @returns Updated user object.\n */\n const uploadAvatar = async (\n file: File,\n otherOptions: FetcherOptions = {}\n ) => {\n const buffer = await file.arrayBuffer();\n\n const baseHeaders: Record<string, string> = {\n 'Content-Type': file.type || 'image/jpeg',\n };\n\n // Forward auth cookies / credentials from authAPIOptions headers\n const authHeaders =\n (authAPIOptions.headers as Record<string, string> | undefined) ?? {};\n\n const response = await fetch(\n buildRouteURL(backendURL, userGroup, userEndpoints.uploadAvatar),\n {\n method: userEndpoints.uploadAvatar.method,\n credentials: 'include',\n headers: { ...authHeaders, ...baseHeaders },\n body: buffer,\n signal: otherOptions.signal as AbortSignal | undefined,\n }\n );\n\n if (!response.ok) {\n const result = await response.json();\n throw new Error(JSON.stringify(result.error) ?? 'Avatar upload failed');\n }\n\n return (await response.json()) as UploadUserAvatarResult;\n };\n\n /**\n * Gets the verify email status URL to use in the SSE.\n * @param userId - User ID.\n * @returns The verify email status URL.\n */\n const getVerifyEmailStatusURL = (userId: string | UserAPI['id']) =>\n buildRouteURL(backendURL, userGroup, userEndpoints.verifyEmailStatusSSE, {\n userId: String(userId),\n });\n\n return {\n createUser,\n getUsers,\n getUserById,\n getUserByEmail,\n updateUser,\n deleteUser,\n uploadAvatar,\n getVerifyEmailStatusURL,\n };\n};\n\n/**\n * Authenticated `user` endpoint bound to an Intlayer CMS authenticator.\n *\n * Pass an authenticator created with `createIntlayerCMS`, or omit it to use\n * the build-time configuration (`@intlayer/config/built`).\n */\nexport const userEndpoint = createEndpoint(getUserAPI);\n"],"mappings":";;;;;;;;;AAgCA,MAAM,YAAY,EAChB,QAAQ,YACV;;;;;AAMA,MAAM,gBAAgB;CACpB,gBAAgB;EAAE,QAAQ;EAAO,MAAM;CAAS;CAChD,UAAU;EAAE,QAAQ;EAAO,MAAM;CAAI;CACrC,YAAY;EAAE,QAAQ;EAAO,MAAM;CAAI;CACvC,YAAY;EAAE,QAAQ;EAAQ,MAAM;CAAI;CACxC,aAAa;EAAE,QAAQ;EAAO,MAAM;CAAW;CAC/C,gBAAgB;EAAE,QAAQ;EAAO,MAAM;CAAgB;CACvD,YAAY;EAAE,QAAQ;EAAU,MAAM;CAAW;CACjD,sBAAsB;EAAE,QAAQ;EAAO,MAAM;CAA+B;CAC5E,cAAc;EAAE,QAAQ;EAAQ,MAAM;CAAU;AAClD;AAEA,MAAa,cACX,iBAAiC,CAAC,GAClC,mBACG;CACH,MAAM,aACJ,gBAAgB,QAAQ,cAAcA,8BAAO,cAAcC;;;;;;CAO7D,MAAM,WAAW,OACf,SACA,eAA+B,CAAC,MAEhC,MAAMC,4BACJC,sDAAc,YAAY,WAAW,cAAc,QAAQ,GAC3D,gBACA,cACA;EACE,OAAO;EAEP,QAAQ;CACV,CACF;;;;;;CAOF,MAAM,cAAc,OAClB,QACA,eAA+B,CAAC,MAEhC,MAAMD,4BACJC,sDAAc,YAAY,WAAW,cAAc,aAAa,EAC9D,QAAQ,OAAO,MAAM,EACvB,CAAC,GACD,gBACA,cACA,EACE,OAAO,WACT,CACF;;;;;;CAOF,MAAM,iBAAiB,OACrB,OACA,eAA+B,CAAC,MAEhC,MAAMD,4BACJC,sDAAc,YAAY,WAAW,cAAc,gBAAgB,EACjE,MACF,CAAC,GACD,gBACA,cACA,EACE,OAAO,WACT,CACF;;;;;;;;;;;CAYF,MAAM,aAAa,OACjB,MACA,eAA+B,CAAC,MAEhC,MAAMD,4BACJC,sDAAc,YAAY,WAAW,cAAc,UAAU,GAC7D,gBACA,cACA;EACE,QAAQ,cAAc,WAAW;EACjC,MAAM;CACR,CACF;;;;;;CAOF,MAAM,aAAa,OACjB,MACA,eAA+B,CAAC,MAEhC,MAAMD,4BACJC,sDAAc,YAAY,WAAW,cAAc,UAAU,GAC7D,gBACA,cACA;EACE,QAAQ,cAAc,WAAW;EACjC,MAAM;CACR,CACF;;;;;;CAOF,MAAM,aAAa,OACjB,QACA,eAA+B,CAAC,MAEhC,MAAMD,4BACJC,sDAAc,YAAY,WAAW,cAAc,YAAY,EAC7D,QAAQ,OAAO,MAAM,EACvB,CAAC,GACD,gBACA,cACA,EACE,QAAQ,cAAc,WAAW,OACnC,CACF;;;;;;CAOF,MAAM,eAAe,OACnB,MACA,eAA+B,CAAC,MAC7B;EACH,MAAM,SAAS,MAAM,KAAK,YAAY;EAEtC,MAAM,cAAsC,EAC1C,gBAAgB,KAAK,QAAQ,aAC/B;EAGA,MAAM,cACH,eAAe,WAAkD,CAAC;EAErE,MAAM,WAAW,MAAM,UACrBA,sDAAc,YAAY,WAAW,cAAc,YAAY,GAC/D;GACE,QAAQ,cAAc,aAAa;GACnC,aAAa;GACb,SAAS;IAAE,GAAG;IAAa,GAAG;GAAY;GAC1C,MAAM;GACN,QAAQ,aAAa;EACvB,CACF;EAEA,IAAI,CAAC,SAAS,IAAI;GAChB,MAAM,SAAS,MAAM,SAAS,KAAK;GACnC,MAAM,IAAI,MAAM,KAAK,UAAU,OAAO,KAAK,KAAK,sBAAsB;EACxE;EAEA,OAAQ,MAAM,SAAS,KAAK;CAC9B;;;;;;CAOA,MAAM,2BAA2B,eAC/BA,sDAAc,YAAY,WAAW,cAAc,sBAAsB,EACvE,QAAQ,OAAO,MAAM,EACvB,CAAC;CAEH,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;AACF;;;;;;;AAQA,MAAa,eAAeC,6CAAe,UAAU"}
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -9,9 +9,12 @@ const require_getIntlayerAPI_analytics = require('./getIntlayerAPI/analytics.cjs
|
|
|
9
9
|
const require_getIntlayerAPI_asset = require('./getIntlayerAPI/asset.cjs');
|
|
10
10
|
const require_getIntlayerAPI_audit = require('./getIntlayerAPI/audit.cjs');
|
|
11
11
|
const require_getIntlayerAPI_bitbucket = require('./getIntlayerAPI/bitbucket.cjs');
|
|
12
|
+
const require_getIntlayerAPI_forge = require('./getIntlayerAPI/forge.cjs');
|
|
13
|
+
const require_getIntlayerAPI_codeberg = require('./getIntlayerAPI/codeberg.cjs');
|
|
12
14
|
const require_getIntlayerAPI_dictionary = require('./getIntlayerAPI/dictionary.cjs');
|
|
13
15
|
const require_getIntlayerAPI_editor = require('./getIntlayerAPI/editor.cjs');
|
|
14
16
|
const require_getIntlayerAPI_environment = require('./getIntlayerAPI/environment.cjs');
|
|
17
|
+
const require_getIntlayerAPI_gitee = require('./getIntlayerAPI/gitee.cjs');
|
|
15
18
|
const require_getIntlayerAPI_github = require('./getIntlayerAPI/github.cjs');
|
|
16
19
|
const require_getIntlayerAPI_gitlab = require('./getIntlayerAPI/gitlab.cjs');
|
|
17
20
|
const require_getIntlayerAPI_newsletter = require('./getIntlayerAPI/newsletter.cjs');
|
|
@@ -38,8 +41,10 @@ exports.assetEndpoint = require_getIntlayerAPI_asset.assetEndpoint;
|
|
|
38
41
|
exports.auditEndpoint = require_getIntlayerAPI_audit.auditEndpoint;
|
|
39
42
|
exports.bitbucketEndpoint = require_getIntlayerAPI_bitbucket.bitbucketEndpoint;
|
|
40
43
|
exports.clearAccessTokenCache = require_cms_createAuthManager.clearAccessTokenCache;
|
|
44
|
+
exports.codebergEndpoint = require_getIntlayerAPI_codeberg.codebergEndpoint;
|
|
41
45
|
exports.createAuthManager = require_cms_createAuthManager.createAuthManager;
|
|
42
46
|
exports.createEndpoint = require_cms_createIntlayerCMS.createEndpoint;
|
|
47
|
+
exports.createForgeAPI = require_getIntlayerAPI_forge.createForgeAPI;
|
|
43
48
|
exports.createIntlayerCMS = require_cms_createIntlayerCMS.createIntlayerCMS;
|
|
44
49
|
exports.dictionaryEndpoint = require_getIntlayerAPI_dictionary.dictionaryEndpoint;
|
|
45
50
|
exports.editorEndpoint = require_getIntlayerAPI_editor.editorEndpoint;
|
|
@@ -53,9 +58,11 @@ exports.getAnalyticsAPI = require_getIntlayerAPI_analytics.getAnalyticsAPI;
|
|
|
53
58
|
exports.getAssetAPI = require_getIntlayerAPI_asset.getAssetAPI;
|
|
54
59
|
exports.getAuditAPI = require_getIntlayerAPI_audit.getAuditAPI;
|
|
55
60
|
exports.getBitbucketAPI = require_getIntlayerAPI_bitbucket.getBitbucketAPI;
|
|
61
|
+
exports.getCodebergAPI = require_getIntlayerAPI_codeberg.getCodebergAPI;
|
|
56
62
|
exports.getDictionaryAPI = require_getIntlayerAPI_dictionary.getDictionaryAPI;
|
|
57
63
|
exports.getEditorAPI = require_getIntlayerAPI_editor.getEditorAPI;
|
|
58
64
|
exports.getEnvironmentAPI = require_getIntlayerAPI_environment.getEnvironmentAPI;
|
|
65
|
+
exports.getGiteeAPI = require_getIntlayerAPI_gitee.getGiteeAPI;
|
|
59
66
|
exports.getGithubAPI = require_getIntlayerAPI_github.getGithubAPI;
|
|
60
67
|
exports.getGitlabAPI = require_getIntlayerAPI_gitlab.getGitlabAPI;
|
|
61
68
|
exports.getIntlayerAPI = require_getIntlayerAPI_index.getIntlayerAPI;
|
|
@@ -72,6 +79,7 @@ exports.getStripeAPI = require_getIntlayerAPI_stripe.getStripeAPI;
|
|
|
72
79
|
exports.getTagAPI = require_getIntlayerAPI_tag.getTagAPI;
|
|
73
80
|
exports.getTranslateAPI = require_getIntlayerAPI_translate.getTranslateAPI;
|
|
74
81
|
exports.getUserAPI = require_getIntlayerAPI_user.getUserAPI;
|
|
82
|
+
exports.giteeEndpoint = require_getIntlayerAPI_gitee.giteeEndpoint;
|
|
75
83
|
exports.githubEndpoint = require_getIntlayerAPI_github.githubEndpoint;
|
|
76
84
|
exports.gitlabEndpoint = require_getIntlayerAPI_gitlab.gitlabEndpoint;
|
|
77
85
|
exports.newsletterEndpoint = require_getIntlayerAPI_newsletter.newsletterEndpoint;
|
package/dist/cjs/proxy.cjs
CHANGED
|
@@ -6,9 +6,11 @@ const require_getIntlayerAPI_analytics = require('./getIntlayerAPI/analytics.cjs
|
|
|
6
6
|
const require_getIntlayerAPI_asset = require('./getIntlayerAPI/asset.cjs');
|
|
7
7
|
const require_getIntlayerAPI_audit = require('./getIntlayerAPI/audit.cjs');
|
|
8
8
|
const require_getIntlayerAPI_bitbucket = require('./getIntlayerAPI/bitbucket.cjs');
|
|
9
|
+
const require_getIntlayerAPI_codeberg = require('./getIntlayerAPI/codeberg.cjs');
|
|
9
10
|
const require_getIntlayerAPI_dictionary = require('./getIntlayerAPI/dictionary.cjs');
|
|
10
11
|
const require_getIntlayerAPI_editor = require('./getIntlayerAPI/editor.cjs');
|
|
11
12
|
const require_getIntlayerAPI_environment = require('./getIntlayerAPI/environment.cjs');
|
|
13
|
+
const require_getIntlayerAPI_gitee = require('./getIntlayerAPI/gitee.cjs');
|
|
12
14
|
const require_getIntlayerAPI_github = require('./getIntlayerAPI/github.cjs');
|
|
13
15
|
const require_getIntlayerAPI_gitlab = require('./getIntlayerAPI/gitlab.cjs');
|
|
14
16
|
const require_getIntlayerAPI_newsletter = require('./getIntlayerAPI/newsletter.cjs');
|
|
@@ -44,6 +46,8 @@ const sectionFactories = {
|
|
|
44
46
|
github: require_getIntlayerAPI_github.getGithubAPI,
|
|
45
47
|
gitlab: require_getIntlayerAPI_gitlab.getGitlabAPI,
|
|
46
48
|
bitbucket: require_getIntlayerAPI_bitbucket.getBitbucketAPI,
|
|
49
|
+
codeberg: require_getIntlayerAPI_codeberg.getCodebergAPI,
|
|
50
|
+
gitee: require_getIntlayerAPI_gitee.getGiteeAPI,
|
|
47
51
|
showcaseProject: require_getIntlayerAPI_showcaseProject.getShowcaseProjectAPI,
|
|
48
52
|
translate: require_getIntlayerAPI_translate.getTranslateAPI,
|
|
49
53
|
reviewer: require_getIntlayerAPI_reviewer.getReviewerAPI,
|
package/dist/cjs/proxy.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proxy.cjs","names":["getAssetAPI","getOrganizationAPI","getProjectAPI","getEnvironmentAPI","getUserAPI","getOAuthAPI","getDictionaryAPI","getStripeAPI","getAiAPI","getAnalyticsAPI","getAuditAPI","getTagAPI","getSearchAPI","getEditorAPI","getNewsletterAPI","getGithubAPI","getGitlabAPI","getBitbucketAPI","getShowcaseProjectAPI","getTranslateAPI","getReviewerAPI","getStatusAPI","createIntlayerCMS"],"sources":["../../src/proxy.ts"],"sourcesContent":["import { editor } from '@intlayer/config/built';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { createIntlayerCMS, type IntlayerCMS } from './cms/createIntlayerCMS';\nimport type { FetcherOptions } from './fetcher';\nimport { getAiAPI } from './getIntlayerAPI/ai';\nimport { getAnalyticsAPI } from './getIntlayerAPI/analytics';\nimport { getAssetAPI } from './getIntlayerAPI/asset';\nimport { getAuditAPI } from './getIntlayerAPI/audit';\nimport { getBitbucketAPI } from './getIntlayerAPI/bitbucket';\nimport { getDictionaryAPI } from './getIntlayerAPI/dictionary';\nimport { getEditorAPI } from './getIntlayerAPI/editor';\nimport { getEnvironmentAPI } from './getIntlayerAPI/environment';\nimport { getGithubAPI } from './getIntlayerAPI/github';\nimport { getGitlabAPI } from './getIntlayerAPI/gitlab';\nimport type { IntlayerAPI } from './getIntlayerAPI/index';\nimport { getNewsletterAPI } from './getIntlayerAPI/newsletter';\nimport { getOAuthAPI } from './getIntlayerAPI/oAuth';\nimport { getOrganizationAPI } from './getIntlayerAPI/organization';\nimport { getProjectAPI } from './getIntlayerAPI/project';\nimport { getReviewerAPI } from './getIntlayerAPI/reviewer';\nimport { getSearchAPI } from './getIntlayerAPI/search';\nimport { getShowcaseProjectAPI } from './getIntlayerAPI/showcaseProject';\nimport { getStatusAPI } from './getIntlayerAPI/status';\nimport { getStripeAPI } from './getIntlayerAPI/stripe';\nimport { getTagAPI } from './getIntlayerAPI/tag';\nimport { getTranslateAPI } from './getIntlayerAPI/translate';\nimport { getUserAPI } from './getIntlayerAPI/user';\n\ntype SectionKey = keyof IntlayerAPI;\n\n/**\n * Homogeneous factory map: every domain factory normalized to the same\n * `(fetcherOptions, config) => section` signature, keyed by section name.\n * Declaring it as a single mapped type lets a generic lookup stay callable\n * (a union of factory signatures would not be).\n */\ntype SectionFactories = {\n [Key in SectionKey]: (\n fetcherOptions: FetcherOptions,\n intlayerConfig: IntlayerConfig\n ) => IntlayerAPI[Key];\n};\n\nconst sectionFactories: SectionFactories = {\n asset: getAssetAPI,\n organization: getOrganizationAPI,\n project: getProjectAPI,\n environment: getEnvironmentAPI,\n user: getUserAPI,\n oAuth: getOAuthAPI,\n dictionary: getDictionaryAPI,\n stripe: getStripeAPI,\n ai: getAiAPI,\n analytics: getAnalyticsAPI,\n audit: getAuditAPI,\n tag: getTagAPI,\n search: getSearchAPI,\n editor: getEditorAPI,\n newsletter: getNewsletterAPI,\n github: getGithubAPI,\n gitlab: getGitlabAPI,\n bitbucket: getBitbucketAPI,\n showcaseProject: getShowcaseProjectAPI,\n translate: getTranslateAPI,\n reviewer: getReviewerAPI,\n status: getStatusAPI,\n};\n\n// The OAuth2 token endpoint must never receive an injected Bearer token —\n// it is the call that issues one.\nconst AUTH_FREE_SECTIONS: ReadonlySet<SectionKey> = new Set<SectionKey>([\n 'oAuth',\n]);\n\n/**\n * Builds the **complete** auto-authenticated Intlayer API as a single lazy\n * object. Every domain is reachable through it, so it pulls every domain client\n * into the bundle.\n *\n * Prefer {@link createIntlayerCMS} together with the per-domain endpoint binders\n * (e.g. `dictionaryEndpoint`) in bundle-sensitive code — they include only the\n * domains you use. This helper is a convenience for Node tools (such as the CLI)\n * where bundle size is not a concern.\n */\nexport const getIntlayerAPIProxy = (\n baseAuthOptions: FetcherOptions = {},\n intlayerConfig: Pick<IntlayerConfig, 'editor'> = { editor },\n sessionToken?: string\n): IntlayerAPI => {\n const cms: IntlayerCMS = createIntlayerCMS(intlayerConfig, {\n baseFetcherOptions: baseAuthOptions,\n sessionToken,\n });\n\n const sectionCache = new Map<SectionKey, unknown>();\n\n // Generic over `Key` so `sectionFactories[key]` resolves to a single\n // `(opts, config) => IntlayerAPI[Key]` signature rather than the union of all\n // factory signatures (which would not be callable).\n const buildSection = <Key extends SectionKey>(key: Key): IntlayerAPI[Key] => {\n const factory = sectionFactories[key] as (\n fetcherOptions: FetcherOptions,\n intlayerConfig: IntlayerConfig\n ) => Record<string, unknown>;\n\n return cms.bindSection(factory, {\n skipAuth: AUTH_FREE_SECTIONS.has(key) ? true : undefined,\n }) as IntlayerAPI[Key];\n };\n\n return new Proxy({} as IntlayerAPI, {\n get(_target, property) {\n const key = property as SectionKey;\n if (!(key in sectionFactories)) return undefined;\n\n if (!sectionCache.has(key)) {\n sectionCache.set(key, buildSection(key));\n }\n\n return sectionCache.get(key);\n },\n has(_target, property) {\n return (property as SectionKey) in sectionFactories;\n },\n ownKeys() {\n return Reflect.ownKeys(sectionFactories);\n },\n getOwnPropertyDescriptor() {\n return { enumerable: true, configurable: true };\n },\n });\n};\n\n/**\n * The complete auto-authenticated Intlayer API returned by\n * {@link getIntlayerAPIProxy}. Equivalent in shape to `IntlayerAPI`.\n */\nexport type IntlayerAPIProxy = ReturnType<typeof getIntlayerAPIProxy>;\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"proxy.cjs","names":["getAssetAPI","getOrganizationAPI","getProjectAPI","getEnvironmentAPI","getUserAPI","getOAuthAPI","getDictionaryAPI","getStripeAPI","getAiAPI","getAnalyticsAPI","getAuditAPI","getTagAPI","getSearchAPI","getEditorAPI","getNewsletterAPI","getGithubAPI","getGitlabAPI","getBitbucketAPI","getCodebergAPI","getGiteeAPI","getShowcaseProjectAPI","getTranslateAPI","getReviewerAPI","getStatusAPI","createIntlayerCMS"],"sources":["../../src/proxy.ts"],"sourcesContent":["import { editor } from '@intlayer/config/built';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { createIntlayerCMS, type IntlayerCMS } from './cms/createIntlayerCMS';\nimport type { FetcherOptions } from './fetcher';\nimport { getAiAPI } from './getIntlayerAPI/ai';\nimport { getAnalyticsAPI } from './getIntlayerAPI/analytics';\nimport { getAssetAPI } from './getIntlayerAPI/asset';\nimport { getAuditAPI } from './getIntlayerAPI/audit';\nimport { getBitbucketAPI } from './getIntlayerAPI/bitbucket';\nimport { getCodebergAPI } from './getIntlayerAPI/codeberg';\nimport { getDictionaryAPI } from './getIntlayerAPI/dictionary';\nimport { getEditorAPI } from './getIntlayerAPI/editor';\nimport { getEnvironmentAPI } from './getIntlayerAPI/environment';\nimport { getGiteeAPI } from './getIntlayerAPI/gitee';\nimport { getGithubAPI } from './getIntlayerAPI/github';\nimport { getGitlabAPI } from './getIntlayerAPI/gitlab';\nimport type { IntlayerAPI } from './getIntlayerAPI/index';\nimport { getNewsletterAPI } from './getIntlayerAPI/newsletter';\nimport { getOAuthAPI } from './getIntlayerAPI/oAuth';\nimport { getOrganizationAPI } from './getIntlayerAPI/organization';\nimport { getProjectAPI } from './getIntlayerAPI/project';\nimport { getReviewerAPI } from './getIntlayerAPI/reviewer';\nimport { getSearchAPI } from './getIntlayerAPI/search';\nimport { getShowcaseProjectAPI } from './getIntlayerAPI/showcaseProject';\nimport { getStatusAPI } from './getIntlayerAPI/status';\nimport { getStripeAPI } from './getIntlayerAPI/stripe';\nimport { getTagAPI } from './getIntlayerAPI/tag';\nimport { getTranslateAPI } from './getIntlayerAPI/translate';\nimport { getUserAPI } from './getIntlayerAPI/user';\n\ntype SectionKey = keyof IntlayerAPI;\n\n/**\n * Homogeneous factory map: every domain factory normalized to the same\n * `(fetcherOptions, config) => section` signature, keyed by section name.\n * Declaring it as a single mapped type lets a generic lookup stay callable\n * (a union of factory signatures would not be).\n */\ntype SectionFactories = {\n [Key in SectionKey]: (\n fetcherOptions: FetcherOptions,\n intlayerConfig: IntlayerConfig\n ) => IntlayerAPI[Key];\n};\n\nconst sectionFactories: SectionFactories = {\n asset: getAssetAPI,\n organization: getOrganizationAPI,\n project: getProjectAPI,\n environment: getEnvironmentAPI,\n user: getUserAPI,\n oAuth: getOAuthAPI,\n dictionary: getDictionaryAPI,\n stripe: getStripeAPI,\n ai: getAiAPI,\n analytics: getAnalyticsAPI,\n audit: getAuditAPI,\n tag: getTagAPI,\n search: getSearchAPI,\n editor: getEditorAPI,\n newsletter: getNewsletterAPI,\n github: getGithubAPI,\n gitlab: getGitlabAPI,\n bitbucket: getBitbucketAPI,\n codeberg: getCodebergAPI,\n gitee: getGiteeAPI,\n showcaseProject: getShowcaseProjectAPI,\n translate: getTranslateAPI,\n reviewer: getReviewerAPI,\n status: getStatusAPI,\n};\n\n// The OAuth2 token endpoint must never receive an injected Bearer token —\n// it is the call that issues one.\nconst AUTH_FREE_SECTIONS: ReadonlySet<SectionKey> = new Set<SectionKey>([\n 'oAuth',\n]);\n\n/**\n * Builds the **complete** auto-authenticated Intlayer API as a single lazy\n * object. Every domain is reachable through it, so it pulls every domain client\n * into the bundle.\n *\n * Prefer {@link createIntlayerCMS} together with the per-domain endpoint binders\n * (e.g. `dictionaryEndpoint`) in bundle-sensitive code — they include only the\n * domains you use. This helper is a convenience for Node tools (such as the CLI)\n * where bundle size is not a concern.\n */\nexport const getIntlayerAPIProxy = (\n baseAuthOptions: FetcherOptions = {},\n intlayerConfig: Pick<IntlayerConfig, 'editor'> = { editor },\n sessionToken?: string\n): IntlayerAPI => {\n const cms: IntlayerCMS = createIntlayerCMS(intlayerConfig, {\n baseFetcherOptions: baseAuthOptions,\n sessionToken,\n });\n\n const sectionCache = new Map<SectionKey, unknown>();\n\n // Generic over `Key` so `sectionFactories[key]` resolves to a single\n // `(opts, config) => IntlayerAPI[Key]` signature rather than the union of all\n // factory signatures (which would not be callable).\n const buildSection = <Key extends SectionKey>(key: Key): IntlayerAPI[Key] => {\n const factory = sectionFactories[key] as (\n fetcherOptions: FetcherOptions,\n intlayerConfig: IntlayerConfig\n ) => Record<string, unknown>;\n\n return cms.bindSection(factory, {\n skipAuth: AUTH_FREE_SECTIONS.has(key) ? true : undefined,\n }) as IntlayerAPI[Key];\n };\n\n return new Proxy({} as IntlayerAPI, {\n get(_target, property) {\n const key = property as SectionKey;\n if (!(key in sectionFactories)) return undefined;\n\n if (!sectionCache.has(key)) {\n sectionCache.set(key, buildSection(key));\n }\n\n return sectionCache.get(key);\n },\n has(_target, property) {\n return (property as SectionKey) in sectionFactories;\n },\n ownKeys() {\n return Reflect.ownKeys(sectionFactories);\n },\n getOwnPropertyDescriptor() {\n return { enumerable: true, configurable: true };\n },\n });\n};\n\n/**\n * The complete auto-authenticated Intlayer API returned by\n * {@link getIntlayerAPIProxy}. Equivalent in shape to `IntlayerAPI`.\n */\nexport type IntlayerAPIProxy = ReturnType<typeof getIntlayerAPIProxy>;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6CA,MAAM,mBAAqC;CACzC,OAAOA;CACP,cAAcC;CACd,SAASC;CACT,aAAaC;CACb,MAAMC;CACN,OAAOC;CACP,YAAYC;CACZ,QAAQC;CACR,IAAIC;CACJ,WAAWC;CACX,OAAOC;CACP,KAAKC;CACL,QAAQC;CACR,QAAQC;CACR,YAAYC;CACZ,QAAQC;CACR,QAAQC;CACR,WAAWC;CACX,UAAUC;CACV,OAAOC;CACP,iBAAiBC;CACjB,WAAWC;CACX,UAAUC;CACV,QAAQC;AACV;AAIA,MAAM,qCAA8C,IAAI,IAAgB,CACtE,OACF,CAAC;;;;;;;;;;;AAYD,MAAa,uBACX,kBAAkC,CAAC,GACnC,iBAAiD,EAAE,sCAAO,GAC1D,iBACgB;CAChB,MAAM,MAAmBC,gDAAkB,gBAAgB;EACzD,oBAAoB;EACpB;CACF,CAAC;CAED,MAAM,+BAAe,IAAI,IAAyB;CAKlD,MAAM,gBAAwC,QAA+B;EAC3E,MAAM,UAAU,iBAAiB;EAKjC,OAAO,IAAI,YAAY,SAAS,EAC9B,UAAU,mBAAmB,IAAI,GAAG,IAAI,OAAO,OACjD,CAAC;CACH;CAEA,OAAO,IAAI,MAAM,CAAC,GAAkB;EAClC,IAAI,SAAS,UAAU;GACrB,MAAM,MAAM;GACZ,IAAI,EAAE,OAAO,mBAAmB,OAAO;GAEvC,IAAI,CAAC,aAAa,IAAI,GAAG,GACvB,aAAa,IAAI,KAAK,aAAa,GAAG,CAAC;GAGzC,OAAO,aAAa,IAAI,GAAG;EAC7B;EACA,IAAI,SAAS,UAAU;GACrB,OAAQ,YAA2B;EACrC;EACA,UAAU;GACR,OAAO,QAAQ,QAAQ,gBAAgB;EACzC;EACA,2BAA2B;GACzB,OAAO;IAAE,YAAY;IAAM,cAAc;GAAK;EAChD;CACF,CAAC;AACH"}
|
|
@@ -59,6 +59,25 @@ const writeStoredToken = (cached) => {
|
|
|
59
59
|
* @param options - Optional configuration override.
|
|
60
60
|
* @returns A client that authenticates itself with the public project key.
|
|
61
61
|
*/
|
|
62
|
+
/**
|
|
63
|
+
* Public routes, checked against the backend contract at compile time. Kept
|
|
64
|
+
* as plain strings: this client ships in end-user browser bundles.
|
|
65
|
+
*/
|
|
66
|
+
const publicPrefix = "/api/public";
|
|
67
|
+
const publicEndpoints = {
|
|
68
|
+
createPublicBrowserToken: {
|
|
69
|
+
method: "POST",
|
|
70
|
+
path: "/token"
|
|
71
|
+
},
|
|
72
|
+
getPublicDictionaryKeys: {
|
|
73
|
+
method: "GET",
|
|
74
|
+
path: "/dictionaries/keys"
|
|
75
|
+
},
|
|
76
|
+
getPublicDictionaries: {
|
|
77
|
+
method: "GET",
|
|
78
|
+
path: "/dictionaries"
|
|
79
|
+
}
|
|
80
|
+
};
|
|
62
81
|
const createPublicClient = ({ intlayerConfig } = {}) => {
|
|
63
82
|
const resolvedEditor = intlayerConfig?.editor ?? _intlayer_config_built.editor;
|
|
64
83
|
const backendURL = (resolvedEditor?.backendURL ?? "").replace(/\/$/, "");
|
|
@@ -67,8 +86,9 @@ const createPublicClient = ({ intlayerConfig } = {}) => {
|
|
|
67
86
|
let pendingExchange = null;
|
|
68
87
|
const isUsable = (candidate) => candidate !== null && candidate.expiresAt - EXPIRY_MARGIN_MS > Date.now();
|
|
69
88
|
const exchange = async () => {
|
|
70
|
-
const
|
|
71
|
-
|
|
89
|
+
const { method, path } = publicEndpoints.createPublicBrowserToken;
|
|
90
|
+
const response = await fetch(`${backendURL}${publicPrefix}${path}`, {
|
|
91
|
+
method,
|
|
72
92
|
headers: { "Content-Type": "application/json" },
|
|
73
93
|
body: JSON.stringify({ clientId }),
|
|
74
94
|
credentials: "omit",
|
|
@@ -103,7 +123,7 @@ const createPublicClient = ({ intlayerConfig } = {}) => {
|
|
|
103
123
|
const request = async (path, fallback) => {
|
|
104
124
|
const token = await getToken();
|
|
105
125
|
if (!token) return fallback;
|
|
106
|
-
const response = await fetch(`${backendURL}
|
|
126
|
+
const response = await fetch(`${backendURL}${publicPrefix}${path}`, {
|
|
107
127
|
headers: { Authorization: `Bearer ${token}` },
|
|
108
128
|
credentials: "omit",
|
|
109
129
|
mode: "cors"
|
|
@@ -113,8 +133,8 @@ const createPublicClient = ({ intlayerConfig } = {}) => {
|
|
|
113
133
|
};
|
|
114
134
|
return {
|
|
115
135
|
getToken,
|
|
116
|
-
getDictionaryKeys: () => request(
|
|
117
|
-
getDictionaries: (keys) => request(
|
|
136
|
+
getDictionaryKeys: () => request(publicEndpoints.getPublicDictionaryKeys.path, []),
|
|
137
|
+
getDictionaries: (keys) => request(`${publicEndpoints.getPublicDictionaries.path}?keys=${encodeURIComponent(keys.join(","))}`, [])
|
|
118
138
|
};
|
|
119
139
|
};
|
|
120
140
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createPublicClient.cjs","names":["editor"],"sources":["../../../src/public/createPublicClient.ts"],"sourcesContent":["import type { DictionaryAPI } from '@intlayer/backend';\nimport { editor } from '@intlayer/config/built';\nimport type { IntlayerConfig } from '@intlayer/types/config';\n\n/**\n * Browser-safe Intlayer client, authenticated without any confidential\n * credential.\n *\n * This is the Google-Analytics model applied to the whole SDK: the page ships\n * only the **public** `editor.clientId`, exchanges it for a short-lived scoped\n * token, and calls the API directly. No server route, no server action, and no\n * `clientSecret` in the bundle.\n *\n * What it can do is deliberately narrow, and that is what makes shipping the\n * key safe: read the project's published dictionary content — the content the\n * page already renders — and submit analytics events. Writing content, reading\n * a project, an organization or a user still require a real credential\n * (server-side) or a signed-in user.\n *\n * @example\n * ```ts\n * import { createPublicClient } from '@intlayer/api/public';\n *\n * const client = createPublicClient();\n *\n * const keys = await client.getDictionaryKeys();\n * const [dictionary] = await client.getDictionaries(['navbar']);\n * ```\n */\n\n/** `sessionStorage` key holding the cached token for this tab. */\nconst TOKEN_STORAGE_KEY = '__intlayer_public_token__';\n\n/**\n * Refresh margin: a token within this window of expiry is treated as expired,\n * so a request is never sent with a token that dies in flight.\n */\nconst EXPIRY_MARGIN_MS = 60 * 1000;\n\ntype CachedToken = {\n token: string;\n /** Epoch milliseconds. */\n expiresAt: number;\n};\n\n/** Reads the cached token for this tab, ignoring an unusable cache. */\nconst readStoredToken = (): CachedToken | null => {\n try {\n const raw = globalThis.sessionStorage?.getItem(TOKEN_STORAGE_KEY);\n if (!raw) return null;\n\n const parsed = JSON.parse(raw) as CachedToken;\n\n if (typeof parsed?.token !== 'string') return null;\n if (typeof parsed?.expiresAt !== 'number') return null;\n\n return parsed;\n } catch {\n // Private mode, disabled storage, or a corrupted entry — start fresh.\n return null;\n }\n};\n\n/** Persists the token for this tab. Best-effort: storage may be unavailable. */\nconst writeStoredToken = (cached: CachedToken): void => {\n try {\n globalThis.sessionStorage?.setItem(\n TOKEN_STORAGE_KEY,\n JSON.stringify(cached)\n );\n } catch {\n /* ignore — the in-memory cache still applies for this page */\n }\n};\n\n/** Options accepted by {@link createPublicClient}. */\nexport type PublicClientOptions = {\n /** Overrides the build-time `editor` configuration. */\n intlayerConfig?: Pick<IntlayerConfig, 'editor'>;\n};\n\n/** The credential-free client returned by {@link createPublicClient}. */\nexport type PublicClient = {\n /**\n * Returns the current token, exchanging the public `clientId` for one when\n * needed. `null` when the project is unknown or the origin is not allowed.\n */\n getToken: () => Promise<string | null>;\n /** Every dictionary key published for the project. */\n getDictionaryKeys: () => Promise<string[]>;\n /**\n * Published dictionary content for the given keys.\n *\n * @param keys - Dictionary keys to fetch (at most 100 per call).\n */\n getDictionaries: (keys: string[]) => Promise<DictionaryAPI[]>;\n};\n\n/**\n * Creates a {@link PublicClient} for the configured project.\n *\n * @param options - Optional configuration override.\n * @returns A client that authenticates itself with the public project key.\n */\nexport const createPublicClient = ({\n intlayerConfig,\n}: PublicClientOptions = {}): PublicClient => {\n const resolvedEditor = intlayerConfig?.editor ?? editor;\n const backendURL = (resolvedEditor?.backendURL ?? '').replace(/\\/$/, '');\n const clientId = resolvedEditor?.clientId;\n\n let cached: CachedToken | null = null;\n let pendingExchange: Promise<string | null> | null = null;\n\n const isUsable = (candidate: CachedToken | null): candidate is CachedToken =>\n candidate !== null && candidate.expiresAt - EXPIRY_MARGIN_MS > Date.now();\n\n const exchange = async (): Promise<string | null> => {\n const response = await fetch(`${backendURL}
|
|
1
|
+
{"version":3,"file":"createPublicClient.cjs","names":["editor"],"sources":["../../../src/public/createPublicClient.ts"],"sourcesContent":["import type { RouteEndpoints } from '@intlayer/backend-contract/defineRoute';\nimport type { DictionaryAPI } from '@intlayer/backend-contract/dictionary';\nimport type {\n PublicRoutes,\n publicContract,\n} from '@intlayer/backend-contract/public';\nimport { editor } from '@intlayer/config/built';\nimport type { IntlayerConfig } from '@intlayer/types/config';\n\n/**\n * Browser-safe Intlayer client, authenticated without any confidential\n * credential.\n *\n * This is the Google-Analytics model applied to the whole SDK: the page ships\n * only the **public** `editor.clientId`, exchanges it for a short-lived scoped\n * token, and calls the API directly. No server route, no server action, and no\n * `clientSecret` in the bundle.\n *\n * What it can do is deliberately narrow, and that is what makes shipping the\n * key safe: read the project's published dictionary content — the content the\n * page already renders — and submit analytics events. Writing content, reading\n * a project, an organization or a user still require a real credential\n * (server-side) or a signed-in user.\n *\n * @example\n * ```ts\n * import { createPublicClient } from '@intlayer/api/public';\n *\n * const client = createPublicClient();\n *\n * const keys = await client.getDictionaryKeys();\n * const [dictionary] = await client.getDictionaries(['navbar']);\n * ```\n */\n\n/** `sessionStorage` key holding the cached token for this tab. */\nconst TOKEN_STORAGE_KEY = '__intlayer_public_token__';\n\n/**\n * Refresh margin: a token within this window of expiry is treated as expired,\n * so a request is never sent with a token that dies in flight.\n */\nconst EXPIRY_MARGIN_MS = 60 * 1000;\n\ntype CachedToken = {\n token: string;\n /** Epoch milliseconds. */\n expiresAt: number;\n};\n\n/** Reads the cached token for this tab, ignoring an unusable cache. */\nconst readStoredToken = (): CachedToken | null => {\n try {\n const raw = globalThis.sessionStorage?.getItem(TOKEN_STORAGE_KEY);\n if (!raw) return null;\n\n const parsed = JSON.parse(raw) as CachedToken;\n\n if (typeof parsed?.token !== 'string') return null;\n if (typeof parsed?.expiresAt !== 'number') return null;\n\n return parsed;\n } catch {\n // Private mode, disabled storage, or a corrupted entry — start fresh.\n return null;\n }\n};\n\n/** Persists the token for this tab. Best-effort: storage may be unavailable. */\nconst writeStoredToken = (cached: CachedToken): void => {\n try {\n globalThis.sessionStorage?.setItem(\n TOKEN_STORAGE_KEY,\n JSON.stringify(cached)\n );\n } catch {\n /* ignore — the in-memory cache still applies for this page */\n }\n};\n\n/** Options accepted by {@link createPublicClient}. */\nexport type PublicClientOptions = {\n /** Overrides the build-time `editor` configuration. */\n intlayerConfig?: Pick<IntlayerConfig, 'editor'>;\n};\n\n/** The credential-free client returned by {@link createPublicClient}. */\nexport type PublicClient = {\n /**\n * Returns the current token, exchanging the public `clientId` for one when\n * needed. `null` when the project is unknown or the origin is not allowed.\n */\n getToken: () => Promise<string | null>;\n /** Every dictionary key published for the project. */\n getDictionaryKeys: () => Promise<string[]>;\n /**\n * Published dictionary content for the given keys.\n *\n * @param keys - Dictionary keys to fetch (at most 100 per call).\n */\n getDictionaries: (keys: string[]) => Promise<DictionaryAPI[]>;\n};\n\n/**\n * Creates a {@link PublicClient} for the configured project.\n *\n * @param options - Optional configuration override.\n * @returns A client that authenticates itself with the public project key.\n */\n/**\n * Public routes, checked against the backend contract at compile time. Kept\n * as plain strings: this client ships in end-user browser bundles.\n */\nconst publicPrefix = '/api/public' satisfies (typeof publicContract)['prefix'];\nconst publicEndpoints = {\n createPublicBrowserToken: { method: 'POST', path: '/token' },\n getPublicDictionaryKeys: { method: 'GET', path: '/dictionaries/keys' },\n getPublicDictionaries: { method: 'GET', path: '/dictionaries' },\n} as const satisfies RouteEndpoints<PublicRoutes>;\n\nexport const createPublicClient = ({\n intlayerConfig,\n}: PublicClientOptions = {}): PublicClient => {\n const resolvedEditor = intlayerConfig?.editor ?? editor;\n const backendURL = (resolvedEditor?.backendURL ?? '').replace(/\\/$/, '');\n const clientId = resolvedEditor?.clientId;\n\n let cached: CachedToken | null = null;\n let pendingExchange: Promise<string | null> | null = null;\n\n const isUsable = (candidate: CachedToken | null): candidate is CachedToken =>\n candidate !== null && candidate.expiresAt - EXPIRY_MARGIN_MS > Date.now();\n\n const exchange = async (): Promise<string | null> => {\n const { method, path } = publicEndpoints.createPublicBrowserToken;\n const response = await fetch(`${backendURL}${publicPrefix}${path}`, {\n method,\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ clientId }),\n // Authorised by `Origin`, never by cookies.\n credentials: 'omit',\n mode: 'cors',\n });\n\n if (!response.ok) return null;\n\n const payload = (await response.json()) as {\n data?: { token?: string | null; expiresIn?: number };\n };\n\n const token = payload?.data?.token;\n const expiresIn = payload?.data?.expiresIn ?? 0;\n\n if (!token || expiresIn <= 0) return null;\n\n cached = { token, expiresAt: Date.now() + expiresIn * 1000 };\n writeStoredToken(cached);\n\n return token;\n };\n\n const getToken = async (): Promise<string | null> => {\n if (isUsable(cached)) return cached.token;\n\n const stored = readStoredToken();\n if (isUsable(stored)) {\n cached = stored;\n return stored.token;\n }\n\n if (!clientId) return null;\n\n // De-duplicate concurrent exchanges so a burst of calls triggers one fetch.\n pendingExchange ??= exchange().finally(() => {\n pendingExchange = null;\n });\n\n return await pendingExchange;\n };\n\n /** Issues an authorised GET against the public surface. */\n const request = async <Result>(\n path: string,\n fallback: Result\n ): Promise<Result> => {\n const token = await getToken();\n\n if (!token) return fallback;\n\n const response = await fetch(`${backendURL}${publicPrefix}${path}`, {\n headers: { Authorization: `Bearer ${token}` },\n credentials: 'omit',\n mode: 'cors',\n });\n\n if (!response.ok) return fallback;\n\n const payload = (await response.json()) as { data?: Result };\n\n return payload?.data ?? fallback;\n };\n\n return {\n getToken,\n getDictionaryKeys: () =>\n request<string[]>(publicEndpoints.getPublicDictionaryKeys.path, []),\n getDictionaries: (keys) =>\n request<DictionaryAPI[]>(\n `${publicEndpoints.getPublicDictionaries.path}?keys=${encodeURIComponent(keys.join(','))}`,\n []\n ),\n };\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoCA,MAAM,oBAAoB;;;;;AAM1B,MAAM,mBAAmB;;AASzB,MAAM,wBAA4C;CAChD,IAAI;EACF,MAAM,MAAM,WAAW,gBAAgB,QAAQ,iBAAiB;EAChE,IAAI,CAAC,KAAK,OAAO;EAEjB,MAAM,SAAS,KAAK,MAAM,GAAG;EAE7B,IAAI,OAAO,QAAQ,UAAU,UAAU,OAAO;EAC9C,IAAI,OAAO,QAAQ,cAAc,UAAU,OAAO;EAElD,OAAO;CACT,QAAQ;EAEN,OAAO;CACT;AACF;;AAGA,MAAM,oBAAoB,WAA8B;CACtD,IAAI;EACF,WAAW,gBAAgB,QACzB,mBACA,KAAK,UAAU,MAAM,CACvB;CACF,QAAQ,CAER;AACF;;;;;;;;;;;AAmCA,MAAM,eAAe;AACrB,MAAM,kBAAkB;CACtB,0BAA0B;EAAE,QAAQ;EAAQ,MAAM;CAAS;CAC3D,yBAAyB;EAAE,QAAQ;EAAO,MAAM;CAAqB;CACrE,uBAAuB;EAAE,QAAQ;EAAO,MAAM;CAAgB;AAChE;AAEA,MAAa,sBAAsB,EACjC,mBACuB,CAAC,MAAoB;CAC5C,MAAM,iBAAiB,gBAAgB,UAAUA;CACjD,MAAM,cAAc,gBAAgB,cAAc,GAAE,CAAE,QAAQ,OAAO,EAAE;CACvE,MAAM,WAAW,gBAAgB;CAEjC,IAAI,SAA6B;CACjC,IAAI,kBAAiD;CAErD,MAAM,YAAY,cAChB,cAAc,QAAQ,UAAU,YAAY,mBAAmB,KAAK,IAAI;CAE1E,MAAM,WAAW,YAAoC;EACnD,MAAM,EAAE,QAAQ,SAAS,gBAAgB;EACzC,MAAM,WAAW,MAAM,MAAM,GAAG,aAAa,eAAe,QAAQ;GAClE;GACA,SAAS,EAAE,gBAAgB,mBAAmB;GAC9C,MAAM,KAAK,UAAU,EAAE,SAAS,CAAC;GAEjC,aAAa;GACb,MAAM;EACR,CAAC;EAED,IAAI,CAAC,SAAS,IAAI,OAAO;EAEzB,MAAM,UAAW,MAAM,SAAS,KAAK;EAIrC,MAAM,QAAQ,SAAS,MAAM;EAC7B,MAAM,YAAY,SAAS,MAAM,aAAa;EAE9C,IAAI,CAAC,SAAS,aAAa,GAAG,OAAO;EAErC,SAAS;GAAE;GAAO,WAAW,KAAK,IAAI,IAAI,YAAY;EAAK;EAC3D,iBAAiB,MAAM;EAEvB,OAAO;CACT;CAEA,MAAM,WAAW,YAAoC;EACnD,IAAI,SAAS,MAAM,GAAG,OAAO,OAAO;EAEpC,MAAM,SAAS,gBAAgB;EAC/B,IAAI,SAAS,MAAM,GAAG;GACpB,SAAS;GACT,OAAO,OAAO;EAChB;EAEA,IAAI,CAAC,UAAU,OAAO;EAGtB,oBAAoB,SAAS,CAAC,CAAC,cAAc;GAC3C,kBAAkB;EACpB,CAAC;EAED,OAAO,MAAM;CACf;;CAGA,MAAM,UAAU,OACd,MACA,aACoB;EACpB,MAAM,QAAQ,MAAM,SAAS;EAE7B,IAAI,CAAC,OAAO,OAAO;EAEnB,MAAM,WAAW,MAAM,MAAM,GAAG,aAAa,eAAe,QAAQ;GAClE,SAAS,EAAE,eAAe,UAAU,QAAQ;GAC5C,aAAa;GACb,MAAM;EACR,CAAC;EAED,IAAI,CAAC,SAAS,IAAI,OAAO;EAIzB,QAAO,MAFgB,SAAS,KAAK,EAEvB,EAAE,QAAQ;CAC1B;CAEA,OAAO;EACL;EACA,yBACE,QAAkB,gBAAgB,wBAAwB,MAAM,CAAC,CAAC;EACpE,kBAAkB,SAChB,QACE,GAAG,gBAAgB,sBAAsB,KAAK,QAAQ,mBAAmB,KAAK,KAAK,GAAG,CAAC,KACvF,CAAC,CACH;CACJ;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetchDistantDictionaries.mjs","names":[],"sources":["../../../src/distantDictionary/fetchDistantDictionaries.ts"],"sourcesContent":["import type { DictionaryAPI } from '@intlayer/backend';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { createIntlayerCMS } from '../cms/createIntlayerCMS';\nimport { dictionaryEndpoint } from '../getIntlayerAPI/dictionary';\n\n/**\n * Fetch distant dictionary\n */\nexport const fetchDistantDictionaries = async (\n intlayerConfig: IntlayerConfig\n): Promise<DictionaryAPI[] | null | undefined> => {\n try {\n const { clientId, clientSecret } = intlayerConfig.editor;\n\n if (!clientId || !clientSecret) {\n throw new Error(\n 'Missing OAuth2 client ID or client secret. To get access token go to https://app.intlayer.org/project.'\n );\n }\n\n const dictionary = dictionaryEndpoint(createIntlayerCMS(intlayerConfig));\n\n // Fetch the dictionary list\n const getDictionaryResult = await dictionary.getDictionaries();\n\n const distantDictionaries = getDictionaryResult.data;\n\n return distantDictionaries;\n } catch (error) {\n console.error(error);\n return undefined;\n }\n};\n"],"mappings":";;;;;;;AAQA,MAAa,2BAA2B,OACtC,mBACgD;CAChD,IAAI;EACF,MAAM,EAAE,UAAU,iBAAiB,eAAe;EAElD,IAAI,CAAC,YAAY,CAAC,cAChB,MAAM,IAAI,MACR,wGACF;EAUF,QAF4B,MALT,mBAAmB,kBAAkB,cAAc,CAG3B,CAAC,CAAC,gBAAgB,EAEd,CAAC;CAGlD,SAAS,OAAO;EACd,QAAQ,MAAM,KAAK;EACnB;CACF;AACF"}
|
|
1
|
+
{"version":3,"file":"fetchDistantDictionaries.mjs","names":[],"sources":["../../../src/distantDictionary/fetchDistantDictionaries.ts"],"sourcesContent":["import type { DictionaryAPI } from '@intlayer/backend-contract/dictionary';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { createIntlayerCMS } from '../cms/createIntlayerCMS';\nimport { dictionaryEndpoint } from '../getIntlayerAPI/dictionary';\n\n/**\n * Fetch distant dictionary\n */\nexport const fetchDistantDictionaries = async (\n intlayerConfig: IntlayerConfig\n): Promise<DictionaryAPI[] | null | undefined> => {\n try {\n const { clientId, clientSecret } = intlayerConfig.editor;\n\n if (!clientId || !clientSecret) {\n throw new Error(\n 'Missing OAuth2 client ID or client secret. To get access token go to https://app.intlayer.org/project.'\n );\n }\n\n const dictionary = dictionaryEndpoint(createIntlayerCMS(intlayerConfig));\n\n // Fetch the dictionary list\n const getDictionaryResult = await dictionary.getDictionaries();\n\n const distantDictionaries = getDictionaryResult.data;\n\n return distantDictionaries;\n } catch (error) {\n console.error(error);\n return undefined;\n }\n};\n"],"mappings":";;;;;;;AAQA,MAAa,2BAA2B,OACtC,mBACgD;CAChD,IAAI;EACF,MAAM,EAAE,UAAU,iBAAiB,eAAe;EAElD,IAAI,CAAC,YAAY,CAAC,cAChB,MAAM,IAAI,MACR,wGACF;EAUF,QAF4B,MALT,mBAAmB,kBAAkB,cAAc,CAG3B,CAAC,CAAC,gBAAgB,EAEd,CAAC;CAGlD,SAAS,OAAO;EACd,QAAQ,MAAM,KAAK;EACnB;CACF;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetchDistantDictionary.mjs","names":[],"sources":["../../../src/distantDictionary/fetchDistantDictionary.ts"],"sourcesContent":["import type { DictionaryAPI } from '@intlayer/backend';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { createIntlayerCMS } from '../cms/createIntlayerCMS';\nimport { dictionaryEndpoint } from '../getIntlayerAPI/dictionary';\n\n/**\n * Fetch distant dictionary\n */\nexport const fetchDistantDictionary = async (\n dictionaryKey: string,\n intlayerConfig: IntlayerConfig\n): Promise<DictionaryAPI | undefined> => {\n try {\n const { clientId, clientSecret } = intlayerConfig.editor;\n\n if (!clientId || !clientSecret) {\n throw new Error(\n 'Missing OAuth2 client ID or client secret. To get access token go to https://app.intlayer.org/project.'\n );\n }\n\n const dictionary = dictionaryEndpoint(createIntlayerCMS(intlayerConfig));\n\n // Fetch the dictionary\n const getDictionaryResult = await dictionary.getDictionary(dictionaryKey);\n\n const distantDictionary = getDictionaryResult.data;\n\n if (!distantDictionary) {\n throw new Error(`Dictionary ${dictionaryKey} not found on remote`);\n }\n\n return distantDictionary;\n } catch (error) {\n console.error(error);\n return undefined;\n }\n};\n"],"mappings":";;;;;;;AAQA,MAAa,yBAAyB,OACpC,eACA,mBACuC;CACvC,IAAI;EACF,MAAM,EAAE,UAAU,iBAAiB,eAAe;EAElD,IAAI,CAAC,YAAY,CAAC,cAChB,MAAM,IAAI,MACR,wGACF;EAQF,MAAM,qBAAoB,MALP,mBAAmB,kBAAkB,cAAc,CAG3B,CAAC,CAAC,cAAc,aAAa,EAE3B,CAAC;EAE9C,IAAI,CAAC,mBACH,MAAM,IAAI,MAAM,cAAc,cAAc,qBAAqB;EAGnE,OAAO;CACT,SAAS,OAAO;EACd,QAAQ,MAAM,KAAK;EACnB;CACF;AACF"}
|
|
1
|
+
{"version":3,"file":"fetchDistantDictionary.mjs","names":[],"sources":["../../../src/distantDictionary/fetchDistantDictionary.ts"],"sourcesContent":["import type { DictionaryAPI } from '@intlayer/backend-contract/dictionary';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { createIntlayerCMS } from '../cms/createIntlayerCMS';\nimport { dictionaryEndpoint } from '../getIntlayerAPI/dictionary';\n\n/**\n * Fetch distant dictionary\n */\nexport const fetchDistantDictionary = async (\n dictionaryKey: string,\n intlayerConfig: IntlayerConfig\n): Promise<DictionaryAPI | undefined> => {\n try {\n const { clientId, clientSecret } = intlayerConfig.editor;\n\n if (!clientId || !clientSecret) {\n throw new Error(\n 'Missing OAuth2 client ID or client secret. To get access token go to https://app.intlayer.org/project.'\n );\n }\n\n const dictionary = dictionaryEndpoint(createIntlayerCMS(intlayerConfig));\n\n // Fetch the dictionary\n const getDictionaryResult = await dictionary.getDictionary(dictionaryKey);\n\n const distantDictionary = getDictionaryResult.data;\n\n if (!distantDictionary) {\n throw new Error(`Dictionary ${dictionaryKey} not found on remote`);\n }\n\n return distantDictionary;\n } catch (error) {\n console.error(error);\n return undefined;\n }\n};\n"],"mappings":";;;;;;;AAQA,MAAa,yBAAyB,OACpC,eACA,mBACuC;CACvC,IAAI;EACF,MAAM,EAAE,UAAU,iBAAiB,eAAe;EAElD,IAAI,CAAC,YAAY,CAAC,cAChB,MAAM,IAAI,MACR,wGACF;EAQF,MAAM,qBAAoB,MALP,mBAAmB,kBAAkB,cAAc,CAG3B,CAAC,CAAC,cAAc,aAAa,EAE3B,CAAC;EAE9C,IAAI,CAAC,mBACH,MAAM,IAAI,MAAM,cAAc,cAAc,qBAAqB;EAGnE,OAAO;CACT,SAAS,OAAO;EACd,QAAQ,MAAM,KAAK;EACnB;CACF;AACF"}
|
package/dist/esm/fetcher.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetcher.mjs","names":[],"sources":["../../src/fetcher.ts"],"sourcesContent":["import { resolveInternalBackendUrl } from './resolveInternalBackendUrl';\n\n/**\n * Error thrown when the backend answers with a non-ok response.\n *\n * Carries the HTTP status and the backend error code alongside the message, so\n * callers can tell a transient failure (5xx, network) from a deterministic one\n * (4xx) instead of blindly retrying.\n */\nexport class FetcherError extends Error {\n /** HTTP status code of the response. */\n public readonly status: number;\n /** Error code returned by the backend, when available (ex: `DICTIONARY_NOT_FOUND`). */\n public readonly code?: string;\n /** Raw error payload returned by the backend. */\n public readonly data?: unknown;\n\n constructor(\n message: string,\n details: { status: number; code?: string; data?: unknown }\n ) {\n super(message);\n\n this.name = 'FetcherError';\n this.status = details.status;\n this.code = details.code;\n this.data = details.data;\n }\n}\n\n/**\n * Type definition for options used in the fetcher function.\n * Extends the standard RequestInit interface (excluding 'body'),\n * and adds 'body' and 'params' properties for convenience.\n */\nexport type FetcherOptions = Omit<RequestInit, 'body'> & {\n /**\n * Body of the request. Should be a key-value pair object.\n */\n body?: Record<string, unknown>;\n /**\n * Query parameters to be appended to the URL.\n */\n params?:\n | Record
|
|
1
|
+
{"version":3,"file":"fetcher.mjs","names":[],"sources":["../../src/fetcher.ts"],"sourcesContent":["import { resolveInternalBackendUrl } from './resolveInternalBackendUrl';\n\n/**\n * Error thrown when the backend answers with a non-ok response.\n *\n * Carries the HTTP status and the backend error code alongside the message, so\n * callers can tell a transient failure (5xx, network) from a deterministic one\n * (4xx) instead of blindly retrying.\n */\nexport class FetcherError extends Error {\n /** HTTP status code of the response. */\n public readonly status: number;\n /** Error code returned by the backend, when available (ex: `DICTIONARY_NOT_FOUND`). */\n public readonly code?: string;\n /** Raw error payload returned by the backend. */\n public readonly data?: unknown;\n\n constructor(\n message: string,\n details: { status: number; code?: string; data?: unknown }\n ) {\n super(message);\n\n this.name = 'FetcherError';\n this.status = details.status;\n this.code = details.code;\n this.data = details.data;\n }\n}\n\n/**\n * Type definition for options used in the fetcher function.\n * Extends the standard RequestInit interface (excluding 'body'),\n * and adds 'body' and 'params' properties for convenience.\n */\nexport type FetcherOptions = Omit<RequestInit, 'body'> & {\n /**\n * Body of the request. Should be a key-value pair object.\n */\n body?: Record<string, unknown>;\n /**\n * Query parameters to be appended to the URL.\n */\n params?:\n | Record<\n string,\n string | number | boolean | (string | number)[] | undefined\n >\n | string[]\n | URLSearchParams;\n};\n\n/**\n * Default options for the fetcher function.\n * Sets the default method to 'GET', the 'Content-Type' header to 'application/json',\n * and includes credentials in the request.\n */\nexport const fetcherOptions: FetcherOptions = {\n method: 'GET', // Default HTTP method\n headers: {\n 'Content-Type': 'application/json', // Default content type\n },\n credentials: 'include',\n};\n\n/**\n * Utility function to remove properties with undefined values from an object.\n * This helps prevent sending undefined values in the request options.\n *\n * @param obj - The object to clean.\n * @returns The cleaned object without undefined values.\n */\nconst removeUndefined = (obj: object) => {\n Object.keys(obj).forEach((key) => {\n if (obj[key as keyof typeof obj] === undefined) {\n delete obj[key as keyof typeof obj];\n }\n });\n return obj;\n};\n\n/**\n * Deeply merges an array of objects into a single object.\n * Later objects in the array overwrite properties of earlier ones.\n *\n * @template T - The type of objects being merged.\n * @param objects - An array of objects to merge.\n * @returns The merged object.\n */\nconst deepMerge = <T extends object>(objects: (T | undefined)[]): T =>\n objects.reduce((acc, obj) => {\n const acc1: T = (acc ?? {}) as T;\n const obj1: T = removeUndefined(obj ?? {}) as T;\n\n if (typeof acc1 === 'object' && typeof obj1 === 'object') {\n // Merge the two objects\n return { ...acc1, ...obj1 };\n }\n\n // If one of them is not an object, return the defined one\n return obj1 ?? acc1;\n }, {} as T)!;\n\n/**\n * Fetcher function to make HTTP requests.\n * It merges default options with user-provided options,\n * handles query parameters and request body,\n * and returns the parsed JSON response.\n *\n * @template T - The expected type of the response data.\n * @param url - The endpoint URL.\n * @param options - Additional options to customize the request.\n * @returns A promise that resolves with the response data of type T.\n *\n * @example\n * ```typescript\n * // Making a GET request with query parameters\n * const data = await fetcher<MyResponseType>('https://api.example.com/data', {\n * params: { search: 'query' },\n * });\n *\n * // Making a POST request with a JSON body\n * const result = await fetcher<AnotherResponseType>('https://api.example.com/submit', {\n * method: 'POST',\n * body: { key: 'value' },\n * });\n *\n * // Merge body, headers, and params\n * const result = await fetcher<AnotherResponseType>('https://api.example.com/submit', {\n * method: 'POST',\n * body: { key: 'value' },\n * headers: { 'Content-Type': 'application/json' },\n * params: { search: 'query' },\n * },\n * {\n * headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n * params: { page: 1 },\n * });\n * ```\n *\n * Result:\n * ```typescript\n * {\n * method: 'POST',\n * headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n * params: { page: 1, search: 'query' },\n * body: { key: 'value' },\n * }\n * ```\n */\nexport const fetcher = async <T>(\n url: string,\n ...options: FetcherOptions[]\n): Promise<T> => {\n const { signal } = new AbortController();\n\n // Initialize query parameters string and request body string\n let paramsString = '';\n let bodyString: string | undefined;\n\n // Extract other options excluding 'body', 'params', and 'headers'\n const otherOptions = options.map(\n ({ body, params, headers, ...otherOptions }) => otherOptions\n );\n\n // Merge default options with user-provided options\n const mergedOptions = deepMerge([fetcherOptions, ...otherOptions]);\n\n // Merge default headers with user-provided headers\n const mergedHeaders = deepMerge([\n fetcherOptions.headers,\n ...options.map((option) => option.headers),\n ]);\n\n // Merge query parameters\n const params = deepMerge(options.map((option) => option.params));\n\n const method = mergedOptions.method;\n\n // If the request method is not 'GET' or 'HEAD', prepare the request body\n if (method !== 'GET' && method !== 'HEAD') {\n // Merge all 'body' options\n const body = deepMerge(options.map((option) => option.body));\n if (\n mergedHeaders?.['Content-Type' as keyof HeadersInit] ===\n 'application/x-www-form-urlencoded'\n ) {\n // If the content type is 'application/x-www-form-urlencoded', encode the body accordingly\n bodyString = new URLSearchParams(\n body as Record<string, string>\n ).toString();\n } else {\n // Otherwise, stringify the body as JSON\n bodyString = JSON.stringify(body);\n }\n }\n\n // If there are query parameters, append them to the URL\n if (Object.entries(params).length > 0) {\n paramsString = `?${new URLSearchParams(\n params as Record<string, string>\n ).toString()}`;\n }\n\n // Prepare the final request options\n const formattedOptions: RequestInit = {\n ...mergedOptions,\n headers: mergedHeaders,\n body: bodyString,\n signal,\n };\n\n // Construct the full URL with query parameters. Server code inside a private\n // network may need to reach the backend under another origin — see\n // `resolveInternalBackendUrl`.\n const urlResult = resolveInternalBackendUrl(`${url}${paramsString}`);\n\n // Make the HTTP request using fetch\n const response = await fetch(urlResult, formattedOptions);\n\n if (!response.ok) {\n const result = await response.json().catch(() => undefined);\n\n // You can customize the error message or include more details\n throw new FetcherError(\n JSON.stringify(result?.error) ?? 'An error occurred',\n {\n status: response.status,\n code: result?.error?.code,\n data: result?.error,\n }\n );\n }\n return await response.json();\n};\n"],"mappings":";;;;;;;;;;AASA,IAAa,eAAb,cAAkC,MAAM;;CAEtC,AAAgB;;CAEhB,AAAgB;;CAEhB,AAAgB;CAEhB,YACE,SACA,SACA;EACA,MAAM,OAAO;EAEb,KAAK,OAAO;EACZ,KAAK,SAAS,QAAQ;EACtB,KAAK,OAAO,QAAQ;EACpB,KAAK,OAAO,QAAQ;CACtB;AACF;;;;;;AA6BA,MAAa,iBAAiC;CAC5C,QAAQ;CACR,SAAS,EACP,gBAAgB,mBAClB;CACA,aAAa;AACf;;;;;;;;AASA,MAAM,mBAAmB,QAAgB;CACvC,OAAO,KAAK,GAAG,CAAC,CAAC,SAAS,QAAQ;EAChC,IAAI,IAAI,SAA6B,QACnC,OAAO,IAAI;CAEf,CAAC;CACD,OAAO;AACT;;;;;;;;;AAUA,MAAM,aAA+B,YACnC,QAAQ,QAAQ,KAAK,QAAQ;CAC3B,MAAM,OAAW,OAAO,CAAC;CACzB,MAAM,OAAU,gBAAgB,OAAO,CAAC,CAAC;CAEzC,IAAI,OAAO,SAAS,YAAY,OAAO,SAAS,UAE9C,OAAO;EAAE,GAAG;EAAM,GAAG;CAAK;CAI5B,OAAO,QAAQ;AACjB,GAAG,CAAC,CAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiDZ,MAAa,UAAU,OACrB,KACA,GAAG,YACY;CACf,MAAM,EAAE,WAAW,IAAI,gBAAgB;CAGvC,IAAI,eAAe;CACnB,IAAI;CAGJ,MAAM,eAAe,QAAQ,KAC1B,EAAE,MAAM,QAAQ,SAAS,GAAG,mBAAmB,YAClD;CAGA,MAAM,gBAAgB,UAAU,CAAC,gBAAgB,GAAG,YAAY,CAAC;CAGjE,MAAM,gBAAgB,UAAU,CAC9B,eAAe,SACf,GAAG,QAAQ,KAAK,WAAW,OAAO,OAAO,CAC3C,CAAC;CAGD,MAAM,SAAS,UAAU,QAAQ,KAAK,WAAW,OAAO,MAAM,CAAC;CAE/D,MAAM,SAAS,cAAc;CAG7B,IAAI,WAAW,SAAS,WAAW,QAAQ;EAEzC,MAAM,OAAO,UAAU,QAAQ,KAAK,WAAW,OAAO,IAAI,CAAC;EAC3D,IACE,gBAAgB,oBAChB,qCAGA,aAAa,IAAI,gBACf,IACF,CAAC,CAAC,SAAS;OAGX,aAAa,KAAK,UAAU,IAAI;CAEpC;CAGA,IAAI,OAAO,QAAQ,MAAM,CAAC,CAAC,SAAS,GAClC,eAAe,IAAI,IAAI,gBACrB,MACF,CAAC,CAAC,SAAS;CAIb,MAAM,mBAAgC;EACpC,GAAG;EACH,SAAS;EACT,MAAM;EACN;CACF;CAKA,MAAM,YAAY,0BAA0B,GAAG,MAAM,cAAc;CAGnE,MAAM,WAAW,MAAM,MAAM,WAAW,gBAAgB;CAExD,IAAI,CAAC,SAAS,IAAI;EAChB,MAAM,SAAS,MAAM,SAAS,KAAK,CAAC,CAAC,YAAY,MAAS;EAG1D,MAAM,IAAI,aACR,KAAK,UAAU,QAAQ,KAAK,KAAK,qBACjC;GACE,QAAQ,SAAS;GACjB,MAAM,QAAQ,OAAO;GACrB,MAAM,QAAQ;EAChB,CACF;CACF;CACA,OAAO,MAAM,SAAS,KAAK;AAC7B"}
|