ts-typed-api 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BROWSER_USAGE.md +133 -0
- package/dist/client-only.d.ts +5 -0
- package/dist/client-only.js +12 -0
- package/dist/server-only.d.ts +5 -0
- package/dist/server-only.js +9 -0
- package/examples/browser-client-example.ts +94 -0
- package/package.json +15 -1
- package/src/client-only.ts +33 -0
- package/src/server-only.ts +17 -0
package/BROWSER_USAGE.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Browser Usage Guide
|
|
2
|
+
|
|
3
|
+
This guide explains how to use `ts-typed-api` in browser environments without including server-side dependencies.
|
|
4
|
+
|
|
5
|
+
## Problem
|
|
6
|
+
|
|
7
|
+
When using the main package import in browsers, you might encounter issues with Node.js-specific dependencies like `busboy` and `multer` that are used for server-side file uploads. These dependencies reference Node.js APIs like `Buffer` that don't exist in browsers.
|
|
8
|
+
|
|
9
|
+
## Solution
|
|
10
|
+
|
|
11
|
+
The package now provides separate entry points for client-side and server-side code:
|
|
12
|
+
|
|
13
|
+
### Client-Only Import (Browser-Safe)
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
// ✅ Browser-safe import - no server dependencies
|
|
17
|
+
import { ApiClient, CreateApiDefinition, CreateResponses } from 'ts-typed-api/client';
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
This import includes:
|
|
21
|
+
- `ApiClient` - HTTP client for making API calls
|
|
22
|
+
- `CreateApiDefinition` - Function to define API structure
|
|
23
|
+
- `CreateResponses` - Function to define response schemas
|
|
24
|
+
- All necessary types for client-side usage
|
|
25
|
+
- Zod for validation
|
|
26
|
+
|
|
27
|
+
This import **does NOT include**:
|
|
28
|
+
- `RegisterHandlers` (server-side)
|
|
29
|
+
- `UploadedFile` type (server-side)
|
|
30
|
+
- Express/Multer dependencies
|
|
31
|
+
- Any Node.js-specific code
|
|
32
|
+
|
|
33
|
+
### Server-Only Import
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
// Server-side import - includes server dependencies
|
|
37
|
+
import { RegisterHandlers, UploadedFile } from 'ts-typed-api/server';
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Full Import (Node.js Only)
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
// Traditional import - includes everything (Node.js only)
|
|
44
|
+
import { ApiClient, RegisterHandlers } from 'ts-typed-api';
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Example Usage
|
|
48
|
+
|
|
49
|
+
### Browser Client
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
import { ApiClient, CreateApiDefinition, CreateResponses } from 'ts-typed-api/client';
|
|
53
|
+
import { z } from 'zod';
|
|
54
|
+
|
|
55
|
+
const ApiDefinition = CreateApiDefinition({
|
|
56
|
+
prefix: '/api',
|
|
57
|
+
endpoints: {
|
|
58
|
+
users: {
|
|
59
|
+
getUser: {
|
|
60
|
+
path: '/users/:id',
|
|
61
|
+
method: 'GET',
|
|
62
|
+
params: z.object({ id: z.string() }),
|
|
63
|
+
responses: CreateResponses({
|
|
64
|
+
200: z.object({
|
|
65
|
+
id: z.string(),
|
|
66
|
+
name: z.string(),
|
|
67
|
+
email: z.string()
|
|
68
|
+
})
|
|
69
|
+
})
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const client = new ApiClient('http://localhost:3000', ApiDefinition);
|
|
76
|
+
|
|
77
|
+
// Use in browser
|
|
78
|
+
const result = await client.callApi('users', 'getUser',
|
|
79
|
+
{ params: { id: '123' } },
|
|
80
|
+
{
|
|
81
|
+
200: ({ data }) => data,
|
|
82
|
+
422: ({ error }) => { throw new Error('Validation failed'); }
|
|
83
|
+
}
|
|
84
|
+
);
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Server Implementation
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
import express from 'express';
|
|
91
|
+
import { RegisterHandlers } from 'ts-typed-api/server';
|
|
92
|
+
// Import the same ApiDefinition used by the client
|
|
93
|
+
|
|
94
|
+
const app = express();
|
|
95
|
+
|
|
96
|
+
RegisterHandlers(app, ApiDefinition, {
|
|
97
|
+
users: {
|
|
98
|
+
getUser: async (req, res) => {
|
|
99
|
+
const { id } = req.params;
|
|
100
|
+
// ... server logic
|
|
101
|
+
res.respond(200, { id, name: 'John', email: 'john@example.com' });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Bundle Size Benefits
|
|
108
|
+
|
|
109
|
+
Using the client-only import significantly reduces bundle size for browser applications by excluding:
|
|
110
|
+
- Express framework
|
|
111
|
+
- Multer file upload middleware
|
|
112
|
+
- Busboy multipart parser
|
|
113
|
+
- Other Node.js-specific dependencies
|
|
114
|
+
|
|
115
|
+
## Migration Guide
|
|
116
|
+
|
|
117
|
+
If you're currently using the main import in browser code:
|
|
118
|
+
|
|
119
|
+
**Before:**
|
|
120
|
+
```typescript
|
|
121
|
+
import { ApiClient } from 'ts-typed-api';
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**After:**
|
|
125
|
+
```typescript
|
|
126
|
+
import { ApiClient } from 'ts-typed-api/client';
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
The API remains exactly the same - only the import path changes.
|
|
130
|
+
|
|
131
|
+
## TypeScript Support
|
|
132
|
+
|
|
133
|
+
All imports provide full TypeScript support with proper type inference and autocompletion.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { ApiClient, FetchHttpClientAdapter } from './client';
|
|
2
|
+
export { CreateApiDefinition, CreateResponses } from './definition';
|
|
3
|
+
export { z as ZodSchema } from 'zod';
|
|
4
|
+
export type { ApiDefinitionSchema, RouteSchema, UnifiedError, InferDataFromUnifiedResponse, ApiClientParams, ApiClientQuery, ApiClientBody, ApiResponse, ApiBody, ApiParams, ApiQuery, FileType, HttpSuccessStatusCode, HttpClientErrorStatusCode, HttpServerErrorStatusCode, AllowedInputStatusCode, AllowedResponseStatusCode } from './definition';
|
|
5
|
+
export type { HttpRequestOptions, HttpResponse, HttpClientAdapter, ApiCallResult, CallApiOptions } from './client';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ZodSchema = exports.CreateResponses = exports.CreateApiDefinition = exports.FetchHttpClientAdapter = exports.ApiClient = void 0;
|
|
4
|
+
// Client-only exports - no server dependencies
|
|
5
|
+
var client_1 = require("./client");
|
|
6
|
+
Object.defineProperty(exports, "ApiClient", { enumerable: true, get: function () { return client_1.ApiClient; } });
|
|
7
|
+
Object.defineProperty(exports, "FetchHttpClientAdapter", { enumerable: true, get: function () { return client_1.FetchHttpClientAdapter; } });
|
|
8
|
+
var definition_1 = require("./definition");
|
|
9
|
+
Object.defineProperty(exports, "CreateApiDefinition", { enumerable: true, get: function () { return definition_1.CreateApiDefinition; } });
|
|
10
|
+
Object.defineProperty(exports, "CreateResponses", { enumerable: true, get: function () { return definition_1.CreateResponses; } });
|
|
11
|
+
var zod_1 = require("zod");
|
|
12
|
+
Object.defineProperty(exports, "ZodSchema", { enumerable: true, get: function () { return zod_1.z; } });
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { RegisterHandlers, EndpointMiddleware } from './object-handlers';
|
|
2
|
+
export { File as UploadedFile } from './router';
|
|
3
|
+
export { createRouteHandler, makeRouteHandlerCreator } from './router';
|
|
4
|
+
export type { TypedRequest, TypedResponse } from './router';
|
|
5
|
+
export type { ObjectHandlers } from './object-handlers';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.makeRouteHandlerCreator = exports.createRouteHandler = exports.RegisterHandlers = void 0;
|
|
4
|
+
// Server-only exports - includes server dependencies
|
|
5
|
+
var object_handlers_1 = require("./object-handlers");
|
|
6
|
+
Object.defineProperty(exports, "RegisterHandlers", { enumerable: true, get: function () { return object_handlers_1.RegisterHandlers; } });
|
|
7
|
+
var router_1 = require("./router");
|
|
8
|
+
Object.defineProperty(exports, "createRouteHandler", { enumerable: true, get: function () { return router_1.createRouteHandler; } });
|
|
9
|
+
Object.defineProperty(exports, "makeRouteHandlerCreator", { enumerable: true, get: function () { return router_1.makeRouteHandlerCreator; } });
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// Example of using the client-only import for browser environments
|
|
2
|
+
// This import will NOT include server dependencies like multer/busboy
|
|
3
|
+
|
|
4
|
+
import { ApiClient, CreateApiDefinition, CreateResponses } from 'ts-typed-api/client';
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
|
|
7
|
+
// Define a simple API (this would typically be shared between client and server)
|
|
8
|
+
const ApiDefinition = CreateApiDefinition({
|
|
9
|
+
prefix: '/api',
|
|
10
|
+
endpoints: {
|
|
11
|
+
users: {
|
|
12
|
+
getUser: {
|
|
13
|
+
path: '/users/:id',
|
|
14
|
+
method: 'GET',
|
|
15
|
+
params: z.object({
|
|
16
|
+
id: z.string()
|
|
17
|
+
}),
|
|
18
|
+
responses: CreateResponses({
|
|
19
|
+
200: z.object({
|
|
20
|
+
id: z.string(),
|
|
21
|
+
name: z.string(),
|
|
22
|
+
email: z.string()
|
|
23
|
+
})
|
|
24
|
+
})
|
|
25
|
+
},
|
|
26
|
+
createUser: {
|
|
27
|
+
path: '/users',
|
|
28
|
+
method: 'POST',
|
|
29
|
+
body: z.object({
|
|
30
|
+
name: z.string(),
|
|
31
|
+
email: z.string()
|
|
32
|
+
}),
|
|
33
|
+
responses: CreateResponses({
|
|
34
|
+
201: z.object({
|
|
35
|
+
id: z.string(),
|
|
36
|
+
name: z.string(),
|
|
37
|
+
email: z.string()
|
|
38
|
+
})
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Create client instance
|
|
46
|
+
const client = new ApiClient('http://localhost:3000', ApiDefinition);
|
|
47
|
+
|
|
48
|
+
// Example usage in browser
|
|
49
|
+
async function exampleUsage() {
|
|
50
|
+
try {
|
|
51
|
+
// Get a user
|
|
52
|
+
const getUserResult = await client.callApi('users', 'getUser',
|
|
53
|
+
{ params: { id: '123' } },
|
|
54
|
+
{
|
|
55
|
+
200: ({ data }) => {
|
|
56
|
+
console.log('User found:', data);
|
|
57
|
+
return data;
|
|
58
|
+
},
|
|
59
|
+
422: ({ error }) => {
|
|
60
|
+
console.error('Validation error:', error);
|
|
61
|
+
throw new Error('Validation failed');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
// Create a user
|
|
67
|
+
const createUserResult = await client.callApi('users', 'createUser',
|
|
68
|
+
{
|
|
69
|
+
body: {
|
|
70
|
+
name: 'John Doe',
|
|
71
|
+
email: 'john@example.com'
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
201: ({ data }) => {
|
|
76
|
+
console.log('User created:', data);
|
|
77
|
+
return data;
|
|
78
|
+
},
|
|
79
|
+
422: ({ error }) => {
|
|
80
|
+
console.error('Validation error:', error);
|
|
81
|
+
throw new Error('Validation failed');
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
return { getUserResult, createUserResult };
|
|
87
|
+
} catch (error) {
|
|
88
|
+
console.error('API call failed:', error);
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Export for use in browser
|
|
94
|
+
export { client, exampleUsage };
|
package/package.json
CHANGED
|
@@ -1,9 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ts-typed-api",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "A lightweight, type-safe RPC library for TypeScript with Zod validation",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./client": {
|
|
13
|
+
"types": "./dist/client-only.d.ts",
|
|
14
|
+
"default": "./dist/client-only.js"
|
|
15
|
+
},
|
|
16
|
+
"./server": {
|
|
17
|
+
"types": "./dist/server-only.d.ts",
|
|
18
|
+
"default": "./dist/server-only.js"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
7
21
|
"scripts": {
|
|
8
22
|
"build": "tsc",
|
|
9
23
|
"lint": "eslint . --ext .ts",
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Client-only exports - no server dependencies
|
|
2
|
+
export { ApiClient, FetchHttpClientAdapter } from './client';
|
|
3
|
+
export { CreateApiDefinition, CreateResponses } from './definition';
|
|
4
|
+
export { z as ZodSchema } from 'zod';
|
|
5
|
+
|
|
6
|
+
// Re-export types that are safe for client use
|
|
7
|
+
export type {
|
|
8
|
+
ApiDefinitionSchema,
|
|
9
|
+
RouteSchema,
|
|
10
|
+
UnifiedError,
|
|
11
|
+
InferDataFromUnifiedResponse,
|
|
12
|
+
ApiClientParams,
|
|
13
|
+
ApiClientQuery,
|
|
14
|
+
ApiClientBody,
|
|
15
|
+
ApiResponse,
|
|
16
|
+
ApiBody,
|
|
17
|
+
ApiParams,
|
|
18
|
+
ApiQuery,
|
|
19
|
+
FileType,
|
|
20
|
+
HttpSuccessStatusCode,
|
|
21
|
+
HttpClientErrorStatusCode,
|
|
22
|
+
HttpServerErrorStatusCode,
|
|
23
|
+
AllowedInputStatusCode,
|
|
24
|
+
AllowedResponseStatusCode
|
|
25
|
+
} from './definition';
|
|
26
|
+
|
|
27
|
+
export type {
|
|
28
|
+
HttpRequestOptions,
|
|
29
|
+
HttpResponse,
|
|
30
|
+
HttpClientAdapter,
|
|
31
|
+
ApiCallResult,
|
|
32
|
+
CallApiOptions
|
|
33
|
+
} from './client';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Server-only exports - includes server dependencies
|
|
2
|
+
export { RegisterHandlers, EndpointMiddleware } from './object-handlers';
|
|
3
|
+
export { File as UploadedFile } from './router';
|
|
4
|
+
export {
|
|
5
|
+
createRouteHandler,
|
|
6
|
+
makeRouteHandlerCreator
|
|
7
|
+
} from './router';
|
|
8
|
+
|
|
9
|
+
// Re-export types that are needed for server-side development
|
|
10
|
+
export type {
|
|
11
|
+
TypedRequest,
|
|
12
|
+
TypedResponse
|
|
13
|
+
} from './router';
|
|
14
|
+
|
|
15
|
+
export type {
|
|
16
|
+
ObjectHandlers
|
|
17
|
+
} from './object-handlers';
|