@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.
@@ -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
+ };
@@ -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
+ }