@flyo/nitro-next 1.1.0 → 1.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/server.d.mts CHANGED
@@ -1,5 +1,7 @@
1
+ import * as react from 'react';
1
2
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { Configuration, ConfigResponse, PagesApi, EntitiesApi, Page, Block } from '@flyo/nitro-typescript';
3
+ import { Metadata } from 'next';
4
+ import { Configuration, ConfigResponse, PagesApi, EntitiesApi, Entity, Page, Block } from '@flyo/nitro-typescript';
3
5
 
4
6
  declare const initNitro: ({ accessToken, lang, components, showMissingComponentAlert }: {
5
7
  accessToken: string;
@@ -10,6 +12,26 @@ declare const initNitro: ({ accessToken, lang, components, showMissingComponentA
10
12
  declare const getNitroConfig: () => Promise<ConfigResponse>;
11
13
  declare function getNitroPages(): PagesApi;
12
14
  declare function getNitroEntities(): EntitiesApi;
15
+ /**
16
+ * Route params type for Next.js catch-all routes
17
+ */
18
+ type RouteParams = {
19
+ params: Promise<{
20
+ slug?: string[];
21
+ }>;
22
+ };
23
+ /**
24
+ * Generic route params type for entity routes
25
+ * Allows any param structure from Next.js app router
26
+ */
27
+ type EntityRouteParams<T = any> = {
28
+ params: Promise<T>;
29
+ };
30
+ /**
31
+ * Entity resolver function type
32
+ * Users provide this to resolve entities from their route params
33
+ */
34
+ type EntityResolver<T = any> = (params: Promise<T>) => Promise<Entity>;
13
35
  /**
14
36
  * NitroPage component renders all blocks from a Flyo page
15
37
  */
@@ -19,5 +41,104 @@ declare function NitroPage({ page, }: {
19
41
  declare function NitroBlock({ block, }: {
20
42
  block: Block;
21
43
  }): react_jsx_runtime.JSX.Element | null;
44
+ /**
45
+ * Default page route handler for Nitro pages
46
+ * Can be re-exported directly from Next.js app routes
47
+ *
48
+ * @example
49
+ * ```ts
50
+ * // app/[[...slug]]/page.tsx
51
+ * export { nitroPageRoute as default } from '@flyo/nitro-next/server';
52
+ * ```
53
+ */
54
+ declare function nitroPageRoute(props: RouteParams): Promise<react_jsx_runtime.JSX.Element>;
55
+ /**
56
+ * Generate metadata for Nitro pages
57
+ * Provides basic meta tags based on Flyo page data
58
+ * Can be re-exported directly from Next.js app routes
59
+ *
60
+ * @example
61
+ * ```ts
62
+ * // app/[[...slug]]/page.tsx
63
+ * export { nitroPageGenerateMetadata as generateMetadata } from '@flyo/nitro-next/server';
64
+ * ```
65
+ */
66
+ declare function nitroPageGenerateMetadata(props: RouteParams): Promise<Metadata>;
67
+ /**
68
+ * Generate static params for all Nitro pages
69
+ * Enables static site generation (SSG) for all pages
70
+ * Can be re-exported directly from Next.js app routes
71
+ *
72
+ * @example
73
+ * ```ts
74
+ * // app/[[...slug]]/page.tsx
75
+ * export { nitroPageGenerateStaticParams as generateStaticParams } from '@flyo/nitro-next/server';
76
+ * ```
77
+ */
78
+ declare function nitroPageGenerateStaticParams(): Promise<{
79
+ slug: string[] | undefined;
80
+ }[]>;
81
+ /**
82
+ * Default entity route handler with custom resolver
83
+ * Flexible solution that works with any route param structure
84
+ *
85
+ * @example
86
+ * ```ts
87
+ * // app/blog/[slug]/page.tsx
88
+ * const resolver = async (params: Promise<{ slug: string }>) => {
89
+ * const { slug } = await params;
90
+ * return getNitroEntities().entityBySlug({ slug, typeId: 123 });
91
+ * };
92
+ *
93
+ * export default (props) => nitroEntityRoute(props, {
94
+ * resolver,
95
+ * render: (entity) => <h1>{entity.entity?.entity_title}</h1>
96
+ * });
97
+ * ```
98
+ *
99
+ * @example
100
+ * ```ts
101
+ * // app/items/[uniqueid]/page.tsx
102
+ * const resolver = async (params: Promise<{ uniqueid: string }>) => {
103
+ * const { uniqueid } = await params;
104
+ * return getNitroEntities().entityByUniqueid({ uniqueid });
105
+ * };
106
+ *
107
+ * export default (props) => nitroEntityRoute(props, { resolver });
108
+ * ```
109
+ *
110
+ * @example
111
+ * ```ts
112
+ * // app/custom/[whatever]/page.tsx
113
+ * const resolver = async (params: Promise<{ whatever: string }>) => {
114
+ * const { whatever } = await params;
115
+ * return getNitroEntities().entityBySlug({ slug: whatever });
116
+ * };
117
+ *
118
+ * export default (props) => nitroEntityRoute(props, { resolver });
119
+ * ```
120
+ */
121
+ declare function nitroEntityRoute<T = any>(props: EntityRouteParams<T>, options: {
122
+ resolver: EntityResolver<T>;
123
+ render?: (entity: Entity) => React.ReactNode;
124
+ }): Promise<string | number | bigint | boolean | react_jsx_runtime.JSX.Element | Iterable<react.ReactNode> | null | undefined>;
125
+ /**
126
+ * Generate metadata for Nitro entities with custom resolver
127
+ * Works with any route param structure
128
+ *
129
+ * @example
130
+ * ```ts
131
+ * // app/blog/[slug]/page.tsx
132
+ * const resolver = async (params: Promise<{ slug: string }>) => {
133
+ * const { slug } = await params;
134
+ * return getNitroEntities().entityBySlug({ slug, typeId: 123 });
135
+ * };
136
+ *
137
+ * export const generateMetadata = (props) => nitroEntityGenerateMetadata(props, { resolver });
138
+ * ```
139
+ */
140
+ declare function nitroEntityGenerateMetadata<T = any>(props: EntityRouteParams<T>, options: {
141
+ resolver: EntityResolver<T>;
142
+ }): Promise<Metadata>;
22
143
 
23
- export { NitroBlock, NitroPage, getNitroConfig, getNitroEntities, getNitroPages, initNitro };
144
+ export { type EntityResolver, NitroBlock, NitroPage, getNitroConfig, getNitroEntities, getNitroPages, initNitro, nitroEntityGenerateMetadata, nitroEntityRoute, nitroPageGenerateMetadata, nitroPageGenerateStaticParams, nitroPageRoute };
package/dist/server.d.ts CHANGED
@@ -1,5 +1,7 @@
1
+ import * as react from 'react';
1
2
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { Configuration, ConfigResponse, PagesApi, EntitiesApi, Page, Block } from '@flyo/nitro-typescript';
3
+ import { Metadata } from 'next';
4
+ import { Configuration, ConfigResponse, PagesApi, EntitiesApi, Entity, Page, Block } from '@flyo/nitro-typescript';
3
5
 
4
6
  declare const initNitro: ({ accessToken, lang, components, showMissingComponentAlert }: {
5
7
  accessToken: string;
@@ -10,6 +12,26 @@ declare const initNitro: ({ accessToken, lang, components, showMissingComponentA
10
12
  declare const getNitroConfig: () => Promise<ConfigResponse>;
11
13
  declare function getNitroPages(): PagesApi;
12
14
  declare function getNitroEntities(): EntitiesApi;
15
+ /**
16
+ * Route params type for Next.js catch-all routes
17
+ */
18
+ type RouteParams = {
19
+ params: Promise<{
20
+ slug?: string[];
21
+ }>;
22
+ };
23
+ /**
24
+ * Generic route params type for entity routes
25
+ * Allows any param structure from Next.js app router
26
+ */
27
+ type EntityRouteParams<T = any> = {
28
+ params: Promise<T>;
29
+ };
30
+ /**
31
+ * Entity resolver function type
32
+ * Users provide this to resolve entities from their route params
33
+ */
34
+ type EntityResolver<T = any> = (params: Promise<T>) => Promise<Entity>;
13
35
  /**
14
36
  * NitroPage component renders all blocks from a Flyo page
15
37
  */
@@ -19,5 +41,104 @@ declare function NitroPage({ page, }: {
19
41
  declare function NitroBlock({ block, }: {
20
42
  block: Block;
21
43
  }): react_jsx_runtime.JSX.Element | null;
44
+ /**
45
+ * Default page route handler for Nitro pages
46
+ * Can be re-exported directly from Next.js app routes
47
+ *
48
+ * @example
49
+ * ```ts
50
+ * // app/[[...slug]]/page.tsx
51
+ * export { nitroPageRoute as default } from '@flyo/nitro-next/server';
52
+ * ```
53
+ */
54
+ declare function nitroPageRoute(props: RouteParams): Promise<react_jsx_runtime.JSX.Element>;
55
+ /**
56
+ * Generate metadata for Nitro pages
57
+ * Provides basic meta tags based on Flyo page data
58
+ * Can be re-exported directly from Next.js app routes
59
+ *
60
+ * @example
61
+ * ```ts
62
+ * // app/[[...slug]]/page.tsx
63
+ * export { nitroPageGenerateMetadata as generateMetadata } from '@flyo/nitro-next/server';
64
+ * ```
65
+ */
66
+ declare function nitroPageGenerateMetadata(props: RouteParams): Promise<Metadata>;
67
+ /**
68
+ * Generate static params for all Nitro pages
69
+ * Enables static site generation (SSG) for all pages
70
+ * Can be re-exported directly from Next.js app routes
71
+ *
72
+ * @example
73
+ * ```ts
74
+ * // app/[[...slug]]/page.tsx
75
+ * export { nitroPageGenerateStaticParams as generateStaticParams } from '@flyo/nitro-next/server';
76
+ * ```
77
+ */
78
+ declare function nitroPageGenerateStaticParams(): Promise<{
79
+ slug: string[] | undefined;
80
+ }[]>;
81
+ /**
82
+ * Default entity route handler with custom resolver
83
+ * Flexible solution that works with any route param structure
84
+ *
85
+ * @example
86
+ * ```ts
87
+ * // app/blog/[slug]/page.tsx
88
+ * const resolver = async (params: Promise<{ slug: string }>) => {
89
+ * const { slug } = await params;
90
+ * return getNitroEntities().entityBySlug({ slug, typeId: 123 });
91
+ * };
92
+ *
93
+ * export default (props) => nitroEntityRoute(props, {
94
+ * resolver,
95
+ * render: (entity) => <h1>{entity.entity?.entity_title}</h1>
96
+ * });
97
+ * ```
98
+ *
99
+ * @example
100
+ * ```ts
101
+ * // app/items/[uniqueid]/page.tsx
102
+ * const resolver = async (params: Promise<{ uniqueid: string }>) => {
103
+ * const { uniqueid } = await params;
104
+ * return getNitroEntities().entityByUniqueid({ uniqueid });
105
+ * };
106
+ *
107
+ * export default (props) => nitroEntityRoute(props, { resolver });
108
+ * ```
109
+ *
110
+ * @example
111
+ * ```ts
112
+ * // app/custom/[whatever]/page.tsx
113
+ * const resolver = async (params: Promise<{ whatever: string }>) => {
114
+ * const { whatever } = await params;
115
+ * return getNitroEntities().entityBySlug({ slug: whatever });
116
+ * };
117
+ *
118
+ * export default (props) => nitroEntityRoute(props, { resolver });
119
+ * ```
120
+ */
121
+ declare function nitroEntityRoute<T = any>(props: EntityRouteParams<T>, options: {
122
+ resolver: EntityResolver<T>;
123
+ render?: (entity: Entity) => React.ReactNode;
124
+ }): Promise<string | number | bigint | boolean | react_jsx_runtime.JSX.Element | Iterable<react.ReactNode> | null | undefined>;
125
+ /**
126
+ * Generate metadata for Nitro entities with custom resolver
127
+ * Works with any route param structure
128
+ *
129
+ * @example
130
+ * ```ts
131
+ * // app/blog/[slug]/page.tsx
132
+ * const resolver = async (params: Promise<{ slug: string }>) => {
133
+ * const { slug } = await params;
134
+ * return getNitroEntities().entityBySlug({ slug, typeId: 123 });
135
+ * };
136
+ *
137
+ * export const generateMetadata = (props) => nitroEntityGenerateMetadata(props, { resolver });
138
+ * ```
139
+ */
140
+ declare function nitroEntityGenerateMetadata<T = any>(props: EntityRouteParams<T>, options: {
141
+ resolver: EntityResolver<T>;
142
+ }): Promise<Metadata>;
22
143
 
23
- export { NitroBlock, NitroPage, getNitroConfig, getNitroEntities, getNitroPages, initNitro };
144
+ export { type EntityResolver, NitroBlock, NitroPage, getNitroConfig, getNitroEntities, getNitroPages, initNitro, nitroEntityGenerateMetadata, nitroEntityRoute, nitroPageGenerateMetadata, nitroPageGenerateStaticParams, nitroPageRoute };
package/dist/server.js CHANGED
@@ -25,10 +25,16 @@ __export(server_exports, {
25
25
  getNitroConfig: () => getNitroConfig,
26
26
  getNitroEntities: () => getNitroEntities,
27
27
  getNitroPages: () => getNitroPages,
28
- initNitro: () => initNitro
28
+ initNitro: () => initNitro,
29
+ nitroEntityGenerateMetadata: () => nitroEntityGenerateMetadata,
30
+ nitroEntityRoute: () => nitroEntityRoute,
31
+ nitroPageGenerateMetadata: () => nitroPageGenerateMetadata,
32
+ nitroPageGenerateStaticParams: () => nitroPageGenerateStaticParams,
33
+ nitroPageRoute: () => nitroPageRoute
29
34
  });
30
35
  module.exports = __toCommonJS(server_exports);
31
36
  var import_react = require("react");
37
+ var import_navigation = require("next/navigation");
32
38
  var import_nitro_typescript = require("@flyo/nitro-typescript");
33
39
  var import_jsx_runtime = require("react/jsx-runtime");
34
40
  var globalConfiguration = null;
@@ -58,6 +64,31 @@ function getNitroPages() {
58
64
  function getNitroEntities() {
59
65
  return new import_nitro_typescript.EntitiesApi(globalConfiguration);
60
66
  }
67
+ var resolveNitroRoute = (0, import_react.cache)(async ({ params }) => {
68
+ const { slug } = await params;
69
+ const path = slug?.join("/") ?? "";
70
+ const cfg = await getNitroConfig();
71
+ if (!cfg.pages?.includes(path)) {
72
+ (0, import_navigation.notFound)();
73
+ }
74
+ const page = await getNitroPages().page({ slug: path }).catch((error) => {
75
+ console.error("Error fetching page:", path, error);
76
+ (0, import_navigation.notFound)();
77
+ });
78
+ if (!page) {
79
+ (0, import_navigation.notFound)();
80
+ }
81
+ return { page, path, cfg };
82
+ });
83
+ function createCachedEntityResolver(resolver) {
84
+ return (0, import_react.cache)(async ({ params }) => {
85
+ const entity = await resolver(params);
86
+ if (!entity) {
87
+ (0, import_navigation.notFound)();
88
+ }
89
+ return entity;
90
+ });
91
+ }
61
92
  function NitroPage({
62
93
  page
63
94
  }) {
@@ -91,6 +122,73 @@ function NitroBlock({
91
122
  }
92
123
  return null;
93
124
  }
125
+ async function nitroPageRoute(props) {
126
+ const { page } = await resolveNitroRoute(props);
127
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(NitroPage, { page });
128
+ }
129
+ async function nitroPageGenerateMetadata(props) {
130
+ const { page } = await resolveNitroRoute(props);
131
+ const meta = page.meta_json;
132
+ const title = meta?.title ?? page.title ?? "Page";
133
+ const description = meta?.description ?? "";
134
+ const image = meta?.image ?? "";
135
+ return {
136
+ title,
137
+ description,
138
+ openGraph: {
139
+ title,
140
+ description,
141
+ images: image ? [image] : [],
142
+ type: "website"
143
+ },
144
+ twitter: {
145
+ card: "summary_large_image",
146
+ title,
147
+ description,
148
+ images: image ? [image] : []
149
+ }
150
+ };
151
+ }
152
+ async function nitroPageGenerateStaticParams() {
153
+ const cfg = await getNitroConfig();
154
+ const pages = cfg.pages ?? [];
155
+ return pages.map((path) => ({
156
+ slug: path === "" ? void 0 : path.split("/")
157
+ }));
158
+ }
159
+ function nitroEntityRoute(props, options) {
160
+ const cachedResolver = createCachedEntityResolver(options.resolver);
161
+ return (async () => {
162
+ const entity = await cachedResolver(props);
163
+ if (options.render) {
164
+ return options.render(entity);
165
+ }
166
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: entity.entity?.entity_title });
167
+ })();
168
+ }
169
+ async function nitroEntityGenerateMetadata(props, options) {
170
+ const cachedResolver = createCachedEntityResolver(options.resolver);
171
+ const entity = await cachedResolver(props);
172
+ const title = entity.entity?.entity_title ?? "Entity";
173
+ const description = entity.entity?.entity_teaser ?? "";
174
+ const image = entity.entity?.entity_image ?? "";
175
+ return {
176
+ title,
177
+ description,
178
+ openGraph: {
179
+ title,
180
+ description,
181
+ images: image ? [image] : [],
182
+ type: "website"
183
+ },
184
+ twitter: {
185
+ card: "summary_large_image",
186
+ title,
187
+ description,
188
+ images: image ? [image] : []
189
+ }
190
+ };
191
+ }
94
192
  // Annotate the CommonJS export names for ESM import in node:
95
193
  0 && (module.exports = {
96
194
  NitroBlock,
@@ -98,6 +196,11 @@ function NitroBlock({
98
196
  getNitroConfig,
99
197
  getNitroEntities,
100
198
  getNitroPages,
101
- initNitro
199
+ initNitro,
200
+ nitroEntityGenerateMetadata,
201
+ nitroEntityRoute,
202
+ nitroPageGenerateMetadata,
203
+ nitroPageGenerateStaticParams,
204
+ nitroPageRoute
102
205
  });
103
206
  //# sourceMappingURL=server.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/server.tsx"],"sourcesContent":["import { cache } from 'react';\nimport {\n Page,\n Block,\n ConfigApi,\n ConfigResponse,\n Configuration,\n PagesApi,\n EntitiesApi\n} from '@flyo/nitro-typescript';\n\nlet globalConfiguration: Configuration | null = null;\nlet globalLang: string | null = null;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet globalComponents: Record<string, any> = {};\nlet globalShowMissingComponentAlert: boolean = false;\n\nexport const initNitro = ({accessToken, lang, components, showMissingComponentAlert}: {accessToken: string, lang?: string, components?: object, showMissingComponentAlert?: boolean}): ( () => Configuration ) => {\n\n if (!globalConfiguration) {\n globalConfiguration = new Configuration({\n apiKey: accessToken,\n });\n }\n\n globalLang = lang ?? null;\n globalComponents = components ?? {};\n globalShowMissingComponentAlert = showMissingComponentAlert ?? false;\n\n return () => globalConfiguration!;\n}\n\nexport const getNitroConfig = cache(async (): Promise<ConfigResponse> => {\n\n const configApi = new ConfigApi(globalConfiguration!);\n const useLang = globalLang ?? undefined;\n\n const config = await configApi.config({ lang: useLang });\n \n return config;\n});\n\nexport function getNitroPages(): PagesApi {\n return new PagesApi(globalConfiguration!);\n}\n\nexport function getNitroEntities(): EntitiesApi {\n return new EntitiesApi(globalConfiguration!);\n}\n\n\n/**\n * NitroPage component renders all blocks from a Flyo page\n */\nexport function NitroPage({\n page,\n}: {\n page: Page\n}) {\n if (!page?.json || !Array.isArray(page.json)) {\n return null;\n }\n\n return (\n <>\n {page.json.map((block: Block, index: number) => (\n <NitroBlock\n key={block.uid || index}\n block={block}\n />\n ))}\n </>\n );\n}\n\nexport function NitroBlock({\n block,\n}: {\n block: Block\n}) {\n if (!block) {\n return null;\n }\n\n const Component = block.component ? globalComponents[block.component] : undefined;\n\n if (Component) {\n return <Component block={block} />;\n }\n\n if (globalShowMissingComponentAlert) {\n return (\n <div style={{ border: '1px solid #fff', padding: '1rem', marginBottom: '1rem', backgroundColor: 'red' }}>\n Component <b>{block.component}</b> not found.\n </div>\n );\n }\n\n return null;\n}"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAsB;AACtB,8BAQO;AAuDH;AArDJ,IAAI,sBAA4C;AAChD,IAAI,aAA4B;AAEhC,IAAI,mBAAwC,CAAC;AAC7C,IAAI,kCAA2C;AAExC,IAAM,YAAY,CAAC,EAAC,aAAa,MAAM,YAAY,0BAAyB,MAAiI;AAEhN,MAAI,CAAC,qBAAqB;AACxB,0BAAsB,IAAI,sCAAc;AAAA,MACtC,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AAEA,eAAa,QAAQ;AACrB,qBAAmB,cAAc,CAAC;AAClC,oCAAkC,6BAA6B;AAE/D,SAAO,MAAM;AACjB;AAEO,IAAM,qBAAiB,oBAAM,YAAqC;AAErE,QAAM,YAAY,IAAI,kCAAU,mBAAoB;AACpD,QAAM,UAAU,cAAc;AAE9B,QAAM,SAAS,MAAM,UAAU,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEvD,SAAO;AACX,CAAC;AAEM,SAAS,gBAA0B;AACxC,SAAO,IAAI,iCAAS,mBAAoB;AAC1C;AAEO,SAAS,mBAAgC;AAC9C,SAAO,IAAI,oCAAY,mBAAoB;AAC7C;AAMO,SAAS,UAAU;AAAA,EACxB;AACF,GAEG;AACD,MAAI,CAAC,MAAM,QAAQ,CAAC,MAAM,QAAQ,KAAK,IAAI,GAAG;AAC5C,WAAO;AAAA,EACT;AAEA,SACE,2EACG,eAAK,KAAK,IAAI,CAAC,OAAc,UAC5B;AAAA,IAAC;AAAA;AAAA,MAEC;AAAA;AAAA,IADK,MAAM,OAAO;AAAA,EAEpB,CACD,GACH;AAEJ;AAEO,SAAS,WAAW;AAAA,EACzB;AACF,GAEG;AACD,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AAEA,QAAM,YAAY,MAAM,YAAY,iBAAiB,MAAM,SAAS,IAAI;AAExE,MAAI,WAAW;AACb,WAAO,4CAAC,aAAU,OAAc;AAAA,EAClC;AAEA,MAAI,iCAAiC;AACnC,WACE,6CAAC,SAAI,OAAO,EAAE,QAAQ,kBAAkB,SAAS,QAAQ,cAAc,QAAQ,iBAAiB,MAAM,GAAG;AAAA;AAAA,MAC7F,4CAAC,OAAG,gBAAM,WAAU;AAAA,MAAI;AAAA,OACpC;AAAA,EAEJ;AAEA,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../src/server.tsx"],"sourcesContent":["import { cache } from 'react';\nimport type { Metadata } from 'next';\nimport { notFound } from 'next/navigation';\nimport {\n Page,\n Block,\n Entity,\n ConfigApi,\n ConfigResponse,\n Configuration,\n PagesApi,\n EntitiesApi\n} from '@flyo/nitro-typescript';\n\nlet globalConfiguration: Configuration | null = null;\nlet globalLang: string | null = null;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet globalComponents: Record<string, any> = {};\nlet globalShowMissingComponentAlert: boolean = false;\n\nexport const initNitro = ({accessToken, lang, components, showMissingComponentAlert}: {accessToken: string, lang?: string, components?: object, showMissingComponentAlert?: boolean}): ( () => Configuration ) => {\n\n if (!globalConfiguration) {\n globalConfiguration = new Configuration({\n apiKey: accessToken,\n });\n }\n\n globalLang = lang ?? null;\n globalComponents = components ?? {};\n globalShowMissingComponentAlert = showMissingComponentAlert ?? false;\n\n return () => globalConfiguration!;\n}\n\nexport const getNitroConfig = cache(async (): Promise<ConfigResponse> => {\n\n const configApi = new ConfigApi(globalConfiguration!);\n const useLang = globalLang ?? undefined;\n\n const config = await configApi.config({ lang: useLang });\n \n return config;\n});\n\nexport function getNitroPages(): PagesApi {\n return new PagesApi(globalConfiguration!);\n}\n\nexport function getNitroEntities(): EntitiesApi {\n return new EntitiesApi(globalConfiguration!);\n}\n\n/**\n * Route params type for Next.js catch-all routes\n */\ntype RouteParams = {\n params: Promise<{ slug?: string[] }>;\n};\n\n/**\n * Generic route params type for entity routes\n * Allows any param structure from Next.js app router\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype EntityRouteParams<T = any> = {\n params: Promise<T>;\n};\n\n/**\n * Internal helper to resolve Nitro page from route params\n * Uses React cache to avoid duplicate fetching\n */\nconst resolveNitroRoute = cache(async ({ params }: RouteParams) => {\n const { slug } = await params;\n const path = slug?.join('/') ?? '';\n\n const cfg = await getNitroConfig();\n\n if (!cfg.pages?.includes(path)) {\n notFound();\n }\n\n const page = await getNitroPages()\n .page({ slug: path })\n .catch((error: unknown) => {\n console.error('Error fetching page:', path, error);\n notFound();\n });\n\n if (!page) {\n notFound();\n }\n\n return { page, path, cfg };\n});\n\n/**\n * Entity resolver function type\n * Users provide this to resolve entities from their route params\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type EntityResolver<T = any> = (params: Promise<T>) => Promise<Entity>;\n\n/**\n * Internal helper to wrap and cache entity resolvers\n * Ensures the resolver is only called once per unique params\n */\nfunction createCachedEntityResolver<T>(\n resolver: EntityResolver<T>\n): (props: EntityRouteParams<T>) => Promise<Entity> {\n return cache(async ({ params }: EntityRouteParams<T>) => {\n const entity = await resolver(params);\n \n if (!entity) {\n notFound();\n }\n \n return entity;\n });\n}\n\n\n/**\n * NitroPage component renders all blocks from a Flyo page\n */\nexport function NitroPage({\n page,\n}: {\n page: Page\n}) {\n if (!page?.json || !Array.isArray(page.json)) {\n return null;\n }\n\n return (\n <>\n {page.json.map((block: Block, index: number) => (\n <NitroBlock\n key={block.uid || index}\n block={block}\n />\n ))}\n </>\n );\n}\n\nexport function NitroBlock({\n block,\n}: {\n block: Block\n}) {\n if (!block) {\n return null;\n }\n\n const Component = block.component ? globalComponents[block.component] : undefined;\n\n if (Component) {\n return <Component block={block} />;\n }\n\n if (globalShowMissingComponentAlert) {\n return (\n <div style={{ border: '1px solid #fff', padding: '1rem', marginBottom: '1rem', backgroundColor: 'red' }}>\n Component <b>{block.component}</b> not found.\n </div>\n );\n }\n\n return null;\n}\n\n/**\n * Default page route handler for Nitro pages\n * Can be re-exported directly from Next.js app routes\n * \n * @example\n * ```ts\n * // app/[[...slug]]/page.tsx\n * export { nitroPageRoute as default } from '@flyo/nitro-next/server';\n * ```\n */\nexport async function nitroPageRoute(props: RouteParams) {\n const { page } = await resolveNitroRoute(props);\n return <NitroPage page={page} />;\n}\n\n/**\n * Generate metadata for Nitro pages\n * Provides basic meta tags based on Flyo page data\n * Can be re-exported directly from Next.js app routes\n * \n * @example\n * ```ts\n * // app/[[...slug]]/page.tsx\n * export { nitroPageGenerateMetadata as generateMetadata } from '@flyo/nitro-next/server';\n * ```\n */\nexport async function nitroPageGenerateMetadata(\n props: RouteParams\n): Promise<Metadata> {\n const { page } = await resolveNitroRoute(props);\n\n // Extract meta information from page\n const meta = page.meta_json;\n \n const title = meta?.title ?? page.title ?? 'Page';\n const description = meta?.description ?? '';\n const image = meta?.image ?? '';\n\n return {\n title,\n description,\n openGraph: {\n title,\n description,\n images: image ? [image] : [],\n type: 'website',\n },\n twitter: {\n card: 'summary_large_image',\n title,\n description,\n images: image ? [image] : [],\n },\n };\n}\n\n/**\n * Generate static params for all Nitro pages\n * Enables static site generation (SSG) for all pages\n * Can be re-exported directly from Next.js app routes\n * \n * @example\n * ```ts\n * // app/[[...slug]]/page.tsx\n * export { nitroPageGenerateStaticParams as generateStaticParams } from '@flyo/nitro-next/server';\n * ```\n */\nexport async function nitroPageGenerateStaticParams() {\n const cfg = await getNitroConfig();\n const pages = cfg.pages ?? [];\n\n return pages.map((path: string) => ({\n slug: path === '' ? undefined : path.split('/'),\n }));\n}\n\n/**\n * Default entity route handler with custom resolver\n * Flexible solution that works with any route param structure\n * \n * @example\n * ```ts\n * // app/blog/[slug]/page.tsx\n * const resolver = async (params: Promise<{ slug: string }>) => {\n * const { slug } = await params;\n * return getNitroEntities().entityBySlug({ slug, typeId: 123 });\n * };\n * \n * export default (props) => nitroEntityRoute(props, {\n * resolver,\n * render: (entity) => <h1>{entity.entity?.entity_title}</h1>\n * });\n * ```\n * \n * @example\n * ```ts\n * // app/items/[uniqueid]/page.tsx\n * const resolver = async (params: Promise<{ uniqueid: string }>) => {\n * const { uniqueid } = await params;\n * return getNitroEntities().entityByUniqueid({ uniqueid });\n * };\n * \n * export default (props) => nitroEntityRoute(props, { resolver });\n * ```\n * \n * @example\n * ```ts\n * // app/custom/[whatever]/page.tsx\n * const resolver = async (params: Promise<{ whatever: string }>) => {\n * const { whatever } = await params;\n * return getNitroEntities().entityBySlug({ slug: whatever });\n * };\n * \n * export default (props) => nitroEntityRoute(props, { resolver });\n * ```\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function nitroEntityRoute<T = any>(\n props: EntityRouteParams<T>,\n options: {\n resolver: EntityResolver<T>;\n render?: (entity: Entity) => React.ReactNode;\n }\n) {\n const cachedResolver = createCachedEntityResolver(options.resolver);\n \n return (async () => {\n const entity = await cachedResolver(props);\n \n if (options.render) {\n return options.render(entity);\n }\n\n // Default simple render - users should provide their own render function\n return <div>{entity.entity?.entity_title}</div>;\n })();\n}\n\n/**\n * Generate metadata for Nitro entities with custom resolver\n * Works with any route param structure\n * \n * @example\n * ```ts\n * // app/blog/[slug]/page.tsx\n * const resolver = async (params: Promise<{ slug: string }>) => {\n * const { slug } = await params;\n * return getNitroEntities().entityBySlug({ slug, typeId: 123 });\n * };\n * \n * export const generateMetadata = (props) => nitroEntityGenerateMetadata(props, { resolver });\n * ```\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport async function nitroEntityGenerateMetadata<T = any>(\n props: EntityRouteParams<T>,\n options: {\n resolver: EntityResolver<T>;\n }\n): Promise<Metadata> {\n const cachedResolver = createCachedEntityResolver(options.resolver);\n const entity = await cachedResolver(props);\n\n const title = entity.entity?.entity_title ?? 'Entity';\n const description = entity.entity?.entity_teaser ?? '';\n const image = entity.entity?.entity_image ?? '';\n\n return {\n title,\n description,\n openGraph: {\n title,\n description,\n images: image ? [image] : [],\n type: 'website',\n },\n twitter: {\n card: 'summary_large_image',\n title,\n description,\n images: image ? [image] : [],\n },\n };\n}"],"mappings":"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","names":[]}
package/dist/server.mjs CHANGED
@@ -1,5 +1,6 @@
1
1
  // src/server.tsx
2
2
  import { cache } from "react";
3
+ import { notFound } from "next/navigation";
3
4
  import {
4
5
  ConfigApi,
5
6
  Configuration,
@@ -34,6 +35,31 @@ function getNitroPages() {
34
35
  function getNitroEntities() {
35
36
  return new EntitiesApi(globalConfiguration);
36
37
  }
38
+ var resolveNitroRoute = cache(async ({ params }) => {
39
+ const { slug } = await params;
40
+ const path = slug?.join("/") ?? "";
41
+ const cfg = await getNitroConfig();
42
+ if (!cfg.pages?.includes(path)) {
43
+ notFound();
44
+ }
45
+ const page = await getNitroPages().page({ slug: path }).catch((error) => {
46
+ console.error("Error fetching page:", path, error);
47
+ notFound();
48
+ });
49
+ if (!page) {
50
+ notFound();
51
+ }
52
+ return { page, path, cfg };
53
+ });
54
+ function createCachedEntityResolver(resolver) {
55
+ return cache(async ({ params }) => {
56
+ const entity = await resolver(params);
57
+ if (!entity) {
58
+ notFound();
59
+ }
60
+ return entity;
61
+ });
62
+ }
37
63
  function NitroPage({
38
64
  page
39
65
  }) {
@@ -67,12 +93,84 @@ function NitroBlock({
67
93
  }
68
94
  return null;
69
95
  }
96
+ async function nitroPageRoute(props) {
97
+ const { page } = await resolveNitroRoute(props);
98
+ return /* @__PURE__ */ jsx(NitroPage, { page });
99
+ }
100
+ async function nitroPageGenerateMetadata(props) {
101
+ const { page } = await resolveNitroRoute(props);
102
+ const meta = page.meta_json;
103
+ const title = meta?.title ?? page.title ?? "Page";
104
+ const description = meta?.description ?? "";
105
+ const image = meta?.image ?? "";
106
+ return {
107
+ title,
108
+ description,
109
+ openGraph: {
110
+ title,
111
+ description,
112
+ images: image ? [image] : [],
113
+ type: "website"
114
+ },
115
+ twitter: {
116
+ card: "summary_large_image",
117
+ title,
118
+ description,
119
+ images: image ? [image] : []
120
+ }
121
+ };
122
+ }
123
+ async function nitroPageGenerateStaticParams() {
124
+ const cfg = await getNitroConfig();
125
+ const pages = cfg.pages ?? [];
126
+ return pages.map((path) => ({
127
+ slug: path === "" ? void 0 : path.split("/")
128
+ }));
129
+ }
130
+ function nitroEntityRoute(props, options) {
131
+ const cachedResolver = createCachedEntityResolver(options.resolver);
132
+ return (async () => {
133
+ const entity = await cachedResolver(props);
134
+ if (options.render) {
135
+ return options.render(entity);
136
+ }
137
+ return /* @__PURE__ */ jsx("div", { children: entity.entity?.entity_title });
138
+ })();
139
+ }
140
+ async function nitroEntityGenerateMetadata(props, options) {
141
+ const cachedResolver = createCachedEntityResolver(options.resolver);
142
+ const entity = await cachedResolver(props);
143
+ const title = entity.entity?.entity_title ?? "Entity";
144
+ const description = entity.entity?.entity_teaser ?? "";
145
+ const image = entity.entity?.entity_image ?? "";
146
+ return {
147
+ title,
148
+ description,
149
+ openGraph: {
150
+ title,
151
+ description,
152
+ images: image ? [image] : [],
153
+ type: "website"
154
+ },
155
+ twitter: {
156
+ card: "summary_large_image",
157
+ title,
158
+ description,
159
+ images: image ? [image] : []
160
+ }
161
+ };
162
+ }
70
163
  export {
71
164
  NitroBlock,
72
165
  NitroPage,
73
166
  getNitroConfig,
74
167
  getNitroEntities,
75
168
  getNitroPages,
76
- initNitro
169
+ initNitro,
170
+ nitroEntityGenerateMetadata,
171
+ nitroEntityRoute,
172
+ nitroPageGenerateMetadata,
173
+ nitroPageGenerateStaticParams,
174
+ nitroPageRoute
77
175
  };
78
176
  //# sourceMappingURL=server.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/server.tsx"],"sourcesContent":["import { cache } from 'react';\nimport {\n Page,\n Block,\n ConfigApi,\n ConfigResponse,\n Configuration,\n PagesApi,\n EntitiesApi\n} from '@flyo/nitro-typescript';\n\nlet globalConfiguration: Configuration | null = null;\nlet globalLang: string | null = null;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet globalComponents: Record<string, any> = {};\nlet globalShowMissingComponentAlert: boolean = false;\n\nexport const initNitro = ({accessToken, lang, components, showMissingComponentAlert}: {accessToken: string, lang?: string, components?: object, showMissingComponentAlert?: boolean}): ( () => Configuration ) => {\n\n if (!globalConfiguration) {\n globalConfiguration = new Configuration({\n apiKey: accessToken,\n });\n }\n\n globalLang = lang ?? null;\n globalComponents = components ?? {};\n globalShowMissingComponentAlert = showMissingComponentAlert ?? false;\n\n return () => globalConfiguration!;\n}\n\nexport const getNitroConfig = cache(async (): Promise<ConfigResponse> => {\n\n const configApi = new ConfigApi(globalConfiguration!);\n const useLang = globalLang ?? undefined;\n\n const config = await configApi.config({ lang: useLang });\n \n return config;\n});\n\nexport function getNitroPages(): PagesApi {\n return new PagesApi(globalConfiguration!);\n}\n\nexport function getNitroEntities(): EntitiesApi {\n return new EntitiesApi(globalConfiguration!);\n}\n\n\n/**\n * NitroPage component renders all blocks from a Flyo page\n */\nexport function NitroPage({\n page,\n}: {\n page: Page\n}) {\n if (!page?.json || !Array.isArray(page.json)) {\n return null;\n }\n\n return (\n <>\n {page.json.map((block: Block, index: number) => (\n <NitroBlock\n key={block.uid || index}\n block={block}\n />\n ))}\n </>\n );\n}\n\nexport function NitroBlock({\n block,\n}: {\n block: Block\n}) {\n if (!block) {\n return null;\n }\n\n const Component = block.component ? globalComponents[block.component] : undefined;\n\n if (Component) {\n return <Component block={block} />;\n }\n\n if (globalShowMissingComponentAlert) {\n return (\n <div style={{ border: '1px solid #fff', padding: '1rem', marginBottom: '1rem', backgroundColor: 'red' }}>\n Component <b>{block.component}</b> not found.\n </div>\n );\n }\n\n return null;\n}"],"mappings":";AAAA,SAAS,aAAa;AACtB;AAAA,EAGE;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAuDH,mBAEI,KA0BF,YA5BF;AArDJ,IAAI,sBAA4C;AAChD,IAAI,aAA4B;AAEhC,IAAI,mBAAwC,CAAC;AAC7C,IAAI,kCAA2C;AAExC,IAAM,YAAY,CAAC,EAAC,aAAa,MAAM,YAAY,0BAAyB,MAAiI;AAEhN,MAAI,CAAC,qBAAqB;AACxB,0BAAsB,IAAI,cAAc;AAAA,MACtC,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AAEA,eAAa,QAAQ;AACrB,qBAAmB,cAAc,CAAC;AAClC,oCAAkC,6BAA6B;AAE/D,SAAO,MAAM;AACjB;AAEO,IAAM,iBAAiB,MAAM,YAAqC;AAErE,QAAM,YAAY,IAAI,UAAU,mBAAoB;AACpD,QAAM,UAAU,cAAc;AAE9B,QAAM,SAAS,MAAM,UAAU,OAAO,EAAE,MAAM,QAAQ,CAAC;AAEvD,SAAO;AACX,CAAC;AAEM,SAAS,gBAA0B;AACxC,SAAO,IAAI,SAAS,mBAAoB;AAC1C;AAEO,SAAS,mBAAgC;AAC9C,SAAO,IAAI,YAAY,mBAAoB;AAC7C;AAMO,SAAS,UAAU;AAAA,EACxB;AACF,GAEG;AACD,MAAI,CAAC,MAAM,QAAQ,CAAC,MAAM,QAAQ,KAAK,IAAI,GAAG;AAC5C,WAAO;AAAA,EACT;AAEA,SACE,gCACG,eAAK,KAAK,IAAI,CAAC,OAAc,UAC5B;AAAA,IAAC;AAAA;AAAA,MAEC;AAAA;AAAA,IADK,MAAM,OAAO;AAAA,EAEpB,CACD,GACH;AAEJ;AAEO,SAAS,WAAW;AAAA,EACzB;AACF,GAEG;AACD,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AAEA,QAAM,YAAY,MAAM,YAAY,iBAAiB,MAAM,SAAS,IAAI;AAExE,MAAI,WAAW;AACb,WAAO,oBAAC,aAAU,OAAc;AAAA,EAClC;AAEA,MAAI,iCAAiC;AACnC,WACE,qBAAC,SAAI,OAAO,EAAE,QAAQ,kBAAkB,SAAS,QAAQ,cAAc,QAAQ,iBAAiB,MAAM,GAAG;AAAA;AAAA,MAC7F,oBAAC,OAAG,gBAAM,WAAU;AAAA,MAAI;AAAA,OACpC;AAAA,EAEJ;AAEA,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../src/server.tsx"],"sourcesContent":["import { cache } from 'react';\nimport type { Metadata } from 'next';\nimport { notFound } from 'next/navigation';\nimport {\n Page,\n Block,\n Entity,\n ConfigApi,\n ConfigResponse,\n Configuration,\n PagesApi,\n EntitiesApi\n} from '@flyo/nitro-typescript';\n\nlet globalConfiguration: Configuration | null = null;\nlet globalLang: string | null = null;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet globalComponents: Record<string, any> = {};\nlet globalShowMissingComponentAlert: boolean = false;\n\nexport const initNitro = ({accessToken, lang, components, showMissingComponentAlert}: {accessToken: string, lang?: string, components?: object, showMissingComponentAlert?: boolean}): ( () => Configuration ) => {\n\n if (!globalConfiguration) {\n globalConfiguration = new Configuration({\n apiKey: accessToken,\n });\n }\n\n globalLang = lang ?? null;\n globalComponents = components ?? {};\n globalShowMissingComponentAlert = showMissingComponentAlert ?? false;\n\n return () => globalConfiguration!;\n}\n\nexport const getNitroConfig = cache(async (): Promise<ConfigResponse> => {\n\n const configApi = new ConfigApi(globalConfiguration!);\n const useLang = globalLang ?? undefined;\n\n const config = await configApi.config({ lang: useLang });\n \n return config;\n});\n\nexport function getNitroPages(): PagesApi {\n return new PagesApi(globalConfiguration!);\n}\n\nexport function getNitroEntities(): EntitiesApi {\n return new EntitiesApi(globalConfiguration!);\n}\n\n/**\n * Route params type for Next.js catch-all routes\n */\ntype RouteParams = {\n params: Promise<{ slug?: string[] }>;\n};\n\n/**\n * Generic route params type for entity routes\n * Allows any param structure from Next.js app router\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype EntityRouteParams<T = any> = {\n params: Promise<T>;\n};\n\n/**\n * Internal helper to resolve Nitro page from route params\n * Uses React cache to avoid duplicate fetching\n */\nconst resolveNitroRoute = cache(async ({ params }: RouteParams) => {\n const { slug } = await params;\n const path = slug?.join('/') ?? '';\n\n const cfg = await getNitroConfig();\n\n if (!cfg.pages?.includes(path)) {\n notFound();\n }\n\n const page = await getNitroPages()\n .page({ slug: path })\n .catch((error: unknown) => {\n console.error('Error fetching page:', path, error);\n notFound();\n });\n\n if (!page) {\n notFound();\n }\n\n return { page, path, cfg };\n});\n\n/**\n * Entity resolver function type\n * Users provide this to resolve entities from their route params\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type EntityResolver<T = any> = (params: Promise<T>) => Promise<Entity>;\n\n/**\n * Internal helper to wrap and cache entity resolvers\n * Ensures the resolver is only called once per unique params\n */\nfunction createCachedEntityResolver<T>(\n resolver: EntityResolver<T>\n): (props: EntityRouteParams<T>) => Promise<Entity> {\n return cache(async ({ params }: EntityRouteParams<T>) => {\n const entity = await resolver(params);\n \n if (!entity) {\n notFound();\n }\n \n return entity;\n });\n}\n\n\n/**\n * NitroPage component renders all blocks from a Flyo page\n */\nexport function NitroPage({\n page,\n}: {\n page: Page\n}) {\n if (!page?.json || !Array.isArray(page.json)) {\n return null;\n }\n\n return (\n <>\n {page.json.map((block: Block, index: number) => (\n <NitroBlock\n key={block.uid || index}\n block={block}\n />\n ))}\n </>\n );\n}\n\nexport function NitroBlock({\n block,\n}: {\n block: Block\n}) {\n if (!block) {\n return null;\n }\n\n const Component = block.component ? globalComponents[block.component] : undefined;\n\n if (Component) {\n return <Component block={block} />;\n }\n\n if (globalShowMissingComponentAlert) {\n return (\n <div style={{ border: '1px solid #fff', padding: '1rem', marginBottom: '1rem', backgroundColor: 'red' }}>\n Component <b>{block.component}</b> not found.\n </div>\n );\n }\n\n return null;\n}\n\n/**\n * Default page route handler for Nitro pages\n * Can be re-exported directly from Next.js app routes\n * \n * @example\n * ```ts\n * // app/[[...slug]]/page.tsx\n * export { nitroPageRoute as default } from '@flyo/nitro-next/server';\n * ```\n */\nexport async function nitroPageRoute(props: RouteParams) {\n const { page } = await resolveNitroRoute(props);\n return <NitroPage page={page} />;\n}\n\n/**\n * Generate metadata for Nitro pages\n * Provides basic meta tags based on Flyo page data\n * Can be re-exported directly from Next.js app routes\n * \n * @example\n * ```ts\n * // app/[[...slug]]/page.tsx\n * export { nitroPageGenerateMetadata as generateMetadata } from '@flyo/nitro-next/server';\n * ```\n */\nexport async function nitroPageGenerateMetadata(\n props: RouteParams\n): Promise<Metadata> {\n const { page } = await resolveNitroRoute(props);\n\n // Extract meta information from page\n const meta = page.meta_json;\n \n const title = meta?.title ?? page.title ?? 'Page';\n const description = meta?.description ?? '';\n const image = meta?.image ?? '';\n\n return {\n title,\n description,\n openGraph: {\n title,\n description,\n images: image ? [image] : [],\n type: 'website',\n },\n twitter: {\n card: 'summary_large_image',\n title,\n description,\n images: image ? [image] : [],\n },\n };\n}\n\n/**\n * Generate static params for all Nitro pages\n * Enables static site generation (SSG) for all pages\n * Can be re-exported directly from Next.js app routes\n * \n * @example\n * ```ts\n * // app/[[...slug]]/page.tsx\n * export { nitroPageGenerateStaticParams as generateStaticParams } from '@flyo/nitro-next/server';\n * ```\n */\nexport async function nitroPageGenerateStaticParams() {\n const cfg = await getNitroConfig();\n const pages = cfg.pages ?? [];\n\n return pages.map((path: string) => ({\n slug: path === '' ? undefined : path.split('/'),\n }));\n}\n\n/**\n * Default entity route handler with custom resolver\n * Flexible solution that works with any route param structure\n * \n * @example\n * ```ts\n * // app/blog/[slug]/page.tsx\n * const resolver = async (params: Promise<{ slug: string }>) => {\n * const { slug } = await params;\n * return getNitroEntities().entityBySlug({ slug, typeId: 123 });\n * };\n * \n * export default (props) => nitroEntityRoute(props, {\n * resolver,\n * render: (entity) => <h1>{entity.entity?.entity_title}</h1>\n * });\n * ```\n * \n * @example\n * ```ts\n * // app/items/[uniqueid]/page.tsx\n * const resolver = async (params: Promise<{ uniqueid: string }>) => {\n * const { uniqueid } = await params;\n * return getNitroEntities().entityByUniqueid({ uniqueid });\n * };\n * \n * export default (props) => nitroEntityRoute(props, { resolver });\n * ```\n * \n * @example\n * ```ts\n * // app/custom/[whatever]/page.tsx\n * const resolver = async (params: Promise<{ whatever: string }>) => {\n * const { whatever } = await params;\n * return getNitroEntities().entityBySlug({ slug: whatever });\n * };\n * \n * export default (props) => nitroEntityRoute(props, { resolver });\n * ```\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function nitroEntityRoute<T = any>(\n props: EntityRouteParams<T>,\n options: {\n resolver: EntityResolver<T>;\n render?: (entity: Entity) => React.ReactNode;\n }\n) {\n const cachedResolver = createCachedEntityResolver(options.resolver);\n \n return (async () => {\n const entity = await cachedResolver(props);\n \n if (options.render) {\n return options.render(entity);\n }\n\n // Default simple render - users should provide their own render function\n return <div>{entity.entity?.entity_title}</div>;\n })();\n}\n\n/**\n * Generate metadata for Nitro entities with custom resolver\n * Works with any route param structure\n * \n * @example\n * ```ts\n * // app/blog/[slug]/page.tsx\n * const resolver = async (params: Promise<{ slug: string }>) => {\n * const { slug } = await params;\n * return getNitroEntities().entityBySlug({ slug, typeId: 123 });\n * };\n * \n * export const generateMetadata = (props) => nitroEntityGenerateMetadata(props, { resolver });\n * ```\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport async function nitroEntityGenerateMetadata<T = any>(\n props: EntityRouteParams<T>,\n options: {\n resolver: EntityResolver<T>;\n }\n): Promise<Metadata> {\n const cachedResolver = createCachedEntityResolver(options.resolver);\n const entity = await cachedResolver(props);\n\n const title = entity.entity?.entity_title ?? 'Entity';\n const description = entity.entity?.entity_teaser ?? '';\n const image = entity.entity?.entity_image ?? '';\n\n return {\n title,\n description,\n openGraph: {\n title,\n description,\n images: image ? [image] : [],\n type: 'website',\n },\n twitter: {\n card: 'summary_large_image',\n title,\n description,\n images: image ? [image] : [],\n },\n };\n}"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flyo/nitro-next",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Connecting Flyo Headless Content Hub into your Next.js project.",
5
5
  "homepage": "https://dev.flyo.cloud/nitro",
6
6
  "keywords": [