@karmaniverous/smoz 0.2.4 → 0.2.6

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.
@@ -495,13 +495,17 @@ const collect = async (root) => {
495
495
  buckets.serverless.sort();
496
496
  return buckets;
497
497
  };
498
- const makeImports = (root, files) => {
499
- return files.map((abs) => {
500
- const rel = toPosix$1(path.relative(root, abs));
501
- const noExt = withoutTsExt(rel);
502
- return `import '@/${noExt}';`;
503
- });
504
- };
498
+ /**
499
+ * Build ESM import lines using POSIX-relative specifiers from the generated
500
+ * file directory (app/generated) to each target file. Avoids "@/" alias so
501
+ * dynamic import in the inline server works reliably under tsx.
502
+ */
503
+ const makeImports = (root, outDir, files) => files.map((abs) => {
504
+ const relFromOut = toPosix$1(path.relative(outDir, abs));
505
+ const noExt = withoutTsExt(relFromOut);
506
+ const spec = noExt.startsWith('.') ? noExt : `./${noExt}`;
507
+ return `import '${spec}';`;
508
+ });
505
509
  const buildFile = (imports) => {
506
510
  if (imports.length === 0)
507
511
  return `${HEADER}\n`;
@@ -509,10 +513,10 @@ const buildFile = (imports) => {
509
513
  };
510
514
  const runRegister = async (root) => {
511
515
  const buckets = await collect(root);
512
- const lambdaImports = makeImports(root, buckets.lambda);
513
- const openapiImports = makeImports(root, buckets.openapi);
514
- const serverlessImports = makeImports(root, buckets.serverless);
515
516
  const outDir = path.join(root, 'app', 'generated');
517
+ const lambdaImports = makeImports(root, outDir, buckets.lambda);
518
+ const openapiImports = makeImports(root, outDir, buckets.openapi);
519
+ const serverlessImports = makeImports(root, outDir, buckets.serverless);
516
520
  const fnsPath = path.join(outDir, 'register.functions.ts');
517
521
  const oaiPath = path.join(outDir, 'register.openapi.ts');
518
522
  const srvPath = path.join(outDir, 'register.serverless.ts');
@@ -529,11 +533,6 @@ const runRegister = async (root) => {
529
533
  return { wrote };
530
534
  };
531
535
 
532
- /* Dev loop orchestrator
533
- * - Watches author sources; debounces bursts; runs tasks in order: register → openapi.
534
- * - Optional local serving (--local inline|offline).
535
- * - Stage/env: seeds process.env with concrete values for the selected stage.
536
- */
537
536
  const runDev = async (root, opts) => {
538
537
  const verbose = !!opts.verbose;
539
538
  const stage = typeof opts.stage === 'string'
@@ -547,7 +546,8 @@ const runDev = async (root, opts) => {
547
546
  if (verbose)
548
547
  console.warn('[dev] env seeding warning:', e.message);
549
548
  }
550
- const mode = opts.local;
549
+ const modeInitial = opts.local;
550
+ let mode = modeInitial;
551
551
  const port = typeof opts.port === 'number' ? opts.port : 0;
552
552
  if (verbose) {
553
553
  console.log(`[dev] options: register=${String(opts.register)} ` +
@@ -633,8 +633,18 @@ const runDev = async (root, opts) => {
633
633
  offline = await launchOffline(root, { stage, port, verbose });
634
634
  }
635
635
  else if (mode === 'inline') {
636
- inlineChild = await launchInline(root, { stage, port, verbose });
637
- } // Watch sources
636
+ try {
637
+ inlineChild = await launchInline(root, { stage, port, verbose });
638
+ }
639
+ catch (e) {
640
+ const msg = e.message;
641
+ console.warn('[dev] inline unavailable:', msg);
642
+ console.warn('[dev] Falling back to serverless-offline.');
643
+ mode = 'offline';
644
+ offline = await launchOffline(root, { stage, port, verbose });
645
+ }
646
+ }
647
+ // Watch sources
638
648
  const globs = [
639
649
  path.join(root, 'app', 'functions', '**', 'lambda.ts'),
640
650
  path.join(root, 'app', 'functions', '**', 'openapi.ts'),
@@ -742,29 +752,53 @@ const seedEnvForStage = async (root, stage, verbose) => {
742
752
  };
743
753
  // Inline local runner: spawn tsx to run a TS server script.
744
754
  const launchInline = async (root, opts) => {
745
- const { spawn } = await import('node:child_process');
755
+ const { spawn, spawnSync } = await import('node:child_process');
746
756
  const path = await import('node:path');
747
757
  const fs = await import('node:fs');
748
- const tsxCli = path.resolve(root, 'node_modules', 'tsx', 'dist', 'cli.js');
749
- const entry = path.resolve(root, 'src', 'cli', 'local', 'inline.server.ts');
758
+ // Resolve packaged inline server from the project root so this works
759
+ // both when running the built CLI and via tsx on sources.
760
+ const entry = path.resolve(root, 'dist', 'mjs', 'cli', 'inline-server.js');
750
761
  if (!fs.existsSync(entry)) {
751
- throw new Error('inline server entry missing: src/cli/local/inline.server.ts');
762
+ throw new Error('inline server entry missing in package (dist/mjs/cli/inline-server.js)');
752
763
  }
753
- const args = [tsxCli, entry];
754
- if (!fs.existsSync(tsxCli)) {
755
- // Fallback to PATH resolution
756
- args.shift();
757
- args.unshift(process.platform === 'win32' ? 'tsx.cmd' : 'tsx');
764
+ // Prefer project-local tsx; otherwise probe PATH for tsx availability
765
+ const tsxCli = path.resolve(root, 'node_modules', 'tsx', 'dist', 'cli.js');
766
+ let cmd;
767
+ let args;
768
+ let useShell = false;
769
+ let tsxAvailable = false;
770
+ if (fs.existsSync(tsxCli)) {
771
+ tsxAvailable = true;
772
+ cmd = process.execPath;
773
+ // Pass the TSX CLI script followed by our entry. On Windows, avoid
774
+ // putting unknown flags before the script to prevent Node from treating
775
+ // them as its own options. Enable tsconfig-paths via env only.
776
+ args = [tsxCli, entry];
758
777
  }
759
778
  else {
760
- args.unshift(process.execPath);
779
+ // Probe PATH: tsx --version
780
+ const probe = spawnSync(process.platform === 'win32' ? 'tsx.cmd' : 'tsx', ['--version'], { shell: true });
781
+ if (typeof probe.status === 'number' && probe.status === 0)
782
+ tsxAvailable = true;
783
+ cmd = process.platform === 'win32' ? 'tsx.cmd' : 'tsx';
784
+ // Invoke tsx from PATH with just the script entry; rely on
785
+ // TSX_TSCONFIG_PATHS=1 in the environment for path alias resolution.
786
+ args = [entry];
787
+ useShell = true;
788
+ }
789
+ if (!tsxAvailable) {
790
+ throw new Error('tsx not found (required for inline). Install "tsx" as a devDependency or use --local offline.');
761
791
  }
762
- const spawnChild = () => spawn(args[0], args.slice(1), {
792
+ const spawnChild = () => spawn(cmd, args, {
763
793
  cwd: root,
764
794
  stdio: 'inherit',
765
- shell: !args[0].endsWith('.js'),
795
+ shell: useShell,
796
+ // Enable tsconfig paths resolution for "@/..." via environment;
797
+ // avoids passing CLI flags that can confuse Node on Windows.
798
+ // Keep additional SMOZ_* env for server configuration.
766
799
  env: {
767
800
  ...process.env,
801
+ TSX_TSCONFIG_PATHS: '1',
768
802
  SMOZ_STAGE: opts.stage,
769
803
  SMOZ_PORT: String(opts.port),
770
804
  SMOZ_VERBOSE: opts.verbose ? '1' : '',
@@ -1426,7 +1460,7 @@ const main = () => {
1426
1460
  .option('-l, --local [mode]', 'Local server mode: inline|offline', 'inline')
1427
1461
  .option('-s, --stage <name>', 'Stage name (default inferred)')
1428
1462
  .option('-p, --port <n>', 'Port (0=random)', (v) => Number(v), 0)
1429
- .option('-v, --verbose', 'Verbose logging', false)
1463
+ .option('-V, --verbose', 'Verbose logging', false)
1430
1464
  .action(async (opts) => {
1431
1465
  try {
1432
1466
  const cfg = readSmozConfig(root).cliDefaults?.dev ?? {};
@@ -0,0 +1,296 @@
1
+ import http from 'node:http';
2
+ import { URL, pathToFileURL } from 'node:url';
3
+ import path from 'node:path';
4
+
5
+ const firstVal = (v) => Array.isArray(v) ? v[0] : v;
6
+ const arrVal = (v) => typeof v === 'string' ? [v] : Array.isArray(v) ? v : undefined;
7
+ const toHeaders = (raw) => {
8
+ const single = {};
9
+ const multi = {};
10
+ for (const [k, v] of Object.entries(raw)) {
11
+ const fv = firstVal(v);
12
+ const av = arrVal(v);
13
+ if (typeof fv === 'string')
14
+ single[k] = fv;
15
+ if (Array.isArray(av))
16
+ multi[k] = av;
17
+ }
18
+ return { single, multi };
19
+ };
20
+ const readBody = (req) => new Promise((resolve) => {
21
+ const chunks = [];
22
+ req.on('data', (c) => chunks.push(Buffer.isBuffer(c) ? c : Buffer.from(String(c))));
23
+ req.on('end', () => {
24
+ resolve(Buffer.concat(chunks).toString('utf8'));
25
+ });
26
+ req.on('error', () => {
27
+ resolve('');
28
+ });
29
+ });
30
+ const match = (segs, pathName) => {
31
+ const parts = pathName
32
+ .replace(/^\/+|\/+$/g, '')
33
+ .split('/')
34
+ .filter(Boolean);
35
+ if (parts.length !== segs.length)
36
+ return { ok: false, params: {} };
37
+ const params = {};
38
+ for (let i = 0; i < segs.length; i += 1) {
39
+ const seg = segs[i];
40
+ const p = parts[i];
41
+ if (seg.literal) {
42
+ if (seg.literal !== p)
43
+ return { ok: false, params: {} };
44
+ }
45
+ else if (seg.key) {
46
+ params[seg.key] = p;
47
+ }
48
+ }
49
+ return { ok: true, params };
50
+ };
51
+ const toEvent = async (req, route, params) => {
52
+ const url = new URL(req.url ?? '/', `http://${req.headers.host ?? 'localhost'}`);
53
+ const { single, multi } = toHeaders(req.headers);
54
+ const method = (req.method ?? '').toUpperCase();
55
+ const stage = process.env.SMOZ_STAGE ?? 'dev';
56
+ const search = new URLSearchParams(url.search);
57
+ const query = {};
58
+ const mquery = {};
59
+ for (const key of Array.from(new Set(search.keys()))) {
60
+ const vals = search.getAll(key);
61
+ if (vals.length > 0) {
62
+ query[key] = vals[0];
63
+ mquery[key] = vals;
64
+ }
65
+ }
66
+ let body = '';
67
+ if (method !== 'GET' && method !== 'HEAD') {
68
+ body = await readBody(req);
69
+ }
70
+ return {
71
+ httpMethod: method,
72
+ headers: single,
73
+ multiValueHeaders: multi,
74
+ body,
75
+ isBase64Encoded: false,
76
+ path: url.pathname,
77
+ queryStringParameters: Object.keys(query).length ? query : {},
78
+ multiValueQueryStringParameters: Object.keys(mquery).length ? mquery : {},
79
+ pathParameters: Object.keys(params).length ? params : {},
80
+ stageVariables: null,
81
+ resource: route.pattern,
82
+ requestContext: {
83
+ accountId: 'acc',
84
+ apiId: 'inline',
85
+ httpMethod: method,
86
+ identity: {},
87
+ path: url.pathname,
88
+ stage,
89
+ requestId: String(Date.now()),
90
+ requestTimeEpoch: Date.now(),
91
+ resourceId: 'res',
92
+ resourcePath: route.pattern,
93
+ authorizer: {},
94
+ protocol: 'HTTP/1.1',
95
+ },
96
+ };
97
+ };
98
+ const writeResult = (res, result) => {
99
+ const status = typeof result.statusCode === 'number' ? result.statusCode : 200;
100
+ const headers = result.headers ?? {};
101
+ const body = typeof result.body === 'string' ? result.body : '';
102
+ for (const [k, v] of Object.entries(headers)) {
103
+ if (typeof v === 'string')
104
+ res.setHeader(k, v);
105
+ }
106
+ res.statusCode = status;
107
+ res.end(body);
108
+ };
109
+
110
+ /**
111
+ * Load downstream registers to populate the app registry.
112
+ * Tries TS/JS candidates and logs which one was loaded when SMOZ_VERBOSE is set.
113
+ */
114
+ const loadRegisters = async (root) => {
115
+ const candidates = [
116
+ path.resolve(root, 'app', 'generated', 'register.functions.ts'),
117
+ path.resolve(root, 'app', 'generated', 'register.functions.mts'),
118
+ path.resolve(root, 'app', 'generated', 'register.functions.js'),
119
+ path.resolve(root, 'app', 'generated', 'register.functions.mjs'),
120
+ ];
121
+ for (const p of candidates) {
122
+ try {
123
+ const url = pathToFileURL(p).href;
124
+ await import(url);
125
+ if (process.env.SMOZ_VERBOSE) {
126
+ const rel = path.relative(root, p).split(path.sep).join('/');
127
+ console.log('[inline] registers loaded:', rel);
128
+ }
129
+ return;
130
+ }
131
+ catch {
132
+ // try next candidate
133
+ }
134
+ }
135
+ console.warn('[inline] Could not load app/generated/register.functions.*. Run "npx smoz register" before inline dev.');
136
+ };
137
+ /**
138
+ * Load the App instance (TS source) from the downstream project.
139
+ * Returns only the surface needed by the inline server.
140
+ */
141
+ const loadApp = async (root) => {
142
+ const p = path.resolve(root, 'app', 'config', 'app.config.ts');
143
+ const url = pathToFileURL(p).href;
144
+ const mod = (await import(url));
145
+ const app = mod.app;
146
+ if (!app || typeof app.buildAllServerlessFunctions !== 'function') {
147
+ throw new Error('Failed to load app/config/app.config.ts (missing export "app").');
148
+ }
149
+ return app;
150
+ };
151
+
152
+ const splitPattern = (p) => p
153
+ .replace(/\\/g, '/')
154
+ .replace(/^\/+|\/+$/g, '')
155
+ .split('/')
156
+ .filter(Boolean)
157
+ .map((s) => s.startsWith('{') && s.endsWith('}')
158
+ ? { key: s.slice(1, -1) }
159
+ : { literal: s });
160
+ /**
161
+ * Build route table from the downstream app's aggregated serverless functions.
162
+ */
163
+ const loadHandlers = async (root, app) => {
164
+ const fns = app.buildAllServerlessFunctions();
165
+ const routes = [];
166
+ for (const [, defUnknown] of Object.entries(fns)) {
167
+ const def = defUnknown;
168
+ if (typeof def.handler !== 'string' || !Array.isArray(def.events))
169
+ continue;
170
+ const [moduleRel, exportName] = (() => {
171
+ const lastDot = def.handler.lastIndexOf('.');
172
+ if (lastDot < 0)
173
+ return [def.handler, 'handler'];
174
+ return [
175
+ def.handler.slice(0, lastDot),
176
+ def.handler.slice(lastDot + 1),
177
+ ];
178
+ })();
179
+ // Resolve TS source module; dev runs via tsx so TS imports are OK
180
+ const candidates = [
181
+ path.resolve(root, `${moduleRel}.ts`),
182
+ path.resolve(root, `${moduleRel}.mts`),
183
+ path.resolve(root, `${moduleRel}.js`),
184
+ path.resolve(root, `${moduleRel}.mjs`),
185
+ ];
186
+ // Always try the first candidate (TS is expected in authoring).
187
+ const modUrl = pathToFileURL(candidates[0]).href;
188
+ const mod = (await import(modUrl));
189
+ const handler = mod[exportName];
190
+ if (typeof handler !== 'function')
191
+ continue;
192
+ for (const evt of def.events) {
193
+ const httpEvt = evt
194
+ .http;
195
+ const method = (httpEvt?.method ?? '').toUpperCase();
196
+ const pattern = '/' + (httpEvt?.path ?? '').replace(/^\/+/, '');
197
+ if (!method || !pattern)
198
+ continue;
199
+ routes.push({
200
+ method,
201
+ pattern,
202
+ segs: splitPattern(pattern),
203
+ handlerRef: `${moduleRel}.${exportName}`,
204
+ handler: handler,
205
+ });
206
+ }
207
+ }
208
+ return routes;
209
+ };
210
+
211
+ /**
212
+ * Inline HTTP dev server (module entry).
213
+ *
214
+ * Decomposed from the original single-file implementation to improve
215
+ * readability and maintainability:
216
+ * - loaders.ts: register/app loaders
217
+ * - routes.ts: route table construction
218
+ * - http.ts: request/event mapping helpers
219
+ */
220
+ const start = async () => {
221
+ const root = process.cwd();
222
+ // Ensure register side-effects are loaded so the registry has routes
223
+ await loadRegisters(root);
224
+ // Load the App instance from the same TS source as the registers
225
+ const app = await loadApp(root);
226
+ const routes = await loadHandlers(root, app);
227
+ const portEnv = process.env.SMOZ_PORT;
228
+ const port = typeof portEnv === 'string' && portEnv.length > 0 ? Number(portEnv) : 0;
229
+ const server = http.createServer((req, res) => {
230
+ void (async () => {
231
+ try {
232
+ const method = (req.method ?? '').toUpperCase();
233
+ const url = new URL(req.url ?? '/', `http://${req.headers.host ?? 'localhost'}`);
234
+ // Allow HEAD to match GET routes; the wrapped handler/middleware will
235
+ // short-circuit HEAD requests to 200 {} and set Content-Type.
236
+ const searchMethod = method === 'HEAD' ? 'GET' : method;
237
+ const route = routes.find((r) => r.method === searchMethod && match(r.segs, url.pathname).ok);
238
+ if (!route) {
239
+ res.statusCode = 404;
240
+ res.setHeader('Content-Type', 'application/json');
241
+ res.end(JSON.stringify({ error: 'Not Found' }));
242
+ return;
243
+ }
244
+ const { params } = match(route.segs, url.pathname);
245
+ const evt = await toEvent(req, route, params);
246
+ const result = await route.handler(evt, {
247
+ awsRequestId: String(Date.now()),
248
+ callbackWaitsForEmptyEventLoop: false,
249
+ functionName: 'inline',
250
+ functionVersion: '$LATEST',
251
+ invokedFunctionArn: 'arn:inline',
252
+ logGroupName: 'lg',
253
+ logStreamName: 'ls',
254
+ memoryLimitInMB: '256',
255
+ getRemainingTimeInMillis: () => 30000,
256
+ done: () => undefined,
257
+ fail: () => undefined,
258
+ succeed: () => undefined,
259
+ });
260
+ writeResult(res, result);
261
+ }
262
+ catch (e) {
263
+ res.statusCode = 500;
264
+ res.setHeader('Content-Type', 'application/json');
265
+ res.end(JSON.stringify({ error: e.message }));
266
+ }
267
+ })();
268
+ });
269
+ server.listen(port, () => {
270
+ const addr = server.address();
271
+ const resolved = typeof addr === 'object' && addr && 'port' in addr
272
+ ? addr.port
273
+ : port;
274
+ // Print route table
275
+ // Keep output consistent with existing tests:
276
+ // "[inline] listening on http://localhost:<port>"
277
+ console.log('[inline] listening on http://localhost:' + String(resolved));
278
+ const header = '[inline] routes:\n';
279
+ if (routes.length === 0) {
280
+ console.log(header + ' (none found)');
281
+ }
282
+ else {
283
+ const body = routes
284
+ .map((r) => ' ' +
285
+ r.method.padEnd(6) +
286
+ ' ' +
287
+ r.pattern +
288
+ ' -> ' +
289
+ r.handlerRef)
290
+ .join('\n');
291
+ console.log(header + body);
292
+ }
293
+ });
294
+ };
295
+ // Start immediately when run via tsx
296
+ void start();
package/package.json CHANGED
@@ -31,9 +31,9 @@
31
31
  },
32
32
  "description": "John Galt Services back end.",
33
33
  "devDependencies": {
34
- "@rollup/plugin-alias": "^5.1.1",
35
34
  "@dotenvx/dotenvx": "^1.49.0",
36
35
  "@eslint/js": "^9.35.0",
36
+ "@rollup/plugin-alias": "^5.1.1",
37
37
  "@rollup/plugin-typescript": "^12.1.4",
38
38
  "@serverless/typescript": "^4.18.2",
39
39
  "@types/aws-lambda": "^8.10.152",
@@ -49,7 +49,6 @@
49
49
  "fs-extra": "^11.3.1",
50
50
  "knip": "^5.63.1",
51
51
  "lefthook": "^1.13.0",
52
- "pkg-dir": "^9.0.0",
53
52
  "prettier": "^3.6.2",
54
53
  "release-it": "^19.0.4",
55
54
  "rimraf": "^6.0.1",
@@ -182,5 +181,5 @@
182
181
  "templates:lint": "eslint --fix -c templates/default/eslint.config.ts \"templates/default/**/*.{ts,tsx,js,jsx}\" \"templates/default/eslint.config.ts\""
183
182
  },
184
183
  "type": "module",
185
- "version": "0.2.4"
184
+ "version": "0.2.6"
186
185
  }
@@ -1,7 +1,6 @@
1
- import * as path from 'node:path';
2
-
3
- import * as fs from 'fs-extra';
1
+ import fs from 'fs-extra';
4
2
  import { packageDirectorySync } from 'package-directory';
3
+ import path from 'path';
5
4
  import { createDocument } from 'zod-openapi';
6
5
 
7
6
  import { app } from '@/app/config/app.config';
@@ -22,18 +21,20 @@ console.log('Generating OpenAPI document...');
22
21
  const paths = app.buildAllOpenApiPaths();
23
22
  export const doc = createDocument({
24
23
  openapi: '3.1.0',
25
- servers: [{ description: 'Dev', url: 'http://localhost' }],
24
+ servers: [
25
+ { description: 'Production', url: 'https://api.example.test' },
26
+ { description: 'Dev', url: 'https://api.dev.example.test' },
27
+ ],
26
28
  info: {
27
- title: process.env.npm_package_name ?? 'smoz-app',
28
- version: process.env.npm_package_version ?? '0.0.0',
29
+ title: process.env.npm_package_name ?? '',
30
+ version: process.env.npm_package_version ?? '',
29
31
  },
30
32
  paths,
31
33
  });
32
34
 
33
35
  const pkgDir = packageDirectorySync();
34
- if (!pkgDir) {
35
- throw new Error('Could not resolve package root directory');
36
- }
36
+ if (!pkgDir) throw new Error('Could not find package root directory');
37
+
37
38
  const outDir = path.join(pkgDir, 'app', 'generated');
38
39
  fs.ensureDirSync(outDir);
39
40
  fs.writeFileSync(
@@ -9,6 +9,18 @@ import { fileURLToPath } from 'url';
9
9
  const tsconfigRootDir = dirname(fileURLToPath(import.meta.url));
10
10
 
11
11
  export default [
12
+ {
13
+ ignores: [
14
+ '.serverless/**',
15
+ '.stan/**',
16
+ '**/.tsbuild/**',
17
+ '**/generated/**',
18
+ 'coverage/**',
19
+ 'dist/**',
20
+ 'docs/**',
21
+ 'node_modules/**',
22
+ ],
23
+ },
12
24
  eslint.configs.recommended,
13
25
  ...tseslint.configs.strictTypeChecked,
14
26
  prettierConfig,
@@ -5,9 +5,9 @@
5
5
  "version": "0.0.0",
6
6
  "dependencies": {
7
7
  "@middy/core": "^6.4.5",
8
- "zod": "^4.1.6",
9
8
  "fs-extra": "^11.3.1",
10
- "package-directory": "^8.1.0"
9
+ "package-directory": "^8.1.0",
10
+ "zod": "^4.1.6"
11
11
  },
12
12
  "devDependencies": {
13
13
  "@serverless/typescript": "^4.18.2",
@@ -107,9 +107,6 @@ const config: AWS = {
107
107
  versionFunctions: false,
108
108
  },
109
109
  functions: app.buildAllServerlessFunctions() as NonNullable<AWS['functions']>,
110
- // Optional esbuild configuration (parity with /app fixture):
111
- // These booleans are driven by global params in app.config.ts:
112
- // ESB_MINIFY, ESB_SOURCEMAP
113
110
  build: {
114
111
  esbuild: {
115
112
  bundle: true,
@@ -7,12 +7,7 @@
7
7
  },
8
8
  "tsBuildInfoFile": ".tsbuild/tsconfig.tsbuildinfo"
9
9
  },
10
- "exclude": [
11
- ".serverless/**",
12
- "node_modules/**",
13
- "app/generated/**",
14
- "dist/**"
15
- ],
10
+ "exclude": [".serverless/**", "node_modules/**", "app/generated/**"],
16
11
  "extends": "./tsconfig.base.json",
17
12
  "include": ["**/*", "**/*.json"]
18
13
  }