@coherent.js/integrations 1.0.0-rc.1
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/LICENSE +21 -0
- package/README.md +37 -0
- package/package.json +99 -0
- package/src/astro/index.js +88 -0
- package/src/express/coherent-express.js +160 -0
- package/src/express/index.js +36 -0
- package/src/fastify/coherent-fastify.js +125 -0
- package/src/fastify/index.js +13 -0
- package/src/koa/coherent-koa.js +124 -0
- package/src/koa/index.js +19 -0
- package/src/nextjs/coherent-nextjs.js +230 -0
- package/src/nextjs/index.js +21 -0
- package/src/remix/index.js +86 -0
- package/src/sveltekit/index.js +121 -0
- package/types/express/index.d.ts +134 -0
- package/types/fastify/index.d.ts +121 -0
- package/types/nextjs/index.d.ts +114 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Koa.js integration for Coherent.js
|
|
3
|
+
* Provides middleware and utilities for using Coherent.js with Koa
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
importPeerDependency,
|
|
8
|
+
renderWithTemplate,
|
|
9
|
+
renderComponentFactory,
|
|
10
|
+
isCoherentComponent
|
|
11
|
+
} from '@coherent.js/core';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Coherent.js Koa middleware
|
|
15
|
+
* Automatically renders Coherent.js components and handles errors
|
|
16
|
+
*
|
|
17
|
+
* @param {Object} options - Configuration options
|
|
18
|
+
* @param {boolean} options.enablePerformanceMonitoring - Enable performance monitoring
|
|
19
|
+
* @param {string} options.template - HTML template with {{content}} placeholder
|
|
20
|
+
* @returns {Function} Koa middleware function
|
|
21
|
+
*/
|
|
22
|
+
export function coherentKoaMiddleware(options = {}) {
|
|
23
|
+
const {
|
|
24
|
+
enablePerformanceMonitoring = false,
|
|
25
|
+
template = '<!DOCTYPE html>\n{{content}}'
|
|
26
|
+
} = options;
|
|
27
|
+
|
|
28
|
+
return async (ctx, next) => {
|
|
29
|
+
await next();
|
|
30
|
+
|
|
31
|
+
// If response body is a Coherent.js object, render it
|
|
32
|
+
if (isCoherentComponent(ctx.body)) {
|
|
33
|
+
try {
|
|
34
|
+
// Use shared rendering utility
|
|
35
|
+
const finalHtml = renderWithTemplate(ctx.body, { enablePerformanceMonitoring, template });
|
|
36
|
+
|
|
37
|
+
// Set content type and body
|
|
38
|
+
ctx.type = 'text/html';
|
|
39
|
+
ctx.body = finalHtml;
|
|
40
|
+
} catch (_error) {
|
|
41
|
+
console.error('Coherent.js rendering _error:', _error);
|
|
42
|
+
throw _error;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Create a Koa route handler for Coherent.js components
|
|
50
|
+
*
|
|
51
|
+
* @param {Function} componentFactory - Function that returns a Coherent.js component
|
|
52
|
+
* @param {Object} options - Handler options
|
|
53
|
+
* @returns {Function} Koa route handler
|
|
54
|
+
*/
|
|
55
|
+
export function createHandler(componentFactory, options = {}) {
|
|
56
|
+
return async (ctx, next) => {
|
|
57
|
+
try {
|
|
58
|
+
// Use shared rendering utility
|
|
59
|
+
const finalHtml = await renderComponentFactory(
|
|
60
|
+
componentFactory,
|
|
61
|
+
[ctx, next],
|
|
62
|
+
options
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
// Set response
|
|
66
|
+
ctx.type = 'text/html';
|
|
67
|
+
ctx.body = finalHtml;
|
|
68
|
+
} catch (_error) {
|
|
69
|
+
console.error('Coherent.js handler _error:', _error);
|
|
70
|
+
throw _error;
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Setup Coherent.js with Koa app
|
|
77
|
+
*
|
|
78
|
+
* @param {Object} app - Koa app instance
|
|
79
|
+
* @param {Object} options - Setup options
|
|
80
|
+
*/
|
|
81
|
+
export function setupCoherent(app, options = {}) {
|
|
82
|
+
const {
|
|
83
|
+
useMiddleware = true,
|
|
84
|
+
enablePerformanceMonitoring = false
|
|
85
|
+
} = options;
|
|
86
|
+
|
|
87
|
+
// Use middleware for automatic rendering
|
|
88
|
+
if (useMiddleware) {
|
|
89
|
+
app.use(coherentKoaMiddleware({ enablePerformanceMonitoring }));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Create Koa integration with dependency checking
|
|
95
|
+
* This function ensures Koa is available before setting up the integration
|
|
96
|
+
*
|
|
97
|
+
* @param {Object} options - Setup options
|
|
98
|
+
* @returns {Promise<Function>} - Function to setup Koa integration
|
|
99
|
+
*/
|
|
100
|
+
export async function createKoaIntegration(options = {}) {
|
|
101
|
+
try {
|
|
102
|
+
// Verify Koa is available
|
|
103
|
+
await importPeerDependency('koa', 'Koa.js');
|
|
104
|
+
|
|
105
|
+
return function(app) {
|
|
106
|
+
if (!app || typeof app.use !== 'function') {
|
|
107
|
+
throw new Error('Invalid Koa app instance provided');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
setupCoherent(app, options);
|
|
111
|
+
return app;
|
|
112
|
+
};
|
|
113
|
+
} catch (_error) {
|
|
114
|
+
throw _error;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Export all utilities
|
|
119
|
+
export default {
|
|
120
|
+
coherentKoaMiddleware,
|
|
121
|
+
createHandler,
|
|
122
|
+
setupCoherent,
|
|
123
|
+
createKoaIntegration
|
|
124
|
+
};
|
package/src/koa/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// src/koa/index.js
|
|
2
|
+
//
|
|
3
|
+
// Public entry point for @coherent.js/integrations/koa. Re-exports the full
|
|
4
|
+
// runtime surface from coherent-koa.js so the runtime matches the legacy
|
|
5
|
+
// @coherent.js/koa export shape.
|
|
6
|
+
//
|
|
7
|
+
// Koa must be installed as a peer dependency to use this integration.
|
|
8
|
+
//
|
|
9
|
+
// Usage:
|
|
10
|
+
// import { setupCoherent } from '@coherent.js/integrations/koa';
|
|
11
|
+
|
|
12
|
+
export {
|
|
13
|
+
coherentKoaMiddleware,
|
|
14
|
+
createHandler,
|
|
15
|
+
setupCoherent,
|
|
16
|
+
createKoaIntegration
|
|
17
|
+
} from './coherent-koa.js';
|
|
18
|
+
|
|
19
|
+
export { default } from './coherent-koa.js';
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Next.js integration for Coherent.js
|
|
3
|
+
* Provides utilities for using Coherent.js with Next.js
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
render,
|
|
8
|
+
performanceMonitor,
|
|
9
|
+
importPeerDependency,
|
|
10
|
+
renderComponentFactory
|
|
11
|
+
} from '@coherent.js/core';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Create a Next.js API route handler for Coherent.js components
|
|
15
|
+
*
|
|
16
|
+
* @param {Function} componentFactory - Function that returns a Coherent.js component
|
|
17
|
+
* @param {Object} options - Handler options
|
|
18
|
+
* @param {boolean} options.enablePerformanceMonitoring - Enable performance monitoring
|
|
19
|
+
* @param {string} options.template - HTML template with {{content}} placeholder
|
|
20
|
+
* @returns {Function} Next.js API route handler
|
|
21
|
+
*/
|
|
22
|
+
export function createCoherentNextHandler(componentFactory, options = {}) {
|
|
23
|
+
return async (req, res) => {
|
|
24
|
+
try {
|
|
25
|
+
// Use shared rendering utility
|
|
26
|
+
const finalHtml = await renderComponentFactory(
|
|
27
|
+
componentFactory,
|
|
28
|
+
[req, res],
|
|
29
|
+
options
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
// Send HTML response
|
|
33
|
+
res.setHeader('Content-Type', 'text/html; charset=utf-8');
|
|
34
|
+
res.status(200).send(finalHtml);
|
|
35
|
+
} catch (_error) {
|
|
36
|
+
console.error('Coherent.js Next.js handler _error:', _error);
|
|
37
|
+
res.status(500).json({ _error: _error.message });
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Create a Next.js App Router route handler for Coherent.js components
|
|
44
|
+
*
|
|
45
|
+
* @param {Function} componentFactory - Function that returns a Coherent.js component
|
|
46
|
+
* @param {Object} options - Handler options
|
|
47
|
+
* @returns {Function} Next.js App Router route handler
|
|
48
|
+
*/
|
|
49
|
+
export function createCoherentAppRouterHandler(componentFactory, options = {}) {
|
|
50
|
+
return async function handler(request) {
|
|
51
|
+
try {
|
|
52
|
+
// Use shared rendering utility
|
|
53
|
+
const finalHtml = await renderComponentFactory(
|
|
54
|
+
componentFactory,
|
|
55
|
+
[request],
|
|
56
|
+
options
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
// Send HTML response
|
|
60
|
+
return new Response(finalHtml, {
|
|
61
|
+
status: 200,
|
|
62
|
+
headers: { 'Content-Type': 'text/html; charset=utf-8' }
|
|
63
|
+
});
|
|
64
|
+
} catch (_error) {
|
|
65
|
+
console.error('Coherent.js Next.js App Router handler _error:', _error);
|
|
66
|
+
return new Response(
|
|
67
|
+
JSON.stringify({ _error: _error.message }),
|
|
68
|
+
{
|
|
69
|
+
status: 500,
|
|
70
|
+
headers: { 'Content-Type': 'application/json' }
|
|
71
|
+
}
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Create a Next.js Server Component for Coherent.js
|
|
79
|
+
*
|
|
80
|
+
* @param {Function} componentFactory - Function that returns a Coherent.js component
|
|
81
|
+
* @param {Object} options - Component options
|
|
82
|
+
* @returns {Function} Next.js Server Component
|
|
83
|
+
*/
|
|
84
|
+
export async function createCoherentServerComponent(componentFactory, options = {}) {
|
|
85
|
+
const {
|
|
86
|
+
enablePerformanceMonitoring = false
|
|
87
|
+
} = options;
|
|
88
|
+
|
|
89
|
+
// Import React using dependency utilities
|
|
90
|
+
let React;
|
|
91
|
+
try {
|
|
92
|
+
React = await importPeerDependency('react', 'React');
|
|
93
|
+
} catch (_error) {
|
|
94
|
+
throw new Error(
|
|
95
|
+
`Next.js Server Component integration requires React. ${ _error.message}`
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return async function CoherentServerComponent(props) {
|
|
100
|
+
try {
|
|
101
|
+
// Create component with props
|
|
102
|
+
const component = await Promise.resolve(
|
|
103
|
+
componentFactory(props)
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
if (!component) {
|
|
107
|
+
return React.default.createElement('div', null, 'Error: Component factory returned null/undefined');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Render component
|
|
111
|
+
let html;
|
|
112
|
+
if (enablePerformanceMonitoring) {
|
|
113
|
+
const renderId = performanceMonitor.startRender();
|
|
114
|
+
html = render(component);
|
|
115
|
+
performanceMonitor.endRender(renderId);
|
|
116
|
+
} else {
|
|
117
|
+
html = render(component);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Return dangerouslySetInnerHTML to render HTML
|
|
121
|
+
return React.default.createElement('div', {
|
|
122
|
+
dangerouslySetInnerHTML: { __html: html }
|
|
123
|
+
});
|
|
124
|
+
} catch (_error) {
|
|
125
|
+
console.error('Coherent.js Next.js Server Component _error:', _error);
|
|
126
|
+
return React.default.createElement('div', null, `Error: ${_error.message}`);
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Create a Next.js Client Component for Coherent.js with hydration support
|
|
133
|
+
*
|
|
134
|
+
* @param {Function} componentFactory - Function that returns a Coherent.js component
|
|
135
|
+
* @param {Object} options - Component options
|
|
136
|
+
* @returns {Function} Next.js Client Component
|
|
137
|
+
*/
|
|
138
|
+
export async function createCoherentClientComponent(componentFactory, options = {}) {
|
|
139
|
+
const {
|
|
140
|
+
enablePerformanceMonitoring = false
|
|
141
|
+
} = options;
|
|
142
|
+
|
|
143
|
+
// Import React using dependency utilities
|
|
144
|
+
let React;
|
|
145
|
+
try {
|
|
146
|
+
React = await importPeerDependency('react', 'React');
|
|
147
|
+
} catch (_error) {
|
|
148
|
+
throw new Error(
|
|
149
|
+
`Next.js Client Component integration requires React. ${ _error.message}`
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return function CoherentClientComponent(props) {
|
|
154
|
+
const [html, setHtml] = React.useState('');
|
|
155
|
+
|
|
156
|
+
React.useEffect(() => {
|
|
157
|
+
async function renderComponent() {
|
|
158
|
+
try {
|
|
159
|
+
// Create component with props
|
|
160
|
+
const component = await Promise.resolve(
|
|
161
|
+
componentFactory(props)
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
if (!component) {
|
|
165
|
+
setHtml('Error: Component factory returned null/undefined');
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Render component
|
|
170
|
+
let renderedHtml;
|
|
171
|
+
if (enablePerformanceMonitoring) {
|
|
172
|
+
const renderId = performanceMonitor.startRender();
|
|
173
|
+
renderedHtml = render(component);
|
|
174
|
+
performanceMonitor.endRender(renderId);
|
|
175
|
+
} else {
|
|
176
|
+
renderedHtml = render(component);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
setHtml(renderedHtml);
|
|
180
|
+
} catch (_error) {
|
|
181
|
+
console.error('Coherent.js Next.js Client Component _error:', _error);
|
|
182
|
+
setHtml(`Error: ${_error.message}`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
renderComponent();
|
|
187
|
+
}, [props]);
|
|
188
|
+
|
|
189
|
+
return React.createElement('div', {
|
|
190
|
+
dangerouslySetInnerHTML: { __html: html }
|
|
191
|
+
});
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Create Next.js integration with dependency checking
|
|
197
|
+
* This function ensures Next.js and React are available before setting up the integration
|
|
198
|
+
*
|
|
199
|
+
* @param {Object} options - Setup options
|
|
200
|
+
* @returns {Promise<Object>} - Object with Next.js integration utilities
|
|
201
|
+
*/
|
|
202
|
+
export async function createNextIntegration(options = {}) {
|
|
203
|
+
try {
|
|
204
|
+
// Verify Next.js and React are available
|
|
205
|
+
await importPeerDependency('next', 'Next.js');
|
|
206
|
+
await importPeerDependency('react', 'React');
|
|
207
|
+
|
|
208
|
+
return {
|
|
209
|
+
createCoherentNextHandler: (componentFactory, handlerOptions = {}) =>
|
|
210
|
+
createCoherentNextHandler(componentFactory, { ...options, ...handlerOptions }),
|
|
211
|
+
createCoherentAppRouterHandler: (componentFactory, handlerOptions = {}) =>
|
|
212
|
+
createCoherentAppRouterHandler(componentFactory, { ...options, ...handlerOptions }),
|
|
213
|
+
createCoherentServerComponent: (componentFactory, componentOptions = {}) =>
|
|
214
|
+
createCoherentServerComponent(componentFactory, { ...options, ...componentOptions }),
|
|
215
|
+
createCoherentClientComponent: (componentFactory, componentOptions = {}) =>
|
|
216
|
+
createCoherentClientComponent(componentFactory, { ...options, ...componentOptions })
|
|
217
|
+
};
|
|
218
|
+
} catch (_error) {
|
|
219
|
+
throw _error;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Export all utilities
|
|
224
|
+
export default {
|
|
225
|
+
createCoherentNextHandler,
|
|
226
|
+
createCoherentAppRouterHandler,
|
|
227
|
+
createCoherentServerComponent,
|
|
228
|
+
createCoherentClientComponent,
|
|
229
|
+
createNextIntegration
|
|
230
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// src/nextjs/index.js
|
|
2
|
+
//
|
|
3
|
+
// Public entry point for @coherent.js/integrations/nextjs. Re-exports the full
|
|
4
|
+
// runtime surface from coherent-nextjs.js so the runtime matches the legacy
|
|
5
|
+
// @coherent.js/nextjs export shape.
|
|
6
|
+
//
|
|
7
|
+
// Next.js and React must be installed as peer dependencies to use this
|
|
8
|
+
// integration.
|
|
9
|
+
//
|
|
10
|
+
// Usage:
|
|
11
|
+
// import { createCoherentNextHandler } from '@coherent.js/integrations/nextjs';
|
|
12
|
+
|
|
13
|
+
export {
|
|
14
|
+
createCoherentNextHandler,
|
|
15
|
+
createCoherentAppRouterHandler,
|
|
16
|
+
createCoherentServerComponent,
|
|
17
|
+
createCoherentClientComponent,
|
|
18
|
+
createNextIntegration
|
|
19
|
+
} from './coherent-nextjs.js';
|
|
20
|
+
|
|
21
|
+
export { default } from './coherent-nextjs.js';
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// src/remix/index.js
|
|
2
|
+
//
|
|
3
|
+
// Public entry point for @coherent.js/integrations/remix. Provides SSR
|
|
4
|
+
// integration and loader utilities for Remix projects.
|
|
5
|
+
//
|
|
6
|
+
// Remix must be installed as a peer dependency to use this integration.
|
|
7
|
+
//
|
|
8
|
+
// Usage:
|
|
9
|
+
// import { createRemixAdapter } from '@coherent.js/integrations/remix';
|
|
10
|
+
|
|
11
|
+
import { render } from '@coherent.js/core';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Create a Remix adapter for Coherent.js
|
|
15
|
+
*
|
|
16
|
+
* @param {Object} [options] - Adapter options
|
|
17
|
+
* @param {boolean} [options.hydrate] - Enable client-side hydration
|
|
18
|
+
* @returns {Object} Remix adapter utilities
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* const adapter = createRemixAdapter();
|
|
22
|
+
* const html = adapter.renderComponent(MyComponent, { title: 'Hello' });
|
|
23
|
+
*/
|
|
24
|
+
export function createRemixAdapter(_options = {}) {
|
|
25
|
+
return {
|
|
26
|
+
/**
|
|
27
|
+
* Render a Coherent.js component to HTML
|
|
28
|
+
*/
|
|
29
|
+
renderComponent(component, props = {}) {
|
|
30
|
+
const def = typeof component === 'function' ? component(props) : component;
|
|
31
|
+
return render(def);
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Create a Remix loader that renders a Coherent.js component
|
|
36
|
+
*/
|
|
37
|
+
createLoader(component, getProps) {
|
|
38
|
+
return async ({ request, params, context }) => {
|
|
39
|
+
const props = getProps
|
|
40
|
+
? await getProps({ request, params, context })
|
|
41
|
+
: { request, params };
|
|
42
|
+
|
|
43
|
+
const def = typeof component === 'function' ? component(props) : component;
|
|
44
|
+
const html = render(def);
|
|
45
|
+
|
|
46
|
+
return new Response(html, {
|
|
47
|
+
headers: { 'Content-Type': 'text/html; charset=utf-8' }
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Create a Remix action handler that processes form data
|
|
54
|
+
* and renders a Coherent.js component with the result
|
|
55
|
+
*/
|
|
56
|
+
createAction(component, handler) {
|
|
57
|
+
return async ({ request, params, context }) => {
|
|
58
|
+
const formData = await request.formData();
|
|
59
|
+
const data = Object.fromEntries(formData);
|
|
60
|
+
const result = await handler({ data, request, params, context });
|
|
61
|
+
|
|
62
|
+
if (result instanceof Response) return result;
|
|
63
|
+
|
|
64
|
+
const def = typeof component === 'function' ? component(result) : component;
|
|
65
|
+
const html = render(def);
|
|
66
|
+
|
|
67
|
+
return new Response(html, {
|
|
68
|
+
headers: { 'Content-Type': 'text/html; charset=utf-8' }
|
|
69
|
+
});
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* HOC: Wrap a Coherent.js component for use in Remix routes
|
|
77
|
+
*
|
|
78
|
+
* @param {Function} Component - Coherent.js component function
|
|
79
|
+
* @returns {Function} Remix-compatible component
|
|
80
|
+
*/
|
|
81
|
+
export function withCoherent(Component) {
|
|
82
|
+
return function CoherentRemixComponent(props) {
|
|
83
|
+
const def = typeof Component === 'function' ? Component(props) : Component;
|
|
84
|
+
return render(def);
|
|
85
|
+
};
|
|
86
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
// src/sveltekit/index.js
|
|
2
|
+
//
|
|
3
|
+
// Public entry point for @coherent.js/integrations/sveltekit. Provides
|
|
4
|
+
// server-side rendering and preprocessor integration for SvelteKit projects.
|
|
5
|
+
//
|
|
6
|
+
// SvelteKit must be installed as a peer dependency to use this integration.
|
|
7
|
+
//
|
|
8
|
+
// Usage:
|
|
9
|
+
// import { createSvelteKitAdapter } from '@coherent.js/integrations/sveltekit';
|
|
10
|
+
|
|
11
|
+
import { render } from '@coherent.js/core';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Create a SvelteKit adapter for Coherent.js
|
|
15
|
+
*
|
|
16
|
+
* @param {Object} [options] - Adapter options
|
|
17
|
+
* @returns {Object} SvelteKit adapter utilities
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* const adapter = createSvelteKitAdapter();
|
|
21
|
+
* const html = adapter.renderComponent(MyComponent, { title: 'Hello' });
|
|
22
|
+
*/
|
|
23
|
+
export function createSvelteKitAdapter(_options = {}) {
|
|
24
|
+
return {
|
|
25
|
+
name: '@coherent.js/sveltekit',
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Render a Coherent.js component to HTML
|
|
29
|
+
*/
|
|
30
|
+
renderComponent(component, props = {}) {
|
|
31
|
+
const def = typeof component === 'function' ? component(props) : component;
|
|
32
|
+
return render(def);
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Create a SvelteKit server load function
|
|
37
|
+
*/
|
|
38
|
+
createLoad(component, getProps) {
|
|
39
|
+
return async ({ params, url, fetch }) => {
|
|
40
|
+
const props = getProps
|
|
41
|
+
? await getProps({ params, url, fetch })
|
|
42
|
+
: { params };
|
|
43
|
+
|
|
44
|
+
const def = typeof component === 'function' ? component(props) : component;
|
|
45
|
+
const html = render(def);
|
|
46
|
+
|
|
47
|
+
return { html, props };
|
|
48
|
+
};
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Create a SvelteKit form action handler
|
|
53
|
+
*/
|
|
54
|
+
createAction(handler) {
|
|
55
|
+
return async ({ request, params }) => {
|
|
56
|
+
const formData = await request.formData();
|
|
57
|
+
const data = Object.fromEntries(formData);
|
|
58
|
+
return handler({ data, params });
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Create a Svelte preprocessor for Coherent.js templates
|
|
66
|
+
*
|
|
67
|
+
* Transforms inline Coherent.js object syntax within Svelte components.
|
|
68
|
+
*
|
|
69
|
+
* @param {Object} [options] - Preprocessor options
|
|
70
|
+
* @param {string} [options.tag] - Custom tag to process (default: 'coherent')
|
|
71
|
+
* @returns {Object} Svelte preprocessor
|
|
72
|
+
*/
|
|
73
|
+
export function createPreprocessor(options = {}) {
|
|
74
|
+
const tag = options.tag || 'coherent';
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
name: 'coherent-preprocessor',
|
|
78
|
+
markup({ content, filename: _filename }) {
|
|
79
|
+
// Find <coherent> blocks and render them to HTML
|
|
80
|
+
const regex = new RegExp(`<${tag}>(.*?)</${tag}>`, 'gs');
|
|
81
|
+
let transformed = content;
|
|
82
|
+
let match;
|
|
83
|
+
|
|
84
|
+
while ((match = regex.exec(content)) !== null) {
|
|
85
|
+
try {
|
|
86
|
+
// The content inside <coherent> tags should be a JS object literal
|
|
87
|
+
// This is a basic transform — production use should handle more cases
|
|
88
|
+
const objectStr = match[1].trim();
|
|
89
|
+
transformed = transformed.replace(match[0], `{@html coherentRender(${objectStr})}`);
|
|
90
|
+
} catch {
|
|
91
|
+
// Leave unchanged if parsing fails
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
code: transformed,
|
|
97
|
+
map: null
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* SvelteKit hooks integration
|
|
105
|
+
*
|
|
106
|
+
* @param {Object} [options] - Hook options
|
|
107
|
+
* @returns {Object} SvelteKit handle function
|
|
108
|
+
*/
|
|
109
|
+
export function createHandle(_options = {}) {
|
|
110
|
+
return async ({ event, resolve }) => {
|
|
111
|
+
// Add Coherent.js render function to locals
|
|
112
|
+
event.locals.coherent = {
|
|
113
|
+
render(component, props = {}) {
|
|
114
|
+
const def = typeof component === 'function' ? component(props) : component;
|
|
115
|
+
return render(def);
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
return resolve(event);
|
|
120
|
+
};
|
|
121
|
+
}
|