@major-tech/resource-client 0.1.4 → 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/README.md +116 -44
- package/bin/generate-clients.mjs +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,90 +1,162 @@
|
|
|
1
1
|
# @major-tech/resource-client
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
TS client: PostgreSQL/CustomAPI/HubSpot/S3. Type-safe, 0-dep, universal (Node/browser/edge), ESM+CJS.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
```bash
|
|
7
|
-
pnpm
|
|
7
|
+
pnpm add @major-tech/resource-client
|
|
8
8
|
```
|
|
9
9
|
|
|
10
|
-
##
|
|
11
|
-
|
|
12
|
-
**Config (all clients):**
|
|
10
|
+
## Config (All Clients)
|
|
13
11
|
```typescript
|
|
14
12
|
{ baseUrl: string; applicationId: string; resourceId: string; majorJwtToken?: string; fetch?: typeof fetch }
|
|
15
13
|
```
|
|
16
14
|
|
|
17
|
-
|
|
15
|
+
## Response Format
|
|
16
|
+
```typescript
|
|
17
|
+
{ ok: true; requestId: string; result: T } | { ok: false; requestId: string; error: { message: string; httpStatus?: number } }
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## PostgresResourceClient
|
|
21
|
+
|
|
22
|
+
**Constructor:** `new PostgresResourceClient(config: BaseClientConfig)`
|
|
18
23
|
|
|
19
|
-
**
|
|
24
|
+
**Method:** `invoke(sql: string, params: DbParamPrimitive[] | undefined, invocationKey: string, timeoutMs?: number): Promise<DatabaseInvokeResponse>`
|
|
25
|
+
|
|
26
|
+
**Params:**
|
|
27
|
+
- `sql`: SQL query string
|
|
28
|
+
- `params`: `(string | number | boolean | null)[]` - positional params ($1, $2, etc)
|
|
29
|
+
- `invocationKey`: unique operation ID (regex: `[a-zA-Z0-9][a-zA-Z0-9._:-]*`)
|
|
30
|
+
- `timeoutMs`: optional timeout
|
|
31
|
+
|
|
32
|
+
**Result (ok=true):**
|
|
33
|
+
```typescript
|
|
34
|
+
{ kind: "database"; rows: Record<string, unknown>[]; rowsAffected?: number }
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**Example:**
|
|
20
38
|
```typescript
|
|
21
39
|
import { PostgresResourceClient } from '@major-tech/resource-client';
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
//
|
|
40
|
+
const c = new PostgresResourceClient({ baseUrl, applicationId, resourceId, majorJwtToken });
|
|
41
|
+
const r = await c.invoke('SELECT * FROM users WHERE id = $1', [123], 'fetch-user');
|
|
42
|
+
// r.ok ? r.result.rows : r.error.message
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## CustomApiResourceClient
|
|
46
|
+
|
|
47
|
+
**Constructor:** `new CustomApiResourceClient(config: BaseClientConfig)`
|
|
48
|
+
|
|
49
|
+
**Method:** `invoke(method: HttpMethod, path: string, invocationKey: string, options?: { query?: QueryParams; headers?: Record<string, string>; body?: BodyPayload; timeoutMs?: number }): Promise<ApiInvokeResponse>`
|
|
50
|
+
|
|
51
|
+
**Params:**
|
|
52
|
+
- `method`: `"GET" | "POST" | "PUT" | "PATCH" | "DELETE"`
|
|
53
|
+
- `path`: URL path (appended to resource baseUrl)
|
|
54
|
+
- `invocationKey`: unique operation ID
|
|
55
|
+
- `options.query`: `Record<string, string | string[]>` - query params
|
|
56
|
+
- `options.headers`: `Record<string, string>` - additional headers
|
|
57
|
+
- `options.body`: `{ type: "json"; value: unknown } | { type: "text"; value: string } | { type: "bytes"; base64: string; contentType: string }`
|
|
58
|
+
- `options.timeoutMs`: timeout (default: 30000)
|
|
59
|
+
|
|
60
|
+
**Result (ok=true):**
|
|
61
|
+
```typescript
|
|
62
|
+
{ kind: "api"; status: number; body: { kind: "json"; value: unknown } | { kind: "text"; value: string } | { kind: "bytes"; base64: string; contentType: string } }
|
|
25
63
|
```
|
|
26
64
|
|
|
27
|
-
**
|
|
65
|
+
**Example:**
|
|
28
66
|
```typescript
|
|
29
67
|
import { CustomApiResourceClient } from '@major-tech/resource-client';
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
query: { currency: 'USD' }, headers: { 'X-
|
|
33
|
-
body: { type: 'json', value: {
|
|
68
|
+
const c = new CustomApiResourceClient({ baseUrl, applicationId, resourceId });
|
|
69
|
+
const r = await c.invoke('POST', '/v1/pay', 'create-pay', {
|
|
70
|
+
query: { currency: 'USD' }, headers: { 'X-Key': 'val' },
|
|
71
|
+
body: { type: 'json', value: { amt: 100 } }, timeoutMs: 5000
|
|
34
72
|
});
|
|
35
|
-
//
|
|
73
|
+
// r.ok ? r.result.status : r.error
|
|
36
74
|
```
|
|
37
75
|
|
|
38
|
-
|
|
76
|
+
## HubSpotResourceClient
|
|
77
|
+
|
|
78
|
+
**Constructor:** `new HubSpotResourceClient(config: BaseClientConfig)`
|
|
79
|
+
|
|
80
|
+
**Method:** `invoke(method: HttpMethod, path: string, invocationKey: string, options?: { query?: QueryParams; body?: { type: "json"; value: unknown }; timeoutMs?: number }): Promise<ApiInvokeResponse>`
|
|
81
|
+
|
|
82
|
+
**Params:**
|
|
83
|
+
- `method`: `"GET" | "POST" | "PUT" | "PATCH" | "DELETE"`
|
|
84
|
+
- `path`: HubSpot API path
|
|
85
|
+
- `invocationKey`: unique operation ID
|
|
86
|
+
- `options.query`: `Record<string, string | string[]>`
|
|
87
|
+
- `options.body`: `{ type: "json"; value: unknown }` - JSON only
|
|
88
|
+
- `options.timeoutMs`: timeout (default: 30000)
|
|
89
|
+
|
|
90
|
+
**Result:** Same as CustomApiResourceClient
|
|
91
|
+
|
|
92
|
+
**Example:**
|
|
39
93
|
```typescript
|
|
40
94
|
import { HubSpotResourceClient } from '@major-tech/resource-client';
|
|
41
|
-
const
|
|
42
|
-
const
|
|
43
|
-
//
|
|
95
|
+
const c = new HubSpotResourceClient({ baseUrl, applicationId, resourceId });
|
|
96
|
+
const r = await c.invoke('GET', '/crm/v3/objects/contacts', 'fetch-contacts', { query: { limit: '10' } });
|
|
97
|
+
// r.ok && r.result.body.kind === 'json' ? r.result.body.value : r.error
|
|
44
98
|
```
|
|
45
99
|
|
|
46
|
-
|
|
100
|
+
## S3ResourceClient
|
|
101
|
+
|
|
102
|
+
**Constructor:** `new S3ResourceClient(config: BaseClientConfig)`
|
|
103
|
+
|
|
104
|
+
**Method:** `invoke(command: S3Command, params: Record<string, unknown>, invocationKey: string, options?: { timeoutMs?: number }): Promise<StorageInvokeResponse>`
|
|
105
|
+
|
|
106
|
+
**Params:**
|
|
107
|
+
- `command`: `"ListObjectsV2" | "HeadObject" | "GetObjectTagging" | "PutObjectTagging" | "DeleteObject" | "DeleteObjects" | "CopyObject" | "ListBuckets" | "GetBucketLocation" | "GeneratePresignedUrl"`
|
|
108
|
+
- `params`: Command-specific params (e.g., `{ Bucket, Prefix, Key, expiresIn }`)
|
|
109
|
+
- `invocationKey`: unique operation ID
|
|
110
|
+
- `options.timeoutMs`: optional timeout
|
|
111
|
+
|
|
112
|
+
**Result (ok=true):**
|
|
113
|
+
```typescript
|
|
114
|
+
{ kind: "storage"; command: string; data: unknown } | { kind: "storage"; presignedUrl: string; expiresAt: string }
|
|
115
|
+
```
|
|
116
|
+
- Standard commands return `{ kind: "storage"; command; data }`
|
|
117
|
+
- `GeneratePresignedUrl` returns `{ kind: "storage"; presignedUrl; expiresAt }`
|
|
118
|
+
|
|
119
|
+
**Example:**
|
|
47
120
|
```typescript
|
|
48
121
|
import { S3ResourceClient } from '@major-tech/resource-client';
|
|
49
|
-
const
|
|
50
|
-
const
|
|
51
|
-
//
|
|
52
|
-
const
|
|
53
|
-
//
|
|
122
|
+
const c = new S3ResourceClient({ baseUrl, applicationId, resourceId });
|
|
123
|
+
const r = await c.invoke('ListObjectsV2', { Bucket: 'my-bucket', Prefix: 'uploads/' }, 'list-uploads');
|
|
124
|
+
// r.ok ? r.result.data : r.error
|
|
125
|
+
const u = await c.invoke('GeneratePresignedUrl', { Bucket: 'my-bucket', Key: 'file.pdf', expiresIn: 3600 }, 'presigned');
|
|
126
|
+
// u.ok && 'presignedUrl' in u.result ? u.result.presignedUrl : u.error
|
|
54
127
|
```
|
|
55
128
|
|
|
56
|
-
|
|
129
|
+
## Error Handling
|
|
57
130
|
```typescript
|
|
58
131
|
import { ResourceInvokeError } from '@major-tech/resource-client';
|
|
59
132
|
try { await client.invoke(...); }
|
|
60
133
|
catch (e) { if (e instanceof ResourceInvokeError) { e.message, e.httpStatus, e.requestId } }
|
|
61
134
|
```
|
|
62
135
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
**Types:** All exported: `BaseClientConfig`, `DatabaseInvokeResponse`, `ApiInvokeResponse`, `StorageInvokeResponse`, `HttpMethod`, `QueryParams`, `BodyPayload`, `S3Command`, etc.
|
|
136
|
+
## CLI - Singleton Generator
|
|
66
137
|
|
|
67
|
-
|
|
138
|
+
**Commands:**
|
|
139
|
+
- `npx major-client add <resourceId> <name> <type> <desc> <appId>` - Add resource, generate singleton
|
|
140
|
+
- `npx major-client list` - List all resources
|
|
141
|
+
- `npx major-client remove <name>` - Remove resource
|
|
142
|
+
- `npx major-client regenerate` - Regenerate all clients
|
|
68
143
|
|
|
69
|
-
|
|
144
|
+
**Types:** `database-postgresql | api-custom | api-hubspot | storage-s3`
|
|
70
145
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
146
|
+
**Generated Files:**
|
|
147
|
+
- `resources.json` - Resource registry
|
|
148
|
+
- `src/clients/<name>.ts` - Singleton client
|
|
149
|
+
- `src/clients/index.ts` - Exports
|
|
74
150
|
|
|
75
|
-
|
|
76
|
-
npx major-client list
|
|
151
|
+
**Env Vars:** `MAJOR_API_BASE_URL`, `MAJOR_JWT_TOKEN`
|
|
77
152
|
|
|
78
|
-
|
|
79
|
-
|
|
153
|
+
**Example:**
|
|
154
|
+
```bash
|
|
155
|
+
npx major-client add "res_123" "orders-db" "database-postgresql" "Orders DB" "app_456"
|
|
80
156
|
```
|
|
81
|
-
|
|
82
|
-
This generates TypeScript files in `src/clients/` that you can import:
|
|
83
157
|
```typescript
|
|
84
158
|
import { ordersDbClient } from './clients';
|
|
85
|
-
const
|
|
159
|
+
const r = await ordersDbClient.invoke('SELECT * FROM orders', [], 'list-orders');
|
|
86
160
|
```
|
|
87
161
|
|
|
88
|
-
**Types:** `database-postgresql` | `api-custom` | `api-hubspot` | `storage-s3`
|
|
89
|
-
|
|
90
162
|
MIT License
|
package/bin/generate-clients.mjs
CHANGED
|
@@ -45,7 +45,7 @@ function clientTemplate(data) {
|
|
|
45
45
|
* DO NOT EDIT - Auto-generated by @major-tech/resource-client
|
|
46
46
|
*/
|
|
47
47
|
|
|
48
|
-
const BASE_URL = import.meta.env.MAJOR_API_BASE_URL || 'https://api.major.
|
|
48
|
+
const BASE_URL = import.meta.env.MAJOR_API_BASE_URL || 'https://api.prod.major.build';
|
|
49
49
|
const MAJOR_JWT_TOKEN = import.meta.env.MAJOR_JWT_TOKEN;
|
|
50
50
|
|
|
51
51
|
class ${data.clientName}Singleton {
|
package/package.json
CHANGED