@nlabs/lex 1.48.7 → 1.49.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.
Files changed (105) hide show
  1. package/.storybook/main.ts +9 -2
  2. package/.vscode/settings.json +1 -6
  3. package/README.md +249 -0
  4. package/eslint.config.mjs +24 -0
  5. package/examples/lex.config.js +18 -8
  6. package/examples/serverless-example/README.md +109 -0
  7. package/examples/serverless-example/dist/handlers/echo.js +15 -0
  8. package/examples/serverless-example/dist/handlers/graphql.js +137 -0
  9. package/examples/serverless-example/dist/handlers/hello.js +15 -0
  10. package/examples/serverless-example/dist/handlers/test.js +17 -0
  11. package/examples/serverless-example/dist/handlers/websocket.js +14 -0
  12. package/examples/serverless-example/lex.config.mjs +74 -0
  13. package/jest.config.mjs +13 -12
  14. package/{dist → lib}/LexConfig.d.ts +7 -6
  15. package/lib/LexConfig.js +268 -0
  16. package/lib/commands/ai/ai.js +303 -0
  17. package/{dist → lib}/commands/build/build.d.ts +3 -0
  18. package/lib/commands/build/build.js +494 -0
  19. package/{dist → lib}/commands/clean/clean.js +1 -1
  20. package/lib/commands/compile/compile.js +241 -0
  21. package/lib/commands/copy/copy.js +38 -0
  22. package/{dist → lib}/commands/create/create.js +1 -1
  23. package/{dist → lib}/commands/dev/dev.d.ts +2 -0
  24. package/lib/commands/dev/dev.js +286 -0
  25. package/{dist → lib}/commands/init/init.js +1 -1
  26. package/lib/commands/lint/lint.js +993 -0
  27. package/{dist → lib}/commands/migrate/migrate.js +1 -1
  28. package/lib/commands/publish/publish.js +104 -0
  29. package/lib/commands/serverless/serverless.d.ts +17 -0
  30. package/lib/commands/serverless/serverless.js +662 -0
  31. package/lib/commands/storybook/storybook.js +249 -0
  32. package/lib/commands/test/test.js +428 -0
  33. package/lib/commands/update/update.js +128 -0
  34. package/{dist → lib}/create/changelog.js +1 -1
  35. package/{dist → lib}/index.d.ts +1 -0
  36. package/{dist → lib}/index.js +2 -1
  37. package/lib/lex.js +73 -0
  38. package/lib/utils/aiService.d.ts +9 -0
  39. package/lib/utils/aiService.js +299 -0
  40. package/{dist → lib}/utils/app.d.ts +3 -0
  41. package/lib/utils/app.js +296 -0
  42. package/{dist → lib}/utils/file.d.ts +7 -3
  43. package/lib/utils/file.js +229 -0
  44. package/lib/utils/translations.d.ts +1 -0
  45. package/lib/utils/translations.js +74 -0
  46. package/package.json +59 -53
  47. package/postcss.config.js +5 -3
  48. package/tsconfig.build.json +2 -2
  49. package/webpack.config.js +229 -39
  50. package/dist/LexConfig.js +0 -287
  51. package/dist/commands/ai/ai.js +0 -303
  52. package/dist/commands/build/build.js +0 -404
  53. package/dist/commands/compile/compile.js +0 -234
  54. package/dist/commands/copy/copy.js +0 -38
  55. package/dist/commands/dev/dev.js +0 -74
  56. package/dist/commands/lint/lint.js +0 -993
  57. package/dist/commands/publish/publish.js +0 -104
  58. package/dist/commands/storybook/storybook.js +0 -249
  59. package/dist/commands/test/test.js +0 -429
  60. package/dist/commands/update/update.js +0 -132
  61. package/dist/lex.js +0 -70
  62. package/dist/utils/aiService.d.ts +0 -9
  63. package/dist/utils/aiService.js +0 -299
  64. package/dist/utils/app.js +0 -267
  65. package/dist/utils/file.js +0 -185
  66. package/emptyModule.js +0 -0
  67. package/eslint.config.js +0 -3
  68. /package/{dist → lib}/Button.stories.d.ts +0 -0
  69. /package/{dist → lib}/commands/ai/ai.d.ts +0 -0
  70. /package/{dist → lib}/commands/ai/index.d.ts +0 -0
  71. /package/{dist → lib}/commands/ai/index.js +0 -0
  72. /package/{dist → lib}/commands/clean/clean.d.ts +0 -0
  73. /package/{dist → lib}/commands/compile/compile.d.ts +0 -0
  74. /package/{dist → lib}/commands/config/config.d.ts +0 -0
  75. /package/{dist → lib}/commands/config/config.js +0 -0
  76. /package/{dist → lib}/commands/copy/copy.d.ts +0 -0
  77. /package/{dist → lib}/commands/create/create.d.ts +0 -0
  78. /package/{dist → lib}/commands/init/init.d.ts +0 -0
  79. /package/{dist → lib}/commands/link/link.d.ts +0 -0
  80. /package/{dist → lib}/commands/link/link.js +0 -0
  81. /package/{dist → lib}/commands/lint/autofix.d.ts +0 -0
  82. /package/{dist → lib}/commands/lint/lint.d.ts +0 -0
  83. /package/{dist → lib}/commands/migrate/migrate.d.ts +0 -0
  84. /package/{dist → lib}/commands/publish/publish.d.ts +0 -0
  85. /package/{dist → lib}/commands/storybook/storybook.d.ts +0 -0
  86. /package/{dist → lib}/commands/test/test.d.ts +0 -0
  87. /package/{dist → lib}/commands/update/update.d.ts +0 -0
  88. /package/{dist → lib}/commands/upgrade/upgrade.d.ts +0 -0
  89. /package/{dist → lib}/commands/upgrade/upgrade.js +0 -0
  90. /package/{dist → lib}/commands/versions/versions.d.ts +0 -0
  91. /package/{dist → lib}/commands/versions/versions.js +0 -0
  92. /package/{dist → lib}/create/changelog.d.ts +0 -0
  93. /package/{dist → lib}/lex.d.ts +0 -0
  94. /package/{dist → lib}/storybook/index.d.ts +0 -0
  95. /package/{dist → lib}/storybook/index.js +0 -0
  96. /package/{dist → lib}/test-react/index.d.ts +0 -0
  97. /package/{dist → lib}/test-react/index.js +0 -0
  98. /package/{dist → lib}/types.d.ts +0 -0
  99. /package/{dist → lib}/types.js +0 -0
  100. /package/{dist → lib}/utils/deepMerge.d.ts +0 -0
  101. /package/{dist → lib}/utils/deepMerge.js +0 -0
  102. /package/{dist → lib}/utils/log.d.ts +0 -0
  103. /package/{dist → lib}/utils/log.js +0 -0
  104. /package/{dist → lib}/utils/reactShim.d.ts +0 -0
  105. /package/{dist → lib}/utils/reactShim.js +0 -0
@@ -50,9 +50,9 @@ const config = {
50
50
  loader: 'babel-loader',
51
51
  options: {
52
52
  presets: [
53
- '/Users/nitrog7/Development/gothamjs/node_modules/@babel/preset-typescript',
53
+ '@babel/preset-typescript',
54
54
  [
55
- '/Users/nitrog7/Development/gothamjs/node_modules/@babel/preset-react',
55
+ '@babel/preset-react',
56
56
  {
57
57
  runtime: 'automatic'
58
58
  }
@@ -63,6 +63,13 @@ const config = {
63
63
  ]
64
64
  }
65
65
  ]
66
+ },
67
+ resolve: {
68
+ ...config.resolve,
69
+ extensions: ['.js', '.ts', '.tsx', '.json', '.mdx'],
70
+ extensionAlias: {
71
+ '.js': ['.ts', '.tsx', '.js']
72
+ }
66
73
  }
67
74
  };
68
75
  }
@@ -6,7 +6,7 @@
6
6
  "editor.defaultFormatter": "dbaeumer.vscode-eslint"
7
7
  },
8
8
  "[typescript]": {
9
- "editor.defaultFormatter": "vscode.typescript-language-features"
9
+ "editor.defaultFormatter": "dbaeumer.vscode-eslint"
10
10
  },
11
11
  "[typescriptreact]": {
12
12
  "editor.defaultFormatter": "dbaeumer.vscode-eslint"
@@ -43,12 +43,7 @@
43
43
  "eslint.experimental.useFlatConfig": true,
44
44
  "eslint.format.enable": true,
45
45
  "eslint.lintTask.enable": true,
46
- "eslint.nodePath": "./node_modules",
47
- "eslint.options": {
48
- "overrideConfigFile": "./eslint.config.js"
49
- },
50
46
  "eslint.run": "onType",
51
- "eslint.runtime": "./node_modules/eslint/bin/eslint.js",
52
47
  "eslint.validate": [
53
48
  "javascript",
54
49
  "javascriptreact",
package/README.md CHANGED
@@ -142,8 +142,17 @@ lex dev --bundleAnalyzer
142
142
 
143
143
  # Custom webpack config
144
144
  lex dev --config ./custom.webpack.js
145
+
146
+ # Force refresh cached public IP
147
+ lex dev --usePublicIp
145
148
  ```
146
149
 
150
+ **🌐 Public IP Caching**: Lex automatically caches your public IP address for 1 week to reduce API calls. Use `--usePublicIp` to force refresh the cache when needed.
151
+
152
+ **📁 Static Assets**: If your HTML template references static assets (like favicon.ico, manifest.json, or images) with absolute paths, ensure these files exist in your source directory or use relative paths to avoid webpack compilation errors.
153
+
154
+ **🎨 Public Assets**: Use the `webpack.publicPath` configuration to specify a directory for public assets (images, videos, audio, PDFs, etc.). Files in this directory will be automatically copied to the output and optimized for web delivery.
155
+
147
156
  ### 🏗️ **Production Builds**
148
157
 
149
158
  ```bash
@@ -270,6 +279,246 @@ export default {
270
279
  };
271
280
  ```
272
281
 
282
+ ## 📋 Configuration Options Reference
283
+
284
+ Lex provides extensive configuration options through the `lex.config.js` file. Here's a comprehensive reference of all available options:
285
+
286
+ ### 🎯 **Project Settings**
287
+
288
+ | Option | Type | Default | Description | Example |
289
+ |--------|------|---------|-------------|---------|
290
+ | `entryHTML` | `string` | `'index.html'` | HTML template file | `entryHTML: 'app.html'` |
291
+ | `entryJs` | `string` | `'index.js'` | Main JavaScript entry file | `entryJs: 'main.tsx'` |
292
+ | `outputFile` | `string` | `undefined` | Specific output filename | `outputFile: 'bundle.js'` |
293
+ | `outputFullPath` | `string` | `path.resolve('./dist')` | Absolute output path for build artifacts. Used by webpack dev server for static file serving. | `outputFullPath: '/absolute/build'` |
294
+ | `outputHash` | `boolean` | `false` | Add hash to output filenames | `outputHash: true` |
295
+ | `outputPath` | `string` | `'./dist'` | Output directory path | `outputPath: './build'` |
296
+ | `packageManager` | `'npm' \| 'yarn'` | `'npm'` | Package manager to use | `packageManager: 'yarn'` |
297
+ | `preset` | `'web' \| 'node' \| 'lambda' \| 'mobile'` | `'web'` | Project preset type | `preset: 'node'` |
298
+ | `sourceFullPath` | `string` | `path.resolve('./src')` | Absolute source code path | `sourceFullPath: '/absolute/path'` |
299
+ | `sourcePath` | `string` | `'./src'` | Source code directory path | `sourcePath: './app'` |
300
+ | `targetEnvironment` | `'web' \| 'node'` | `'web'` | Target runtime environment | `targetEnvironment: 'node'` |
301
+ | `useGraphQl` | `boolean` | `false` | Enable GraphQL support | `useGraphQl: true` |
302
+ | `useTypescript` | `boolean` | `false` | Enable TypeScript support | `useTypescript: true` |
303
+
304
+ ### 🤖 **AI Configuration**
305
+
306
+ | Option | Type | Default | Description | Example |
307
+ |--------|------|---------|-------------|---------|
308
+ | `ai.apiKey` | `string` | `undefined` | API key for AI provider | `ai: { apiKey: 'sk-...' }` |
309
+ | `ai.maxTokens` | `number` | `4000` | Maximum tokens for AI responses | `ai: { maxTokens: 8000 }` |
310
+ | `ai.model` | `string` | `'gpt-4o'` | AI model to use | `ai: { model: 'gpt-4' }` |
311
+ | `ai.provider` | `'cursor' \| 'copilot' \| 'openai' \| 'anthropic' \| 'none'` | `'none'` | AI service provider | `ai: { provider: 'openai' }` |
312
+ | `ai.temperature` | `number` | `0.1` | AI response creativity (0-1) | `ai: { temperature: 0.7 }` |
313
+
314
+ ### ⚡ **ESBuild Configuration**
315
+
316
+ | Option | Type | Default | Description | Example |
317
+ |--------|------|---------|-------------|---------|
318
+ | `esbuild.banner` | `Record<string, string>` | `undefined` | Banner text for output files | `esbuild: { banner: { js: '// My Banner' } }` |
319
+ | `esbuild.define` | `Record<string, string>` | `undefined` | Global variable definitions | `esbuild: { define: { 'process.env.NODE_ENV': '"production"' } }` |
320
+ | `esbuild.drop` | `string[]` | `['console', 'debugger']` | Code to drop in production | `esbuild: { drop: ['console'] }` |
321
+ | `esbuild.entryPoints` | `string[]` | `undefined` | Entry points for ESBuild | `esbuild: { entryPoints: ['src/index.ts'] }` |
322
+ | `esbuild.external` | `string[]` | `undefined` | External dependencies | `esbuild: { external: ['react'] }` |
323
+ | `esbuild.footer` | `Record<string, string>` | `undefined` | Footer text for output files | `esbuild: { footer: { js: '// My Footer' } }` |
324
+ | `esbuild.format` | `'cjs' \| 'esm'` | `undefined` | Output format | `esbuild: { format: 'esm' }` |
325
+ | `esbuild.legalComments` | `'none' \| 'inline' \| 'eof' \| 'linked' \| 'separate'` | `'none'` | Legal comments handling | `esbuild: { legalComments: 'inline' }` |
326
+ | `esbuild.metafile` | `boolean` | `false` | Generate metafile | `esbuild: { metafile: true }` |
327
+ | `esbuild.minify` | `boolean` | `true` | Enable minification | `esbuild: { minify: false }` |
328
+ | `esbuild.outdir` | `string` | `undefined` | Output directory for ESBuild | `esbuild: { outdir: './build' }` |
329
+ | `esbuild.platform` | `'node' \| 'browser'` | `undefined` | Target platform | `esbuild: { platform: 'browser' }` |
330
+ | `esbuild.pure` | `string[]` | `['console.log', 'console.warn', 'console.error']` | Pure function calls | `esbuild: { pure: ['console.log'] }` |
331
+ | `esbuild.sourcemap` | `boolean \| 'inline' \| 'external'` | `false` | Source map generation | `esbuild: { sourcemap: true }` |
332
+ | `esbuild.splitting` | `boolean` | `true` | Enable code splitting | `esbuild: { splitting: false }` |
333
+ | `esbuild.target` | `string` | `undefined` | Target environment | `esbuild: { target: 'es2020' }` |
334
+ | `esbuild.treeShaking` | `boolean` | `true` | Enable tree shaking | `esbuild: { treeShaking: false }` |
335
+
336
+ ### 🧪 **Jest Configuration**
337
+
338
+ | Option | Type | Default | Description | Example |
339
+ |--------|------|---------|-------------|---------|
340
+ | `jest.extensionsToTreatAsEsm` | `string[]` | `undefined` | Extensions to treat as ES modules | `jest: { extensionsToTreatAsEsm: ['.ts', '.tsx'] }` |
341
+ | `jest.moduleNameMapper` | `Record<string, string>` | `undefined` | Module name mappings | `jest: { moduleNameMapper: { '\\.(css)$': 'identity-obj-proxy' } }` |
342
+ | `jest.preset` | `string` | `undefined` | Jest preset | `jest: { preset: 'ts-jest' }` |
343
+ | `jest.roots` | `string[]` | `undefined` | Test root directories | `jest: { roots: ['<rootDir>/src'] }` |
344
+ | `jest.testEnvironment` | `string` | `undefined` | Test environment | `jest: { testEnvironment: 'jsdom' }` |
345
+ | `jest.transform` | `Record<string, [string, object]>` | `undefined` | Transform configurations | `jest: { transform: { '^.+\\.tsx?$': ['ts-jest'] } }` |
346
+ | `jest.transformIgnorePatterns` | `string[]` | `undefined` | Patterns to ignore in transforms | `jest: { transformIgnorePatterns: ['node_modules'] }` |
347
+
348
+ ### 🔧 **ESLint Configuration**
349
+
350
+ | Option | Type | Default | Description | Example |
351
+ |--------|------|---------|-------------|---------|
352
+ | `eslint.extends` | `string[]` | `undefined` | ESLint extends configurations | `eslint: { extends: ['@typescript-eslint/recommended'] }` |
353
+ | `eslint.rules` | `Linter.RulesRecord` | `undefined` | ESLint rules | `eslint: { rules: { 'no-console': 'warn' } }` |
354
+
355
+ ### 📦 **Webpack Configuration**
356
+
357
+ | Option | Type | Default | Description | Example |
358
+ |--------|------|---------|-------------|---------|
359
+ | `webpack.entry` | `string \| string[]` | `undefined` | Webpack entry points | `webpack: { entry: './src/index.js' }` |
360
+ | `webpack.module` | `object` | `undefined` | Webpack module configuration | `webpack: { module: { rules: [...] } }` |
361
+ | `webpack.output` | `object` | `undefined` | Webpack output configuration | `webpack: { output: { filename: 'bundle.js' } }` |
362
+ | `webpack.plugins` | `unknown[]` | `undefined` | Webpack plugins | `webpack: { plugins: [new MyPlugin()] }` |
363
+ | `webpack.publicPath` | `string` | `'./src/static'` | Path to public assets directory. Files in this directory will be copied to the output and optimized (images/videos compressed, audio optimized) | `webpack: { publicPath: './assets' }` |
364
+
365
+ ### 🔗 **Library Configuration**
366
+
367
+ | Option | Type | Default | Description | Example |
368
+ |--------|------|---------|-------------|---------|
369
+ | `libraryName` | `string` | `undefined` | Library name for UMD builds | `libraryName: 'MyLibrary'` |
370
+ | `libraryTarget` | `string` | `undefined` | Library target format | `libraryTarget: 'umd'` |
371
+
372
+ ### 📁 **File Management**
373
+
374
+ | Option | Type | Default | Description | Example |
375
+ |--------|------|---------|-------------|---------|
376
+ | `configFiles` | `string[]` | `[]` | Additional config files to include | `configFiles: ['./config/custom.js']` |
377
+ | `copyFiles` | `string[]` | `[]` | Files to copy during build | `copyFiles: ['public/assets']` |
378
+ | `env` | `object` | `null` | Environment variables | `env: { NODE_ENV: 'development' }` |
379
+ | `gitUrl` | `string` | `undefined` | Git repository URL | `gitUrl: 'https://github.com/user/repo'` |
380
+
381
+ ### 📝 **Usage Examples**
382
+
383
+ #### Basic TypeScript Project
384
+
385
+ ```javascript
386
+ export default {
387
+ useTypescript: true,
388
+ sourcePath: './src',
389
+ outputPath: './dist',
390
+ preset: 'web',
391
+ targetEnvironment: 'web'
392
+ };
393
+ ```
394
+
395
+ #### Node.js Library
396
+
397
+ ```javascript
398
+ export default {
399
+ useTypescript: true,
400
+ preset: 'node',
401
+ targetEnvironment: 'node',
402
+ libraryName: 'MyLibrary',
403
+ libraryTarget: 'umd',
404
+ esbuild: {
405
+ format: 'cjs',
406
+ platform: 'node',
407
+ external: ['lodash']
408
+ }
409
+ };
410
+ ```
411
+
412
+ #### AI-Powered Development
413
+
414
+ ```javascript
415
+ export default {
416
+ useTypescript: true,
417
+ ai: {
418
+ provider: 'openai',
419
+ apiKey: process.env.OPENAI_API_KEY,
420
+ model: 'gpt-4',
421
+ maxTokens: 8000,
422
+ temperature: 0.3
423
+ },
424
+ jest: {
425
+ testEnvironment: 'jsdom',
426
+ setupFilesAfterEnv: ['./src/setupTests.ts']
427
+ }
428
+ };
429
+ ```
430
+
431
+ #### Advanced ESBuild Configuration
432
+
433
+ ```javascript
434
+ export default {
435
+ useTypescript: true,
436
+ esbuild: {
437
+ minify: true,
438
+ sourcemap: 'inline',
439
+ target: 'es2020',
440
+ format: 'esm',
441
+ splitting: true,
442
+ metafile: true,
443
+ define: {
444
+ 'process.env.NODE_ENV': '"production"',
445
+ 'global': 'globalThis'
446
+ },
447
+ banner: {
448
+ js: '// My Awesome Library v1.0.0'
449
+ }
450
+ }
451
+ };
452
+ ```
453
+
454
+ ## 🚨 Troubleshooting
455
+
456
+ ### Common Issues
457
+
458
+ #### 404 Error with "Static Paths" Message
459
+
460
+ If you see a 404 error with a message like "Static Paths /path/to/dist", this is likely because the webpack dev server is trying to serve static files from a directory that doesn't exist yet.
461
+
462
+ **Solution**: The `outputFullPath` directory should exist before starting the dev server. You can:
463
+
464
+ - Run `lex build` first to create the output directory
465
+ - Or ensure your `outputPath` configuration points to an existing directory
466
+
467
+ #### Port Already in Use
468
+
469
+ If you get an "address already in use" error, another process is using the default port (7001).
470
+
471
+ **Solution**: Kill the existing process or use a different port:
472
+
473
+ ```bash
474
+ # Kill processes on port 7001
475
+ lsof -ti:7001 | xargs kill -9
476
+
477
+ # Or use a different port
478
+ lex dev --port 3000
479
+ ```
480
+
481
+ #### TypeScript Configuration Issues
482
+
483
+ If TypeScript compilation fails, ensure your `tsconfig.json` is properly configured.
484
+
485
+ **Solution**: Check that your `tsconfig.json` includes the correct paths:
486
+
487
+ ```json
488
+ {
489
+ "compilerOptions": {
490
+ "outDir": "./dist",
491
+ "rootDir": "./src"
492
+ },
493
+ "include": ["src/**/*"],
494
+ "exclude": ["node_modules", "dist"]
495
+ }
496
+ ```
497
+
498
+ #### Missing Static Assets Error
499
+
500
+ If you see webpack compilation errors about missing static assets (like favicon.ico, manifest.json, or images), this is because your HTML template references files that don't exist.
501
+
502
+ **Solution**: Either create the missing files or update your HTML template to use relative paths:
503
+
504
+ ```html
505
+ <!-- Instead of absolute paths -->
506
+ <link rel="icon" href="/favicon.ico" />
507
+ <link rel="manifest" href="/manifest.json" />
508
+
509
+ <!-- Use relative paths -->
510
+ <link rel="icon" href="favicon.ico" />
511
+ <link rel="manifest" href="manifest.json" />
512
+ ```
513
+
514
+ Or create the missing files in your source directory:
515
+
516
+ ```bash
517
+ touch src/favicon.ico
518
+ touch src/manifest.json
519
+ mkdir -p src/images && touch src/images/logo-icon-64.png
520
+ ```
521
+
273
522
  ## 📚 Documentation
274
523
 
275
524
  - 📖 **[Full Documentation](http://lex.nitrogenlabs.com)** - Complete API reference
@@ -0,0 +1,24 @@
1
+ import {typescriptConfig} from 'eslint-config-styleguidejs';
2
+
3
+ export default [
4
+ ...typescriptConfig,
5
+ {
6
+ rules: {
7
+ 'keyword-spacing': ['error', {
8
+ after: true,
9
+ before: true,
10
+ overrides: {
11
+ for: {after: false},
12
+ if: {after: false},
13
+ switch: {after: false},
14
+ while: {after: false}
15
+ }
16
+ }],
17
+ 'space-before-blocks': ['error', {
18
+ classes: 'always',
19
+ functions: 'always',
20
+ keywords: 'always'
21
+ }]
22
+ }
23
+ }
24
+ ];
@@ -7,32 +7,42 @@ export default {
7
7
  // Source and output paths
8
8
  sourcePath: './src',
9
9
  outputPath: './dist',
10
-
10
+
11
11
  // Project settings
12
12
  useTypescript: true,
13
13
  targetEnvironment: 'web',
14
14
  preset: 'web',
15
-
15
+
16
16
  // AI configuration
17
17
  // Use this section to configure AI features for lint --fix and ai commands
18
18
  ai: {
19
19
  // Available providers: 'cursor', 'copilot', 'openai', 'anthropic', 'none'
20
20
  provider: 'cursor',
21
-
21
+
22
22
  // API key for external providers (recommended to use environment variables)
23
23
  // apiKey: process.env.OPENAI_API_KEY,
24
-
24
+
25
25
  // Model configuration (specific to each provider)
26
26
  model: 'cursor-code', // For Cursor IDE
27
27
  // model: 'copilot-codex', // For GitHub Copilot
28
28
  // model: 'gpt-4o', // For OpenAI
29
29
  // model: 'claude-3-sonnet', // For Anthropic
30
-
30
+
31
31
  // Optional parameters
32
32
  maxTokens: 4000,
33
33
  temperature: 0.1
34
34
  },
35
-
35
+
36
+ // Webpack configuration
37
+ webpack: {
38
+ // Path to public assets directory (defaults to './src/static')
39
+ publicPath: './src/static',
40
+
41
+ // Other webpack configuration options
42
+ devtool: 'source-map',
43
+ plugins: []
44
+ },
45
+
36
46
  // Build configuration
37
47
  esbuild: {
38
48
  entryPoints: ['src/index.ts'],
@@ -41,10 +51,10 @@ export default {
41
51
  target: 'es2020',
42
52
  format: 'esm'
43
53
  },
44
-
54
+
45
55
  // Test configuration
46
56
  jest: {
47
57
  roots: ['<rootDir>/src'],
48
58
  testEnvironment: 'node'
49
59
  }
50
- };
60
+ };
@@ -0,0 +1,109 @@
1
+ # Serverless Example
2
+
3
+ This example demonstrates how to use the `lex serverless` command to run AWS Lambda functions locally with HTTP and WebSocket support.
4
+
5
+ ## Setup
6
+
7
+ 1. Navigate to this directory:
8
+
9
+ ```bash
10
+ cd examples/serverless-example
11
+ ```
12
+
13
+ 2. Start the serverless development server:
14
+
15
+ ```bash
16
+ lex serverless
17
+ ```
18
+
19
+ ## Available Endpoints
20
+
21
+ ### HTTP Endpoints
22
+
23
+ - **GET /hello** - Returns a hello message with request details
24
+ - **POST /echo** - Echoes back the request body
25
+
26
+ ### WebSocket Endpoint
27
+
28
+ - **ws://localhost:3002** - WebSocket server for real-time communication
29
+
30
+ ## Testing the Endpoints
31
+
32
+ ### HTTP Testing
33
+
34
+ ```bash
35
+ # Test GET endpoint
36
+ curl http://localhost:3000/hello
37
+
38
+ # Test POST endpoint
39
+ curl -X POST http://localhost:3000/echo \
40
+ -H "Content-Type: application/json" \
41
+ -d '{"message": "Hello from curl!"}'
42
+ ```
43
+
44
+ ### WebSocket Testing
45
+
46
+ You can use a WebSocket client or browser console:
47
+
48
+ ```javascript
49
+ // In browser console
50
+ const ws = new WebSocket('ws://localhost:3002');
51
+ ws.onopen = () => {
52
+ console.log('Connected to WebSocket');
53
+ ws.send(JSON.stringify({
54
+ action: '$default',
55
+ body: 'Hello from WebSocket!'
56
+ }));
57
+ };
58
+ ws.onmessage = (event) => {
59
+ console.log('Received:', JSON.parse(event.data));
60
+ };
61
+ ```
62
+
63
+ ## Configuration
64
+
65
+ The serverless configuration is defined in `lex.config.mjs`:
66
+
67
+ ```javascript
68
+ export default {
69
+ outputFullPath: './dist',
70
+ serverless: {
71
+ functions: {
72
+ hello: {
73
+ handler: 'handlers/hello.js',
74
+ events: [
75
+ {
76
+ http: {
77
+ path: '/hello',
78
+ method: 'GET',
79
+ cors: true
80
+ }
81
+ }
82
+ ]
83
+ }
84
+ },
85
+ custom: {
86
+ 'serverless-offline': {
87
+ httpPort: 3000,
88
+ wsPort: 3002,
89
+ host: 'localhost'
90
+ }
91
+ }
92
+ }
93
+ };
94
+ ```
95
+
96
+ ## Handler Functions
97
+
98
+ Handler functions receive AWS Lambda-style event and context objects:
99
+
100
+ - **event**: Contains request data (HTTP method, path, headers, body, etc.)
101
+ - **context**: Contains Lambda context information (function name, request ID, etc.)
102
+
103
+ ## Features
104
+
105
+ - **HTTP Server**: Routes HTTP requests to appropriate Lambda functions
106
+ - **WebSocket Server**: Handles WebSocket connections and messages
107
+ - **CORS Support**: Automatic CORS headers for cross-origin requests
108
+ - **Dynamic Loading**: Loads handlers from the output directory
109
+ - **AWS Lambda Simulation**: Provides event and context objects similar to AWS Lambda
@@ -0,0 +1,15 @@
1
+ export const handler = async (event, context) => {
2
+ return {
3
+ statusCode: 200,
4
+ headers: {
5
+ 'Content-Type': 'application/json'
6
+ },
7
+ body: JSON.stringify({
8
+ message: 'Echo response',
9
+ receivedData: event.body,
10
+ path: event.path,
11
+ method: event.httpMethod,
12
+ timestamp: new Date().toISOString()
13
+ })
14
+ };
15
+ };
@@ -0,0 +1,137 @@
1
+ export const handler = async (event, context) => {
2
+ console.log('GraphQL handler started');
3
+ console.log('Event:', JSON.stringify(event, null, 2));
4
+
5
+ // Simulate GraphQL resolver logic
6
+ const resolvers = {
7
+ Query: {
8
+ hello: () => {
9
+ console.log('Resolver: hello called');
10
+ return 'Hello from GraphQL!';
11
+ },
12
+ users: () => {
13
+ console.log('Resolver: users called');
14
+ return [
15
+ { id: 1, name: 'John Doe', email: 'john@example.com' },
16
+ { id: 2, name: 'Jane Smith', email: 'jane@example.com' }
17
+ ];
18
+ }
19
+ },
20
+ Mutation: {
21
+ signUp: (_, args) => {
22
+ const user = args.user;
23
+ console.log('Resolver: signUp called with user:', user);
24
+ console.log('Processing signup for:', user.email);
25
+
26
+ // Simulate some processing
27
+ const userId = Math.floor(Math.random() * 1000);
28
+ console.log('Generated user ID:', userId);
29
+
30
+ return {
31
+ userId,
32
+ username: user.username,
33
+ email: user.email
34
+ };
35
+ }
36
+ }
37
+ };
38
+
39
+ try {
40
+ // Parse the GraphQL request
41
+ const body = JSON.parse(event.body);
42
+ console.log('GraphQL Query:', body.query);
43
+ console.log('GraphQL Variables:', body.variables);
44
+
45
+ // Simulate GraphQL execution
46
+ if (body.query.includes('signUp')) {
47
+ console.log('Executing signUp mutation');
48
+ // Extract user data from the query since we're not using a real GraphQL parser
49
+ const userMatch = body.query.match(/signUp\(user:\s*{([^}]+)}\)/);
50
+ if (userMatch) {
51
+ const userData = userMatch[1];
52
+ const emailMatch = userData.match(/email:\s*"([^"]+)"/);
53
+ const passwordMatch = userData.match(/password:\s*"([^"]+)"/);
54
+ const usernameMatch = userData.match(/username:\s*"([^"]+)"/);
55
+ const confirmMatch = userData.match(/confirm:\s*"([^"]+)"/);
56
+
57
+ const user = {
58
+ email: emailMatch ? emailMatch[1] : '',
59
+ password: passwordMatch ? passwordMatch[1] : '',
60
+ username: usernameMatch ? usernameMatch[1] : '',
61
+ confirm: confirmMatch ? confirmMatch[1] : ''
62
+ };
63
+
64
+ const result = resolvers.Mutation.signUp(null, { user });
65
+ console.log('SignUp result:', result);
66
+
67
+ return {
68
+ statusCode: 200,
69
+ headers: {
70
+ 'Content-Type': 'application/json'
71
+ },
72
+ body: JSON.stringify({
73
+ data: {
74
+ users: {
75
+ signUp: result
76
+ }
77
+ }
78
+ })
79
+ };
80
+ }
81
+ } else if (body.query.includes('hello')) {
82
+ console.log('Executing hello query');
83
+ const result = resolvers.Query.hello();
84
+ console.log('Hello result:', result);
85
+
86
+ return {
87
+ statusCode: 200,
88
+ headers: {
89
+ 'Content-Type': 'application/json'
90
+ },
91
+ body: JSON.stringify({
92
+ data: {
93
+ hello: result
94
+ }
95
+ })
96
+ };
97
+ } else if (body.query.includes('users')) {
98
+ console.log('Executing users query');
99
+ const result = resolvers.Query.users();
100
+ console.log('Users result:', result);
101
+
102
+ return {
103
+ statusCode: 200,
104
+ headers: {
105
+ 'Content-Type': 'application/json'
106
+ },
107
+ body: JSON.stringify({
108
+ data: {
109
+ users: result
110
+ }
111
+ })
112
+ };
113
+ }
114
+
115
+ console.log('No matching query found');
116
+ return {
117
+ statusCode: 400,
118
+ headers: {
119
+ 'Content-Type': 'application/json'
120
+ },
121
+ body: JSON.stringify({
122
+ errors: [{ message: 'Query not supported' }]
123
+ })
124
+ };
125
+ } catch (error) {
126
+ console.error('GraphQL handler error:', error);
127
+ return {
128
+ statusCode: 500,
129
+ headers: {
130
+ 'Content-Type': 'application/json'
131
+ },
132
+ body: JSON.stringify({
133
+ errors: [{ message: error.message }]
134
+ })
135
+ };
136
+ }
137
+ };
@@ -0,0 +1,15 @@
1
+ export const handler = async (event, context) => {
2
+ return {
3
+ statusCode: 200,
4
+ headers: {
5
+ 'Content-Type': 'application/json'
6
+ },
7
+ body: JSON.stringify({
8
+ message: 'Hello from serverless!',
9
+ path: event.path,
10
+ method: event.httpMethod,
11
+ queryParams: event.queryStringParameters,
12
+ timestamp: new Date().toISOString()
13
+ })
14
+ };
15
+ };