@silkweave/trpc 1.7.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.
@@ -0,0 +1,93 @@
1
+ import eslint from '@eslint/js'
2
+ import stylistic from '@stylistic/eslint-plugin'
3
+ import { defineConfig } from 'eslint/config'
4
+ import tseslint from 'typescript-eslint'
5
+
6
+ export default defineConfig(eslint.configs.recommended, tseslint.configs.recommendedTypeChecked, tseslint.configs.stylisticTypeChecked, {
7
+ languageOptions: {
8
+ parserOptions: {
9
+ project: 'tsconfig.json',
10
+ tsconfigRootDir: import.meta.dirname
11
+ }
12
+ },
13
+ plugins: { '@stylistic': stylistic },
14
+ rules: {
15
+ '@stylistic/space-in-parens': ['error'],
16
+ '@stylistic/comma-spacing': ['error'],
17
+ '@stylistic/no-multi-spaces': ['error'],
18
+ '@stylistic/no-trailing-spaces': ['error'],
19
+ '@stylistic/no-whitespace-before-property': ['error'],
20
+ '@stylistic/array-bracket-newline': ['error', 'consistent'],
21
+ '@stylistic/array-bracket-spacing': ['error'],
22
+ '@stylistic/arrow-spacing': ['error'],
23
+ '@stylistic/arrow-parens': ['error', 'always'],
24
+ '@stylistic/block-spacing': ['error', 'always'],
25
+ '@stylistic/brace-style': ['error', '1tbs', { 'allowSingleLine': true }],
26
+ '@stylistic/comma-dangle': ['error', 'never'],
27
+ '@stylistic/key-spacing': ['error'],
28
+ '@stylistic/keyword-spacing': ['error'],
29
+ '@stylistic/member-delimiter-style': ['error', { 'multiline': { 'delimiter': 'none' } }],
30
+ '@stylistic/no-extra-semi': ['error'],
31
+ '@stylistic/indent': ['error', 2],
32
+ '@stylistic/no-multiple-empty-lines': ['error', { 'max': 1, 'maxEOF': 0, 'maxBOF': 0 }],
33
+ '@stylistic/object-curly-spacing': ['error', 'always'],
34
+ '@stylistic/quotes': ['error', 'single'],
35
+ '@stylistic/semi': ['error', 'never'],
36
+ '@stylistic/space-before-blocks': ['error', 'always'],
37
+ '@stylistic/space-before-function-paren': ['error', { 'anonymous': 'always', 'named': 'never', 'asyncArrow': 'always' }],
38
+ '@typescript-eslint/adjacent-overload-signatures': 'error',
39
+ '@typescript-eslint/array-type': 'off',
40
+ '@typescript-eslint/await-thenable': 'error',
41
+ '@typescript-eslint/ban-types': 'off',
42
+ '@typescript-eslint/consistent-type-assertions': 'off',
43
+ '@typescript-eslint/explicit-function-return-type': 'off',
44
+ '@typescript-eslint/explicit-member-accessibility': 'off',
45
+ '@typescript-eslint/no-angle-bracket-type-assertion': 'off',
46
+ '@typescript-eslint/no-empty-function': 'off',
47
+ '@typescript-eslint/no-empty-interface': 'off',
48
+ '@typescript-eslint/no-extra-non-null-assertion': 'error',
49
+ '@typescript-eslint/no-floating-promises': 'off',
50
+ '@typescript-eslint/no-misused-new': 'error',
51
+ '@typescript-eslint/no-misused-promises': 'off',
52
+ '@typescript-eslint/no-namespace': 'off',
53
+ '@typescript-eslint/no-non-null-asserted-optional-chain': 'error',
54
+ '@typescript-eslint/no-non-null-assertion': 'off',
55
+ '@typescript-eslint/no-object-literal-type-assertion': 'off',
56
+ '@typescript-eslint/no-parameter-properties': 'off',
57
+ '@typescript-eslint/no-shadow': 'error',
58
+ '@typescript-eslint/no-triple-slash-reference': 'off',
59
+ '@typescript-eslint/no-unused-vars': ['error', {
60
+ 'args': 'all',
61
+ 'argsIgnorePattern': '^_',
62
+ 'caughtErrors': 'all',
63
+ 'caughtErrorsIgnorePattern': '^_',
64
+ 'destructuredArrayIgnorePattern': '^_',
65
+ 'varsIgnorePattern': '^_',
66
+ 'ignoreRestSiblings': true
67
+ }],
68
+ '@typescript-eslint/no-use-before-define': 'off',
69
+ '@typescript-eslint/no-var-requires': 'off',
70
+ '@typescript-eslint/prefer-for-of': 'error',
71
+ '@typescript-eslint/prefer-interface': 'off',
72
+ '@typescript-eslint/prefer-nullish-coalescing': 'off',
73
+ '@typescript-eslint/prefer-optional-chain': 'error',
74
+ '@typescript-eslint/return-await': 'error',
75
+ '@typescript-eslint/unified-signatures': 'error',
76
+ '@typescript-eslint/no-unsafe-return': 'off',
77
+ '@typescript-eslint/no-redundant-type-constituents': 'off',
78
+ '@typescript-eslint/no-unsafe-member-access': 'off',
79
+ '@typescript-eslint/no-unsafe-call': 'off',
80
+ '@typescript-eslint/no-unsafe-argument': 'off',
81
+ '@typescript-eslint/dot-notation': 'off',
82
+ '@typescript-eslint/prefer-regexp-exec': 'off',
83
+ '@typescript-eslint/require-await': 'off',
84
+ '@typescript-eslint/only-throw-error': 'error',
85
+ '@typescript-eslint/no-base-to-string': 'off',
86
+ '@typescript-eslint/restrict-template-expressions': 'off'
87
+ }
88
+ }, {
89
+ files: ['eslint.config.mjs'],
90
+ extends: [tseslint.configs.disableTypeChecked]
91
+ }, {
92
+ ignores: ['build', 'tsdown.config.ts', 'scratch']
93
+ })
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@silkweave/trpc",
3
+ "version": "1.7.0",
4
+ "description": "Silkweave tRPC Adapter",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+ssh://git@github.com/silkweave/silkweave.git",
8
+ "directory": "packages/trpc"
9
+ },
10
+ "type": "module",
11
+ "main": "build/index.mjs",
12
+ "dependencies": {
13
+ "@trpc/server": "^11.7.1",
14
+ "change-case": "^5.4.4",
15
+ "cors": "^2.8.5",
16
+ "zod": "^4.3.6",
17
+ "@silkweave/auth": "1.7.0",
18
+ "@silkweave/core": "1.7.0",
19
+ "@silkweave/logger": "1.7.0"
20
+ },
21
+ "devDependencies": {
22
+ "@eslint/js": "^10.0.1",
23
+ "@stylistic/eslint-plugin": "^5.10.0",
24
+ "@trpc/client": "^11.7.1",
25
+ "@types/cors": "^2.8.19",
26
+ "@types/node": "^22.0.0",
27
+ "rimraf": "^6.1.3",
28
+ "tsdown": "^0.21.8",
29
+ "tsx": "^4.21.0",
30
+ "typescript": "^5.9.3",
31
+ "typescript-eslint": "^8.56.1"
32
+ },
33
+ "scripts": {
34
+ "clean": "rimraf build",
35
+ "build": "tsdown",
36
+ "watch": "tsdown --watch",
37
+ "typecheck": "tsc --noEmit",
38
+ "lint": "eslint",
39
+ "check": "pnpm lint && pnpm typecheck"
40
+ },
41
+ "exports": {
42
+ ".": "./build/index.mjs"
43
+ },
44
+ "types": "./build/index.d.ts"
45
+ }
@@ -0,0 +1,112 @@
1
+ import { AuthConfig } from '@silkweave/auth'
2
+ import { Adapter, AdapterGenerator, SilkweaveOptions } from '@silkweave/core'
3
+ import { fetchRequestHandler } from '@trpc/server/adapters/fetch'
4
+ import { buildRouter, TrpcHandlerContext } from '../lib/buildRouter.js'
5
+ import { createActionLogger, resolveAuth } from '../lib/createContext.js'
6
+
7
+ export interface TrpcFetchAdapterOptions {
8
+ /** URL prefix stripped from incoming requests before tRPC routing. Default `/trpc`. */
9
+ endpoint?: string
10
+ auth?: AuthConfig
11
+ }
12
+
13
+ export type FetchHandler = (request: Request) => Promise<Response>
14
+
15
+ export interface TrpcFetchAdapter {
16
+ adapter: AdapterGenerator
17
+ handler: FetchHandler
18
+ GET: FetchHandler
19
+ POST: FetchHandler
20
+ }
21
+
22
+ /**
23
+ * Creates a tRPC adapter that exposes a fetch-compatible handler instead of
24
+ * binding its own HTTP server. Use in Astro API routes, Vercel serverless
25
+ * functions, Cloudflare Workers, or any Web Standard runtime.
26
+ *
27
+ * The returned `handler` waits for `server.start()` to complete (via an internal
28
+ * `_ready` promise) before dispatching requests, so it's safe to call from a
29
+ * cold-started serverless invocation.
30
+ *
31
+ * CORS is intentionally not configured here - handle it in your host framework
32
+ * (Astro middleware, `vercel.json` headers, Worker response headers, etc).
33
+ */
34
+ export function trpcFetch(options: TrpcFetchAdapterOptions = {}): TrpcFetchAdapter {
35
+ const endpoint = (options.endpoint ?? '/trpc').replace(/\/$/, '')
36
+
37
+ let resolveReady!: () => void
38
+ const ready = new Promise<void>((resolve) => { resolveReady = resolve })
39
+
40
+ let handler: FetchHandler = async () => new Response(
41
+ JSON.stringify({ error: 'not_ready', message: 'tRPC adapter has not started yet' }),
42
+ { status: 503, headers: { 'Content-Type': 'application/json' } }
43
+ )
44
+
45
+ const adapter: AdapterGenerator = (_silkweaveOptions: SilkweaveOptions, baseContext): Adapter => {
46
+ const context = baseContext.fork({ adapter: 'trpc' })
47
+ return {
48
+ context,
49
+ start: async (actions) => {
50
+ const router = buildRouter(actions)
51
+ const logger = createActionLogger()
52
+
53
+ const createContext = async (
54
+ opts: { req: Request }
55
+ ): Promise<TrpcHandlerContext> => {
56
+ const resolved = await resolveAuth(
57
+ options.auth,
58
+ opts.req.headers.get('authorization'),
59
+ context.fork({ request: opts.req })
60
+ )
61
+ if (resolved.kind === 'error') {
62
+ const err = new Error('Unauthorized') as Error & { silkweaveAuthError?: typeof resolved.error }
63
+ err.silkweaveAuthError = resolved.error
64
+ throw err
65
+ }
66
+ return {
67
+ silkweaveContext: context.fork({
68
+ logger,
69
+ request: opts.req,
70
+ ...(resolved.authInfo ? { auth: resolved.authInfo } : {})
71
+ })
72
+ }
73
+ }
74
+
75
+ handler = async (request: Request): Promise<Response> => {
76
+ try {
77
+ return await fetchRequestHandler({
78
+ endpoint,
79
+ req: request,
80
+ router,
81
+ createContext
82
+ })
83
+ } catch (error) {
84
+ const authError = (error as { silkweaveAuthError?: { statusCode: number; headers: Record<string, string>; body: object } }).silkweaveAuthError
85
+ if (authError) {
86
+ return new Response(JSON.stringify(authError.body), {
87
+ status: authError.statusCode,
88
+ headers: { 'Content-Type': 'application/json', ...authError.headers }
89
+ })
90
+ }
91
+ throw error
92
+ }
93
+ }
94
+
95
+ resolveReady()
96
+ },
97
+ stop: async () => { /* no-op for fetch adapter */ }
98
+ }
99
+ }
100
+
101
+ const dispatch: FetchHandler = async (request) => {
102
+ await ready
103
+ return handler(request)
104
+ }
105
+
106
+ return {
107
+ adapter,
108
+ handler: dispatch,
109
+ GET: dispatch,
110
+ POST: dispatch
111
+ }
112
+ }
@@ -0,0 +1,105 @@
1
+ import { AuthConfig } from '@silkweave/auth'
2
+ import { AdapterFactory } from '@silkweave/core'
3
+ import { createHTTPHandler } from '@trpc/server/adapters/standalone'
4
+ import cors, { CorsOptions } from 'cors'
5
+ import http, { IncomingMessage, ServerResponse } from 'http'
6
+ import { buildRouter, TrpcHandlerContext } from '../lib/buildRouter.js'
7
+ import { createActionLogger, resolveAuth } from '../lib/createContext.js'
8
+
9
+ export interface TrpcAdapterOptions {
10
+ host?: string
11
+ port?: number
12
+ /** URL prefix stripped from incoming requests before tRPC routing. Default `/trpc/`. */
13
+ endpoint?: string
14
+ /** CORS configuration. `false` to disable, `true`/`undefined` for permissive defaults, or a CorsOptions object. */
15
+ cors?: CorsOptions | boolean
16
+ auth?: AuthConfig
17
+ }
18
+
19
+ type CorsMiddleware = (req: IncomingMessage, res: ServerResponse, next: (err?: unknown) => void) => void
20
+
21
+ function resolveCors(corsConfig: CorsOptions | boolean | undefined): CorsMiddleware | null {
22
+ if (corsConfig === false) { return null }
23
+ const userConfig = corsConfig === true || corsConfig === undefined ? {} : corsConfig
24
+ return cors({ origin: '*', ...userConfig }) as CorsMiddleware
25
+ }
26
+
27
+ export const trpc: AdapterFactory<TrpcAdapterOptions> = (options) => {
28
+ return (_silkweaveOptions, baseContext) => {
29
+ const context = baseContext.fork({ adapter: 'trpc' })
30
+ const host = options.host ?? '0.0.0.0'
31
+ const port = options.port ?? 8080
32
+ const endpoint = (options.endpoint ?? '/trpc/').replace(/\/?$/, '/')
33
+ let server: http.Server | undefined
34
+
35
+ return {
36
+ context,
37
+ start: async (actions) => {
38
+ const router = buildRouter(actions)
39
+ const corsMiddleware = resolveCors(options.cors)
40
+ const logger = createActionLogger()
41
+
42
+ const createContext = async (
43
+ opts: { req: IncomingMessage; res: ServerResponse }
44
+ ): Promise<TrpcHandlerContext> => {
45
+ const resolved = await resolveAuth(
46
+ options.auth,
47
+ opts.req.headers.authorization,
48
+ context.fork({ request: opts.req })
49
+ )
50
+ if (resolved.kind === 'error') {
51
+ for (const [key, value] of Object.entries(resolved.error.headers)) {
52
+ opts.res.setHeader(key, value)
53
+ }
54
+ opts.res.statusCode = resolved.error.statusCode
55
+ opts.res.setHeader('Content-Type', 'application/json')
56
+ opts.res.end(JSON.stringify(resolved.error.body))
57
+ throw new Error('Unauthorized')
58
+ }
59
+ return {
60
+ silkweaveContext: context.fork({
61
+ logger,
62
+ request: opts.req,
63
+ ...(resolved.authInfo ? { auth: resolved.authInfo } : {})
64
+ })
65
+ }
66
+ }
67
+
68
+ const trpcHandler = createHTTPHandler({ router, basePath: endpoint, createContext })
69
+
70
+ const handler = (req: IncomingMessage, res: ServerResponse) => {
71
+ if (!req.url?.startsWith(endpoint)) {
72
+ res.statusCode = 404
73
+ res.setHeader('Content-Type', 'application/json')
74
+ res.end(JSON.stringify({ error: 'not_found', message: `No route for ${req.url}` }))
75
+ return
76
+ }
77
+ trpcHandler(req, res)
78
+ }
79
+
80
+ server = http.createServer((req, res) => {
81
+ if (corsMiddleware) {
82
+ corsMiddleware(req, res, () => {
83
+ if (req.method === 'OPTIONS') { res.statusCode = 204; res.end(); return }
84
+ handler(req, res)
85
+ })
86
+ } else {
87
+ handler(req, res)
88
+ }
89
+ })
90
+
91
+ await new Promise<void>((resolve) => {
92
+ server!.listen(port, host, () => { resolve() })
93
+ })
94
+ },
95
+ stop: async () => {
96
+ if (!server) { return }
97
+ await new Promise<void>((resolve, reject) => {
98
+ server!.close((err) => {
99
+ if (err) { reject(err) } else { resolve() }
100
+ })
101
+ })
102
+ }
103
+ }
104
+ }
105
+ }
package/src/index.ts ADDED
@@ -0,0 +1,6 @@
1
+ export * from './adapter/fetch.js'
2
+ export * from './adapter/trpc.js'
3
+ export { buildRouter } from './lib/buildRouter.js'
4
+ export type { TrpcHandlerContext } from './lib/buildRouter.js'
5
+ export { mapError } from './lib/errors.js'
6
+ export type { InferTrpcRouter } from './lib/inferRouter.js'
@@ -0,0 +1,27 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import { Action, SilkweaveContext } from '@silkweave/core'
3
+ import { initTRPC } from '@trpc/server'
4
+ import { camelCase } from 'change-case'
5
+ import { mapError } from './errors.js'
6
+
7
+ export interface TrpcHandlerContext {
8
+ silkweaveContext: SilkweaveContext
9
+ }
10
+
11
+ export function buildRouter(actions: Action[]) {
12
+ const t = initTRPC.context<TrpcHandlerContext>().create()
13
+ const record: Record<string, any> = {}
14
+ for (const action of actions) {
15
+ const key = camelCase(action.name)
16
+ const base = t.procedure.input(action.input)
17
+ const handler = async ({ input, ctx }: { input: object; ctx: TrpcHandlerContext }) => {
18
+ try {
19
+ return await action.run(input, ctx.silkweaveContext)
20
+ } catch (error) {
21
+ throw mapError(error)
22
+ }
23
+ }
24
+ record[key] = action.kind === 'query' ? base.query(handler) : base.mutation(handler)
25
+ }
26
+ return t.router(record)
27
+ }
@@ -0,0 +1,44 @@
1
+ import { AuthConfig, AuthInfo, validateToken } from '@silkweave/auth'
2
+ import { SilkweaveContext } from '@silkweave/core'
3
+ import { buildLogLevels, Logger, LogLevel } from '@silkweave/logger'
4
+
5
+ const CONSOLE_LEVEL_MAP: Record<LogLevel, 'log' | 'info' | 'warn' | 'error'> = {
6
+ emergency: 'error',
7
+ alert: 'error',
8
+ critical: 'error',
9
+ error: 'error',
10
+ warning: 'warn',
11
+ notice: 'info',
12
+ info: 'info',
13
+ debug: 'log'
14
+ }
15
+
16
+ export function createActionLogger(): Logger {
17
+ return {
18
+ ...buildLogLevels((level, data) => {
19
+ console[CONSOLE_LEVEL_MAP[level]](data)
20
+ }),
21
+ progress: () => { /* progress notifications not supported on tRPC HTTP */ }
22
+ }
23
+ }
24
+
25
+ export interface AuthErrorPayload {
26
+ statusCode: number
27
+ headers: Record<string, string>
28
+ body: { error: string; error_description: string }
29
+ }
30
+
31
+ export type ResolvedAuth =
32
+ | { kind: 'ok'; authInfo?: AuthInfo }
33
+ | { kind: 'error'; error: AuthErrorPayload }
34
+
35
+ export async function resolveAuth(
36
+ auth: AuthConfig | undefined,
37
+ authHeader: string | null | undefined,
38
+ context: SilkweaveContext
39
+ ): Promise<ResolvedAuth> {
40
+ if (!auth) { return { kind: 'ok' } }
41
+ const result = await validateToken(authHeader, auth, context)
42
+ if (result.error) { return { kind: 'error', error: result.error } }
43
+ return { kind: 'ok', authInfo: result.auth }
44
+ }
@@ -0,0 +1,42 @@
1
+ import { SilkweaveError } from '@silkweave/core'
2
+ import { TRPCError } from '@trpc/server'
3
+ import { z } from 'zod'
4
+
5
+ type TRPCErrorCode = TRPCError['code']
6
+
7
+ const CODE_MAP: Record<number, TRPCErrorCode> = {
8
+ 400: 'BAD_REQUEST',
9
+ 401: 'UNAUTHORIZED',
10
+ 403: 'FORBIDDEN',
11
+ 404: 'NOT_FOUND',
12
+ 408: 'TIMEOUT',
13
+ 409: 'CONFLICT',
14
+ 412: 'PRECONDITION_FAILED',
15
+ 413: 'PAYLOAD_TOO_LARGE',
16
+ 429: 'TOO_MANY_REQUESTS',
17
+ 499: 'CLIENT_CLOSED_REQUEST',
18
+ 500: 'INTERNAL_SERVER_ERROR',
19
+ 501: 'NOT_IMPLEMENTED',
20
+ 502: 'BAD_GATEWAY',
21
+ 503: 'SERVICE_UNAVAILABLE',
22
+ 504: 'GATEWAY_TIMEOUT'
23
+ }
24
+
25
+ export function mapError(error: unknown): TRPCError {
26
+ if (error instanceof TRPCError) { return error }
27
+ if (error instanceof z.ZodError) {
28
+ return new TRPCError({ code: 'BAD_REQUEST', message: error.message, cause: error })
29
+ }
30
+ if (error instanceof SilkweaveError) {
31
+ return new TRPCError({
32
+ code: CODE_MAP[error.statusCode] ?? 'INTERNAL_SERVER_ERROR',
33
+ message: error.message,
34
+ cause: error
35
+ })
36
+ }
37
+ return new TRPCError({
38
+ code: 'INTERNAL_SERVER_ERROR',
39
+ message: error instanceof Error ? error.message : 'Internal error',
40
+ cause: error instanceof Error ? error : undefined
41
+ })
42
+ }
@@ -0,0 +1,50 @@
1
+ import { Action, Silkweave } from '@silkweave/core'
2
+ import type {
3
+ AnyTRPCRootTypes,
4
+ TRPCBuiltRouter,
5
+ TRPCMutationProcedure,
6
+ TRPCQueryProcedure
7
+ } from '@trpc/server'
8
+ import type { z } from 'zod'
9
+
10
+ type CamelCase<S extends string> = S extends `${infer A}-${infer B}`
11
+ ? `${A}${Capitalize<CamelCase<B>>}`
12
+ : S extends `${infer A}_${infer B}`
13
+ ? `${A}${Capitalize<CamelCase<B>>}`
14
+ : S
15
+
16
+ type ActionToProcedure<A extends Action> = 'query' extends NonNullable<A['kind']>
17
+ ? TRPCQueryProcedure<{
18
+ meta: object
19
+ input: z.infer<A['input']>
20
+ output: Awaited<ReturnType<A['run']>>
21
+ }>
22
+ : TRPCMutationProcedure<{
23
+ meta: object
24
+ input: z.infer<A['input']>
25
+ output: Awaited<ReturnType<A['run']>>
26
+ }>
27
+
28
+ type ActionsToRouterRecord<Actions extends Record<string, Action>> = {
29
+ [K in keyof Actions & string as CamelCase<Actions[K]['name']>]: ActionToProcedure<Actions[K]>
30
+ }
31
+
32
+ type TrpcRootTypes = {
33
+ ctx: object
34
+ meta: object
35
+ errorShape: unknown
36
+ transformer: false
37
+ } & AnyTRPCRootTypes
38
+
39
+ /**
40
+ * Extracts a fully-typed tRPC router from a Silkweave builder instance.
41
+ *
42
+ * Usage:
43
+ * ```ts
44
+ * const server = silkweave(opts).adapter(trpc({ port: 8080 })).action(HelloAction)
45
+ * export type AppRouter = InferTrpcRouter<typeof server>
46
+ * ```
47
+ */
48
+ export type InferTrpcRouter<S> = S extends Silkweave<infer Actions>
49
+ ? TRPCBuiltRouter<TrpcRootTypes, ActionsToRouterRecord<Actions>>
50
+ : never
package/tsconfig.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "lib": ["ES2022"],
7
+ "outDir": "build",
8
+ "rootDir": "src",
9
+ "strict": true,
10
+ "esModuleInterop": true,
11
+ "skipLibCheck": true,
12
+ "forceConsistentCasingInFileNames": true,
13
+ "allowSyntheticDefaultImports": true,
14
+ "resolveJsonModule": true,
15
+ "composite": true,
16
+ "declaration": true,
17
+ "declarationMap": true,
18
+ "sourceMap": true
19
+ },
20
+ "include": ["src"],
21
+ "exclude": ["node_modules", "build"]
22
+ }