@intlayer/api 8.9.6-canary.0 → 8.9.7

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.
@@ -28,7 +28,7 @@ const getIntlayerAPI = (authAPIOptions = {}, intlayerConfig = _intlayer_config_b
28
28
  organization: require_getIntlayerAPI_organization.getOrganizationAPI(authAPIOptions, resolvedConfig),
29
29
  project: require_getIntlayerAPI_project.getProjectAPI(authAPIOptions, resolvedConfig),
30
30
  user: require_getIntlayerAPI_user.getUserAPI(authAPIOptions, resolvedConfig),
31
- oAuth: require_getIntlayerAPI_oAuth.getOAuthAPI(resolvedConfig),
31
+ oAuth: require_getIntlayerAPI_oAuth.getOAuthAPI(authAPIOptions, resolvedConfig),
32
32
  dictionary: require_getIntlayerAPI_dictionary.getDictionaryAPI(authAPIOptions, resolvedConfig),
33
33
  stripe: require_getIntlayerAPI_stripe.getStripeAPI(authAPIOptions, resolvedConfig),
34
34
  ai: require_getIntlayerAPI_ai.getAiAPI(authAPIOptions, resolvedConfig),
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["config","getOrganizationAPI","getProjectAPI","getUserAPI","getOAuthAPI","getDictionaryAPI","getStripeAPI","getAiAPI","getAuditAPI","getTagAPI","getSearchAPI","getEditorAPI","getNewsletterAPI","getGithubAPI","getGitlabAPI","getBitbucketAPI","getShowcaseProjectAPI","getTranslateAPI"],"sources":["../../../src/getIntlayerAPI/index.ts"],"sourcesContent":["import config from '@intlayer/config/built';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { defu } from 'defu';\nimport type { FetcherOptions } from '../fetcher';\nimport { getAiAPI } from './ai';\nimport { getAuditAPI } from './audit';\nimport { getBitbucketAPI } from './bitbucket';\nimport { getDictionaryAPI } from './dictionary';\nimport { getEditorAPI } from './editor';\nimport { getGithubAPI } from './github';\nimport { getGitlabAPI } from './gitlab';\nimport { getNewsletterAPI } from './newsletter';\nimport { getOAuthAPI } from './oAuth';\nimport { getOrganizationAPI } from './organization';\nimport { getProjectAPI } from './project';\nimport { getSearchAPI } from './search';\nimport { getShowcaseProjectAPI } from './showcaseProject';\nimport { getStripeAPI } from './stripe';\nimport { getTagAPI } from './tag';\nimport { getTranslateAPI } from './translate';\nimport { getUserAPI } from './user';\n\ninterface IntlayerAPIReturn {\n organization: ReturnType<typeof getOrganizationAPI>;\n project: ReturnType<typeof getProjectAPI>;\n user: ReturnType<typeof getUserAPI>;\n oAuth: ReturnType<typeof getOAuthAPI>;\n dictionary: ReturnType<typeof getDictionaryAPI>;\n stripe: ReturnType<typeof getStripeAPI>;\n ai: ReturnType<typeof getAiAPI>;\n audit: ReturnType<typeof getAuditAPI>;\n tag: ReturnType<typeof getTagAPI>;\n search: ReturnType<typeof getSearchAPI>;\n editor: ReturnType<typeof getEditorAPI>;\n newsletter: ReturnType<typeof getNewsletterAPI>;\n github: ReturnType<typeof getGithubAPI>;\n gitlab: ReturnType<typeof getGitlabAPI>;\n bitbucket: ReturnType<typeof getBitbucketAPI>;\n showcaseProject: ReturnType<typeof getShowcaseProjectAPI>;\n translate: ReturnType<typeof getTranslateAPI>;\n}\n\nexport const getIntlayerAPI = (\n authAPIOptions: FetcherOptions = {},\n intlayerConfig: IntlayerConfig = config\n): IntlayerAPIReturn => {\n const resolvedConfig = defu(intlayerConfig ?? {}, config) as IntlayerConfig;\n\n return {\n organization: getOrganizationAPI(authAPIOptions, resolvedConfig),\n project: getProjectAPI(authAPIOptions, resolvedConfig),\n user: getUserAPI(authAPIOptions, resolvedConfig),\n oAuth: getOAuthAPI(resolvedConfig),\n dictionary: getDictionaryAPI(authAPIOptions, resolvedConfig),\n stripe: getStripeAPI(authAPIOptions, resolvedConfig),\n ai: getAiAPI(authAPIOptions, resolvedConfig),\n audit: getAuditAPI(authAPIOptions, resolvedConfig),\n tag: getTagAPI(authAPIOptions, resolvedConfig),\n search: getSearchAPI(authAPIOptions, resolvedConfig),\n editor: getEditorAPI(authAPIOptions, resolvedConfig),\n newsletter: getNewsletterAPI(authAPIOptions, resolvedConfig),\n github: getGithubAPI(authAPIOptions, resolvedConfig),\n gitlab: getGitlabAPI(authAPIOptions, resolvedConfig),\n bitbucket: getBitbucketAPI(authAPIOptions, resolvedConfig),\n showcaseProject: getShowcaseProjectAPI(authAPIOptions, resolvedConfig),\n translate: getTranslateAPI(authAPIOptions, resolvedConfig),\n };\n};\n\nexport type IntlayerAPI = ReturnType<typeof getIntlayerAPI>;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA0CA,MAAa,kBACX,iBAAiC,EAAE,EACnC,iBAAiCA,mCACX;CACtB,MAAM,gCAAsB,kBAAkB,EAAE,EAAEA,+BAAO;CAEzD,OAAO;EACL,cAAcC,uDAAmB,gBAAgB,eAAe;EAChE,SAASC,6CAAc,gBAAgB,eAAe;EACtD,MAAMC,uCAAW,gBAAgB,eAAe;EAChD,OAAOC,yCAAY,eAAe;EAClC,YAAYC,mDAAiB,gBAAgB,eAAe;EAC5D,QAAQC,2CAAa,gBAAgB,eAAe;EACpD,IAAIC,mCAAS,gBAAgB,eAAe;EAC5C,OAAOC,yCAAY,gBAAgB,eAAe;EAClD,KAAKC,qCAAU,gBAAgB,eAAe;EAC9C,QAAQC,2CAAa,gBAAgB,eAAe;EACpD,QAAQC,2CAAa,gBAAgB,eAAe;EACpD,YAAYC,mDAAiB,gBAAgB,eAAe;EAC5D,QAAQC,2CAAa,gBAAgB,eAAe;EACpD,QAAQC,2CAAa,gBAAgB,eAAe;EACpD,WAAWC,iDAAgB,gBAAgB,eAAe;EAC1D,iBAAiBC,6DAAsB,gBAAgB,eAAe;EACtE,WAAWC,iDAAgB,gBAAgB,eAAe;EAC3D"}
1
+ {"version":3,"file":"index.cjs","names":["config","getOrganizationAPI","getProjectAPI","getUserAPI","getOAuthAPI","getDictionaryAPI","getStripeAPI","getAiAPI","getAuditAPI","getTagAPI","getSearchAPI","getEditorAPI","getNewsletterAPI","getGithubAPI","getGitlabAPI","getBitbucketAPI","getShowcaseProjectAPI","getTranslateAPI"],"sources":["../../../src/getIntlayerAPI/index.ts"],"sourcesContent":["import config from '@intlayer/config/built';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { defu } from 'defu';\nimport type { FetcherOptions } from '../fetcher';\nimport { getAiAPI } from './ai';\nimport { getAuditAPI } from './audit';\nimport { getBitbucketAPI } from './bitbucket';\nimport { getDictionaryAPI } from './dictionary';\nimport { getEditorAPI } from './editor';\nimport { getGithubAPI } from './github';\nimport { getGitlabAPI } from './gitlab';\nimport { getNewsletterAPI } from './newsletter';\nimport { getOAuthAPI } from './oAuth';\nimport { getOrganizationAPI } from './organization';\nimport { getProjectAPI } from './project';\nimport { getSearchAPI } from './search';\nimport { getShowcaseProjectAPI } from './showcaseProject';\nimport { getStripeAPI } from './stripe';\nimport { getTagAPI } from './tag';\nimport { getTranslateAPI } from './translate';\nimport { getUserAPI } from './user';\n\ninterface IntlayerAPIReturn {\n organization: ReturnType<typeof getOrganizationAPI>;\n project: ReturnType<typeof getProjectAPI>;\n user: ReturnType<typeof getUserAPI>;\n oAuth: ReturnType<typeof getOAuthAPI>;\n dictionary: ReturnType<typeof getDictionaryAPI>;\n stripe: ReturnType<typeof getStripeAPI>;\n ai: ReturnType<typeof getAiAPI>;\n audit: ReturnType<typeof getAuditAPI>;\n tag: ReturnType<typeof getTagAPI>;\n search: ReturnType<typeof getSearchAPI>;\n editor: ReturnType<typeof getEditorAPI>;\n newsletter: ReturnType<typeof getNewsletterAPI>;\n github: ReturnType<typeof getGithubAPI>;\n gitlab: ReturnType<typeof getGitlabAPI>;\n bitbucket: ReturnType<typeof getBitbucketAPI>;\n showcaseProject: ReturnType<typeof getShowcaseProjectAPI>;\n translate: ReturnType<typeof getTranslateAPI>;\n}\n\nexport const getIntlayerAPI = (\n authAPIOptions: FetcherOptions = {},\n intlayerConfig: IntlayerConfig = config\n): IntlayerAPIReturn => {\n const resolvedConfig = defu(intlayerConfig ?? {}, config) as IntlayerConfig;\n\n return {\n organization: getOrganizationAPI(authAPIOptions, resolvedConfig),\n project: getProjectAPI(authAPIOptions, resolvedConfig),\n user: getUserAPI(authAPIOptions, resolvedConfig),\n oAuth: getOAuthAPI(authAPIOptions, resolvedConfig),\n dictionary: getDictionaryAPI(authAPIOptions, resolvedConfig),\n stripe: getStripeAPI(authAPIOptions, resolvedConfig),\n ai: getAiAPI(authAPIOptions, resolvedConfig),\n audit: getAuditAPI(authAPIOptions, resolvedConfig),\n tag: getTagAPI(authAPIOptions, resolvedConfig),\n search: getSearchAPI(authAPIOptions, resolvedConfig),\n editor: getEditorAPI(authAPIOptions, resolvedConfig),\n newsletter: getNewsletterAPI(authAPIOptions, resolvedConfig),\n github: getGithubAPI(authAPIOptions, resolvedConfig),\n gitlab: getGitlabAPI(authAPIOptions, resolvedConfig),\n bitbucket: getBitbucketAPI(authAPIOptions, resolvedConfig),\n showcaseProject: getShowcaseProjectAPI(authAPIOptions, resolvedConfig),\n translate: getTranslateAPI(authAPIOptions, resolvedConfig),\n };\n};\n\nexport type IntlayerAPI = ReturnType<typeof getIntlayerAPI>;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA0CA,MAAa,kBACX,iBAAiC,EAAE,EACnC,iBAAiCA,mCACX;CACtB,MAAM,gCAAsB,kBAAkB,EAAE,EAAEA,+BAAO;CAEzD,OAAO;EACL,cAAcC,uDAAmB,gBAAgB,eAAe;EAChE,SAASC,6CAAc,gBAAgB,eAAe;EACtD,MAAMC,uCAAW,gBAAgB,eAAe;EAChD,OAAOC,yCAAY,gBAAgB,eAAe;EAClD,YAAYC,mDAAiB,gBAAgB,eAAe;EAC5D,QAAQC,2CAAa,gBAAgB,eAAe;EACpD,IAAIC,mCAAS,gBAAgB,eAAe;EAC5C,OAAOC,yCAAY,gBAAgB,eAAe;EAClD,KAAKC,qCAAU,gBAAgB,eAAe;EAC9C,QAAQC,2CAAa,gBAAgB,eAAe;EACpD,QAAQC,2CAAa,gBAAgB,eAAe;EACpD,YAAYC,mDAAiB,gBAAgB,eAAe;EAC5D,QAAQC,2CAAa,gBAAgB,eAAe;EACpD,QAAQC,2CAAa,gBAAgB,eAAe;EACpD,WAAWC,iDAAgB,gBAAgB,eAAe;EAC1D,iBAAiBC,6DAAsB,gBAAgB,eAAe;EACtE,WAAWC,iDAAgB,gBAAgB,eAAe;EAC3D"}
@@ -5,12 +5,11 @@ let _intlayer_config_built = require("@intlayer/config/built");
5
5
  _intlayer_config_built = require_runtime.__toESM(_intlayer_config_built);
6
6
 
7
7
  //#region src/getIntlayerAPI/oAuth.ts
8
- const getOAuthAPI = (intlayerConfig = _intlayer_config_built.default) => {
8
+ const getOAuthAPI = (authAPIOptions = {}, intlayerConfig = _intlayer_config_built.default) => {
9
9
  const backendURL = intlayerConfig.editor.backendURL;
10
10
  const { clientId, clientSecret } = intlayerConfig.editor;
11
11
  /**
12
- * Gets an oAuth2 accessToken
13
- * @return The token information
12
+ * Gets an oAuth2 accessToken via client_credentials grant
14
13
  */
15
14
  const getOAuth2AccessToken = async (otherOptions = {}) => await require_fetcher.fetcher(`${backendURL}/oauth2/token`, {}, otherOptions, {
16
15
  method: "POST",
@@ -21,7 +20,21 @@ const getOAuthAPI = (intlayerConfig = _intlayer_config_built.default) => {
21
20
  client_secret: clientSecret
22
21
  }
23
22
  });
24
- return { getOAuth2AccessToken };
23
+ /**
24
+ * Creates a short-lived (2h) CLI session token for the authenticated user.
25
+ * Requires a valid browser session cookie.
26
+ */
27
+ const createCliSessionToken = async (otherOptions = {}) => await require_fetcher.fetcher(`${backendURL}/api/cli-session`, authAPIOptions, otherOptions, { method: "POST" });
28
+ /**
29
+ * Verifies a CLI session token and returns the associated project context.
30
+ * Useful for checking config consistency in the CLI.
31
+ */
32
+ const getCliSessionMe = async (otherOptions = {}) => await require_fetcher.fetcher(`${backendURL}/api/cli-session/me`, authAPIOptions, otherOptions);
33
+ return {
34
+ getOAuth2AccessToken,
35
+ createCliSessionToken,
36
+ getCliSessionMe
37
+ };
25
38
  };
26
39
 
27
40
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"oAuth.cjs","names":["config","fetcher"],"sources":["../../../src/getIntlayerAPI/oAuth.ts"],"sourcesContent":["import type {\n GetOAuth2TokenBody,\n GetOAuth2TokenResult,\n} from '@intlayer/backend';\nimport config from '@intlayer/config/built';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { type FetcherOptions, fetcher } from '../fetcher';\n\nexport const getOAuthAPI = (intlayerConfig: IntlayerConfig = config) => {\n const backendURL = intlayerConfig.editor.backendURL;\n const { clientId, clientSecret } = intlayerConfig.editor;\n\n /**\n * Gets an oAuth2 accessToken\n * @return The token information\n */\n const getOAuth2AccessToken = async (otherOptions: FetcherOptions = {}) =>\n await fetcher<GetOAuth2TokenResult>(\n `${backendURL}/oauth2/token`,\n {},\n otherOptions,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: {\n grant_type: 'client_credentials',\n client_id: clientId!,\n client_secret: clientSecret!,\n } satisfies GetOAuth2TokenBody,\n }\n );\n\n return {\n getOAuth2AccessToken,\n };\n};\n"],"mappings":";;;;;;;AAQA,MAAa,eAAe,iBAAiCA,mCAAW;CACtE,MAAM,aAAa,eAAe,OAAO;CACzC,MAAM,EAAE,UAAU,iBAAiB,eAAe;;;;;CAMlD,MAAM,uBAAuB,OAAO,eAA+B,EAAE,KACnE,MAAMC,wBACJ,GAAG,WAAW,gBACd,EAAE,EACF,cACA;EACE,QAAQ;EACR,SAAS,EACP,gBAAgB,qCACjB;EACD,MAAM;GACJ,YAAY;GACZ,WAAW;GACX,eAAe;GAChB;EACF,CACF;CAEH,OAAO,EACL,sBACD"}
1
+ {"version":3,"file":"oAuth.cjs","names":["config","fetcher"],"sources":["../../../src/getIntlayerAPI/oAuth.ts"],"sourcesContent":["import type {\n CreateCliSessionTokenResult,\n GetCliSessionMeResult,\n GetOAuth2TokenBody,\n GetOAuth2TokenResult,\n} from '@intlayer/backend';\nimport config from '@intlayer/config/built';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { type FetcherOptions, fetcher } from '../fetcher';\n\nexport const getOAuthAPI = (\n authAPIOptions: FetcherOptions = {},\n intlayerConfig: IntlayerConfig = config\n) => {\n const backendURL = intlayerConfig.editor.backendURL;\n const { clientId, clientSecret } = intlayerConfig.editor;\n\n /**\n * Gets an oAuth2 accessToken via client_credentials grant\n */\n const getOAuth2AccessToken = async (otherOptions: FetcherOptions = {}) =>\n await fetcher<GetOAuth2TokenResult>(\n `${backendURL}/oauth2/token`,\n {},\n otherOptions,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: {\n grant_type: 'client_credentials',\n client_id: clientId!,\n client_secret: clientSecret!,\n } satisfies GetOAuth2TokenBody,\n }\n );\n\n /**\n * Creates a short-lived (2h) CLI session token for the authenticated user.\n * Requires a valid browser session cookie.\n */\n const createCliSessionToken = async (otherOptions: FetcherOptions = {}) =>\n await fetcher<CreateCliSessionTokenResult>(\n `${backendURL}/api/cli-session`,\n authAPIOptions,\n otherOptions,\n { method: 'POST' }\n );\n\n /**\n * Verifies a CLI session token and returns the associated project context.\n * Useful for checking config consistency in the CLI.\n */\n const getCliSessionMe = async (otherOptions: FetcherOptions = {}) =>\n await fetcher<GetCliSessionMeResult>(\n `${backendURL}/api/cli-session/me`,\n authAPIOptions,\n otherOptions\n );\n\n return {\n getOAuth2AccessToken,\n createCliSessionToken,\n getCliSessionMe,\n };\n};\n"],"mappings":";;;;;;;AAUA,MAAa,eACX,iBAAiC,EAAE,EACnC,iBAAiCA,mCAC9B;CACH,MAAM,aAAa,eAAe,OAAO;CACzC,MAAM,EAAE,UAAU,iBAAiB,eAAe;;;;CAKlD,MAAM,uBAAuB,OAAO,eAA+B,EAAE,KACnE,MAAMC,wBACJ,GAAG,WAAW,gBACd,EAAE,EACF,cACA;EACE,QAAQ;EACR,SAAS,EACP,gBAAgB,qCACjB;EACD,MAAM;GACJ,YAAY;GACZ,WAAW;GACX,eAAe;GAChB;EACF,CACF;;;;;CAMH,MAAM,wBAAwB,OAAO,eAA+B,EAAE,KACpE,MAAMA,wBACJ,GAAG,WAAW,mBACd,gBACA,cACA,EAAE,QAAQ,QAAQ,CACnB;;;;;CAMH,MAAM,kBAAkB,OAAO,eAA+B,EAAE,KAC9D,MAAMA,wBACJ,GAAG,WAAW,sBACd,gBACA,aACD;CAEH,OAAO;EACL;EACA;EACA;EACD"}
@@ -26,11 +26,22 @@ let pendingRefresh;
26
26
  * - Injects Authorization header for each request
27
27
  * - Refreshes token proactively when near expiry
28
28
  *
29
+ * When `sessionToken` is provided (a CLI session token starting with
30
+ * "clisession_"), it is used directly as the Bearer token without any OAuth2
31
+ * exchange — the backend validates it against the CliSessionToken collection.
32
+ *
29
33
  * The returned API matches the shape of getIntlayerAPI.
30
34
  */
31
- const getIntlayerAPIProxy = (baseAuthOptions = {}, intlayerConfig) => {
32
- const authOptionsRef = { ...baseAuthOptions };
33
- const hasCMSAuth = intlayerConfig?.editor?.clientId && intlayerConfig?.editor?.clientSecret;
35
+ const getIntlayerAPIProxy = (baseAuthOptions = {}, intlayerConfig, sessionToken) => {
36
+ const authOptionsRef = {
37
+ ...baseAuthOptions,
38
+ credentials: "omit"
39
+ };
40
+ const hasCMSAuth = Boolean(sessionToken) || Boolean(intlayerConfig?.editor?.clientId && intlayerConfig?.editor?.clientSecret);
41
+ if (sessionToken) authOptionsRef.headers = {
42
+ ...authOptionsRef.headers ?? {},
43
+ Authorization: `Bearer ${sessionToken}`
44
+ };
34
45
  const baseApi = require_getIntlayerAPI_index.getIntlayerAPI(authOptionsRef, intlayerConfig);
35
46
  const needsRefresh = () => {
36
47
  if (!currentAccessToken) return true;
@@ -39,7 +50,7 @@ const getIntlayerAPIProxy = (baseAuthOptions = {}, intlayerConfig) => {
39
50
  };
40
51
  const refreshToken = async () => {
41
52
  const doRefresh = async () => {
42
- const tokenData = (await require_getIntlayerAPI_oAuth.getOAuthAPI(intlayerConfig).getOAuth2AccessToken())?.data;
53
+ const tokenData = (await require_getIntlayerAPI_oAuth.getOAuthAPI({}, intlayerConfig).getOAuth2AccessToken())?.data;
43
54
  currentAccessToken = tokenData?.accessToken;
44
55
  currentExpiryTs = getExpiryTimestamp(tokenData);
45
56
  };
@@ -62,14 +73,14 @@ const getIntlayerAPIProxy = (baseAuthOptions = {}, intlayerConfig) => {
62
73
  return new Proxy(section, { get(target, prop, receiver) {
63
74
  const value = Reflect.get(target, prop, receiver);
64
75
  if (typeof value === "function") return async (...args) => {
65
- if (!skipAuth) {
76
+ if (!skipAuth) if (sessionToken) {} else {
66
77
  await ensureValidToken();
67
78
  applyAuthHeaderToRef();
68
79
  }
69
80
  try {
70
81
  return await value.apply(target, args);
71
82
  } catch (err) {
72
- if (!skipAuth) {
83
+ if (!skipAuth && !sessionToken) {
73
84
  await refreshToken();
74
85
  applyAuthHeaderToRef();
75
86
  return await value.apply(target, args);
@@ -1 +1 @@
1
- {"version":3,"file":"proxy.cjs","names":["getIntlayerAPI","getOAuthAPI"],"sources":["../../src/proxy.ts"],"sourcesContent":["import type { IntlayerConfig } from '@intlayer/types/config';\nimport type { FetcherOptions } from './fetcher';\nimport { getIntlayerAPI } from './getIntlayerAPI';\nimport type { IntlayerAPI } from './getIntlayerAPI/index';\nimport { getOAuthAPI } from './getIntlayerAPI/oAuth';\n\ntype OAuthTokenLike = {\n accessToken?: string;\n accessTokenExpiresAt?: string | Date;\n expires_in?: number;\n expiresIn?: number;\n expiresAt?: string | Date;\n};\n\nconst ONE_MINUTE_MS = 60_000;\n\n/**\n * Returns the expiration timestamp in ms from an OAuth token-like object.\n */\nconst getExpiryTimestamp = (\n token: OAuthTokenLike | undefined\n): number | undefined => {\n if (!token) return undefined;\n const dateLike = (token.accessTokenExpiresAt ?? token.expiresAt) as\n | string\n | Date\n | undefined;\n if (dateLike) {\n const ts =\n typeof dateLike === 'string'\n ? Date.parse(dateLike)\n : dateLike.getTime?.();\n if (typeof ts === 'number' && Number.isFinite(ts)) return ts;\n }\n const seconds = token.expires_in ?? token.expiresIn;\n if (typeof seconds === 'number' && Number.isFinite(seconds)) {\n return Date.now() + seconds * 1000;\n }\n return undefined;\n};\n\nlet currentAccessToken: string | undefined;\nlet currentExpiryTs: number | undefined;\nlet pendingRefresh: Promise<void> | undefined;\n\n/**\n * Build an auto-auth proxy around getIntlayerAPI that:\n * - Fetches an OAuth2 token when needed\n * - Injects Authorization header for each request\n * - Refreshes token proactively when near expiry\n *\n * The returned API matches the shape of getIntlayerAPI.\n */\nexport const getIntlayerAPIProxy = (\n baseAuthOptions: FetcherOptions = {},\n intlayerConfig?: IntlayerConfig\n): IntlayerAPI => {\n // Use a shared mutable auth options object captured by the API closures\n const authOptionsRef: FetcherOptions = { ...baseAuthOptions };\n const hasCMSAuth =\n intlayerConfig?.editor?.clientId && intlayerConfig?.editor?.clientSecret;\n const baseApi = getIntlayerAPI(authOptionsRef, intlayerConfig);\n\n const needsRefresh = (): boolean => {\n if (!currentAccessToken) return true;\n if (!currentExpiryTs) return false; // If unknown, assume usable until failure\n\n return Date.now() + ONE_MINUTE_MS >= currentExpiryTs; // refresh 1 min before expiry\n };\n\n const refreshToken = async (): Promise<void> => {\n const doRefresh = async () => {\n const authApi = getOAuthAPI(intlayerConfig);\n const res = await authApi.getOAuth2AccessToken();\n const tokenData = res?.data as OAuthTokenLike | undefined;\n\n currentAccessToken = tokenData?.accessToken;\n currentExpiryTs = getExpiryTimestamp(tokenData);\n };\n\n if (!pendingRefresh) {\n pendingRefresh = doRefresh().finally(() => {\n pendingRefresh = undefined;\n });\n }\n await pendingRefresh;\n };\n\n const ensureValidToken = async () => {\n if (needsRefresh()) {\n await refreshToken();\n }\n };\n\n const applyAuthHeaderToRef = () => {\n if (!currentAccessToken) return;\n authOptionsRef.headers = {\n ...(authOptionsRef.headers ?? {}),\n Authorization: `Bearer ${currentAccessToken}`,\n } as HeadersInit;\n };\n\n const wrapSection = <T extends Record<string, unknown>>(\n section: T,\n skipAuth = !hasCMSAuth\n ): T => {\n return new Proxy(section, {\n get(target, prop, receiver) {\n const value = Reflect.get(target, prop, receiver);\n\n if (typeof value === 'function') {\n // Wrap section method to inject token and headers\n return async (...args: unknown[]) => {\n if (!skipAuth) {\n await ensureValidToken();\n applyAuthHeaderToRef();\n }\n\n try {\n return await value.apply(target, args);\n } catch (err) {\n // Best-effort retry: if token might be stale, refresh once and retry\n if (!skipAuth) {\n await refreshToken();\n applyAuthHeaderToRef();\n return await value.apply(target, args);\n }\n throw err;\n }\n };\n }\n\n return value;\n },\n });\n };\n\n return {\n organization: wrapSection(baseApi.organization),\n project: wrapSection(baseApi.project),\n user: wrapSection(baseApi.user),\n oAuth: wrapSection(baseApi.oAuth, true), // do NOT inject auth for token endpoint\n dictionary: wrapSection(baseApi.dictionary),\n stripe: wrapSection(baseApi.stripe),\n ai: wrapSection(baseApi.ai),\n tag: wrapSection(baseApi.tag),\n search: wrapSection(baseApi.search),\n editor: wrapSection(baseApi.editor),\n newsletter: wrapSection(baseApi.newsletter),\n github: wrapSection(baseApi.github),\n } as IntlayerAPI;\n};\n\nexport type IntlayerAPIProxy = ReturnType<typeof getIntlayerAPIProxy>;\n"],"mappings":";;;;;AAcA,MAAM,gBAAgB;;;;AAKtB,MAAM,sBACJ,UACuB;CACvB,IAAI,CAAC,OAAO,OAAO;CACnB,MAAM,WAAY,MAAM,wBAAwB,MAAM;CAItD,IAAI,UAAU;EACZ,MAAM,KACJ,OAAO,aAAa,WAChB,KAAK,MAAM,SAAS,GACpB,SAAS,WAAW;EAC1B,IAAI,OAAO,OAAO,YAAY,OAAO,SAAS,GAAG,EAAE,OAAO;;CAE5D,MAAM,UAAU,MAAM,cAAc,MAAM;CAC1C,IAAI,OAAO,YAAY,YAAY,OAAO,SAAS,QAAQ,EACzD,OAAO,KAAK,KAAK,GAAG,UAAU;;AAKlC,IAAI;AACJ,IAAI;AACJ,IAAI;;;;;;;;;AAUJ,MAAa,uBACX,kBAAkC,EAAE,EACpC,mBACgB;CAEhB,MAAM,iBAAiC,EAAE,GAAG,iBAAiB;CAC7D,MAAM,aACJ,gBAAgB,QAAQ,YAAY,gBAAgB,QAAQ;CAC9D,MAAM,UAAUA,4CAAe,gBAAgB,eAAe;CAE9D,MAAM,qBAA8B;EAClC,IAAI,CAAC,oBAAoB,OAAO;EAChC,IAAI,CAAC,iBAAiB,OAAO;EAE7B,OAAO,KAAK,KAAK,GAAG,iBAAiB;;CAGvC,MAAM,eAAe,YAA2B;EAC9C,MAAM,YAAY,YAAY;GAG5B,MAAM,aAAY,MAFFC,yCAAY,eACH,CAAC,sBAAsB,GACzB;GAEvB,qBAAqB,WAAW;GAChC,kBAAkB,mBAAmB,UAAU;;EAGjD,IAAI,CAAC,gBACH,iBAAiB,WAAW,CAAC,cAAc;GACzC,iBAAiB;IACjB;EAEJ,MAAM;;CAGR,MAAM,mBAAmB,YAAY;EACnC,IAAI,cAAc,EAChB,MAAM,cAAc;;CAIxB,MAAM,6BAA6B;EACjC,IAAI,CAAC,oBAAoB;EACzB,eAAe,UAAU;GACvB,GAAI,eAAe,WAAW,EAAE;GAChC,eAAe,UAAU;GAC1B;;CAGH,MAAM,eACJ,SACA,WAAW,CAAC,eACN;EACN,OAAO,IAAI,MAAM,SAAS,EACxB,IAAI,QAAQ,MAAM,UAAU;GAC1B,MAAM,QAAQ,QAAQ,IAAI,QAAQ,MAAM,SAAS;GAEjD,IAAI,OAAO,UAAU,YAEnB,OAAO,OAAO,GAAG,SAAoB;IACnC,IAAI,CAAC,UAAU;KACb,MAAM,kBAAkB;KACxB,sBAAsB;;IAGxB,IAAI;KACF,OAAO,MAAM,MAAM,MAAM,QAAQ,KAAK;aAC/B,KAAK;KAEZ,IAAI,CAAC,UAAU;MACb,MAAM,cAAc;MACpB,sBAAsB;MACtB,OAAO,MAAM,MAAM,MAAM,QAAQ,KAAK;;KAExC,MAAM;;;GAKZ,OAAO;KAEV,CAAC;;CAGJ,OAAO;EACL,cAAc,YAAY,QAAQ,aAAa;EAC/C,SAAS,YAAY,QAAQ,QAAQ;EACrC,MAAM,YAAY,QAAQ,KAAK;EAC/B,OAAO,YAAY,QAAQ,OAAO,KAAK;EACvC,YAAY,YAAY,QAAQ,WAAW;EAC3C,QAAQ,YAAY,QAAQ,OAAO;EACnC,IAAI,YAAY,QAAQ,GAAG;EAC3B,KAAK,YAAY,QAAQ,IAAI;EAC7B,QAAQ,YAAY,QAAQ,OAAO;EACnC,QAAQ,YAAY,QAAQ,OAAO;EACnC,YAAY,YAAY,QAAQ,WAAW;EAC3C,QAAQ,YAAY,QAAQ,OAAO;EACpC"}
1
+ {"version":3,"file":"proxy.cjs","names":["getIntlayerAPI","getOAuthAPI"],"sources":["../../src/proxy.ts"],"sourcesContent":["import type { IntlayerConfig } from '@intlayer/types/config';\nimport type { FetcherOptions } from './fetcher';\nimport { getIntlayerAPI } from './getIntlayerAPI';\nimport type { IntlayerAPI } from './getIntlayerAPI/index';\nimport { getOAuthAPI } from './getIntlayerAPI/oAuth';\n\ntype OAuthTokenLike = {\n accessToken?: string;\n accessTokenExpiresAt?: string | Date;\n expires_in?: number;\n expiresIn?: number;\n expiresAt?: string | Date;\n};\n\nconst ONE_MINUTE_MS = 60_000;\n\n/**\n * Returns the expiration timestamp in ms from an OAuth token-like object.\n */\nconst getExpiryTimestamp = (\n token: OAuthTokenLike | undefined\n): number | undefined => {\n if (!token) return undefined;\n const dateLike = (token.accessTokenExpiresAt ?? token.expiresAt) as\n | string\n | Date\n | undefined;\n if (dateLike) {\n const ts =\n typeof dateLike === 'string'\n ? Date.parse(dateLike)\n : dateLike.getTime?.();\n if (typeof ts === 'number' && Number.isFinite(ts)) return ts;\n }\n const seconds = token.expires_in ?? token.expiresIn;\n if (typeof seconds === 'number' && Number.isFinite(seconds)) {\n return Date.now() + seconds * 1000;\n }\n return undefined;\n};\n\nlet currentAccessToken: string | undefined;\nlet currentExpiryTs: number | undefined;\nlet pendingRefresh: Promise<void> | undefined;\n\n/**\n * Build an auto-auth proxy around getIntlayerAPI that:\n * - Fetches an OAuth2 token when needed\n * - Injects Authorization header for each request\n * - Refreshes token proactively when near expiry\n *\n * When `sessionToken` is provided (a CLI session token starting with\n * \"clisession_\"), it is used directly as the Bearer token without any OAuth2\n * exchange — the backend validates it against the CliSessionToken collection.\n *\n * The returned API matches the shape of getIntlayerAPI.\n */\nexport const getIntlayerAPIProxy = (\n baseAuthOptions: FetcherOptions = {},\n intlayerConfig?: IntlayerConfig,\n sessionToken?: string\n): IntlayerAPI => {\n // Use a shared mutable auth options object captured by the API closures.\n // credentials: 'omit' prevents the browser from attaching session cookies to\n // these requests; authentication is handled exclusively via the Bearer token\n // injected below. This is required because the backend only sets\n // Access-Control-Allow-Credentials: true for whitelisted first-party origins.\n const authOptionsRef: FetcherOptions = {\n ...baseAuthOptions,\n credentials: 'omit',\n };\n const hasCMSAuth =\n Boolean(sessionToken) ||\n Boolean(\n intlayerConfig?.editor?.clientId && intlayerConfig?.editor?.clientSecret\n );\n\n // When a CLI session token is provided, inject it immediately and skip the\n // OAuth2 client_credentials exchange entirely.\n if (sessionToken) {\n authOptionsRef.headers = {\n ...(authOptionsRef.headers ?? {}),\n Authorization: `Bearer ${sessionToken}`,\n } as HeadersInit;\n }\n\n const baseApi = getIntlayerAPI(authOptionsRef, intlayerConfig);\n\n const needsRefresh = (): boolean => {\n if (!currentAccessToken) return true;\n if (!currentExpiryTs) return false; // If unknown, assume usable until failure\n\n return Date.now() + ONE_MINUTE_MS >= currentExpiryTs; // refresh 1 min before expiry\n };\n\n const refreshToken = async (): Promise<void> => {\n const doRefresh = async () => {\n const authApi = getOAuthAPI({}, intlayerConfig);\n const res = await authApi.getOAuth2AccessToken();\n const tokenData = res?.data as OAuthTokenLike | undefined;\n\n currentAccessToken = tokenData?.accessToken;\n currentExpiryTs = getExpiryTimestamp(tokenData);\n };\n\n if (!pendingRefresh) {\n pendingRefresh = doRefresh().finally(() => {\n pendingRefresh = undefined;\n });\n }\n await pendingRefresh;\n };\n\n const ensureValidToken = async () => {\n if (needsRefresh()) {\n await refreshToken();\n }\n };\n\n const applyAuthHeaderToRef = () => {\n if (!currentAccessToken) return;\n authOptionsRef.headers = {\n ...(authOptionsRef.headers ?? {}),\n Authorization: `Bearer ${currentAccessToken}`,\n } as HeadersInit;\n };\n\n const wrapSection = <T extends Record<string, unknown>>(\n section: T,\n skipAuth = !hasCMSAuth\n ): T => {\n return new Proxy(section, {\n get(target, prop, receiver) {\n const value = Reflect.get(target, prop, receiver);\n\n if (typeof value === 'function') {\n // Wrap section method to inject token and headers\n return async (...args: unknown[]) => {\n if (!skipAuth) {\n if (sessionToken) {\n // Session token is pre-injected in authOptionsRef; no OAuth2 exchange needed\n } else {\n await ensureValidToken();\n applyAuthHeaderToRef();\n }\n }\n\n try {\n return await value.apply(target, args);\n } catch (err) {\n // Best-effort retry: if token might be stale, refresh once and retry\n if (!skipAuth && !sessionToken) {\n await refreshToken();\n applyAuthHeaderToRef();\n return await value.apply(target, args);\n }\n throw err;\n }\n };\n }\n\n return value;\n },\n });\n };\n\n return {\n organization: wrapSection(baseApi.organization),\n project: wrapSection(baseApi.project),\n user: wrapSection(baseApi.user),\n oAuth: wrapSection(baseApi.oAuth, true), // do NOT inject auth for token endpoint\n dictionary: wrapSection(baseApi.dictionary),\n stripe: wrapSection(baseApi.stripe),\n ai: wrapSection(baseApi.ai),\n tag: wrapSection(baseApi.tag),\n search: wrapSection(baseApi.search),\n editor: wrapSection(baseApi.editor),\n newsletter: wrapSection(baseApi.newsletter),\n github: wrapSection(baseApi.github),\n } as IntlayerAPI;\n};\n\nexport type IntlayerAPIProxy = ReturnType<typeof getIntlayerAPIProxy>;\n"],"mappings":";;;;;AAcA,MAAM,gBAAgB;;;;AAKtB,MAAM,sBACJ,UACuB;CACvB,IAAI,CAAC,OAAO,OAAO;CACnB,MAAM,WAAY,MAAM,wBAAwB,MAAM;CAItD,IAAI,UAAU;EACZ,MAAM,KACJ,OAAO,aAAa,WAChB,KAAK,MAAM,SAAS,GACpB,SAAS,WAAW;EAC1B,IAAI,OAAO,OAAO,YAAY,OAAO,SAAS,GAAG,EAAE,OAAO;;CAE5D,MAAM,UAAU,MAAM,cAAc,MAAM;CAC1C,IAAI,OAAO,YAAY,YAAY,OAAO,SAAS,QAAQ,EACzD,OAAO,KAAK,KAAK,GAAG,UAAU;;AAKlC,IAAI;AACJ,IAAI;AACJ,IAAI;;;;;;;;;;;;;AAcJ,MAAa,uBACX,kBAAkC,EAAE,EACpC,gBACA,iBACgB;CAMhB,MAAM,iBAAiC;EACrC,GAAG;EACH,aAAa;EACd;CACD,MAAM,aACJ,QAAQ,aAAa,IACrB,QACE,gBAAgB,QAAQ,YAAY,gBAAgB,QAAQ,aAC7D;CAIH,IAAI,cACF,eAAe,UAAU;EACvB,GAAI,eAAe,WAAW,EAAE;EAChC,eAAe,UAAU;EAC1B;CAGH,MAAM,UAAUA,4CAAe,gBAAgB,eAAe;CAE9D,MAAM,qBAA8B;EAClC,IAAI,CAAC,oBAAoB,OAAO;EAChC,IAAI,CAAC,iBAAiB,OAAO;EAE7B,OAAO,KAAK,KAAK,GAAG,iBAAiB;;CAGvC,MAAM,eAAe,YAA2B;EAC9C,MAAM,YAAY,YAAY;GAG5B,MAAM,aAAY,MAFFC,yCAAY,EAAE,EAAE,eACP,CAAC,sBAAsB,GACzB;GAEvB,qBAAqB,WAAW;GAChC,kBAAkB,mBAAmB,UAAU;;EAGjD,IAAI,CAAC,gBACH,iBAAiB,WAAW,CAAC,cAAc;GACzC,iBAAiB;IACjB;EAEJ,MAAM;;CAGR,MAAM,mBAAmB,YAAY;EACnC,IAAI,cAAc,EAChB,MAAM,cAAc;;CAIxB,MAAM,6BAA6B;EACjC,IAAI,CAAC,oBAAoB;EACzB,eAAe,UAAU;GACvB,GAAI,eAAe,WAAW,EAAE;GAChC,eAAe,UAAU;GAC1B;;CAGH,MAAM,eACJ,SACA,WAAW,CAAC,eACN;EACN,OAAO,IAAI,MAAM,SAAS,EACxB,IAAI,QAAQ,MAAM,UAAU;GAC1B,MAAM,QAAQ,QAAQ,IAAI,QAAQ,MAAM,SAAS;GAEjD,IAAI,OAAO,UAAU,YAEnB,OAAO,OAAO,GAAG,SAAoB;IACnC,IAAI,CAAC,UACH,IAAI,cAAc,QAEX;KACL,MAAM,kBAAkB;KACxB,sBAAsB;;IAI1B,IAAI;KACF,OAAO,MAAM,MAAM,MAAM,QAAQ,KAAK;aAC/B,KAAK;KAEZ,IAAI,CAAC,YAAY,CAAC,cAAc;MAC9B,MAAM,cAAc;MACpB,sBAAsB;MACtB,OAAO,MAAM,MAAM,MAAM,QAAQ,KAAK;;KAExC,MAAM;;;GAKZ,OAAO;KAEV,CAAC;;CAGJ,OAAO;EACL,cAAc,YAAY,QAAQ,aAAa;EAC/C,SAAS,YAAY,QAAQ,QAAQ;EACrC,MAAM,YAAY,QAAQ,KAAK;EAC/B,OAAO,YAAY,QAAQ,OAAO,KAAK;EACvC,YAAY,YAAY,QAAQ,WAAW;EAC3C,QAAQ,YAAY,QAAQ,OAAO;EACnC,IAAI,YAAY,QAAQ,GAAG;EAC3B,KAAK,YAAY,QAAQ,IAAI;EAC7B,QAAQ,YAAY,QAAQ,OAAO;EACnC,QAAQ,YAAY,QAAQ,OAAO;EACnC,YAAY,YAAY,QAAQ,WAAW;EAC3C,QAAQ,YAAY,QAAQ,OAAO;EACpC"}
@@ -25,7 +25,7 @@ const getIntlayerAPI = (authAPIOptions = {}, intlayerConfig = config) => {
25
25
  organization: getOrganizationAPI(authAPIOptions, resolvedConfig),
26
26
  project: getProjectAPI(authAPIOptions, resolvedConfig),
27
27
  user: getUserAPI(authAPIOptions, resolvedConfig),
28
- oAuth: getOAuthAPI(resolvedConfig),
28
+ oAuth: getOAuthAPI(authAPIOptions, resolvedConfig),
29
29
  dictionary: getDictionaryAPI(authAPIOptions, resolvedConfig),
30
30
  stripe: getStripeAPI(authAPIOptions, resolvedConfig),
31
31
  ai: getAiAPI(authAPIOptions, resolvedConfig),
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/getIntlayerAPI/index.ts"],"sourcesContent":["import config from '@intlayer/config/built';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { defu } from 'defu';\nimport type { FetcherOptions } from '../fetcher';\nimport { getAiAPI } from './ai';\nimport { getAuditAPI } from './audit';\nimport { getBitbucketAPI } from './bitbucket';\nimport { getDictionaryAPI } from './dictionary';\nimport { getEditorAPI } from './editor';\nimport { getGithubAPI } from './github';\nimport { getGitlabAPI } from './gitlab';\nimport { getNewsletterAPI } from './newsletter';\nimport { getOAuthAPI } from './oAuth';\nimport { getOrganizationAPI } from './organization';\nimport { getProjectAPI } from './project';\nimport { getSearchAPI } from './search';\nimport { getShowcaseProjectAPI } from './showcaseProject';\nimport { getStripeAPI } from './stripe';\nimport { getTagAPI } from './tag';\nimport { getTranslateAPI } from './translate';\nimport { getUserAPI } from './user';\n\ninterface IntlayerAPIReturn {\n organization: ReturnType<typeof getOrganizationAPI>;\n project: ReturnType<typeof getProjectAPI>;\n user: ReturnType<typeof getUserAPI>;\n oAuth: ReturnType<typeof getOAuthAPI>;\n dictionary: ReturnType<typeof getDictionaryAPI>;\n stripe: ReturnType<typeof getStripeAPI>;\n ai: ReturnType<typeof getAiAPI>;\n audit: ReturnType<typeof getAuditAPI>;\n tag: ReturnType<typeof getTagAPI>;\n search: ReturnType<typeof getSearchAPI>;\n editor: ReturnType<typeof getEditorAPI>;\n newsletter: ReturnType<typeof getNewsletterAPI>;\n github: ReturnType<typeof getGithubAPI>;\n gitlab: ReturnType<typeof getGitlabAPI>;\n bitbucket: ReturnType<typeof getBitbucketAPI>;\n showcaseProject: ReturnType<typeof getShowcaseProjectAPI>;\n translate: ReturnType<typeof getTranslateAPI>;\n}\n\nexport const getIntlayerAPI = (\n authAPIOptions: FetcherOptions = {},\n intlayerConfig: IntlayerConfig = config\n): IntlayerAPIReturn => {\n const resolvedConfig = defu(intlayerConfig ?? {}, config) as IntlayerConfig;\n\n return {\n organization: getOrganizationAPI(authAPIOptions, resolvedConfig),\n project: getProjectAPI(authAPIOptions, resolvedConfig),\n user: getUserAPI(authAPIOptions, resolvedConfig),\n oAuth: getOAuthAPI(resolvedConfig),\n dictionary: getDictionaryAPI(authAPIOptions, resolvedConfig),\n stripe: getStripeAPI(authAPIOptions, resolvedConfig),\n ai: getAiAPI(authAPIOptions, resolvedConfig),\n audit: getAuditAPI(authAPIOptions, resolvedConfig),\n tag: getTagAPI(authAPIOptions, resolvedConfig),\n search: getSearchAPI(authAPIOptions, resolvedConfig),\n editor: getEditorAPI(authAPIOptions, resolvedConfig),\n newsletter: getNewsletterAPI(authAPIOptions, resolvedConfig),\n github: getGithubAPI(authAPIOptions, resolvedConfig),\n gitlab: getGitlabAPI(authAPIOptions, resolvedConfig),\n bitbucket: getBitbucketAPI(authAPIOptions, resolvedConfig),\n showcaseProject: getShowcaseProjectAPI(authAPIOptions, resolvedConfig),\n translate: getTranslateAPI(authAPIOptions, resolvedConfig),\n };\n};\n\nexport type IntlayerAPI = ReturnType<typeof getIntlayerAPI>;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA0CA,MAAa,kBACX,iBAAiC,EAAE,EACnC,iBAAiC,WACX;CACtB,MAAM,iBAAiB,KAAK,kBAAkB,EAAE,EAAE,OAAO;CAEzD,OAAO;EACL,cAAc,mBAAmB,gBAAgB,eAAe;EAChE,SAAS,cAAc,gBAAgB,eAAe;EACtD,MAAM,WAAW,gBAAgB,eAAe;EAChD,OAAO,YAAY,eAAe;EAClC,YAAY,iBAAiB,gBAAgB,eAAe;EAC5D,QAAQ,aAAa,gBAAgB,eAAe;EACpD,IAAI,SAAS,gBAAgB,eAAe;EAC5C,OAAO,YAAY,gBAAgB,eAAe;EAClD,KAAK,UAAU,gBAAgB,eAAe;EAC9C,QAAQ,aAAa,gBAAgB,eAAe;EACpD,QAAQ,aAAa,gBAAgB,eAAe;EACpD,YAAY,iBAAiB,gBAAgB,eAAe;EAC5D,QAAQ,aAAa,gBAAgB,eAAe;EACpD,QAAQ,aAAa,gBAAgB,eAAe;EACpD,WAAW,gBAAgB,gBAAgB,eAAe;EAC1D,iBAAiB,sBAAsB,gBAAgB,eAAe;EACtE,WAAW,gBAAgB,gBAAgB,eAAe;EAC3D"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../src/getIntlayerAPI/index.ts"],"sourcesContent":["import config from '@intlayer/config/built';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { defu } from 'defu';\nimport type { FetcherOptions } from '../fetcher';\nimport { getAiAPI } from './ai';\nimport { getAuditAPI } from './audit';\nimport { getBitbucketAPI } from './bitbucket';\nimport { getDictionaryAPI } from './dictionary';\nimport { getEditorAPI } from './editor';\nimport { getGithubAPI } from './github';\nimport { getGitlabAPI } from './gitlab';\nimport { getNewsletterAPI } from './newsletter';\nimport { getOAuthAPI } from './oAuth';\nimport { getOrganizationAPI } from './organization';\nimport { getProjectAPI } from './project';\nimport { getSearchAPI } from './search';\nimport { getShowcaseProjectAPI } from './showcaseProject';\nimport { getStripeAPI } from './stripe';\nimport { getTagAPI } from './tag';\nimport { getTranslateAPI } from './translate';\nimport { getUserAPI } from './user';\n\ninterface IntlayerAPIReturn {\n organization: ReturnType<typeof getOrganizationAPI>;\n project: ReturnType<typeof getProjectAPI>;\n user: ReturnType<typeof getUserAPI>;\n oAuth: ReturnType<typeof getOAuthAPI>;\n dictionary: ReturnType<typeof getDictionaryAPI>;\n stripe: ReturnType<typeof getStripeAPI>;\n ai: ReturnType<typeof getAiAPI>;\n audit: ReturnType<typeof getAuditAPI>;\n tag: ReturnType<typeof getTagAPI>;\n search: ReturnType<typeof getSearchAPI>;\n editor: ReturnType<typeof getEditorAPI>;\n newsletter: ReturnType<typeof getNewsletterAPI>;\n github: ReturnType<typeof getGithubAPI>;\n gitlab: ReturnType<typeof getGitlabAPI>;\n bitbucket: ReturnType<typeof getBitbucketAPI>;\n showcaseProject: ReturnType<typeof getShowcaseProjectAPI>;\n translate: ReturnType<typeof getTranslateAPI>;\n}\n\nexport const getIntlayerAPI = (\n authAPIOptions: FetcherOptions = {},\n intlayerConfig: IntlayerConfig = config\n): IntlayerAPIReturn => {\n const resolvedConfig = defu(intlayerConfig ?? {}, config) as IntlayerConfig;\n\n return {\n organization: getOrganizationAPI(authAPIOptions, resolvedConfig),\n project: getProjectAPI(authAPIOptions, resolvedConfig),\n user: getUserAPI(authAPIOptions, resolvedConfig),\n oAuth: getOAuthAPI(authAPIOptions, resolvedConfig),\n dictionary: getDictionaryAPI(authAPIOptions, resolvedConfig),\n stripe: getStripeAPI(authAPIOptions, resolvedConfig),\n ai: getAiAPI(authAPIOptions, resolvedConfig),\n audit: getAuditAPI(authAPIOptions, resolvedConfig),\n tag: getTagAPI(authAPIOptions, resolvedConfig),\n search: getSearchAPI(authAPIOptions, resolvedConfig),\n editor: getEditorAPI(authAPIOptions, resolvedConfig),\n newsletter: getNewsletterAPI(authAPIOptions, resolvedConfig),\n github: getGithubAPI(authAPIOptions, resolvedConfig),\n gitlab: getGitlabAPI(authAPIOptions, resolvedConfig),\n bitbucket: getBitbucketAPI(authAPIOptions, resolvedConfig),\n showcaseProject: getShowcaseProjectAPI(authAPIOptions, resolvedConfig),\n translate: getTranslateAPI(authAPIOptions, resolvedConfig),\n };\n};\n\nexport type IntlayerAPI = ReturnType<typeof getIntlayerAPI>;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA0CA,MAAa,kBACX,iBAAiC,EAAE,EACnC,iBAAiC,WACX;CACtB,MAAM,iBAAiB,KAAK,kBAAkB,EAAE,EAAE,OAAO;CAEzD,OAAO;EACL,cAAc,mBAAmB,gBAAgB,eAAe;EAChE,SAAS,cAAc,gBAAgB,eAAe;EACtD,MAAM,WAAW,gBAAgB,eAAe;EAChD,OAAO,YAAY,gBAAgB,eAAe;EAClD,YAAY,iBAAiB,gBAAgB,eAAe;EAC5D,QAAQ,aAAa,gBAAgB,eAAe;EACpD,IAAI,SAAS,gBAAgB,eAAe;EAC5C,OAAO,YAAY,gBAAgB,eAAe;EAClD,KAAK,UAAU,gBAAgB,eAAe;EAC9C,QAAQ,aAAa,gBAAgB,eAAe;EACpD,QAAQ,aAAa,gBAAgB,eAAe;EACpD,YAAY,iBAAiB,gBAAgB,eAAe;EAC5D,QAAQ,aAAa,gBAAgB,eAAe;EACpD,QAAQ,aAAa,gBAAgB,eAAe;EACpD,WAAW,gBAAgB,gBAAgB,eAAe;EAC1D,iBAAiB,sBAAsB,gBAAgB,eAAe;EACtE,WAAW,gBAAgB,gBAAgB,eAAe;EAC3D"}
@@ -2,12 +2,11 @@ import { fetcher } from "../fetcher.mjs";
2
2
  import config from "@intlayer/config/built";
3
3
 
4
4
  //#region src/getIntlayerAPI/oAuth.ts
5
- const getOAuthAPI = (intlayerConfig = config) => {
5
+ const getOAuthAPI = (authAPIOptions = {}, intlayerConfig = config) => {
6
6
  const backendURL = intlayerConfig.editor.backendURL;
7
7
  const { clientId, clientSecret } = intlayerConfig.editor;
8
8
  /**
9
- * Gets an oAuth2 accessToken
10
- * @return The token information
9
+ * Gets an oAuth2 accessToken via client_credentials grant
11
10
  */
12
11
  const getOAuth2AccessToken = async (otherOptions = {}) => await fetcher(`${backendURL}/oauth2/token`, {}, otherOptions, {
13
12
  method: "POST",
@@ -18,7 +17,21 @@ const getOAuthAPI = (intlayerConfig = config) => {
18
17
  client_secret: clientSecret
19
18
  }
20
19
  });
21
- return { getOAuth2AccessToken };
20
+ /**
21
+ * Creates a short-lived (2h) CLI session token for the authenticated user.
22
+ * Requires a valid browser session cookie.
23
+ */
24
+ const createCliSessionToken = async (otherOptions = {}) => await fetcher(`${backendURL}/api/cli-session`, authAPIOptions, otherOptions, { method: "POST" });
25
+ /**
26
+ * Verifies a CLI session token and returns the associated project context.
27
+ * Useful for checking config consistency in the CLI.
28
+ */
29
+ const getCliSessionMe = async (otherOptions = {}) => await fetcher(`${backendURL}/api/cli-session/me`, authAPIOptions, otherOptions);
30
+ return {
31
+ getOAuth2AccessToken,
32
+ createCliSessionToken,
33
+ getCliSessionMe
34
+ };
22
35
  };
23
36
 
24
37
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"oAuth.mjs","names":[],"sources":["../../../src/getIntlayerAPI/oAuth.ts"],"sourcesContent":["import type {\n GetOAuth2TokenBody,\n GetOAuth2TokenResult,\n} from '@intlayer/backend';\nimport config from '@intlayer/config/built';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { type FetcherOptions, fetcher } from '../fetcher';\n\nexport const getOAuthAPI = (intlayerConfig: IntlayerConfig = config) => {\n const backendURL = intlayerConfig.editor.backendURL;\n const { clientId, clientSecret } = intlayerConfig.editor;\n\n /**\n * Gets an oAuth2 accessToken\n * @return The token information\n */\n const getOAuth2AccessToken = async (otherOptions: FetcherOptions = {}) =>\n await fetcher<GetOAuth2TokenResult>(\n `${backendURL}/oauth2/token`,\n {},\n otherOptions,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: {\n grant_type: 'client_credentials',\n client_id: clientId!,\n client_secret: clientSecret!,\n } satisfies GetOAuth2TokenBody,\n }\n );\n\n return {\n getOAuth2AccessToken,\n };\n};\n"],"mappings":";;;;AAQA,MAAa,eAAe,iBAAiC,WAAW;CACtE,MAAM,aAAa,eAAe,OAAO;CACzC,MAAM,EAAE,UAAU,iBAAiB,eAAe;;;;;CAMlD,MAAM,uBAAuB,OAAO,eAA+B,EAAE,KACnE,MAAM,QACJ,GAAG,WAAW,gBACd,EAAE,EACF,cACA;EACE,QAAQ;EACR,SAAS,EACP,gBAAgB,qCACjB;EACD,MAAM;GACJ,YAAY;GACZ,WAAW;GACX,eAAe;GAChB;EACF,CACF;CAEH,OAAO,EACL,sBACD"}
1
+ {"version":3,"file":"oAuth.mjs","names":[],"sources":["../../../src/getIntlayerAPI/oAuth.ts"],"sourcesContent":["import type {\n CreateCliSessionTokenResult,\n GetCliSessionMeResult,\n GetOAuth2TokenBody,\n GetOAuth2TokenResult,\n} from '@intlayer/backend';\nimport config from '@intlayer/config/built';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { type FetcherOptions, fetcher } from '../fetcher';\n\nexport const getOAuthAPI = (\n authAPIOptions: FetcherOptions = {},\n intlayerConfig: IntlayerConfig = config\n) => {\n const backendURL = intlayerConfig.editor.backendURL;\n const { clientId, clientSecret } = intlayerConfig.editor;\n\n /**\n * Gets an oAuth2 accessToken via client_credentials grant\n */\n const getOAuth2AccessToken = async (otherOptions: FetcherOptions = {}) =>\n await fetcher<GetOAuth2TokenResult>(\n `${backendURL}/oauth2/token`,\n {},\n otherOptions,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: {\n grant_type: 'client_credentials',\n client_id: clientId!,\n client_secret: clientSecret!,\n } satisfies GetOAuth2TokenBody,\n }\n );\n\n /**\n * Creates a short-lived (2h) CLI session token for the authenticated user.\n * Requires a valid browser session cookie.\n */\n const createCliSessionToken = async (otherOptions: FetcherOptions = {}) =>\n await fetcher<CreateCliSessionTokenResult>(\n `${backendURL}/api/cli-session`,\n authAPIOptions,\n otherOptions,\n { method: 'POST' }\n );\n\n /**\n * Verifies a CLI session token and returns the associated project context.\n * Useful for checking config consistency in the CLI.\n */\n const getCliSessionMe = async (otherOptions: FetcherOptions = {}) =>\n await fetcher<GetCliSessionMeResult>(\n `${backendURL}/api/cli-session/me`,\n authAPIOptions,\n otherOptions\n );\n\n return {\n getOAuth2AccessToken,\n createCliSessionToken,\n getCliSessionMe,\n };\n};\n"],"mappings":";;;;AAUA,MAAa,eACX,iBAAiC,EAAE,EACnC,iBAAiC,WAC9B;CACH,MAAM,aAAa,eAAe,OAAO;CACzC,MAAM,EAAE,UAAU,iBAAiB,eAAe;;;;CAKlD,MAAM,uBAAuB,OAAO,eAA+B,EAAE,KACnE,MAAM,QACJ,GAAG,WAAW,gBACd,EAAE,EACF,cACA;EACE,QAAQ;EACR,SAAS,EACP,gBAAgB,qCACjB;EACD,MAAM;GACJ,YAAY;GACZ,WAAW;GACX,eAAe;GAChB;EACF,CACF;;;;;CAMH,MAAM,wBAAwB,OAAO,eAA+B,EAAE,KACpE,MAAM,QACJ,GAAG,WAAW,mBACd,gBACA,cACA,EAAE,QAAQ,QAAQ,CACnB;;;;;CAMH,MAAM,kBAAkB,OAAO,eAA+B,EAAE,KAC9D,MAAM,QACJ,GAAG,WAAW,sBACd,gBACA,aACD;CAEH,OAAO;EACL;EACA;EACA;EACD"}
@@ -25,11 +25,22 @@ let pendingRefresh;
25
25
  * - Injects Authorization header for each request
26
26
  * - Refreshes token proactively when near expiry
27
27
  *
28
+ * When `sessionToken` is provided (a CLI session token starting with
29
+ * "clisession_"), it is used directly as the Bearer token without any OAuth2
30
+ * exchange — the backend validates it against the CliSessionToken collection.
31
+ *
28
32
  * The returned API matches the shape of getIntlayerAPI.
29
33
  */
30
- const getIntlayerAPIProxy = (baseAuthOptions = {}, intlayerConfig) => {
31
- const authOptionsRef = { ...baseAuthOptions };
32
- const hasCMSAuth = intlayerConfig?.editor?.clientId && intlayerConfig?.editor?.clientSecret;
34
+ const getIntlayerAPIProxy = (baseAuthOptions = {}, intlayerConfig, sessionToken) => {
35
+ const authOptionsRef = {
36
+ ...baseAuthOptions,
37
+ credentials: "omit"
38
+ };
39
+ const hasCMSAuth = Boolean(sessionToken) || Boolean(intlayerConfig?.editor?.clientId && intlayerConfig?.editor?.clientSecret);
40
+ if (sessionToken) authOptionsRef.headers = {
41
+ ...authOptionsRef.headers ?? {},
42
+ Authorization: `Bearer ${sessionToken}`
43
+ };
33
44
  const baseApi = getIntlayerAPI(authOptionsRef, intlayerConfig);
34
45
  const needsRefresh = () => {
35
46
  if (!currentAccessToken) return true;
@@ -38,7 +49,7 @@ const getIntlayerAPIProxy = (baseAuthOptions = {}, intlayerConfig) => {
38
49
  };
39
50
  const refreshToken = async () => {
40
51
  const doRefresh = async () => {
41
- const tokenData = (await getOAuthAPI(intlayerConfig).getOAuth2AccessToken())?.data;
52
+ const tokenData = (await getOAuthAPI({}, intlayerConfig).getOAuth2AccessToken())?.data;
42
53
  currentAccessToken = tokenData?.accessToken;
43
54
  currentExpiryTs = getExpiryTimestamp(tokenData);
44
55
  };
@@ -61,14 +72,14 @@ const getIntlayerAPIProxy = (baseAuthOptions = {}, intlayerConfig) => {
61
72
  return new Proxy(section, { get(target, prop, receiver) {
62
73
  const value = Reflect.get(target, prop, receiver);
63
74
  if (typeof value === "function") return async (...args) => {
64
- if (!skipAuth) {
75
+ if (!skipAuth) if (sessionToken) {} else {
65
76
  await ensureValidToken();
66
77
  applyAuthHeaderToRef();
67
78
  }
68
79
  try {
69
80
  return await value.apply(target, args);
70
81
  } catch (err) {
71
- if (!skipAuth) {
82
+ if (!skipAuth && !sessionToken) {
72
83
  await refreshToken();
73
84
  applyAuthHeaderToRef();
74
85
  return await value.apply(target, args);
@@ -1 +1 @@
1
- {"version":3,"file":"proxy.mjs","names":[],"sources":["../../src/proxy.ts"],"sourcesContent":["import type { IntlayerConfig } from '@intlayer/types/config';\nimport type { FetcherOptions } from './fetcher';\nimport { getIntlayerAPI } from './getIntlayerAPI';\nimport type { IntlayerAPI } from './getIntlayerAPI/index';\nimport { getOAuthAPI } from './getIntlayerAPI/oAuth';\n\ntype OAuthTokenLike = {\n accessToken?: string;\n accessTokenExpiresAt?: string | Date;\n expires_in?: number;\n expiresIn?: number;\n expiresAt?: string | Date;\n};\n\nconst ONE_MINUTE_MS = 60_000;\n\n/**\n * Returns the expiration timestamp in ms from an OAuth token-like object.\n */\nconst getExpiryTimestamp = (\n token: OAuthTokenLike | undefined\n): number | undefined => {\n if (!token) return undefined;\n const dateLike = (token.accessTokenExpiresAt ?? token.expiresAt) as\n | string\n | Date\n | undefined;\n if (dateLike) {\n const ts =\n typeof dateLike === 'string'\n ? Date.parse(dateLike)\n : dateLike.getTime?.();\n if (typeof ts === 'number' && Number.isFinite(ts)) return ts;\n }\n const seconds = token.expires_in ?? token.expiresIn;\n if (typeof seconds === 'number' && Number.isFinite(seconds)) {\n return Date.now() + seconds * 1000;\n }\n return undefined;\n};\n\nlet currentAccessToken: string | undefined;\nlet currentExpiryTs: number | undefined;\nlet pendingRefresh: Promise<void> | undefined;\n\n/**\n * Build an auto-auth proxy around getIntlayerAPI that:\n * - Fetches an OAuth2 token when needed\n * - Injects Authorization header for each request\n * - Refreshes token proactively when near expiry\n *\n * The returned API matches the shape of getIntlayerAPI.\n */\nexport const getIntlayerAPIProxy = (\n baseAuthOptions: FetcherOptions = {},\n intlayerConfig?: IntlayerConfig\n): IntlayerAPI => {\n // Use a shared mutable auth options object captured by the API closures\n const authOptionsRef: FetcherOptions = { ...baseAuthOptions };\n const hasCMSAuth =\n intlayerConfig?.editor?.clientId && intlayerConfig?.editor?.clientSecret;\n const baseApi = getIntlayerAPI(authOptionsRef, intlayerConfig);\n\n const needsRefresh = (): boolean => {\n if (!currentAccessToken) return true;\n if (!currentExpiryTs) return false; // If unknown, assume usable until failure\n\n return Date.now() + ONE_MINUTE_MS >= currentExpiryTs; // refresh 1 min before expiry\n };\n\n const refreshToken = async (): Promise<void> => {\n const doRefresh = async () => {\n const authApi = getOAuthAPI(intlayerConfig);\n const res = await authApi.getOAuth2AccessToken();\n const tokenData = res?.data as OAuthTokenLike | undefined;\n\n currentAccessToken = tokenData?.accessToken;\n currentExpiryTs = getExpiryTimestamp(tokenData);\n };\n\n if (!pendingRefresh) {\n pendingRefresh = doRefresh().finally(() => {\n pendingRefresh = undefined;\n });\n }\n await pendingRefresh;\n };\n\n const ensureValidToken = async () => {\n if (needsRefresh()) {\n await refreshToken();\n }\n };\n\n const applyAuthHeaderToRef = () => {\n if (!currentAccessToken) return;\n authOptionsRef.headers = {\n ...(authOptionsRef.headers ?? {}),\n Authorization: `Bearer ${currentAccessToken}`,\n } as HeadersInit;\n };\n\n const wrapSection = <T extends Record<string, unknown>>(\n section: T,\n skipAuth = !hasCMSAuth\n ): T => {\n return new Proxy(section, {\n get(target, prop, receiver) {\n const value = Reflect.get(target, prop, receiver);\n\n if (typeof value === 'function') {\n // Wrap section method to inject token and headers\n return async (...args: unknown[]) => {\n if (!skipAuth) {\n await ensureValidToken();\n applyAuthHeaderToRef();\n }\n\n try {\n return await value.apply(target, args);\n } catch (err) {\n // Best-effort retry: if token might be stale, refresh once and retry\n if (!skipAuth) {\n await refreshToken();\n applyAuthHeaderToRef();\n return await value.apply(target, args);\n }\n throw err;\n }\n };\n }\n\n return value;\n },\n });\n };\n\n return {\n organization: wrapSection(baseApi.organization),\n project: wrapSection(baseApi.project),\n user: wrapSection(baseApi.user),\n oAuth: wrapSection(baseApi.oAuth, true), // do NOT inject auth for token endpoint\n dictionary: wrapSection(baseApi.dictionary),\n stripe: wrapSection(baseApi.stripe),\n ai: wrapSection(baseApi.ai),\n tag: wrapSection(baseApi.tag),\n search: wrapSection(baseApi.search),\n editor: wrapSection(baseApi.editor),\n newsletter: wrapSection(baseApi.newsletter),\n github: wrapSection(baseApi.github),\n } as IntlayerAPI;\n};\n\nexport type IntlayerAPIProxy = ReturnType<typeof getIntlayerAPIProxy>;\n"],"mappings":";;;;AAcA,MAAM,gBAAgB;;;;AAKtB,MAAM,sBACJ,UACuB;CACvB,IAAI,CAAC,OAAO,OAAO;CACnB,MAAM,WAAY,MAAM,wBAAwB,MAAM;CAItD,IAAI,UAAU;EACZ,MAAM,KACJ,OAAO,aAAa,WAChB,KAAK,MAAM,SAAS,GACpB,SAAS,WAAW;EAC1B,IAAI,OAAO,OAAO,YAAY,OAAO,SAAS,GAAG,EAAE,OAAO;;CAE5D,MAAM,UAAU,MAAM,cAAc,MAAM;CAC1C,IAAI,OAAO,YAAY,YAAY,OAAO,SAAS,QAAQ,EACzD,OAAO,KAAK,KAAK,GAAG,UAAU;;AAKlC,IAAI;AACJ,IAAI;AACJ,IAAI;;;;;;;;;AAUJ,MAAa,uBACX,kBAAkC,EAAE,EACpC,mBACgB;CAEhB,MAAM,iBAAiC,EAAE,GAAG,iBAAiB;CAC7D,MAAM,aACJ,gBAAgB,QAAQ,YAAY,gBAAgB,QAAQ;CAC9D,MAAM,UAAU,eAAe,gBAAgB,eAAe;CAE9D,MAAM,qBAA8B;EAClC,IAAI,CAAC,oBAAoB,OAAO;EAChC,IAAI,CAAC,iBAAiB,OAAO;EAE7B,OAAO,KAAK,KAAK,GAAG,iBAAiB;;CAGvC,MAAM,eAAe,YAA2B;EAC9C,MAAM,YAAY,YAAY;GAG5B,MAAM,aAAY,MAFF,YAAY,eACH,CAAC,sBAAsB,GACzB;GAEvB,qBAAqB,WAAW;GAChC,kBAAkB,mBAAmB,UAAU;;EAGjD,IAAI,CAAC,gBACH,iBAAiB,WAAW,CAAC,cAAc;GACzC,iBAAiB;IACjB;EAEJ,MAAM;;CAGR,MAAM,mBAAmB,YAAY;EACnC,IAAI,cAAc,EAChB,MAAM,cAAc;;CAIxB,MAAM,6BAA6B;EACjC,IAAI,CAAC,oBAAoB;EACzB,eAAe,UAAU;GACvB,GAAI,eAAe,WAAW,EAAE;GAChC,eAAe,UAAU;GAC1B;;CAGH,MAAM,eACJ,SACA,WAAW,CAAC,eACN;EACN,OAAO,IAAI,MAAM,SAAS,EACxB,IAAI,QAAQ,MAAM,UAAU;GAC1B,MAAM,QAAQ,QAAQ,IAAI,QAAQ,MAAM,SAAS;GAEjD,IAAI,OAAO,UAAU,YAEnB,OAAO,OAAO,GAAG,SAAoB;IACnC,IAAI,CAAC,UAAU;KACb,MAAM,kBAAkB;KACxB,sBAAsB;;IAGxB,IAAI;KACF,OAAO,MAAM,MAAM,MAAM,QAAQ,KAAK;aAC/B,KAAK;KAEZ,IAAI,CAAC,UAAU;MACb,MAAM,cAAc;MACpB,sBAAsB;MACtB,OAAO,MAAM,MAAM,MAAM,QAAQ,KAAK;;KAExC,MAAM;;;GAKZ,OAAO;KAEV,CAAC;;CAGJ,OAAO;EACL,cAAc,YAAY,QAAQ,aAAa;EAC/C,SAAS,YAAY,QAAQ,QAAQ;EACrC,MAAM,YAAY,QAAQ,KAAK;EAC/B,OAAO,YAAY,QAAQ,OAAO,KAAK;EACvC,YAAY,YAAY,QAAQ,WAAW;EAC3C,QAAQ,YAAY,QAAQ,OAAO;EACnC,IAAI,YAAY,QAAQ,GAAG;EAC3B,KAAK,YAAY,QAAQ,IAAI;EAC7B,QAAQ,YAAY,QAAQ,OAAO;EACnC,QAAQ,YAAY,QAAQ,OAAO;EACnC,YAAY,YAAY,QAAQ,WAAW;EAC3C,QAAQ,YAAY,QAAQ,OAAO;EACpC"}
1
+ {"version":3,"file":"proxy.mjs","names":[],"sources":["../../src/proxy.ts"],"sourcesContent":["import type { IntlayerConfig } from '@intlayer/types/config';\nimport type { FetcherOptions } from './fetcher';\nimport { getIntlayerAPI } from './getIntlayerAPI';\nimport type { IntlayerAPI } from './getIntlayerAPI/index';\nimport { getOAuthAPI } from './getIntlayerAPI/oAuth';\n\ntype OAuthTokenLike = {\n accessToken?: string;\n accessTokenExpiresAt?: string | Date;\n expires_in?: number;\n expiresIn?: number;\n expiresAt?: string | Date;\n};\n\nconst ONE_MINUTE_MS = 60_000;\n\n/**\n * Returns the expiration timestamp in ms from an OAuth token-like object.\n */\nconst getExpiryTimestamp = (\n token: OAuthTokenLike | undefined\n): number | undefined => {\n if (!token) return undefined;\n const dateLike = (token.accessTokenExpiresAt ?? token.expiresAt) as\n | string\n | Date\n | undefined;\n if (dateLike) {\n const ts =\n typeof dateLike === 'string'\n ? Date.parse(dateLike)\n : dateLike.getTime?.();\n if (typeof ts === 'number' && Number.isFinite(ts)) return ts;\n }\n const seconds = token.expires_in ?? token.expiresIn;\n if (typeof seconds === 'number' && Number.isFinite(seconds)) {\n return Date.now() + seconds * 1000;\n }\n return undefined;\n};\n\nlet currentAccessToken: string | undefined;\nlet currentExpiryTs: number | undefined;\nlet pendingRefresh: Promise<void> | undefined;\n\n/**\n * Build an auto-auth proxy around getIntlayerAPI that:\n * - Fetches an OAuth2 token when needed\n * - Injects Authorization header for each request\n * - Refreshes token proactively when near expiry\n *\n * When `sessionToken` is provided (a CLI session token starting with\n * \"clisession_\"), it is used directly as the Bearer token without any OAuth2\n * exchange — the backend validates it against the CliSessionToken collection.\n *\n * The returned API matches the shape of getIntlayerAPI.\n */\nexport const getIntlayerAPIProxy = (\n baseAuthOptions: FetcherOptions = {},\n intlayerConfig?: IntlayerConfig,\n sessionToken?: string\n): IntlayerAPI => {\n // Use a shared mutable auth options object captured by the API closures.\n // credentials: 'omit' prevents the browser from attaching session cookies to\n // these requests; authentication is handled exclusively via the Bearer token\n // injected below. This is required because the backend only sets\n // Access-Control-Allow-Credentials: true for whitelisted first-party origins.\n const authOptionsRef: FetcherOptions = {\n ...baseAuthOptions,\n credentials: 'omit',\n };\n const hasCMSAuth =\n Boolean(sessionToken) ||\n Boolean(\n intlayerConfig?.editor?.clientId && intlayerConfig?.editor?.clientSecret\n );\n\n // When a CLI session token is provided, inject it immediately and skip the\n // OAuth2 client_credentials exchange entirely.\n if (sessionToken) {\n authOptionsRef.headers = {\n ...(authOptionsRef.headers ?? {}),\n Authorization: `Bearer ${sessionToken}`,\n } as HeadersInit;\n }\n\n const baseApi = getIntlayerAPI(authOptionsRef, intlayerConfig);\n\n const needsRefresh = (): boolean => {\n if (!currentAccessToken) return true;\n if (!currentExpiryTs) return false; // If unknown, assume usable until failure\n\n return Date.now() + ONE_MINUTE_MS >= currentExpiryTs; // refresh 1 min before expiry\n };\n\n const refreshToken = async (): Promise<void> => {\n const doRefresh = async () => {\n const authApi = getOAuthAPI({}, intlayerConfig);\n const res = await authApi.getOAuth2AccessToken();\n const tokenData = res?.data as OAuthTokenLike | undefined;\n\n currentAccessToken = tokenData?.accessToken;\n currentExpiryTs = getExpiryTimestamp(tokenData);\n };\n\n if (!pendingRefresh) {\n pendingRefresh = doRefresh().finally(() => {\n pendingRefresh = undefined;\n });\n }\n await pendingRefresh;\n };\n\n const ensureValidToken = async () => {\n if (needsRefresh()) {\n await refreshToken();\n }\n };\n\n const applyAuthHeaderToRef = () => {\n if (!currentAccessToken) return;\n authOptionsRef.headers = {\n ...(authOptionsRef.headers ?? {}),\n Authorization: `Bearer ${currentAccessToken}`,\n } as HeadersInit;\n };\n\n const wrapSection = <T extends Record<string, unknown>>(\n section: T,\n skipAuth = !hasCMSAuth\n ): T => {\n return new Proxy(section, {\n get(target, prop, receiver) {\n const value = Reflect.get(target, prop, receiver);\n\n if (typeof value === 'function') {\n // Wrap section method to inject token and headers\n return async (...args: unknown[]) => {\n if (!skipAuth) {\n if (sessionToken) {\n // Session token is pre-injected in authOptionsRef; no OAuth2 exchange needed\n } else {\n await ensureValidToken();\n applyAuthHeaderToRef();\n }\n }\n\n try {\n return await value.apply(target, args);\n } catch (err) {\n // Best-effort retry: if token might be stale, refresh once and retry\n if (!skipAuth && !sessionToken) {\n await refreshToken();\n applyAuthHeaderToRef();\n return await value.apply(target, args);\n }\n throw err;\n }\n };\n }\n\n return value;\n },\n });\n };\n\n return {\n organization: wrapSection(baseApi.organization),\n project: wrapSection(baseApi.project),\n user: wrapSection(baseApi.user),\n oAuth: wrapSection(baseApi.oAuth, true), // do NOT inject auth for token endpoint\n dictionary: wrapSection(baseApi.dictionary),\n stripe: wrapSection(baseApi.stripe),\n ai: wrapSection(baseApi.ai),\n tag: wrapSection(baseApi.tag),\n search: wrapSection(baseApi.search),\n editor: wrapSection(baseApi.editor),\n newsletter: wrapSection(baseApi.newsletter),\n github: wrapSection(baseApi.github),\n } as IntlayerAPI;\n};\n\nexport type IntlayerAPIProxy = ReturnType<typeof getIntlayerAPIProxy>;\n"],"mappings":";;;;AAcA,MAAM,gBAAgB;;;;AAKtB,MAAM,sBACJ,UACuB;CACvB,IAAI,CAAC,OAAO,OAAO;CACnB,MAAM,WAAY,MAAM,wBAAwB,MAAM;CAItD,IAAI,UAAU;EACZ,MAAM,KACJ,OAAO,aAAa,WAChB,KAAK,MAAM,SAAS,GACpB,SAAS,WAAW;EAC1B,IAAI,OAAO,OAAO,YAAY,OAAO,SAAS,GAAG,EAAE,OAAO;;CAE5D,MAAM,UAAU,MAAM,cAAc,MAAM;CAC1C,IAAI,OAAO,YAAY,YAAY,OAAO,SAAS,QAAQ,EACzD,OAAO,KAAK,KAAK,GAAG,UAAU;;AAKlC,IAAI;AACJ,IAAI;AACJ,IAAI;;;;;;;;;;;;;AAcJ,MAAa,uBACX,kBAAkC,EAAE,EACpC,gBACA,iBACgB;CAMhB,MAAM,iBAAiC;EACrC,GAAG;EACH,aAAa;EACd;CACD,MAAM,aACJ,QAAQ,aAAa,IACrB,QACE,gBAAgB,QAAQ,YAAY,gBAAgB,QAAQ,aAC7D;CAIH,IAAI,cACF,eAAe,UAAU;EACvB,GAAI,eAAe,WAAW,EAAE;EAChC,eAAe,UAAU;EAC1B;CAGH,MAAM,UAAU,eAAe,gBAAgB,eAAe;CAE9D,MAAM,qBAA8B;EAClC,IAAI,CAAC,oBAAoB,OAAO;EAChC,IAAI,CAAC,iBAAiB,OAAO;EAE7B,OAAO,KAAK,KAAK,GAAG,iBAAiB;;CAGvC,MAAM,eAAe,YAA2B;EAC9C,MAAM,YAAY,YAAY;GAG5B,MAAM,aAAY,MAFF,YAAY,EAAE,EAAE,eACP,CAAC,sBAAsB,GACzB;GAEvB,qBAAqB,WAAW;GAChC,kBAAkB,mBAAmB,UAAU;;EAGjD,IAAI,CAAC,gBACH,iBAAiB,WAAW,CAAC,cAAc;GACzC,iBAAiB;IACjB;EAEJ,MAAM;;CAGR,MAAM,mBAAmB,YAAY;EACnC,IAAI,cAAc,EAChB,MAAM,cAAc;;CAIxB,MAAM,6BAA6B;EACjC,IAAI,CAAC,oBAAoB;EACzB,eAAe,UAAU;GACvB,GAAI,eAAe,WAAW,EAAE;GAChC,eAAe,UAAU;GAC1B;;CAGH,MAAM,eACJ,SACA,WAAW,CAAC,eACN;EACN,OAAO,IAAI,MAAM,SAAS,EACxB,IAAI,QAAQ,MAAM,UAAU;GAC1B,MAAM,QAAQ,QAAQ,IAAI,QAAQ,MAAM,SAAS;GAEjD,IAAI,OAAO,UAAU,YAEnB,OAAO,OAAO,GAAG,SAAoB;IACnC,IAAI,CAAC,UACH,IAAI,cAAc,QAEX;KACL,MAAM,kBAAkB;KACxB,sBAAsB;;IAI1B,IAAI;KACF,OAAO,MAAM,MAAM,MAAM,QAAQ,KAAK;aAC/B,KAAK;KAEZ,IAAI,CAAC,YAAY,CAAC,cAAc;MAC9B,MAAM,cAAc;MACpB,sBAAsB;MACtB,OAAO,MAAM,MAAM,MAAM,QAAQ,KAAK;;KAExC,MAAM;;;GAKZ,OAAO;KAEV,CAAC;;CAGJ,OAAO;EACL,cAAc,YAAY,QAAQ,aAAa;EAC/C,SAAS,YAAY,QAAQ,QAAQ;EACrC,MAAM,YAAY,QAAQ,KAAK;EAC/B,OAAO,YAAY,QAAQ,OAAO,KAAK;EACvC,YAAY,YAAY,QAAQ,WAAW;EAC3C,QAAQ,YAAY,QAAQ,OAAO;EACnC,IAAI,YAAY,QAAQ,GAAG;EAC3B,KAAK,YAAY,QAAQ,IAAI;EAC7B,QAAQ,YAAY,QAAQ,OAAO;EACnC,QAAQ,YAAY,QAAQ,OAAO;EACnC,YAAY,YAAY,QAAQ,WAAW;EAC3C,QAAQ,YAAY,QAAQ,OAAO;EACpC"}
@@ -2,8 +2,10 @@ import { FetcherOptions } from "../fetcher.js";
2
2
  import { IntlayerConfig } from "@intlayer/types/config";
3
3
 
4
4
  //#region src/getIntlayerAPI/oAuth.d.ts
5
- declare const getOAuthAPI: (intlayerConfig?: IntlayerConfig) => {
5
+ declare const getOAuthAPI: (authAPIOptions?: FetcherOptions, intlayerConfig?: IntlayerConfig) => {
6
6
  getOAuth2AccessToken: (otherOptions?: FetcherOptions) => Promise<GetOAuth2TokenResult>;
7
+ createCliSessionToken: (otherOptions?: FetcherOptions) => Promise<CreateCliSessionTokenResult>;
8
+ getCliSessionMe: (otherOptions?: FetcherOptions) => Promise<GetCliSessionMeResult>;
7
9
  };
8
10
  //#endregion
9
11
  export { getOAuthAPI };
@@ -1 +1 @@
1
- {"version":3,"file":"oAuth.d.ts","names":[],"sources":["../../../src/getIntlayerAPI/oAuth.ts"],"mappings":";;;;cAQa,WAAA,GAAe,cAAA,GAAgB,cAAA;wCAQQ,cAAA,KAAc,OAAA,CAAA,oBAAA;AAAA"}
1
+ {"version":3,"file":"oAuth.d.ts","names":[],"sources":["../../../src/getIntlayerAPI/oAuth.ts"],"mappings":";;;;cAUa,WAAA,GACX,cAAA,GAAgB,cAAA,EAChB,cAAA,GAAgB,cAAA;wCAQkC,cAAA,KAAc,OAAA,CAAA,oBAAA;yCAsBb,cAAA,KAAc,OAAA,CAAA,2BAAA;mCAYpB,cAAA,KAAc,OAAA,CAAA,qBAAA;AAAA"}
@@ -9,9 +9,13 @@ import { IntlayerConfig } from "@intlayer/types/config";
9
9
  * - Injects Authorization header for each request
10
10
  * - Refreshes token proactively when near expiry
11
11
  *
12
+ * When `sessionToken` is provided (a CLI session token starting with
13
+ * "clisession_"), it is used directly as the Bearer token without any OAuth2
14
+ * exchange — the backend validates it against the CliSessionToken collection.
15
+ *
12
16
  * The returned API matches the shape of getIntlayerAPI.
13
17
  */
14
- declare const getIntlayerAPIProxy: (baseAuthOptions?: FetcherOptions, intlayerConfig?: IntlayerConfig) => IntlayerAPI;
18
+ declare const getIntlayerAPIProxy: (baseAuthOptions?: FetcherOptions, intlayerConfig?: IntlayerConfig, sessionToken?: string) => IntlayerAPI;
15
19
  type IntlayerAPIProxy = ReturnType<typeof getIntlayerAPIProxy>;
16
20
  //#endregion
17
21
  export { IntlayerAPIProxy, getIntlayerAPIProxy };
@@ -1 +1 @@
1
- {"version":3,"file":"proxy.d.ts","names":[],"sources":["../../src/proxy.ts"],"mappings":";;;;;;;AAqDA;;;;;;cAAa,mBAAA,GACX,eAAA,GAAiB,cAAA,EACjB,cAAA,GAAiB,cAAA,KAChB,WAAA;AAAA,KAiGS,gBAAA,GAAmB,UAAA,QAAkB,mBAAA"}
1
+ {"version":3,"file":"proxy.d.ts","names":[],"sources":["../../src/proxy.ts"],"mappings":";;;;;;;AAyDA;;;;;;;;;;cAAa,mBAAA,GACX,eAAA,GAAiB,cAAA,EACjB,cAAA,GAAiB,cAAA,EACjB,YAAA,cACC,WAAA;AAAA,KAyHS,gBAAA,GAAmB,UAAA,QAAkB,mBAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intlayer/api",
3
- "version": "8.9.6-canary.0",
3
+ "version": "8.9.7",
4
4
  "private": false,
5
5
  "description": "SDK for interacting with the Intlayer API, enabling content auditing, and managing organizations, projects, and users.",
6
6
  "keywords": [
@@ -72,8 +72,8 @@
72
72
  "typecheck": "tsc --noEmit --project tsconfig.types.json"
73
73
  },
74
74
  "dependencies": {
75
- "@intlayer/config": "8.9.6-canary.0",
76
- "@intlayer/types": "8.9.6-canary.0",
75
+ "@intlayer/config": "8.9.7",
76
+ "@intlayer/types": "8.9.7",
77
77
  "defu": "6.1.7"
78
78
  },
79
79
  "devDependencies": {