@ampless/admin 0.2.0-alpha.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.
@@ -0,0 +1,75 @@
1
+ import { Config } from 'ampless';
2
+ import { AmplessOutputs, EffectiveSiteSettings, EffectiveThemeConfig, Ampless } from '@ampless/runtime';
3
+ import { L as Locale, D as Dictionary } from './i18n-ByHM_Bho.js';
4
+ export { A as AdminLocaleStrings, g as getDictionary, r as resolveLocale, t as translate } from './i18n-ByHM_Bho.js';
5
+ import * as _aws_amplify_adapter_nextjs from '@aws-amplify/adapter-nextjs';
6
+
7
+ /**
8
+ * Build a Next.js Amplify server runner from outputs. Returns the
9
+ * `runWithAmplifyServerContext` helper used by API routes / server
10
+ * components that need cookie-aware Amplify calls (auth, signed-URL
11
+ * media proxy).
12
+ */
13
+ declare function createAmplifyServer(outputs: AmplessOutputs): _aws_amplify_adapter_nextjs.NextServer.CreateServerRunnerOutput;
14
+ type AmplifyServer = ReturnType<typeof createAmplifyServer>;
15
+
16
+ interface ServerSession {
17
+ userId: string;
18
+ email: string;
19
+ groups: string[];
20
+ }
21
+
22
+ interface CreateAdminOpts {
23
+ outputs: AmplessOutputs;
24
+ cmsConfig: Config;
25
+ /**
26
+ * Optional pre-built ampless runtime instance for cross-package
27
+ * sharing. When omitted, admin doesn't build one — server pages
28
+ * (sites list / site edit / theme edit) still need
29
+ * `loadSiteSettings` / `loadThemeConfig`, so passing an `ampless`
30
+ * here lets admin reuse the same runtime your public pages already
31
+ * use. If not provided, the admin's server pages won't be able to
32
+ * load site settings.
33
+ */
34
+ ampless?: Ampless;
35
+ /**
36
+ * Locale for admin UI strings. Pass a string code ('en', 'ja') for a
37
+ * built-in dictionary, or an object literal to override specific
38
+ * strings. Defaults to English.
39
+ */
40
+ locale?: string | Record<string, unknown>;
41
+ }
42
+ interface Admin {
43
+ t(key: string, vars?: Record<string, string | number>): string;
44
+ readonly locale: Locale;
45
+ readonly dict: Dictionary;
46
+ getServerSession(): Promise<ServerSession | null>;
47
+ isAdmin(session: ServerSession | null): boolean;
48
+ isEditor(session: ServerSession | null): boolean;
49
+ readonly amplifyServer: AmplifyServer;
50
+ currentAdminSiteId(): Promise<string>;
51
+ adminSiteOptions(): Array<{
52
+ id: string;
53
+ name: string;
54
+ }>;
55
+ loadSiteSettings(siteId?: string): Promise<EffectiveSiteSettings>;
56
+ loadThemeConfig(siteId?: string): Promise<EffectiveThemeConfig>;
57
+ publicMediaUrl(input: string): string;
58
+ readonly outputs: AmplessOutputs;
59
+ readonly cmsConfig: Config;
60
+ readonly ampless: Ampless | null;
61
+ }
62
+ /**
63
+ * Wire up the admin UI from user-supplied config blobs. Returns an
64
+ * `Admin` instance containing everything page / API factories need —
65
+ * the same instance is shared by `<AdminLayout>`, `<PostForm>`,
66
+ * `<SiteSelector>`, `/api/media`, etc.
67
+ *
68
+ * If `opts.ampless` is omitted, server-side pages that depend on
69
+ * `loadSiteSettings` / `loadThemeConfig` (the sites edit and theme
70
+ * pages) will throw. Pass the same runtime instance you already use on
71
+ * the public side for shared caching.
72
+ */
73
+ declare function createAdmin(opts: CreateAdminOpts): Admin;
74
+
75
+ export { type Admin, type CreateAdminOpts, Dictionary, Locale, type ServerSession, createAdmin };
package/dist/index.js ADDED
@@ -0,0 +1,115 @@
1
+ import {
2
+ ADMIN_SITE_COOKIE,
3
+ createMedia,
4
+ getDictionary,
5
+ resolveLocale,
6
+ translate
7
+ } from "./chunk-TJR3ALRJ.js";
8
+
9
+ // src/lib/admin-site.ts
10
+ import { cookies } from "next/headers";
11
+ import { DEFAULT_SITE_ID, isMultiSite, siteFor } from "ampless";
12
+ function createAdminSite(cmsConfig) {
13
+ async function currentAdminSiteId() {
14
+ if (!isMultiSite(cmsConfig)) return DEFAULT_SITE_ID;
15
+ const sites = cmsConfig.sites ?? {};
16
+ const c = await cookies();
17
+ const v = c.get(ADMIN_SITE_COOKIE)?.value;
18
+ if (v && sites[v]) return v;
19
+ const first = Object.keys(sites)[0];
20
+ return first ?? DEFAULT_SITE_ID;
21
+ }
22
+ function adminSiteOptions() {
23
+ if (!isMultiSite(cmsConfig)) return [];
24
+ return Object.entries(cmsConfig.sites ?? {}).map(([id]) => ({
25
+ id,
26
+ name: siteFor(id, cmsConfig).name
27
+ }));
28
+ }
29
+ return { currentAdminSiteId, adminSiteOptions };
30
+ }
31
+
32
+ // src/lib/amplify-server.ts
33
+ import { createServerRunner } from "@aws-amplify/adapter-nextjs";
34
+ function createAmplifyServer(outputs) {
35
+ return createServerRunner({
36
+ config: outputs
37
+ });
38
+ }
39
+
40
+ // src/lib/auth-server.ts
41
+ import { cookies as cookies2 } from "next/headers";
42
+ import { fetchAuthSession, getCurrentUser } from "aws-amplify/auth/server";
43
+ function createAuthServer(server) {
44
+ const { runWithAmplifyServerContext } = server;
45
+ async function getServerSession() {
46
+ try {
47
+ const session = await runWithAmplifyServerContext({
48
+ nextServerContext: { cookies: cookies2 },
49
+ operation: async (ctx) => {
50
+ const authSession = await fetchAuthSession(ctx);
51
+ const user = await getCurrentUser(ctx);
52
+ const payload = authSession.tokens?.accessToken.payload;
53
+ const groups = payload?.["cognito:groups"] ?? [];
54
+ return {
55
+ userId: user.userId,
56
+ email: user.signInDetails?.loginId ?? "",
57
+ groups
58
+ };
59
+ }
60
+ });
61
+ return session;
62
+ } catch {
63
+ return null;
64
+ }
65
+ }
66
+ function isAdmin(session) {
67
+ return !!session && session.groups.includes("ampless-admin");
68
+ }
69
+ function isEditor(session) {
70
+ return !!session && (session.groups.includes("ampless-admin") || session.groups.includes("ampless-editor"));
71
+ }
72
+ return { getServerSession, isAdmin, isEditor };
73
+ }
74
+
75
+ // src/index.ts
76
+ function createAdmin(opts) {
77
+ const { outputs, cmsConfig, ampless: amplessIn, locale: localeOpt } = opts;
78
+ const { locale, dict } = resolveLocale(localeOpt);
79
+ const adminSite = createAdminSite(cmsConfig);
80
+ const amplifyServer = createAmplifyServer(outputs);
81
+ const auth = createAuthServer(amplifyServer);
82
+ const media = createMedia(outputs, cmsConfig);
83
+ const ampless = amplessIn ?? null;
84
+ function requireAmpless() {
85
+ if (!ampless) {
86
+ throw new Error(
87
+ "[@ampless/admin] createAdmin was called without an `ampless` runtime instance, but a method that needs one (loadSiteSettings / loadThemeConfig) was invoked. Pass `ampless` in the `createAdmin` options so admin can reuse your public-side runtime."
88
+ );
89
+ }
90
+ return ampless;
91
+ }
92
+ return {
93
+ t: (key, vars) => translate(dict, key, vars),
94
+ locale,
95
+ dict,
96
+ getServerSession: auth.getServerSession,
97
+ isAdmin: auth.isAdmin,
98
+ isEditor: auth.isEditor,
99
+ amplifyServer,
100
+ currentAdminSiteId: adminSite.currentAdminSiteId,
101
+ adminSiteOptions: adminSite.adminSiteOptions,
102
+ loadSiteSettings: (siteId) => requireAmpless().loadSiteSettings(siteId),
103
+ loadThemeConfig: (siteId) => requireAmpless().loadThemeConfig(siteId),
104
+ publicMediaUrl: media.publicMediaUrl,
105
+ outputs,
106
+ cmsConfig,
107
+ ampless
108
+ };
109
+ }
110
+ export {
111
+ createAdmin,
112
+ getDictionary,
113
+ resolveLocale,
114
+ translate
115
+ };
@@ -0,0 +1,90 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { Admin } from '../index.js';
3
+ import { ThemeManifest } from 'ampless';
4
+ import '@ampless/runtime';
5
+ import '../i18n-ByHM_Bho.js';
6
+ import '@aws-amplify/adapter-nextjs';
7
+
8
+ /**
9
+ * Build the admin layout component. Wraps every admin route with:
10
+ *
11
+ * - An auth gate (`redirect('/login')` if the visitor isn't in the
12
+ * `ampless-admin` or `ampless-editor` Cognito group).
13
+ * - The admin sidebar (with optional multi-site selector).
14
+ * - An i18n provider hydrated from the resolved locale dict.
15
+ * - A client-side `AdminProviders` shell that configures the Amplify
16
+ * SDK and installs the admin's posts / kv providers once on mount.
17
+ */
18
+ declare function createAdminLayout(admin: Admin): ({ children }: {
19
+ children: React.ReactNode;
20
+ }) => Promise<react_jsx_runtime.JSX.Element>;
21
+
22
+ declare function AdminDashboard(): react_jsx_runtime.JSX.Element;
23
+ /**
24
+ * Admin home / dashboard. Lists post counts. Marked client-side because
25
+ * it reads from the AppSync client directly (no server-rendered query
26
+ * yet — listed posts come from Amplify SDK at mount time).
27
+ */
28
+ declare function createAdminDashboardPage(_admin: unknown): typeof AdminDashboard;
29
+
30
+ declare function PostsList(): react_jsx_runtime.JSX.Element;
31
+ declare function createPostsListPage(_admin: unknown): typeof PostsList;
32
+
33
+ declare function NewPostPage(): react_jsx_runtime.JSX.Element;
34
+ declare function createNewPostPage(_admin: unknown): typeof NewPostPage;
35
+
36
+ declare function EditPostPage({ params }: {
37
+ params: Promise<{
38
+ postId: string;
39
+ }>;
40
+ }): react_jsx_runtime.JSX.Element;
41
+ declare function createEditPostPage(_admin: unknown): typeof EditPostPage;
42
+
43
+ declare function MediaPage(): react_jsx_runtime.JSX.Element;
44
+ declare function createMediaPage(_admin: unknown): typeof MediaPage;
45
+
46
+ /**
47
+ * Sites overview. In single-site mode there's exactly one row
48
+ * (`default`); in multi-site mode each declared site shows up. Adding
49
+ * / removing sites is still done in cms.config.ts (the domains[] field
50
+ * is wired to DNS / SSL outside ampless's reach).
51
+ */
52
+ declare function createSitesListPage(admin: Admin): () => Promise<react_jsx_runtime.JSX.Element>;
53
+
54
+ interface Props$1 {
55
+ params: Promise<{
56
+ siteId: string;
57
+ }>;
58
+ }
59
+ /**
60
+ * Server-rendered: pre-fills the form with the merged settings (so the
61
+ * editor sees what's currently effective). The form itself writes
62
+ * directly to KvStore via the AppSync client; no Server Action needed.
63
+ */
64
+ declare function createSiteEditPage(admin: Admin): ({ params }: Props$1) => Promise<react_jsx_runtime.JSX.Element>;
65
+
66
+ interface Props {
67
+ params: Promise<{
68
+ siteId: string;
69
+ }>;
70
+ }
71
+ interface ThemeListEntry {
72
+ name: string;
73
+ manifest: ThemeManifest;
74
+ }
75
+ /**
76
+ * Theme admin: pick which installed theme is active for this site, plus
77
+ * edit the active theme's customizable manifest fields. Reads through
78
+ * the S3 site-settings cache (same path the public site uses) so the
79
+ * admin sees the same effective state visitors see.
80
+ *
81
+ * The full `themeList` (one entry per installed theme manifest) is
82
+ * passed in because the registry lives in the user's project — admin
83
+ * stays agnostic of which themes a project happens to install.
84
+ */
85
+ declare function createSiteThemePage(admin: Admin, themeList: ReadonlyArray<ThemeListEntry>): ({ params }: Props) => Promise<react_jsx_runtime.JSX.Element>;
86
+
87
+ declare function LoginPage(): react_jsx_runtime.JSX.Element;
88
+ declare function createLoginPage(_admin: unknown): typeof LoginPage;
89
+
90
+ export { createAdminDashboardPage, createAdminLayout, createEditPostPage, createLoginPage, createMediaPage, createNewPostPage, createPostsListPage, createSiteEditPage, createSiteThemePage, createSitesListPage };