@coderule/clients 1.2.0 → 1.4.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.
- package/README.md +173 -96
- package/dist/index.cjs +319 -51
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +99 -13
- package/dist/index.d.ts +99 -13
- package/dist/index.js +318 -52
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Coderule TypeScript Client SDK
|
|
2
2
|
|
|
3
|
-
TypeScript HTTP clients for core Coderule microservices (Auth, Sync, Retrieval) with automatic fetch polyfill support.
|
|
3
|
+
TypeScript HTTP clients for core Coderule microservices (Auth, Sync, Retrieval, AST) with automatic fetch polyfill support.
|
|
4
4
|
|
|
5
5
|
## Requirements
|
|
6
6
|
|
|
@@ -26,132 +26,190 @@ npm run build
|
|
|
26
26
|
|
|
27
27
|
## Usage Examples
|
|
28
28
|
|
|
29
|
-
###
|
|
29
|
+
### Unified client access
|
|
30
30
|
|
|
31
31
|
```typescript
|
|
32
|
-
import {
|
|
32
|
+
import { CoderuleClients } from '@coderule/clients';
|
|
33
|
+
|
|
34
|
+
const clients = new CoderuleClients({
|
|
35
|
+
token: process.env.CODERULE_TOKEN!,
|
|
36
|
+
auth: { baseUrl: 'https://r.coderule.ai:16803' }, // optional, defaults to this host
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const snapshotStatus = await clients.sync.checkSnapshotStatus(snapshotHash);
|
|
40
|
+
const retrieval = await clients.retrieval.query(snapshotHash, 'Find the entrypoint');
|
|
41
|
+
const visitorRules = await clients.ast.getVisitorRulesV2();
|
|
42
|
+
|
|
43
|
+
clients.close();
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The unified client automatically exchanges your long-lived token for short-lived
|
|
47
|
+
JWTs using the Auth service. Tokens are cached and refreshed halfway through
|
|
48
|
+
their lifetime. Whenever the Auth service returns a JWT with a different
|
|
49
|
+
`server_url`, the AST, Retrieval, and Sync clients update their base URLs on
|
|
50
|
+
the fly.
|
|
51
|
+
|
|
52
|
+
You can override individual service hosts or timeouts:
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
const clients = new CoderuleClients({
|
|
56
|
+
token,
|
|
57
|
+
auth: { baseUrl: 'https://internal-auth.example.com' },
|
|
58
|
+
retrieval: { timeout: 90_000 },
|
|
59
|
+
sync: { baseUrl: 'http://localhost:8002' }, // static override keeps sync on localhost
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Manual wiring
|
|
64
|
+
|
|
65
|
+
If you prefer to manage dependency injection yourself, wire the Auth client and
|
|
66
|
+
JWT factory and pass the provider into the other clients.
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
import {
|
|
70
|
+
AuthHttpClient,
|
|
71
|
+
JWTFactory,
|
|
72
|
+
RetrievalHttpClient,
|
|
73
|
+
SyncHttpClient,
|
|
74
|
+
ASTHttpClient,
|
|
75
|
+
} from '@coderule/clients';
|
|
33
76
|
|
|
77
|
+
const authClient = new AuthHttpClient('http://localhost:8001');
|
|
78
|
+
const jwtFactory = new JWTFactory(authClient, longLivedToken);
|
|
79
|
+
|
|
80
|
+
const syncClient = new SyncHttpClient({
|
|
81
|
+
baseUrl: 'http://localhost:8002',
|
|
82
|
+
jwtProvider: jwtFactory,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const astClient = new ASTHttpClient({
|
|
86
|
+
baseUrl: 'http://localhost:8003',
|
|
87
|
+
jwtProvider: jwtFactory,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const retrievalClient = new RetrievalHttpClient({
|
|
91
|
+
baseUrl: 'http://localhost:8004',
|
|
92
|
+
jwtProvider: jwtFactory,
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
const status = await syncClient.checkSnapshotStatus(snapshotHash);
|
|
96
|
+
const queryResult = await retrievalClient.query(snapshotHash, 'Find the entrypoint');
|
|
97
|
+
const rules = await astClient.getVisitorRulesV2();
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Authentication service
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
34
103
|
const authClient = new AuthHttpClient('http://localhost:8001');
|
|
35
104
|
|
|
36
105
|
try {
|
|
37
|
-
// Authenticate and get JWT
|
|
38
106
|
const authResponse = await authClient.authenticate('your-token');
|
|
39
|
-
const jwt = authResponse.jwt;
|
|
40
107
|
console.log(`JWT expires at: ${authResponse.expires_at}`);
|
|
41
108
|
|
|
42
|
-
// Check health
|
|
43
109
|
const health = await authClient.health();
|
|
44
110
|
console.log(`Auth service status: ${health.status}`);
|
|
45
|
-
} catch (error) {
|
|
46
|
-
console.error('Authentication failed:', error);
|
|
47
111
|
} finally {
|
|
48
112
|
authClient.close();
|
|
49
113
|
}
|
|
50
114
|
```
|
|
51
115
|
|
|
52
|
-
### Sync
|
|
116
|
+
### Sync service
|
|
53
117
|
|
|
54
118
|
```typescript
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
119
|
+
const syncClient = new SyncHttpClient({
|
|
120
|
+
baseUrl: 'http://localhost:8002',
|
|
121
|
+
jwtProvider: jwtFactory,
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
const files = [
|
|
125
|
+
{ file_path: 'src/main.ts', content: 'const x = 1;' },
|
|
126
|
+
{ file_path: 'src/utils.ts', content: 'export function util() {}' },
|
|
127
|
+
{ file_path: 'package.json', content: '{"name": "test"}' },
|
|
128
|
+
];
|
|
129
|
+
|
|
130
|
+
const filesInfo = [];
|
|
131
|
+
const fileHashes = [];
|
|
132
|
+
const fileContents = new Map();
|
|
133
|
+
|
|
134
|
+
for (const file of files) {
|
|
135
|
+
const fileHash = SyncHttpClient.calculateFileHash(file.file_path, file.content);
|
|
136
|
+
filesInfo.push({ file_path: file.file_path, file_hash: fileHash });
|
|
137
|
+
fileContents.set(fileHash, {
|
|
138
|
+
path: file.file_path,
|
|
139
|
+
content: Buffer.from(file.content),
|
|
140
|
+
});
|
|
141
|
+
fileHashes.push(fileHash);
|
|
142
|
+
}
|
|
58
143
|
|
|
59
|
-
|
|
60
|
-
// Prepare files for sync (you need to provide the content)
|
|
61
|
-
const files = [
|
|
62
|
-
{ file_path: 'src/main.ts', content: 'const x = 1;' },
|
|
63
|
-
{ file_path: 'src/utils.ts', content: 'export function util() {}' },
|
|
64
|
-
{ file_path: 'package.json', content: '{"name": "test"}' }
|
|
65
|
-
];
|
|
66
|
-
|
|
67
|
-
// Calculate file hashes
|
|
68
|
-
const filesInfo = [];
|
|
69
|
-
const fileHashes = [];
|
|
70
|
-
const fileContents = new Map();
|
|
71
|
-
|
|
72
|
-
for (const file of files) {
|
|
73
|
-
const fileHash = SyncHttpClient.calculateFileHash(file.file_path, file.content);
|
|
74
|
-
filesInfo.push({
|
|
75
|
-
file_path: file.file_path,
|
|
76
|
-
file_hash: fileHash
|
|
77
|
-
});
|
|
78
|
-
fileContents.set(fileHash, {
|
|
79
|
-
path: file.file_path,
|
|
80
|
-
content: Buffer.from(file.content)
|
|
81
|
-
});
|
|
82
|
-
fileHashes.push(fileHash);
|
|
83
|
-
}
|
|
144
|
+
const snapshotHash = SyncHttpClient.calculateSnapshotHash(fileHashes);
|
|
84
145
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
// Upload missing files if needed
|
|
98
|
-
if (result.status === 'MISSING_CONTENT' && result.missing_files) {
|
|
99
|
-
const missingContent = new Map();
|
|
100
|
-
for (const missingFile of result.missing_files) {
|
|
101
|
-
if (fileContents.has(missingFile.file_hash)) {
|
|
102
|
-
missingContent.set(missingFile.file_hash, fileContents.get(missingFile.file_hash));
|
|
103
|
-
}
|
|
146
|
+
const status = await syncClient.checkSnapshotStatus(snapshotHash);
|
|
147
|
+
if (status.status === 'NOT_FOUND') {
|
|
148
|
+
const result = await syncClient.createSnapshot(snapshotHash, filesInfo);
|
|
149
|
+
|
|
150
|
+
if (result.status === 'MISSING_CONTENT' && result.missing_files) {
|
|
151
|
+
const missingContent = new Map();
|
|
152
|
+
for (const missingFile of result.missing_files) {
|
|
153
|
+
if (fileContents.has(missingFile.file_hash)) {
|
|
154
|
+
missingContent.set(
|
|
155
|
+
missingFile.file_hash,
|
|
156
|
+
fileContents.get(missingFile.file_hash)!,
|
|
157
|
+
);
|
|
104
158
|
}
|
|
159
|
+
}
|
|
105
160
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
await syncClient.createSnapshot(snapshotHash, filesInfo);
|
|
110
|
-
}
|
|
161
|
+
if (missingContent.size > 0) {
|
|
162
|
+
await syncClient.uploadFileContent(missingContent);
|
|
163
|
+
await syncClient.createSnapshot(snapshotHash, filesInfo);
|
|
111
164
|
}
|
|
112
165
|
}
|
|
113
|
-
} catch (error) {
|
|
114
|
-
console.error('Sync failed:', error);
|
|
115
|
-
} finally {
|
|
116
|
-
syncClient.close();
|
|
117
166
|
}
|
|
118
167
|
```
|
|
119
168
|
|
|
120
|
-
###
|
|
169
|
+
### AST service
|
|
121
170
|
|
|
122
171
|
```typescript
|
|
123
|
-
|
|
172
|
+
const astClient = new ASTHttpClient({
|
|
173
|
+
baseUrl: 'http://localhost:8003',
|
|
174
|
+
jwtProvider: jwtFactory,
|
|
175
|
+
});
|
|
124
176
|
|
|
125
|
-
const
|
|
177
|
+
const health = await astClient.health();
|
|
178
|
+
console.log(`AST service status: ${health.status}`);
|
|
126
179
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
const result = await retrievalClient.query(
|
|
130
|
-
snapshotHash,
|
|
131
|
-
'Find the main authentication logic',
|
|
132
|
-
3000, // budget tokens
|
|
133
|
-
jwt,
|
|
134
|
-
{
|
|
135
|
-
formatter: 'compact',
|
|
136
|
-
flow_strength: 1.5,
|
|
137
|
-
blend_alpha: 0.8
|
|
138
|
-
}
|
|
139
|
-
);
|
|
180
|
+
const rules = await astClient.getVisitorRulesV2();
|
|
181
|
+
console.log(`Rules format: ${rules.format}`);
|
|
140
182
|
|
|
141
|
-
|
|
183
|
+
const compiled = ASTHttpClient.compileRulesV2(rules);
|
|
184
|
+
const ignoredPredicate = ASTHttpClient.buildIgnoredPredicate(compiled);
|
|
185
|
+
```
|
|
142
186
|
|
|
143
|
-
|
|
144
|
-
const status = await retrievalClient.checkSnapshotStatus(snapshotHash, jwt);
|
|
145
|
-
console.log(`Snapshot indexing status: ${status.status}`);
|
|
187
|
+
### Retrieval service
|
|
146
188
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
189
|
+
```typescript
|
|
190
|
+
const retrievalClient = new RetrievalHttpClient({
|
|
191
|
+
baseUrl: 'http://localhost:8004',
|
|
192
|
+
jwtProvider: jwtFactory,
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
const result = await retrievalClient.query(
|
|
196
|
+
snapshotHash,
|
|
197
|
+
'Find the main authentication logic',
|
|
198
|
+
3000,
|
|
199
|
+
{
|
|
200
|
+
formatter: 'compact',
|
|
201
|
+
flow_strength: 1.5,
|
|
202
|
+
blend_alpha: 0.8,
|
|
203
|
+
},
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
console.log(result.formatted_output);
|
|
207
|
+
|
|
208
|
+
const status = await retrievalClient.checkSnapshotStatus(snapshotHash);
|
|
209
|
+
console.log(`Snapshot indexing status: ${status.status}`);
|
|
210
|
+
|
|
211
|
+
const cacheStats = await retrievalClient.getCacheStats();
|
|
212
|
+
console.log(`Cached snapshots: ${cacheStats.cached_snapshots}`);
|
|
155
213
|
```
|
|
156
214
|
|
|
157
215
|
## Utility Methods
|
|
@@ -195,8 +253,24 @@ All clients support timeout configuration in milliseconds:
|
|
|
195
253
|
|
|
196
254
|
```typescript
|
|
197
255
|
// Custom timeout of 30 seconds
|
|
198
|
-
const
|
|
256
|
+
const retrievalClient = new RetrievalHttpClient({
|
|
257
|
+
baseUrl: 'http://localhost:8004',
|
|
258
|
+
timeout: 30_000,
|
|
259
|
+
jwtProvider: jwtFactory,
|
|
260
|
+
});
|
|
199
261
|
```
|
|
262
|
+
`CoderuleClients` also accepts per-service overrides via the `auth`, `ast`, `retrieval`,
|
|
263
|
+
and `sync` options. `JWTFactory` exposes an `onTokenRefreshed` callback if you need to
|
|
264
|
+
observe token rotations (for example, to log the current `server_url`).
|
|
265
|
+
|
|
266
|
+
## Breaking Changes (v1.4.0)
|
|
267
|
+
|
|
268
|
+
- **Clients now require a JWT provider**: `SyncHttpClient`, `RetrievalHttpClient`, and
|
|
269
|
+
`ASTHttpClient` no longer accept JWT strings per method. Inject a `JWTFactory` or any
|
|
270
|
+
`JWTProvider` implementation through the constructor instead.
|
|
271
|
+
- **Unified entry point**: `CoderuleClients` centralises token exchange. Auth defaults to
|
|
272
|
+
`https://r.coderule.ai:16803`, and other clients automatically adopt the `server_url`
|
|
273
|
+
provided by the Auth service unless explicitly overridden.
|
|
200
274
|
|
|
201
275
|
## Notes
|
|
202
276
|
|
|
@@ -204,7 +278,10 @@ const client = new RetrievalHttpClient('http://localhost:8004', 30000);
|
|
|
204
278
|
- **Optional dependency**: `node-fetch` is only required for Node.js versions < 18
|
|
205
279
|
- **Zero dependencies for Node.js 18+**: Uses native fetch API
|
|
206
280
|
- Clients automatically handle JSON serialization/deserialization
|
|
207
|
-
- JWT
|
|
281
|
+
- JWT handling is centralised through a `JWTProvider` (`JWTFactory` or `CoderuleClients`)
|
|
282
|
+
- AST, Retrieval, and Sync clients update their base URLs when the JWT refresh
|
|
283
|
+
returns a different `server_url` (unless a manual override is configured)
|
|
284
|
+
- Health check endpoints don't require authentication
|
|
208
285
|
- All clients have a `close()` method for consistency, though fetch doesn't maintain persistent connections
|
|
209
286
|
|
|
210
287
|
## Building from Source
|
|
@@ -221,4 +298,4 @@ npm run build
|
|
|
221
298
|
|
|
222
299
|
## License
|
|
223
300
|
|
|
224
|
-
ISC
|
|
301
|
+
ISC
|