typed-bridge 1.0.0 → 2.0.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,3 @@
1
+ {
2
+ "editor.formatOnSave": true
3
+ }
package/context.md ADDED
@@ -0,0 +1,168 @@
1
+ # **Using `typed-bridge` to Build a Backend**
2
+
3
+ ## **What is `typed-bridge`?**
4
+
5
+ `typed-bridge` is an open‑source TypeScript package that lets you define **strictly typed server functions** and automatically generate a matching **typed client** for your frontend.
6
+ It removes the boilerplate of REST/GraphQL by letting you call server functions like local functions — while keeping **end‑to‑end type safety** between backend and frontend.
7
+ It’s framework‑agnostic, works with any frontend (React, Vue, Angular, RN, etc.), supports middleware for auth/validation/logging, and has built‑in graceful shutdown and request logging.
8
+
9
+ **Why use it?**
10
+
11
+ - Prevents API spec drift between backend and frontend
12
+ - Strong TypeScript type checking across the stack
13
+ - Simple middleware for auth, validation, and context sharing
14
+ - No need to hand‑roll REST/GraphQL routes
15
+
16
+ ---
17
+
18
+ ## **How to Start a Server**
19
+
20
+ ```ts
21
+ // src/server.ts
22
+ import { createBridge, tbConfig } from 'typed-bridge'
23
+ import bridge from './bridge/index.js'
24
+ import './middleware/auth.js' // optional middleware
25
+
26
+ // Optional logging
27
+ tbConfig.logs.request = true
28
+ tbConfig.logs.response = true
29
+ tbConfig.logs.error = true
30
+
31
+ createBridge(bridge, 8080, '/bridge')
32
+ console.log(`Bridge running at http://localhost:8080/bridge`)
33
+ ```
34
+
35
+ ---
36
+
37
+ ## **How to Define Routes**
38
+
39
+ ```ts
40
+ // src/bridge/index.ts
41
+ import * as user from './user/index.js'
42
+
43
+ export default {
44
+ 'user.fetch': user.fetch,
45
+ 'user.update': user.update,
46
+ 'user.fetchAll': user.fetchAll
47
+ }
48
+ ```
49
+
50
+ ---
51
+
52
+ ## **How to Write Handlers**
53
+
54
+ ```ts
55
+ // src/bridge/user/index.ts
56
+ export interface User {
57
+ id: number
58
+ name: string
59
+ email: string
60
+ createdAt: Date
61
+ }
62
+
63
+ const users: User[] = [
64
+ { id: 1, name: 'Neil', email: 'neil@example.com', createdAt: new Date() },
65
+ { id: 2, name: 'John', email: 'john@example.com', createdAt: new Date() },
66
+ { id: 3, name: 'Jane', email: 'jane@example.com', createdAt: new Date() }
67
+ ]
68
+
69
+ export const fetch = async (args: { id: number }): Promise<User> => {
70
+ const user = users.find(u => u.id === args.id)
71
+ if (!user) throw new Error(`User ${args.id} not found`)
72
+ return user
73
+ }
74
+
75
+ export const update = async (args: { id: number; name?: string; email?: string }): Promise<User> => {
76
+ const user = users.find(u => u.id === args.id)
77
+ if (!user) throw new Error(`User ${args.id} not found`)
78
+ if (args.name) user.name = args.name
79
+ if (args.email) user.email = args.email
80
+ return user
81
+ }
82
+
83
+ export const fetchAll = async (): Promise<User[]> => users
84
+ ```
85
+
86
+ ---
87
+
88
+ ## **How to Add Middleware**
89
+
90
+ ```ts
91
+ // src/middleware/auth.ts
92
+ import { createMiddleware } from 'typed-bridge'
93
+
94
+ createMiddleware('user.*', async (req, res) => {
95
+ if (req.headers.authorization !== 'Bearer 123') {
96
+ res.status(401).send('Unauthorized')
97
+ return { next: false } // Stop processing
98
+ }
99
+ return { context: { userId: 999 } }
100
+ })
101
+ ```
102
+
103
+ ---
104
+
105
+ ## **How to Validate with `$z` (Zod)**
106
+
107
+ ```ts
108
+ // src/bridge/user/types.ts
109
+ import { $z } from 'typed-bridge'
110
+
111
+ export const fetch = {
112
+ args: $z.object({ id: $z.number().min(1) }),
113
+ res: $z.object({
114
+ id: $z.number(),
115
+ name: $z.string(),
116
+ email: $z.string().email(),
117
+ createdAt: $z.date()
118
+ })
119
+ }
120
+ ```
121
+
122
+ ```ts
123
+ // src/bridge/user/index.ts (validated version)
124
+ import { $z } from 'typed-bridge'
125
+ import * as types from './types.js'
126
+
127
+ export const fetch = async (
128
+ args: $z.infer<typeof types.fetch.args>,
129
+ context: { userId?: number }
130
+ ): Promise<$z.infer<typeof types.fetch.res>> => {
131
+ args = types.fetch.args.parse(args)
132
+ const user = users.find(u => u.id === args.id)
133
+ if (!user) throw new Error(`User ${args.id} not found`)
134
+ return user
135
+ }
136
+ ```
137
+
138
+ ---
139
+
140
+ ## **How to Generate a Typed Client**
141
+
142
+ ```bash
143
+ npm run gen:typed-bridge-client
144
+ # => creates ./bridge.ts
145
+ ```
146
+
147
+ ---
148
+
149
+ ## **How to Use the Generated Client (Frontend)**
150
+
151
+ ```ts
152
+ import bridge, { bridgeConfig } from '../path-to-backend/bridge'
153
+
154
+ bridgeConfig.host = 'http://localhost:8080/bridge'
155
+ bridgeConfig.headers = { 'Content-Type': 'application/json', Authorization: 'Bearer 123' }
156
+
157
+ const user = await bridge['user.fetch']({ id: 1 })
158
+ console.log(user)
159
+ ```
160
+
161
+ ---
162
+
163
+ ## **How to Add a New Route (Checklist)**
164
+
165
+ 1. Create handler in `src/bridge/<module>/index.ts`
166
+ 2. Add `'module.method': handler` to `src/bridge/index.ts`
167
+ 3. (If validating) add types in `src/bridge/<module>/types.ts`
168
+ 4. Run `npm run gen:typed-bridge-client` to refresh the client
@@ -1,6 +1,19 @@
1
- import { Request, Response } from 'express';
2
- declare const _default: (bridge: any, contextParser?: (req: Request, res: Response) => Promise<{
3
- next?: boolean;
4
- context?: any;
5
- } | void>) => any;
6
- export default _default;
1
+ import { Application, Request, Response } from 'express';
2
+ import { Server } from 'http';
3
+ type Bridge = {
4
+ [key: string]: (...args: any[]) => Promise<any>;
5
+ };
6
+ type Middleware = {
7
+ pattern: string;
8
+ handler: (req: Request, res: Response) => Promise<{
9
+ next?: boolean;
10
+ context?: any;
11
+ } | void>;
12
+ };
13
+ export declare const createMiddleware: (pattern: string, handler: Middleware["handler"]) => number;
14
+ export declare const onShutdown: (fn: () => void) => () => void;
15
+ export declare const createBridge: (bridge: Bridge, port: number, path?: string) => {
16
+ app: Application;
17
+ server: Server;
18
+ };
19
+ export {};
@@ -1,23 +1,121 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
- const config_1 = require("../config");
4
- exports.default = (bridge, contextParser) => async (req, res) => {
6
+ exports.createBridge = exports.onShutdown = exports.createMiddleware = void 0;
7
+ const helpers_1 = require("@/helpers");
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const compression_1 = __importDefault(require("compression"));
10
+ const cors_1 = __importDefault(require("cors"));
11
+ const express_1 = __importDefault(require("express"));
12
+ const path_1 = __importDefault(require("path"));
13
+ const __1 = require("..");
14
+ const middlewares = [];
15
+ const createMiddleware = (pattern, handler) => middlewares.push({ pattern, handler });
16
+ exports.createMiddleware = createMiddleware;
17
+ let shutdownCallback = () => { };
18
+ const onShutdown = (fn) => (shutdownCallback = fn);
19
+ exports.onShutdown = onShutdown;
20
+ const createBridge = (bridge, port, path = '/bridge') => {
21
+ const app = (0, express_1.default)();
22
+ // cors
23
+ app.use((0, cors_1.default)());
24
+ // Compression
25
+ app.use((0, compression_1.default)());
26
+ // Body parser
27
+ app.use(express_1.default.json());
28
+ app.use(express_1.default.urlencoded({ extended: true }));
29
+ // Typed bridge middleware
30
+ let requestId = 1;
31
+ app.use((req, res, next) => {
32
+ const _req = req;
33
+ const xForwardedFor = req.headers['x-forwarded-for'];
34
+ let ip = Array.isArray(xForwardedFor)
35
+ ? xForwardedFor[0]
36
+ : (xForwardedFor || '').split(', ')[0] || req.socket.remoteAddress || '';
37
+ if (ip === '::1')
38
+ ip = '127.0.0.1';
39
+ // Bind data
40
+ _req.bind = {
41
+ id: 0,
42
+ ts: Date.now(),
43
+ args: {},
44
+ ip
45
+ };
46
+ // Set typed bridge header
47
+ res.setHeader('X-Powered-By', 'typed-bridge');
48
+ requestId++;
49
+ // Log request
50
+ if (__1.tbConfig.logs.request) {
51
+ console.log(chalk_1.default.blueBright(`REQ | ${new Date().toISOString()} | ${requestId} :: ${req.method} | ${req.path} | ${ip}`));
52
+ }
53
+ // Log response
54
+ const startTime = Date.now();
55
+ res.on('finish', () => {
56
+ const log = `RES | ${new Date().toISOString()} | ${requestId} :: ${res.statusCode} | ${Date.now() - startTime}ms`;
57
+ if (__1.tbConfig.logs.response)
58
+ console.log(res.statusCode < 400 ? chalk_1.default.green(log) : chalk_1.default.red(log));
59
+ });
60
+ next();
61
+ });
62
+ // Handle invalid json in post request
63
+ app.use((error, req, res, next) => {
64
+ if (error?.type === 'entity.parse.failed') {
65
+ res.status(400).send('Can not parse request!');
66
+ }
67
+ else
68
+ next();
69
+ });
70
+ // Custom responseDelay
71
+ if (__1.tbConfig.responseDelay)
72
+ app.use((req, res, next) => {
73
+ setTimeout(next, __1.tbConfig.responseDelay);
74
+ });
75
+ // Server health
76
+ app.use(path_1.default.join(path, 'health'), (req, res) => {
77
+ res.sendStatus(200);
78
+ });
79
+ app.use(path, bridgeHandler(bridge));
80
+ const server = app.listen(port, () => (0, helpers_1.printStartLogs)(port));
81
+ let shuttingDown = false;
82
+ const shutdown = () => {
83
+ if (shuttingDown)
84
+ return;
85
+ shuttingDown = true;
86
+ server.close();
87
+ (0, helpers_1.printStopLogs)();
88
+ shutdownCallback();
89
+ };
90
+ process.on('SIGINT', () => shutdown());
91
+ process.on('SIGTERM', () => shutdown());
92
+ return { app, server };
93
+ };
94
+ exports.createBridge = createBridge;
95
+ const bridgeHandler = (bridge) => async (req, res) => {
5
96
  try {
6
97
  const path = req.path.split('/').pop() || '';
7
98
  const args = req.body;
8
99
  if (!path)
9
100
  throw new Error('Bridge not found!');
10
101
  const serverFunction = bridge[path];
11
- if (!serverFunction)
12
- throw new Error('Bridge not found: ' + path);
13
- let context;
14
- if (contextParser) {
15
- const contextParserRes = await contextParser(req, res);
16
- if (contextParserRes && contextParserRes.next === false)
17
- return;
18
- context = contextParserRes?.context;
102
+ if (!serverFunction) {
103
+ const error = 'Bridge not found: ' + path;
104
+ if (__1.tbConfig.logs.error)
105
+ console.error(error);
106
+ return res.status(404).json({ error });
107
+ }
108
+ let context = {};
109
+ for (const middleware of middlewares) {
110
+ if ((0, helpers_1.matchesPattern)(path, middleware.pattern)) {
111
+ const result = await middleware.handler(req, res);
112
+ if (result?.next === false)
113
+ return;
114
+ if (result?.context)
115
+ context = { ...context, ...result.context };
116
+ }
19
117
  }
20
- res.json(await serverFunction(args, context));
118
+ res.json((await serverFunction(args, context)) || {});
21
119
  }
22
120
  catch (error) {
23
121
  if (Array.isArray(error.errors)) {
@@ -25,7 +123,7 @@ exports.default = (bridge, contextParser) => async (req, res) => {
25
123
  const errorMessage = (keyPath ? keyPath + ': ' : '') + error.errors[0].message;
26
124
  return res.status(400).send(errorMessage);
27
125
  }
28
- if (config_1.config.logs.error)
126
+ if (__1.tbConfig.logs.error)
29
127
  console.error(error);
30
128
  return res.status(500).json({ error: error.message });
31
129
  }
@@ -4,9 +4,7 @@ interface config {
4
4
  response: boolean;
5
5
  error: boolean;
6
6
  };
7
- idPrefix: string;
8
7
  responseDelay: number;
9
- gracefulShutdown: boolean;
10
8
  }
11
9
  export declare const config: config;
12
10
  export {};
@@ -7,7 +7,5 @@ exports.config = {
7
7
  response: true,
8
8
  error: true
9
9
  },
10
- responseDelay: 0,
11
- gracefulShutdown: false,
12
- idPrefix: ''
10
+ responseDelay: 0
13
11
  };
@@ -1,3 +1,4 @@
1
+ import * as user from './user';
1
2
  declare const _default: {
2
3
  'user.fetch': (args: import("zod").TypeOf<import("zod").ZodObject<{
3
4
  id: import("zod").ZodNumber;
@@ -5,7 +6,9 @@ declare const _default: {
5
6
  id: number;
6
7
  }, {
7
8
  id: number;
8
- }>>, context: import("zod").TypeOf<typeof import("./user/types").userContext>) => Promise<import("zod").TypeOf<import("zod").ZodObject<{
9
+ }>>, context: {
10
+ id: number;
11
+ }) => Promise<import("zod").TypeOf<import("zod").ZodObject<{
9
12
  id: import("zod").ZodNumber;
10
13
  name: import("zod").ZodString;
11
14
  }, "strip", import("zod").ZodTypeAny, {
@@ -15,5 +18,11 @@ declare const _default: {
15
18
  id: number;
16
19
  name: string;
17
20
  }>>>;
21
+ 'user.update': (args: {
22
+ id: number;
23
+ name?: string;
24
+ email?: string;
25
+ }) => Promise<user.User>;
26
+ 'user.fetchAll': () => Promise<user.User[]>;
18
27
  };
19
28
  export default _default;
@@ -35,5 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  const user = __importStar(require("./user"));
37
37
  exports.default = {
38
- 'user.fetch': user.fetch
38
+ 'user.fetch': user.fetch,
39
+ 'user.update': user.update,
40
+ 'user.fetchAll': user.fetchAll
39
41
  };
@@ -1,3 +1,17 @@
1
1
  import { $z } from '@/index';
2
2
  import * as types from './types';
3
- export declare const fetch: (args: $z.infer<typeof types.fetch.args>, context: $z.infer<typeof types.userContext>) => Promise<$z.infer<typeof types.fetch.res>>;
3
+ export interface User {
4
+ id: number;
5
+ name: string;
6
+ email: string;
7
+ createdAt: Date;
8
+ }
9
+ export declare const fetch: (args: $z.infer<typeof types.fetch.args>, context: {
10
+ id: number;
11
+ }) => Promise<$z.infer<typeof types.fetch.res>>;
12
+ export declare const update: (args: {
13
+ id: number;
14
+ name?: string;
15
+ email?: string;
16
+ }) => Promise<User>;
17
+ export declare const fetchAll: () => Promise<User[]>;
@@ -33,11 +33,36 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.fetch = void 0;
36
+ exports.fetchAll = exports.update = exports.fetch = void 0;
37
37
  const types = __importStar(require("./types"));
38
+ const users = [
39
+ { id: 1, name: 'Neil', email: 'neil@example.com', createdAt: new Date() },
40
+ { id: 2, name: 'John', email: 'john@example.com', createdAt: new Date() },
41
+ { id: 3, name: 'Jane', email: 'jane@example.com', createdAt: new Date() }
42
+ ];
38
43
  const fetch = async (args, context) => {
39
- types.fetch.args.parse(args);
40
- console.log('Context:', context);
41
- return { id: args.id, name: 'Neil' };
44
+ args = types.fetch.args.parse(args);
45
+ console.log(context);
46
+ const user = users.find(user => user.id === args.id);
47
+ if (!user) {
48
+ throw new Error(`User with ID ${args.id} not found`);
49
+ }
50
+ return user;
42
51
  };
43
52
  exports.fetch = fetch;
53
+ const update = async (args) => {
54
+ const user = users.find(user => user.id === args.id);
55
+ if (!user) {
56
+ throw new Error(`User with ID ${args.id} not found`);
57
+ }
58
+ if (args.name)
59
+ user.name = args.name;
60
+ if (args.email)
61
+ user.email = args.email;
62
+ return user;
63
+ };
64
+ exports.update = update;
65
+ const fetchAll = async () => {
66
+ return users;
67
+ };
68
+ exports.fetchAll = fetchAll;
@@ -1,16 +1,16 @@
1
- import { z } from 'zod';
1
+ import { $z } from '@/index';
2
2
  export declare const fetch: {
3
- args: z.ZodObject<{
4
- id: z.ZodNumber;
5
- }, "strip", z.ZodTypeAny, {
3
+ args: $z.ZodObject<{
4
+ id: $z.ZodNumber;
5
+ }, "strip", $z.ZodTypeAny, {
6
6
  id: number;
7
7
  }, {
8
8
  id: number;
9
9
  }>;
10
- res: z.ZodObject<{
11
- id: z.ZodNumber;
12
- name: z.ZodString;
13
- }, "strip", z.ZodTypeAny, {
10
+ res: $z.ZodObject<{
11
+ id: $z.ZodNumber;
12
+ name: $z.ZodString;
13
+ }, "strip", $z.ZodTypeAny, {
14
14
  id: number;
15
15
  name: string;
16
16
  }, {
@@ -18,9 +18,9 @@ export declare const fetch: {
18
18
  name: string;
19
19
  }>;
20
20
  };
21
- export declare const userContext: z.ZodObject<{
22
- id: z.ZodNumber;
23
- }, "strip", z.ZodTypeAny, {
21
+ export declare const userContext: $z.ZodObject<{
22
+ id: $z.ZodNumber;
23
+ }, "strip", $z.ZodTypeAny, {
24
24
  id: number;
25
25
  }, {
26
26
  id: number;
@@ -1,16 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.userContext = exports.fetch = void 0;
4
- const zod_1 = require("zod");
4
+ const index_1 = require("@/index");
5
5
  exports.fetch = {
6
- args: zod_1.z.object({
7
- id: zod_1.z.number()
6
+ args: index_1.$z.object({
7
+ id: index_1.$z.number().min(1)
8
8
  }),
9
- res: zod_1.z.object({
10
- id: zod_1.z.number(),
11
- name: zod_1.z.string()
9
+ res: index_1.$z.object({
10
+ id: index_1.$z.number(),
11
+ name: index_1.$z.string()
12
12
  })
13
13
  };
14
- exports.userContext = zod_1.z.object({
15
- id: zod_1.z.number()
14
+ exports.userContext = index_1.$z.object({
15
+ id: index_1.$z.number()
16
16
  });
@@ -3,25 +3,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- const index_1 = require("@/index");
6
+ const __1 = require("..");
7
7
  const bridge_1 = __importDefault(require("./bridge"));
8
- index_1.tbConfig.logs.error = true;
9
- index_1.tbConfig.logs.request = true;
10
- index_1.tbConfig.logs.response = true;
11
- const app = (0, index_1.createApp)();
12
- (0, index_1.startServer)(app, 8080);
13
- const contextParser = async (req, res) => {
14
- const headers = req.headers;
15
- const bridge = req.originalUrl.split('/').pop();
16
- if (bridge === 'test.error') {
17
- res.sendStatus(400);
18
- return { next: false };
19
- }
20
- return {
21
- context: {
22
- name: 'Typed Bridge',
23
- authorization: headers.authorization || 'NO_AUTH'
24
- }
25
- };
26
- };
27
- app.use('/bridge', (0, index_1.createBridge)(bridge_1.default, contextParser));
8
+ __1.tbConfig.logs.error = true;
9
+ __1.tbConfig.logs.request = true;
10
+ __1.tbConfig.logs.response = true;
11
+ // tbConfig.responseDelay = 1000
12
+ (0, __1.createBridge)(bridge_1.default, 8080, '/');
@@ -1,2 +1,3 @@
1
1
  export declare const printStartLogs: (port: number) => void;
2
2
  export declare const printStopLogs: () => void;
3
+ export declare const matchesPattern: (str: string, pattern: string) => boolean;
@@ -3,21 +3,30 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.printStopLogs = exports.printStartLogs = void 0;
6
+ exports.matchesPattern = exports.printStopLogs = exports.printStartLogs = void 0;
7
7
  const chalk_1 = __importDefault(require("chalk"));
8
8
  const os_1 = __importDefault(require("os"));
9
- const __1 = require("..");
10
9
  const getLocalIPList = () => {
11
- const ipList = Object.values(os_1.default.networkInterfaces())
12
- .map(x => (x && x[0] ? x[0].address : null))
13
- .filter(ip => /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/.test(ip || ''));
14
- if (ipList.includes('127.0.0.1'))
10
+ const interfaces = os_1.default.networkInterfaces();
11
+ const ipList = [];
12
+ Object.values(interfaces).forEach(ifaceArr => {
13
+ ifaceArr?.forEach(iface => {
14
+ if (iface.family === 'IPv4' && !iface.internal) {
15
+ ipList.push(iface.address);
16
+ }
17
+ });
18
+ });
19
+ // Always include localhost for convenience
20
+ if (!ipList.includes('127.0.0.1'))
21
+ ipList.unshift('localhost');
22
+ else
15
23
  ipList.unshift('localhost');
16
24
  return ipList;
17
25
  };
18
26
  const seperator = '\n-x-x-x-x-x-\n';
19
27
  const printStartLogs = (port) => {
20
28
  const ipList = getLocalIPList();
29
+ console.log(ipList);
21
30
  console.log(seperator);
22
31
  console.log(chalk_1.default.bgWhite.black(' Typed Bridge '));
23
32
  console.log(seperator);
@@ -28,7 +37,15 @@ const printStartLogs = (port) => {
28
37
  exports.printStartLogs = printStartLogs;
29
38
  const printStopLogs = () => {
30
39
  console.log(seperator);
31
- console.log(chalk_1.default.red(`Server${__1.tbConfig.gracefulShutdown ? ' gracefully ' : ' '}stopped at: ` + new Date().toISOString()));
40
+ console.log(chalk_1.default.red(`Server stopped at: ` + new Date().toISOString()));
32
41
  console.log(seperator);
33
42
  };
34
43
  exports.printStopLogs = printStopLogs;
44
+ const matchesPattern = (str, pattern) => {
45
+ // Escape regex special chars except "*"
46
+ const escaped = pattern.replace(/[-\\^$+?.()|[\]{}]/g, '\\$&');
47
+ // Replace "*" with ".*" for wildcard matching
48
+ const regexStr = '^' + escaped.replace(/\*/g, '.*') + '$';
49
+ return new RegExp(regexStr).test(str);
50
+ };
51
+ exports.matchesPattern = matchesPattern;
package/dist/index.d.ts CHANGED
@@ -1,7 +1,5 @@
1
1
  import 'dotenv/config';
2
- export { default as createApp } from './app';
3
- export { default as createBridge } from './bridge';
2
+ export { createBridge, createMiddleware, onShutdown } from './bridge';
4
3
  export { config as tbConfig } from './config';
5
- export { default as startServer } from './server';
6
4
  export { default as $z } from 'zod';
7
5
  export { Application, default as express, NextFunction, Request, Response, Router } from 'express';
package/dist/index.js CHANGED
@@ -3,16 +3,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.Router = exports.express = exports.$z = exports.startServer = exports.tbConfig = exports.createBridge = exports.createApp = void 0;
6
+ exports.Router = exports.express = exports.$z = exports.tbConfig = exports.onShutdown = exports.createMiddleware = exports.createBridge = void 0;
7
7
  require("dotenv/config");
8
- var app_1 = require("./app");
9
- Object.defineProperty(exports, "createApp", { enumerable: true, get: function () { return __importDefault(app_1).default; } });
10
8
  var bridge_1 = require("./bridge");
11
- Object.defineProperty(exports, "createBridge", { enumerable: true, get: function () { return __importDefault(bridge_1).default; } });
9
+ Object.defineProperty(exports, "createBridge", { enumerable: true, get: function () { return bridge_1.createBridge; } });
10
+ Object.defineProperty(exports, "createMiddleware", { enumerable: true, get: function () { return bridge_1.createMiddleware; } });
11
+ Object.defineProperty(exports, "onShutdown", { enumerable: true, get: function () { return bridge_1.onShutdown; } });
12
12
  var config_1 = require("./config");
13
13
  Object.defineProperty(exports, "tbConfig", { enumerable: true, get: function () { return config_1.config; } });
14
- var server_1 = require("./server");
15
- Object.defineProperty(exports, "startServer", { enumerable: true, get: function () { return __importDefault(server_1).default; } });
16
14
  var zod_1 = require("zod");
17
15
  Object.defineProperty(exports, "$z", { enumerable: true, get: function () { return __importDefault(zod_1).default; } });
18
16
  var express_1 = require("express");
@@ -8,7 +8,7 @@ const commander_1 = require("commander");
8
8
  const buildTypeBridge_1 = __importDefault(require("./buildTypeBridge"));
9
9
  const typedBridgeCleaner_1 = __importDefault(require("./typedBridgeCleaner"));
10
10
  commander_1.program
11
- .command('gen-typed-bridge')
11
+ .command('gen-typed-bridge-client')
12
12
  .description('Generate a typed bridge')
13
13
  .option('--src <string>', 'Set typed bridge source file path')
14
14
  .option('--dest <string>', 'Set typed bridge destination file path', 'typedBridge.ts')
@@ -20,5 +20,6 @@ commander_1.program
20
20
  throw new Error('--dest required');
21
21
  await (0, buildTypeBridge_1.default)(src, dest);
22
22
  (0, typedBridgeCleaner_1.default)(dest);
23
+ console.log('\n✅ Bridge generated successfully!\n');
23
24
  });
24
25
  commander_1.program.parse();