@maravilla-labs/functions 0.1.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/README.md ADDED
@@ -0,0 +1,194 @@
1
+ # @maravilla-labs/functions
2
+
3
+ Maravilla Edge Functions bundler and development tools. This package provides esbuild-based bundling for edge functions, transforming multiple JavaScript function files into a single optimized bundle for WASM execution.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install --save-dev @maravilla-labs/functions
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### CLI Commands
14
+
15
+ ```bash
16
+ # Build functions for production
17
+ npx maravilla-functions build
18
+
19
+ # Build with options
20
+ npx maravilla-functions build --output dist --minify --sourcemap
21
+
22
+ # Start development mode with file watching
23
+ npx maravilla-functions dev
24
+
25
+ # Development mode with custom output
26
+ npx maravilla-functions dev --output build
27
+ ```
28
+
29
+ ### Package.json Scripts
30
+
31
+ Add to your `functions/package.json`:
32
+
33
+ ```json
34
+ {
35
+ "scripts": {
36
+ "build": "maravilla-functions build",
37
+ "dev": "maravilla-functions dev",
38
+ "build:prod": "maravilla-functions build --minify"
39
+ },
40
+ "devDependencies": {
41
+ "@maravilla-labs/functions": "latest"
42
+ }
43
+ }
44
+ ```
45
+
46
+ ### Function Structure
47
+
48
+ Functions should be organized in a flat or nested structure:
49
+
50
+ ```
51
+ functions/
52
+ ├── package.json
53
+ ├── hello.js
54
+ ├── user-profile.js
55
+ └── auth/
56
+ └── login.js
57
+ ```
58
+
59
+ Each function file should export HTTP method handlers:
60
+
61
+ ```javascript
62
+ // hello.js
63
+ export const GET = (request, response) => {
64
+ response.json({ message: 'Hello World!' });
65
+ };
66
+
67
+ export const POST = (request, response) => {
68
+ const body = JSON.parse(request.body || '{}');
69
+ response.json({ received: body });
70
+ };
71
+ ```
72
+
73
+ ### Route Mapping
74
+
75
+ Functions are automatically mapped to API routes:
76
+
77
+ - `hello.js` → `/api/hello`
78
+ - `user-profile.js` → `/api/user-profile`
79
+ - `auth/login.js` → `/api/auth/login`
80
+
81
+ ### HTTP Methods
82
+
83
+ Supported export patterns:
84
+
85
+ ```javascript
86
+ // Named method exports
87
+ export const GET = (request, response) => { /* ... */ };
88
+ export const POST = (request, response) => { /* ... */ };
89
+ export const PUT = (request, response) => { /* ... */ };
90
+ export const DELETE = (request, response) => { /* ... */ };
91
+
92
+ // Default export handles all methods
93
+ export default (request, response) => {
94
+ // Handle based on request.method
95
+ };
96
+ ```
97
+
98
+ ### Request Object
99
+
100
+ ```javascript
101
+ {
102
+ method: 'GET', // HTTP method
103
+ url: 'http://...', // Full URL
104
+ path: '/api/hello', // Path part
105
+ query: { id: '123' }, // Query parameters as object
106
+ headers: { ... }, // Headers as object
107
+ body: '...' // Raw body string
108
+ }
109
+ ```
110
+
111
+ ### Response Object
112
+
113
+ ```javascript
114
+ response.status(200) // Set status code
115
+ response.setHeader('key', 'value') // Set header
116
+ response.json({ data: 'value' }) // JSON response
117
+ response.text('plain text') // Text response
118
+ response.html('<h1>HTML</h1>') // HTML response
119
+ ```
120
+
121
+ ## Build Output
122
+
123
+ The bundler generates:
124
+
125
+ - `dist/functions.js` - Single bundled JavaScript file
126
+ - Source maps (if enabled)
127
+ - Minified output (if enabled)
128
+
129
+ The bundle includes:
130
+
131
+ - All function modules with proper ES6 imports
132
+ - Runtime helpers (Request/Response classes)
133
+ - Route registry for path matching
134
+ - Global `handleRequest` function for WASM integration
135
+
136
+ ## Integration with Maravilla CLI
137
+
138
+ The Maravilla CLI automatically detects and uses the bundled output:
139
+
140
+ 1. Looks for `functions/dist/functions.js`
141
+ 2. Compiles to QuickJS bytecode
142
+ 3. Embeds in WASM runtime
143
+ 4. Serves via HTTP with automatic routing
144
+
145
+ ## Development Workflow
146
+
147
+ 1. **Setup functions directory:**
148
+ ```bash
149
+ mkdir functions
150
+ cd functions
151
+ npm init -y
152
+ npm install --save-dev @maravilla-labs/functions
153
+ ```
154
+
155
+ 2. **Add build scripts:**
156
+ ```json
157
+ {
158
+ "scripts": {
159
+ "build": "maravilla-functions build",
160
+ "dev": "maravilla-functions dev"
161
+ }
162
+ }
163
+ ```
164
+
165
+ 3. **Create function files:**
166
+ ```javascript
167
+ // hello.js
168
+ export const GET = (request, response) => {
169
+ response.json({ message: 'Hello from Maravilla!' });
170
+ };
171
+ ```
172
+
173
+ 4. **Build and serve:**
174
+ ```bash
175
+ npm run build
176
+ maravilla serve --dev --framework-port 5173
177
+ ```
178
+
179
+ ## Features
180
+
181
+ - ✅ **esbuild-powered** - Fast, reliable bundling
182
+ - ✅ **ES6 modules** - Native import/export support
183
+ - ✅ **File watching** - Automatic rebuilds in dev mode
184
+ - ✅ **Source maps** - Debug support
185
+ - ✅ **Minification** - Production optimization
186
+ - ✅ **Route mapping** - Automatic API route generation
187
+ - ✅ **Method detection** - HTTP method analysis
188
+ - ✅ **WASM integration** - Seamless CLI integration
189
+
190
+ ## License
191
+
192
+ Proprietary. © 2025 SOLUTAS GmbH, Switzerland. All rights reserved.
193
+ Use is governed by the root LICENSE file or a separate written agreement
194
+ with SOLUTAS GmbH.
package/bin/cli.js ADDED
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { buildFunctions, developmentServer } from '../dist/index.js';
4
+ import { resolve } from 'node:path';
5
+ import { readFileSync } from 'node:fs';
6
+ import { fileURLToPath } from 'node:url';
7
+ import { dirname, join } from 'node:path';
8
+
9
+ const __filename = fileURLToPath(import.meta.url);
10
+ const __dirname = dirname(__filename);
11
+ const packageJson = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf8'));
12
+
13
+ const command = process.argv[2];
14
+ const args = process.argv.slice(3);
15
+
16
+ function parseArgs(args) {
17
+ const options = {};
18
+ for (let i = 0; i < args.length; i++) {
19
+ if (args[i].startsWith('--')) {
20
+ const key = args[i].slice(2);
21
+ const value = args[i + 1] && !args[i + 1].startsWith('--') ? args[i + 1] : true;
22
+ options[key] = value;
23
+ if (value !== true) i++;
24
+ }
25
+ }
26
+ return options;
27
+ }
28
+
29
+ if (command === 'build') {
30
+ const options = parseArgs(args);
31
+ const buildOptions = {
32
+ functionsDir: options.dir || process.env.FUNCTIONS_DIR || 'functions',
33
+ outputDir: options.output || process.env.OUTPUT_DIR || '.maravilla',
34
+ production: options.production || process.env.NODE_ENV === 'production',
35
+ minify: options.minify || process.env.NODE_ENV === 'production',
36
+ sourcemap: options.sourcemap === true || process.env.SOURCEMAP === 'true',
37
+ };
38
+
39
+ console.log('🚀 Building Maravilla functions...');
40
+
41
+ try {
42
+ const manifest = await buildFunctions(buildOptions);
43
+ if (manifest) {
44
+ console.log(`✅ Built ${manifest.functions} functions successfully`);
45
+ process.exit(0);
46
+ } else {
47
+ console.log('ℹ️ No functions found to build');
48
+ process.exit(0);
49
+ }
50
+ } catch (error) {
51
+ console.error('❌ Build failed:', error);
52
+ process.exit(1);
53
+ }
54
+ } else if (command === 'dev') {
55
+ const options = parseArgs(args);
56
+ const devOptions = {
57
+ functionsDir: options.dir || process.env.FUNCTIONS_DIR || 'functions',
58
+ outputDir: options.output || process.env.OUTPUT_DIR || '.maravilla',
59
+ watch: options.watch !== 'false',
60
+ };
61
+
62
+ console.log('🚀 Starting Maravilla functions development server...');
63
+
64
+ try {
65
+ await developmentServer(devOptions);
66
+ } catch (error) {
67
+ console.error('❌ Dev server failed:', error);
68
+ process.exit(1);
69
+ }
70
+ } else if (command === '--version' || command === '-v') {
71
+ console.log(packageJson.version);
72
+ process.exit(0);
73
+ } else {
74
+ console.log('Maravilla Functions CLI v' + packageJson.version);
75
+ console.log('\nUsage:');
76
+ console.log(' @maravilla/functions build [options] Build functions for production');
77
+ console.log(' @maravilla/functions dev [options] Start development server with hot reload');
78
+ console.log('\nBuild Options:');
79
+ console.log(' --dir <path> Functions directory (default: functions)');
80
+ console.log(' --output <path> Output directory (default: .maravilla)');
81
+ console.log(' --minify Minify output');
82
+ console.log(' --sourcemap Generate sourcemaps');
83
+ console.log(' --production Production build');
84
+ console.log('\nDev Options:');
85
+ console.log(' --dir <path> Functions directory (default: functions)');
86
+ console.log(' --output <path> Output directory (default: .maravilla)');
87
+ console.log(' --watch <bool> Watch for changes (default: true)');
88
+ process.exit(command ? 1 : 0);
89
+ }
package/dist/dev.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ import type { BuildOptions } from './types.js';
2
+ export interface DevServerOptions extends BuildOptions {
3
+ watch?: boolean;
4
+ onRebuild?: () => void;
5
+ }
6
+ export declare function developmentServer(options?: DevServerOptions): Promise<(() => void) | undefined>;
7
+ //# sourceMappingURL=dev.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../src/dev.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,MAAM,WAAW,gBAAiB,SAAQ,YAAY;IACpD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;CACxB;AAED,wBAAsB,iBAAiB,CAAC,OAAO,GAAE,gBAAqB,qCAoFrE"}
package/dist/dev.js ADDED
@@ -0,0 +1,70 @@
1
+ import { watch } from 'chokidar';
2
+ import { buildFunctions } from './index.js';
3
+ export async function developmentServer(options = {}) {
4
+ const { functionsDir = 'functions', outputDir = '.maravilla', watch: watchFiles = true, onRebuild, ...buildOptions } = options;
5
+ console.log('🚀 Starting functions development server...');
6
+ // Initial build
7
+ await buildFunctions({
8
+ functionsDir,
9
+ outputDir,
10
+ ...buildOptions,
11
+ production: false,
12
+ });
13
+ if (!watchFiles) {
14
+ return;
15
+ }
16
+ // Watch for changes
17
+ const watcher = watch(functionsDir, {
18
+ ignored: [
19
+ '**/node_modules/**',
20
+ '**/.git/**',
21
+ '**/dist/**',
22
+ '**/.maravilla/**'
23
+ ],
24
+ persistent: true,
25
+ ignoreInitial: true,
26
+ });
27
+ let buildTimeout = null;
28
+ const rebuild = async () => {
29
+ if (buildTimeout) {
30
+ clearTimeout(buildTimeout);
31
+ }
32
+ buildTimeout = setTimeout(async () => {
33
+ console.log('\n🔄 Rebuilding functions...');
34
+ try {
35
+ await buildFunctions({
36
+ functionsDir,
37
+ outputDir,
38
+ ...buildOptions,
39
+ production: false,
40
+ });
41
+ if (onRebuild) {
42
+ onRebuild();
43
+ }
44
+ console.log('✅ Functions rebuilt successfully');
45
+ }
46
+ catch (error) {
47
+ console.error('❌ Failed to rebuild functions:', error);
48
+ }
49
+ }, 100);
50
+ };
51
+ watcher
52
+ .on('add', path => {
53
+ console.log(` Added: ${path}`);
54
+ rebuild();
55
+ })
56
+ .on('change', path => {
57
+ console.log(` Changed: ${path}`);
58
+ rebuild();
59
+ })
60
+ .on('unlink', path => {
61
+ console.log(` Removed: ${path}`);
62
+ rebuild();
63
+ });
64
+ console.log(`👀 Watching for changes in ${functionsDir}...`);
65
+ // Return cleanup function
66
+ return () => {
67
+ watcher.close();
68
+ };
69
+ }
70
+ //# sourceMappingURL=dev.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev.js","sourceRoot":"","sources":["../src/dev.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAEjC,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAQ5C,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,UAA4B,EAAE;IACpE,MAAM,EACJ,YAAY,GAAG,WAAW,EAC1B,SAAS,GAAG,YAAY,EACxB,KAAK,EAAE,UAAU,GAAG,IAAI,EACxB,SAAS,EACT,GAAG,YAAY,EAChB,GAAG,OAAO,CAAC;IAEZ,OAAO,CAAC,GAAG,CAAC,6CAA6C,CAAC,CAAC;IAE3D,gBAAgB;IAChB,MAAM,cAAc,CAAC;QACnB,YAAY;QACZ,SAAS;QACT,GAAG,YAAY;QACf,UAAU,EAAE,KAAK;KAClB,CAAC,CAAC;IAEH,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO;IACT,CAAC;IAED,oBAAoB;IACpB,MAAM,OAAO,GAAG,KAAK,CAAC,YAAY,EAAE;QAClC,OAAO,EAAE;YACP,oBAAoB;YACpB,YAAY;YACZ,YAAY;YACZ,kBAAkB;SACnB;QACD,UAAU,EAAE,IAAI;QAChB,aAAa,EAAE,IAAI;KACpB,CAAC,CAAC;IAEH,IAAI,YAAY,GAA0B,IAAI,CAAC;IAE/C,MAAM,OAAO,GAAG,KAAK,IAAI,EAAE;QACzB,IAAI,YAAY,EAAE,CAAC;YACjB,YAAY,CAAC,YAAY,CAAC,CAAC;QAC7B,CAAC;QAED,YAAY,GAAG,UAAU,CAAC,KAAK,IAAI,EAAE;YACnC,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;YAE5C,IAAI,CAAC;gBACH,MAAM,cAAc,CAAC;oBACnB,YAAY;oBACZ,SAAS;oBACT,GAAG,YAAY;oBACf,UAAU,EAAE,KAAK;iBAClB,CAAC,CAAC;gBAEH,IAAI,SAAS,EAAE,CAAC;oBACd,SAAS,EAAE,CAAC;gBACd,CAAC;gBAED,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;YAClD,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,KAAK,CAAC,gCAAgC,EAAE,KAAK,CAAC,CAAC;YACzD,CAAC;QACH,CAAC,EAAE,GAAG,CAAC,CAAC;IACV,CAAC,CAAC;IAEF,OAAO;SACJ,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE;QAChB,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC;QAChC,OAAO,EAAE,CAAC;IACZ,CAAC,CAAC;SACD,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE;QACnB,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,EAAE,CAAC,CAAC;QAClC,OAAO,EAAE,CAAC;IACZ,CAAC,CAAC;SACD,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE;QACnB,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,EAAE,CAAC,CAAC;QAClC,OAAO,EAAE,CAAC;IACZ,CAAC,CAAC,CAAC;IAEL,OAAO,CAAC,GAAG,CAAC,8BAA8B,YAAY,KAAK,CAAC,CAAC;IAE7D,0BAA0B;IAC1B,OAAO,GAAG,EAAE;QACV,OAAO,CAAC,KAAK,EAAE,CAAC;IAClB,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { DiscoveredFunctions } from './types.js';
2
+ export declare function discoverFunctions(functionsDir: string): Promise<DiscoveredFunctions>;
3
+ //# sourceMappingURL=discover.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discover.d.ts","sourceRoot":"","sources":["../src/discover.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAgB,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEpE,wBAAsB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAO1F"}
@@ -0,0 +1,144 @@
1
+ import { promises as fs } from 'node:fs';
2
+ import { join, relative } from 'node:path';
3
+ export async function discoverFunctions(functionsDir) {
4
+ const functions = {};
5
+ const routes = {};
6
+ await walkDirectory(functionsDir, functionsDir, functions, routes);
7
+ return { functions, routes };
8
+ }
9
+ async function walkDirectory(baseDir, currentDir, functions, routes) {
10
+ const entries = await fs.readdir(currentDir, { withFileTypes: true });
11
+ for (const entry of entries) {
12
+ const fullPath = join(currentDir, entry.name);
13
+ if (entry.isDirectory()) {
14
+ // Skip dist and node_modules
15
+ if (entry.name === 'dist' || entry.name === 'node_modules' || entry.name.startsWith('.')) {
16
+ continue;
17
+ }
18
+ // Check if this is a function directory with package.json
19
+ const packageJsonPath = join(fullPath, 'package.json');
20
+ const hasPackageJson = await fs.access(packageJsonPath).then(() => true).catch(() => false);
21
+ if (hasPackageJson) {
22
+ // This is a function package - look for src directory
23
+ const srcPath = join(fullPath, 'src');
24
+ const hasSrc = await fs.access(srcPath).then(() => true).catch(() => false);
25
+ if (hasSrc) {
26
+ // Walk the src directory for this function
27
+ await walkDirectory(baseDir, srcPath, functions, routes);
28
+ }
29
+ else {
30
+ // Fallback to the function directory itself
31
+ await walkDirectory(baseDir, fullPath, functions, routes);
32
+ }
33
+ }
34
+ else {
35
+ // Regular directory, continue walking
36
+ await walkDirectory(baseDir, fullPath, functions, routes);
37
+ }
38
+ }
39
+ else if (entry.isFile() && (entry.name.endsWith('.js') || entry.name.endsWith('.ts'))) {
40
+ // Skip test files and type definition files
41
+ if (entry.name.includes('.test.') || entry.name.includes('.spec.') || entry.name.endsWith('.d.ts')) {
42
+ continue;
43
+ }
44
+ const relativePath = relative(baseDir, fullPath);
45
+ const functionInfo = await analyzeFunction(fullPath, relativePath);
46
+ if (functionInfo) {
47
+ functions[functionInfo.name] = functionInfo;
48
+ routes[functionInfo.route] = functionInfo;
49
+ }
50
+ }
51
+ }
52
+ }
53
+ async function analyzeFunction(filePath, relativePath) {
54
+ try {
55
+ const content = await fs.readFile(filePath, 'utf8');
56
+ // Generate function name from file path
57
+ const name = generateFunctionName(relativePath);
58
+ // Generate route from file path
59
+ const route = generateRoute(relativePath);
60
+ // Analyze supported HTTP methods
61
+ const methods = analyzeMethods(content);
62
+ // Skip files that don't export any HTTP methods
63
+ if (methods.length === 0) {
64
+ console.log(` Skipping ${relativePath} - no HTTP methods detected`);
65
+ return null;
66
+ }
67
+ return {
68
+ name,
69
+ route,
70
+ methods,
71
+ filePath,
72
+ relativePath,
73
+ importPath: filePath,
74
+ };
75
+ }
76
+ catch (error) {
77
+ console.warn(` Failed to analyze function ${relativePath}:`, error);
78
+ return null;
79
+ }
80
+ }
81
+ function generateFunctionName(relativePath) {
82
+ // Convert path to camelCase function name
83
+ // e.g., "auth/login.js" -> "authLogin"
84
+ const pathWithoutExt = relativePath.replace(/\.(js|ts)$/, '');
85
+ const parts = pathWithoutExt.split(/[\/\\]/);
86
+ return parts
87
+ .map((part, index) => {
88
+ // Remove index suffix from filenames
89
+ if (part === 'index') {
90
+ return '';
91
+ }
92
+ // Convert kebab-case to camelCase
93
+ const camelCased = part.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
94
+ // Capitalize first letter of each part except the first
95
+ return index === 0 ? camelCased : camelCased.charAt(0).toUpperCase() + camelCased.slice(1);
96
+ })
97
+ .filter(Boolean)
98
+ .join('');
99
+ }
100
+ function generateRoute(relativePath) {
101
+ // Convert path to API route
102
+ // e.g., "auth/login.js" -> "/api/auth/login"
103
+ // e.g., "index.js" -> "/api"
104
+ let pathWithoutExt = relativePath.replace(/\.(js|ts)$/, '');
105
+ // Handle index files
106
+ if (pathWithoutExt === 'index') {
107
+ return '/api';
108
+ }
109
+ // Remove index from path parts
110
+ const parts = pathWithoutExt.split(/[\/\\]/).filter(part => part !== 'index');
111
+ // Convert to kebab-case
112
+ const routeParts = parts.map(part => part.replace(/([A-Z])/g, '-$1').toLowerCase());
113
+ return '/api/' + routeParts.join('/');
114
+ }
115
+ function analyzeMethods(content) {
116
+ const methods = [];
117
+ const httpMethods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'];
118
+ // Look for exported HTTP method handlers
119
+ for (const method of httpMethods) {
120
+ // Check for named exports
121
+ if (content.includes(`export const ${method}`) ||
122
+ content.includes(`export function ${method}`) ||
123
+ content.includes(`export async function ${method}`)) {
124
+ methods.push(method);
125
+ }
126
+ }
127
+ // Check for default export that handles all methods
128
+ if (methods.length === 0) {
129
+ const hasDefaultExport = content.includes('export default');
130
+ if (hasDefaultExport) {
131
+ // Check if it looks like a request handler
132
+ const looksLikeHandler = content.includes('request') ||
133
+ content.includes('Request') ||
134
+ content.includes('req.method') ||
135
+ content.includes('request.method');
136
+ if (looksLikeHandler) {
137
+ // Default export handles all methods
138
+ methods.push(...httpMethods);
139
+ }
140
+ }
141
+ }
142
+ return methods;
143
+ }
144
+ //# sourceMappingURL=discover.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discover.js","sourceRoot":"","sources":["../src/discover.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { FunctionInfo } from './types.js';
2
+ export declare function generateEntryFile(functions: Record<string, FunctionInfo>, routes: Record<string, FunctionInfo>): string;
3
+ //# sourceMappingURL=generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../src/generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,EACvC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,GACnC,MAAM,CAsJR"}
@@ -0,0 +1,147 @@
1
+ export function generateEntryFile(functions, routes) {
2
+ let code = `// Maravilla Edge Functions Entry Point
3
+ // Auto-generated file - do not edit
4
+
5
+ `;
6
+ // Import all functions
7
+ for (const [name, func] of Object.entries(functions)) {
8
+ code += `import * as ${name}_exports from '${func.importPath}';\n`;
9
+ }
10
+ code += `
11
+ // Route registry
12
+ const ROUTE_REGISTRY = ${JSON.stringify(routes, null, 2)};
13
+
14
+ // Function registry - map function names to their exports
15
+ const FUNCTION_REGISTRY = {
16
+ `;
17
+ for (const [name] of Object.entries(functions)) {
18
+ code += ` '${name}': ${name}_exports,\n`;
19
+ }
20
+ code += `};
21
+
22
+ // Main request handler for functions
23
+ export async function handleFunctionRequest(request) {
24
+ const url = new URL(request.url);
25
+ const path = url.pathname;
26
+
27
+ // Find matching function
28
+ let functionInfo = ROUTE_REGISTRY[path];
29
+ if (!functionInfo) {
30
+ // Try to match with trailing slash removed
31
+ const pathWithoutSlash = path.replace(/\\/$/, '');
32
+ functionInfo = ROUTE_REGISTRY[pathWithoutSlash];
33
+
34
+ if (!functionInfo) {
35
+ return new Response(
36
+ JSON.stringify({ error: 'Function not found', path }),
37
+ {
38
+ status: 404,
39
+ headers: { 'content-type': 'application/json' }
40
+ }
41
+ );
42
+ }
43
+ }
44
+
45
+ // Get function exports
46
+ const functionExports = FUNCTION_REGISTRY[functionInfo.name];
47
+ if (!functionExports) {
48
+ return new Response(
49
+ JSON.stringify({ error: 'Function not registered', function: functionInfo.name }),
50
+ {
51
+ status: 500,
52
+ headers: { 'content-type': 'application/json' }
53
+ }
54
+ );
55
+ }
56
+
57
+ // Find the appropriate handler
58
+ let handler = null;
59
+ const method = request.method.toUpperCase();
60
+
61
+ // Check for specific method handler
62
+ if (functionExports[method]) {
63
+ handler = functionExports[method];
64
+ } else if (functionExports.default) {
65
+ // Use default export as fallback
66
+ handler = functionExports.default;
67
+ }
68
+
69
+ if (!handler) {
70
+ return new Response(
71
+ JSON.stringify({
72
+ error: 'Method not allowed',
73
+ method: request.method,
74
+ allowed: functionInfo.methods
75
+ }),
76
+ {
77
+ status: 405,
78
+ headers: {
79
+ 'content-type': 'application/json',
80
+ 'allow': functionInfo.methods.join(', ')
81
+ }
82
+ }
83
+ );
84
+ }
85
+
86
+ try {
87
+ // Call the handler - await the result
88
+ const response = await handler(request);
89
+
90
+ // If handler returns a Response object, use it directly
91
+ if (response instanceof Response) {
92
+ return response;
93
+ }
94
+
95
+ // Otherwise, wrap the result in a Response
96
+ return new Response(
97
+ JSON.stringify(response),
98
+ {
99
+ status: 200,
100
+ headers: { 'content-type': 'application/json' }
101
+ }
102
+ );
103
+ } catch (error) {
104
+ console.error('Function execution error:', error);
105
+
106
+ return new Response(
107
+ JSON.stringify({
108
+ error: 'Function execution failed',
109
+ message: error.message,
110
+ stack: process.env.NODE_ENV === 'development' ? error.stack : undefined
111
+ }),
112
+ {
113
+ status: 500,
114
+ headers: { 'content-type': 'application/json' }
115
+ }
116
+ );
117
+ }
118
+ }
119
+
120
+ // Export route matcher for runtime integration
121
+ export function matchFunctionRoute(path) {
122
+ // Direct match
123
+ if (ROUTE_REGISTRY[path]) {
124
+ return true;
125
+ }
126
+
127
+ // Try without trailing slash
128
+ const pathWithoutSlash = path.replace(/\\/$/, '');
129
+ if (ROUTE_REGISTRY[pathWithoutSlash]) {
130
+ return true;
131
+ }
132
+
133
+ return false;
134
+ }
135
+
136
+ // Export function metadata
137
+ export const functionMetadata = {
138
+ routes: Object.keys(ROUTE_REGISTRY),
139
+ functions: Object.keys(FUNCTION_REGISTRY),
140
+ count: Object.keys(FUNCTION_REGISTRY).length,
141
+ };
142
+
143
+ console.log(\`✅ Edge functions router initialized with \${functionMetadata.count} functions\`);
144
+ `;
145
+ return code;
146
+ }
147
+ //# sourceMappingURL=generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator.js","sourceRoot":"","sources":["../src/generator.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,iBAAiB,CAC/B,SAAuC,EACvC,MAAoC;IAEpC,IAAI,IAAI,GAAG;;;CAGZ,CAAC;IAEA,uBAAuB;IACvB,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QACrD,IAAI,IAAI,eAAe,IAAI,kBAAkB,IAAI,CAAC,UAAU,MAAM,CAAC;IACrE,CAAC;IAED,IAAI,IAAI;;yBAEe,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;;;;CAIvD,CAAC;IAEA,KAAK,MAAM,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QAC/C,IAAI,IAAI,MAAM,IAAI,MAAM,IAAI,aAAa,CAAC;IAC5C,CAAC;IAED,IAAI,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4HT,CAAC;IAEA,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { FunctionManifest, BuildOptions } from './types.js';
2
+ export { discoverFunctions } from './discover.js';
3
+ export { developmentServer } from './dev.js';
4
+ export type { FunctionManifest, FunctionRoute, BuildOptions } from './types.js';
5
+ export declare function buildFunctions(options?: BuildOptions): Promise<FunctionManifest | null>;
6
+ export declare function integrateWithManifest(manifestPath: string, functionsManifest: FunctionManifest | null): Promise<void>;
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAiB,YAAY,EAAE,MAAM,YAAY,CAAC;AAEhF,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC7C,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEhF,wBAAsB,cAAc,CAAC,OAAO,GAAE,YAAiB,oCAwG9D;AAwCD,wBAAsB,qBAAqB,CACzC,YAAY,EAAE,MAAM,EACpB,iBAAiB,EAAE,gBAAgB,GAAG,IAAI,iBAyC3C"}
package/dist/index.js ADDED
@@ -0,0 +1,155 @@
1
+ import { promises as fs } from 'node:fs';
2
+ import { join, resolve } from 'node:path';
3
+ import * as esbuild from 'esbuild';
4
+ import { discoverFunctions } from './discover.js';
5
+ import { generateEntryFile } from './generator.js';
6
+ export { discoverFunctions } from './discover.js';
7
+ export { developmentServer } from './dev.js';
8
+ export async function buildFunctions(options = {}) {
9
+ const { functionsDir = 'functions', outputDir = '.maravilla', minify = false, sourcemap = false, production = false, } = options;
10
+ const resolvedFunctionsDir = resolve(functionsDir);
11
+ const resolvedOutputDir = resolve(outputDir);
12
+ console.log('🔨 Building edge functions...');
13
+ console.log(` Functions directory: ${resolvedFunctionsDir}`);
14
+ console.log(` Output directory: ${resolvedOutputDir}`);
15
+ // Check if functions directory exists
16
+ const hasFunctions = await fs.access(resolvedFunctionsDir).then(() => true).catch(() => false);
17
+ if (!hasFunctions) {
18
+ console.log(' No functions directory found, skipping functions build');
19
+ return null;
20
+ }
21
+ // Check for and install function dependencies if needed
22
+ await installFunctionDependencies(resolvedFunctionsDir);
23
+ // Discover all functions
24
+ const { functions, routes } = await discoverFunctions(resolvedFunctionsDir);
25
+ if (Object.keys(functions).length === 0) {
26
+ console.log(' No functions found in directory');
27
+ return null;
28
+ }
29
+ console.log(`📦 Found ${Object.keys(functions).length} functions:`);
30
+ for (const [route, func] of Object.entries(routes)) {
31
+ console.log(` ${route} → ${func.name} (${func.methods.join(', ')})`);
32
+ }
33
+ // Create output directory
34
+ await fs.mkdir(resolvedOutputDir, { recursive: true });
35
+ // Create temp directory for build
36
+ const tempDir = join(resolvedOutputDir, '.temp');
37
+ await fs.mkdir(tempDir, { recursive: true });
38
+ // Generate entry file
39
+ const entryContent = generateEntryFile(functions, routes);
40
+ const entryPath = join(tempDir, 'functions-entry.js');
41
+ await fs.writeFile(entryPath, entryContent);
42
+ // Bundle with esbuild
43
+ const result = await esbuild.build({
44
+ entryPoints: [entryPath],
45
+ bundle: true,
46
+ outfile: join(resolvedOutputDir, 'functions.js'),
47
+ format: 'esm',
48
+ platform: 'neutral',
49
+ target: 'es2022',
50
+ minify: minify || production,
51
+ sourcemap: sourcemap,
52
+ external: [
53
+ // Platform APIs are provided by runtime
54
+ '@maravilla/platform',
55
+ ],
56
+ define: {
57
+ 'process.env.NODE_ENV': production ? '"production"' : '"development"'
58
+ },
59
+ metafile: true,
60
+ });
61
+ // Clean up temp directory
62
+ await fs.rm(tempDir, { recursive: true, force: true });
63
+ // Generate functions manifest
64
+ const functionsManifest = {
65
+ version: 1,
66
+ functions: Object.keys(functions).length,
67
+ routes: Object.entries(routes).map(([path, func]) => ({
68
+ path,
69
+ name: func.name,
70
+ methods: func.methods,
71
+ file: func.relativePath,
72
+ })),
73
+ bundle: 'functions.js',
74
+ buildTime: new Date().toISOString(),
75
+ };
76
+ // Write functions manifest
77
+ await fs.writeFile(join(resolvedOutputDir, 'functions.json'), JSON.stringify(functionsManifest, null, 2));
78
+ if (result.metafile) {
79
+ const analysis = await esbuild.analyzeMetafile(result.metafile);
80
+ console.log('\nBundle analysis:');
81
+ console.log(analysis);
82
+ }
83
+ console.log('✅ Functions build completed successfully!');
84
+ return functionsManifest;
85
+ }
86
+ async function installFunctionDependencies(functionsDir) {
87
+ try {
88
+ const entries = await fs.readdir(functionsDir, { withFileTypes: true });
89
+ for (const entry of entries) {
90
+ if (entry.isDirectory()) {
91
+ const funcDir = join(functionsDir, entry.name);
92
+ const packageJsonPath = join(funcDir, 'package.json');
93
+ // Check if function has package.json
94
+ const hasPackageJson = await fs.access(packageJsonPath).then(() => true).catch(() => false);
95
+ if (hasPackageJson) {
96
+ // Check if node_modules exists
97
+ const nodeModulesPath = join(funcDir, 'node_modules');
98
+ const hasNodeModules = await fs.access(nodeModulesPath).then(() => true).catch(() => false);
99
+ if (!hasNodeModules) {
100
+ console.log(` 📦 Installing dependencies for function: ${entry.name}`);
101
+ const { exec } = await import('child_process');
102
+ const { promisify } = await import('util');
103
+ const execAsync = promisify(exec);
104
+ try {
105
+ // Try npm first, then pnpm if available
106
+ await execAsync('npm install', { cwd: funcDir });
107
+ }
108
+ catch (error) {
109
+ console.warn(` Warning: Failed to install dependencies for ${entry.name}:`, error);
110
+ }
111
+ }
112
+ }
113
+ }
114
+ }
115
+ }
116
+ catch (error) {
117
+ console.warn(' Warning: Could not check for function dependencies:', error);
118
+ }
119
+ }
120
+ export async function integrateWithManifest(manifestPath, functionsManifest) {
121
+ if (!functionsManifest) {
122
+ return;
123
+ }
124
+ // Read existing manifest
125
+ const manifestContent = await fs.readFile(manifestPath, 'utf-8');
126
+ const manifest = JSON.parse(manifestContent);
127
+ // Add functions section to manifest
128
+ manifest.functions = {
129
+ enabled: true,
130
+ bundle: functionsManifest.bundle,
131
+ routes: functionsManifest.routes.map(route => ({
132
+ ...route,
133
+ // Ensure all function routes start with /api
134
+ path: route.path.startsWith('/api') ? route.path : `/api${route.path}`,
135
+ })),
136
+ metadata: {
137
+ count: functionsManifest.functions,
138
+ buildTime: functionsManifest.buildTime,
139
+ }
140
+ };
141
+ // Update routing to include functions
142
+ if (!manifest.routing) {
143
+ manifest.routing = {};
144
+ }
145
+ // Add functions routes to routing configuration
146
+ manifest.routing.functions = functionsManifest.routes.map(route => ({
147
+ path: route.path.startsWith('/api') ? route.path : `/api${route.path}`,
148
+ methods: route.methods,
149
+ handler: 'function',
150
+ }));
151
+ // Write updated manifest
152
+ await fs.writeFile(manifestPath, JSON.stringify(manifest, null, 2));
153
+ console.log('📝 Updated manifest.json with functions configuration');
154
+ }
155
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ export interface FunctionInfo {
2
+ name: string;
3
+ route: string;
4
+ methods: string[];
5
+ filePath: string;
6
+ relativePath: string;
7
+ importPath: string;
8
+ }
9
+ export interface FunctionRoute {
10
+ path: string;
11
+ name: string;
12
+ methods: string[];
13
+ file: string;
14
+ }
15
+ export interface FunctionManifest {
16
+ version: number;
17
+ functions: number;
18
+ routes: FunctionRoute[];
19
+ bundle: string;
20
+ buildTime: string;
21
+ }
22
+ export interface BuildOptions {
23
+ functionsDir?: string;
24
+ outputDir?: string;
25
+ minify?: boolean;
26
+ sourcemap?: boolean;
27
+ production?: boolean;
28
+ }
29
+ export interface DiscoveredFunctions {
30
+ functions: Record<string, FunctionInfo>;
31
+ routes: Record<string, FunctionInfo>;
32
+ }
33
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACxC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;CACtC"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@maravilla-labs/functions",
3
+ "version": "0.1.0",
4
+ "description": "Maravilla Edge Functions bundler and development tools",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "bin"
17
+ ],
18
+ "bin": {
19
+ "maravilla-functions": "./bin/cli.js"
20
+ },
21
+ "scripts": {
22
+ "build": "tsc",
23
+ "dev": "tsc --watch",
24
+ "clean": "rm -rf dist",
25
+ "prepack": "pnpm build"
26
+ },
27
+ "keywords": [
28
+ "edge-functions",
29
+ "serverless",
30
+ "bundler",
31
+ "maravilla",
32
+ "runtime"
33
+ ],
34
+ "author": "SOLUTAS GmbH",
35
+ "license": "Proprietary",
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "https://github.com/solutas/maravilla-runtime.git",
39
+ "directory": "packages/functions"
40
+ },
41
+ "publishConfig": {
42
+ "access": "public"
43
+ },
44
+ "dependencies": {
45
+ "esbuild": "^0.25.8",
46
+ "chokidar": "^3.5.3"
47
+ },
48
+ "devDependencies": {
49
+ "@types/node": "^20.10.5",
50
+ "typescript": "^5.3.3"
51
+ },
52
+ "engines": {
53
+ "node": ">=18.0.0"
54
+ }
55
+ }