@joai/sites 0.1.4 → 0.2.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/admin.d.mts CHANGED
@@ -1,6 +1,7 @@
1
1
  'use client';
2
2
  import * as _$react from "react";
3
3
  import { AppEnv } from "@joai/core";
4
+
4
5
  //#region src/session.d.ts
5
6
  type SiteEditingSessionConfig = {
6
7
  env?: AppEnv;
package/dist/admin.mjs CHANGED
@@ -1,49 +1,66 @@
1
1
  'use client';
2
- import { getAuthFragmentToken } from "@joai/sdk";
2
+ import { beginBrowserAppAuth, completeBrowserAppAuth } from "@joai/sdk";
3
3
  import { useTranslations } from "next-intl";
4
4
  import { useEffect, useState } from "react";
5
- import { getLoginUrl } from "@joai/core";
6
5
  import { createSessionTokenStore } from "@joai/react";
7
6
  import { jsx } from "react/jsx-runtime";
8
7
  //#region src/session.ts
9
- function createSiteLoginUrl(config, redirect) {
10
- const returnUrl = new URL(redirect);
11
- returnUrl.searchParams.set("platform", "app");
12
- return getLoginUrl(config.env ?? "mainnet", returnUrl.toString(), {
13
- team: config.team,
14
- brand: config.brand
15
- });
16
- }
17
8
  function createSiteSessionStore(config) {
18
9
  return createSessionTokenStore(config.sessionStorageKey);
19
10
  }
20
- async function exchangeSiteEditingSession(config, handoffToken) {
21
- const { createClient } = await import("@joai/sdk");
22
- const response = await createClient({
23
- env: config.env ?? "mainnet",
24
- team: config.team,
25
- cache: { enabled: false }
26
- }).auth.exchangeNativeSession(handoffToken);
27
- if (!response.ok || !response.data?.token) throw new Error("session_exchange_failed");
28
- if (!createSiteSessionStore(config).set(response.data.token)) throw new Error("session_store_failed");
29
- return response.data.token;
30
- }
31
11
  //#endregion
32
12
  //#region src/admin-login.tsx
13
+ const safeReturnPath = (value, fallback) => {
14
+ if (!value || value.includes("\\")) return fallback;
15
+ try {
16
+ const target = new URL(value, window.location.origin);
17
+ if (target.origin !== window.location.origin) return fallback;
18
+ return `${target.pathname}${target.search}${target.hash}`;
19
+ } catch {
20
+ return fallback;
21
+ }
22
+ };
33
23
  function SiteAdminLoginClient({ config, redirectTo = "/", className }) {
34
24
  const t = useTranslations("sites");
35
25
  const [message, setMessage] = useState(t("loginRedirecting"));
36
26
  useEffect(() => {
37
- const loginUrl = () => createSiteLoginUrl(config, `${window.location.origin}${window.location.pathname}`);
38
- const token = getAuthFragmentToken(window.location.href);
39
- if (!token) {
40
- window.location.replace(loginUrl());
41
- return;
42
- }
43
- window.history.replaceState(null, "", `${window.location.pathname}${window.location.search}`);
44
- exchangeSiteEditingSession(config, token).then(() => window.location.replace(redirectTo)).catch(() => {
27
+ const current = new URL(window.location.href);
28
+ const returnTo = safeReturnPath(current.searchParams.get("return"), redirectTo);
29
+ const storageKey = `${config.sessionStorageKey}:auth`;
30
+ const begin = async () => {
31
+ current.searchParams.set("return", returnTo);
32
+ const url = await beginBrowserAppAuth({
33
+ callbackUrl: current.toString(),
34
+ env: config.env,
35
+ team: config.team,
36
+ brand: config.brand,
37
+ storageKey
38
+ });
39
+ window.location.replace(url);
40
+ };
41
+ const complete = async () => {
42
+ const token = await completeBrowserAppAuth({
43
+ url: window.location.href,
44
+ env: config.env,
45
+ storageKey
46
+ });
47
+ if (!token) {
48
+ await begin();
49
+ return;
50
+ }
51
+ if (!createSiteSessionStore(config).set(token)) throw new Error("session_store_failed");
52
+ const clean = new URL(window.location.href);
53
+ clean.searchParams.delete("code");
54
+ clean.searchParams.delete("state");
55
+ clean.searchParams.set("return", returnTo);
56
+ window.history.replaceState(null, "", `${clean.pathname}${clean.search}${clean.hash}`);
57
+ window.location.replace(returnTo);
58
+ };
59
+ complete().catch(() => {
45
60
  setMessage(t("loginFailed"));
46
- window.setTimeout(() => window.location.replace(loginUrl()), 1200);
61
+ window.setTimeout(() => {
62
+ begin().catch(() => setMessage(t("loginFailed")));
63
+ }, 1200);
47
64
  });
48
65
  }, [
49
66
  config,
package/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
+ import * as _$_joai_react0 from "@joai/react";
1
2
  import * as _$_joai_core0 from "@joai/core";
2
3
  import { AppEnv, Content, ContentDefinition, ContentValue, Site } from "@joai/core";
3
- import * as _$_joai_react0 from "@joai/react";
4
4
  import { ComponentType, ReactNode } from "react";
5
5
 
6
6
  //#region src/types.d.ts
@@ -134,7 +134,6 @@ type SiteEditingSessionConfig = {
134
134
  };
135
135
  declare function createSiteLoginUrl(config: SiteEditingSessionConfig, redirect: string): string;
136
136
  declare function createSiteSessionStore(config: SiteEditingSessionConfig): _$_joai_react0.SessionTokenStore;
137
- declare function exchangeSiteEditingSession(config: SiteEditingSessionConfig, handoffToken: string): Promise<string>;
138
137
  declare function getSiteAdminLoginPath(config: SiteEditingSessionConfig): string;
139
138
  //#endregion
140
139
  //#region src/theme.d.ts
@@ -253,4 +252,4 @@ declare function buildLlmsTxt(input: {
253
252
  contact?: string;
254
253
  }): string;
255
254
  //#endregion
256
- export { BuildSiteMetadataInput, LlmsTxtPage, LocalBusinessJsonLdInput, ResolveSiteOptions, ResolvedSiteContext, RevalidateHandlerOptions, SiteEditingSessionConfig, SiteHostConfig, SiteMetadataResult, SiteRobotsResult, SiteSitemapEntry, SiteTheme, SiteThemeLayoutProps, SiteThemeLocalConfig, SiteThemeMetadata, SiteThemePage, SiteThemePageProps, SiteThemePath, buildLlmsTxt, buildLocalBusinessJsonLd, buildSiteMetadata, buildSiteRobots, buildSiteSitemap, createRevalidateHandler, createSiteLoginUrl, createSiteSessionStore, createThemeRegistry, defineSiteTheme, exchangeSiteEditingSession, getSiteAdminLoginPath, getSiteContentSlug, getSiteThemeKey, getThemePage, listThemeSitemapPaths, loadSiteContent, normalizeSiteHost, normalizeThemePath, resolveSiteByHost, resolveSiteContext, serializeJsonLd };
255
+ export { BuildSiteMetadataInput, LlmsTxtPage, LocalBusinessJsonLdInput, ResolveSiteOptions, ResolvedSiteContext, RevalidateHandlerOptions, SiteEditingSessionConfig, SiteHostConfig, SiteMetadataResult, SiteRobotsResult, SiteSitemapEntry, SiteTheme, SiteThemeLayoutProps, SiteThemeLocalConfig, SiteThemeMetadata, SiteThemePage, SiteThemePageProps, SiteThemePath, buildLlmsTxt, buildLocalBusinessJsonLd, buildSiteMetadata, buildSiteRobots, buildSiteSitemap, createRevalidateHandler, createSiteLoginUrl, createSiteSessionStore, createThemeRegistry, defineSiteTheme, getSiteAdminLoginPath, getSiteContentSlug, getSiteThemeKey, getThemePage, listThemeSitemapPaths, loadSiteContent, normalizeSiteHost, normalizeThemePath, resolveSiteByHost, resolveSiteContext, serializeJsonLd };
package/dist/index.mjs CHANGED
@@ -1,6 +1,5 @@
1
1
  import { createClient } from "@joai/sdk";
2
2
  import { revalidatePath, revalidateTag } from "next/cache";
3
- import { getLoginUrl } from "@joai/core";
4
3
  import { createSessionTokenStore } from "@joai/react";
5
4
  //#region src/settings.ts
6
5
  const asString = (value) => {
@@ -105,27 +104,13 @@ function createRevalidateHandler(options) {
105
104
  //#endregion
106
105
  //#region src/session.ts
107
106
  function createSiteLoginUrl(config, redirect) {
108
- const returnUrl = new URL(redirect);
109
- returnUrl.searchParams.set("platform", "app");
110
- return getLoginUrl(config.env ?? "mainnet", returnUrl.toString(), {
111
- team: config.team,
112
- brand: config.brand
113
- });
107
+ const url = new URL(getSiteAdminLoginPath(config), "https://site.invalid");
108
+ url.searchParams.set("return", redirect);
109
+ return `${url.pathname}${url.search}`;
114
110
  }
115
111
  function createSiteSessionStore(config) {
116
112
  return createSessionTokenStore(config.sessionStorageKey);
117
113
  }
118
- async function exchangeSiteEditingSession(config, handoffToken) {
119
- const { createClient } = await import("@joai/sdk");
120
- const response = await createClient({
121
- env: config.env ?? "mainnet",
122
- team: config.team,
123
- cache: { enabled: false }
124
- }).auth.exchangeNativeSession(handoffToken);
125
- if (!response.ok || !response.data?.token) throw new Error("session_exchange_failed");
126
- if (!createSiteSessionStore(config).set(response.data.token)) throw new Error("session_store_failed");
127
- return response.data.token;
128
- }
129
114
  function getSiteAdminLoginPath(config) {
130
115
  return config.loginPath ?? "/admin-login";
131
116
  }
@@ -262,4 +247,4 @@ function buildLlmsTxt(input) {
262
247
  return lines.join("\n");
263
248
  }
264
249
  //#endregion
265
- export { buildLlmsTxt, buildLocalBusinessJsonLd, buildSiteMetadata, buildSiteRobots, buildSiteSitemap, createRevalidateHandler, createSiteLoginUrl, createSiteSessionStore, createThemeRegistry, defineSiteTheme, exchangeSiteEditingSession, getSiteAdminLoginPath, getSiteContentSlug, getSiteThemeKey, getThemePage, listThemeSitemapPaths, loadSiteContent, normalizeSiteHost, normalizeThemePath, resolveSiteByHost, resolveSiteContext, serializeJsonLd };
250
+ export { buildLlmsTxt, buildLocalBusinessJsonLd, buildSiteMetadata, buildSiteRobots, buildSiteSitemap, createRevalidateHandler, createSiteLoginUrl, createSiteSessionStore, createThemeRegistry, defineSiteTheme, getSiteAdminLoginPath, getSiteContentSlug, getSiteThemeKey, getThemePage, listThemeSitemapPaths, loadSiteContent, normalizeSiteHost, normalizeThemePath, resolveSiteByHost, resolveSiteContext, serializeJsonLd };
@@ -1,5 +1,5 @@
1
- import { AppEnv } from "@joai/core";
2
1
  import * as _$_joai_react0 from "@joai/react";
2
+ import { AppEnv } from "@joai/core";
3
3
 
4
4
  //#region src/session.d.ts
5
5
  type SiteEditingSessionConfig = {
@@ -11,7 +11,6 @@ type SiteEditingSessionConfig = {
11
11
  };
12
12
  declare function createSiteLoginUrl(config: SiteEditingSessionConfig, redirect: string): string;
13
13
  declare function createSiteSessionStore(config: SiteEditingSessionConfig): _$_joai_react0.SessionTokenStore;
14
- declare function exchangeSiteEditingSession(config: SiteEditingSessionConfig, handoffToken: string): Promise<string>;
15
14
  declare function getSiteAdminLoginPath(config: SiteEditingSessionConfig): string;
16
15
  //#endregion
17
- export { SiteEditingSessionConfig, createSiteLoginUrl, createSiteSessionStore, exchangeSiteEditingSession, getSiteAdminLoginPath };
16
+ export { SiteEditingSessionConfig, createSiteLoginUrl, createSiteSessionStore, getSiteAdminLoginPath };
package/dist/session.mjs CHANGED
@@ -1,30 +1,15 @@
1
- import { getLoginUrl } from "@joai/core";
2
1
  import { createSessionTokenStore } from "@joai/react";
3
2
  //#region src/session.ts
4
3
  function createSiteLoginUrl(config, redirect) {
5
- const returnUrl = new URL(redirect);
6
- returnUrl.searchParams.set("platform", "app");
7
- return getLoginUrl(config.env ?? "mainnet", returnUrl.toString(), {
8
- team: config.team,
9
- brand: config.brand
10
- });
4
+ const url = new URL(getSiteAdminLoginPath(config), "https://site.invalid");
5
+ url.searchParams.set("return", redirect);
6
+ return `${url.pathname}${url.search}`;
11
7
  }
12
8
  function createSiteSessionStore(config) {
13
9
  return createSessionTokenStore(config.sessionStorageKey);
14
10
  }
15
- async function exchangeSiteEditingSession(config, handoffToken) {
16
- const { createClient } = await import("@joai/sdk");
17
- const response = await createClient({
18
- env: config.env ?? "mainnet",
19
- team: config.team,
20
- cache: { enabled: false }
21
- }).auth.exchangeNativeSession(handoffToken);
22
- if (!response.ok || !response.data?.token) throw new Error("session_exchange_failed");
23
- if (!createSiteSessionStore(config).set(response.data.token)) throw new Error("session_store_failed");
24
- return response.data.token;
25
- }
26
11
  function getSiteAdminLoginPath(config) {
27
12
  return config.loginPath ?? "/admin-login";
28
13
  }
29
14
  //#endregion
30
- export { createSiteLoginUrl, createSiteSessionStore, exchangeSiteEditingSession, getSiteAdminLoginPath };
15
+ export { createSiteLoginUrl, createSiteSessionStore, getSiteAdminLoginPath };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@joai/sites",
3
- "version": "0.1.4",
3
+ "version": "0.2.0",
4
4
  "description": "Shared helpers for JoAi-managed multi-tenant websites",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -35,9 +35,9 @@
35
35
  "test": "jest --config jest.config.js"
36
36
  },
37
37
  "dependencies": {
38
- "@joai/core": "^5.4.5",
39
- "@joai/react": "^1.0.5",
40
- "@joai/sdk": "^13.1.3"
38
+ "@joai/core": "^5.4.6",
39
+ "@joai/react": "^2.0.0",
40
+ "@joai/sdk": "^14.2.0"
41
41
  },
42
42
  "peerDependencies": {
43
43
  "next": ">=15.0.0",
@@ -49,7 +49,7 @@
49
49
  "@types/jest": "^30.0.0",
50
50
  "@types/react": "^19.2.14",
51
51
  "jest": "^30.3.0",
52
- "next": "^16.2.0",
52
+ "next": "^16.4.5",
53
53
  "next-intl": "^4.8.3",
54
54
  "react": "^19.2.4",
55
55
  "react-dom": "^19.2.4",