@resourcexjs/registry 2.3.0 → 2.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 +240 -264
- package/dist/index.d.ts +249 -245
- package/dist/index.js +16738 -25495
- package/dist/index.js.map +14 -129
- package/package.json +7 -6
package/README.md
CHANGED
|
@@ -10,52 +10,61 @@ bun add @resourcexjs/registry
|
|
|
10
10
|
|
|
11
11
|
## Overview
|
|
12
12
|
|
|
13
|
-
The `@resourcexjs/registry` package provides a Maven-style registry for storing and resolving resources
|
|
13
|
+
The `@resourcexjs/registry` package provides a Maven-style registry for storing and resolving resources.
|
|
14
14
|
|
|
15
15
|
### Key Concepts
|
|
16
16
|
|
|
17
17
|
- **Registry**: Interface for resource storage and retrieval
|
|
18
|
-
- **
|
|
19
|
-
- **
|
|
20
|
-
- **
|
|
21
|
-
- **
|
|
18
|
+
- **DefaultRegistry**: Main implementation combining Storage with type handling
|
|
19
|
+
- **LocalStorage**: Filesystem-based storage for local resources
|
|
20
|
+
- **Storage**: Abstract interface for different storage backends
|
|
21
|
+
- **Well-known discovery**: Auto-discover registry endpoints via `/.well-known/resourcex`
|
|
22
|
+
- **Isolator**: Sandbox execution for resolver code
|
|
22
23
|
|
|
23
24
|
## Usage
|
|
24
25
|
|
|
25
26
|
### Create Registry
|
|
26
27
|
|
|
27
28
|
```typescript
|
|
28
|
-
import { createRegistry
|
|
29
|
+
import { createRegistry } from "@resourcexjs/registry";
|
|
29
30
|
|
|
30
|
-
//
|
|
31
|
+
// Default registry (uses LocalStorage at ~/.resourcex)
|
|
31
32
|
const registry = createRegistry();
|
|
32
33
|
|
|
33
|
-
//
|
|
34
|
+
// Custom local path
|
|
34
35
|
const registry2 = createRegistry({
|
|
35
36
|
path: "./my-registry",
|
|
36
37
|
});
|
|
37
38
|
|
|
38
|
-
//
|
|
39
|
-
import {
|
|
39
|
+
// With custom resource types
|
|
40
|
+
import { bundleResourceType } from "@resourcexjs/type";
|
|
41
|
+
const promptType = await bundleResourceType("./prompt.type.ts");
|
|
40
42
|
|
|
41
43
|
const registry3 = createRegistry({
|
|
42
|
-
path: "~/.resourcex",
|
|
43
44
|
types: [promptType],
|
|
44
45
|
});
|
|
45
46
|
|
|
46
|
-
//
|
|
47
|
+
// With sandbox isolation
|
|
47
48
|
const registry4 = createRegistry({
|
|
48
|
-
|
|
49
|
+
isolator: "srt", // "none" | "srt" | "cloudflare" | "e2b"
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// With remote mirror
|
|
53
|
+
const registry5 = createRegistry({
|
|
54
|
+
mirror: "https://registry.deepractice.ai/v1",
|
|
49
55
|
});
|
|
50
56
|
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
|
|
57
|
+
// Server mode with custom storage
|
|
58
|
+
import { LocalStorage } from "@resourcexjs/registry";
|
|
59
|
+
|
|
60
|
+
const registry6 = createRegistry({
|
|
61
|
+
storage: new LocalStorage({ path: "./data" }),
|
|
62
|
+
});
|
|
54
63
|
```
|
|
55
64
|
|
|
56
|
-
###
|
|
65
|
+
### Add Resource
|
|
57
66
|
|
|
58
|
-
|
|
67
|
+
Add a resource to the registry:
|
|
59
68
|
|
|
60
69
|
```typescript
|
|
61
70
|
import { loadResource } from "@resourcexjs/loader";
|
|
@@ -64,32 +73,59 @@ import { createRegistry } from "@resourcexjs/registry";
|
|
|
64
73
|
// Load resource from folder
|
|
65
74
|
const rxr = await loadResource("./my-prompt");
|
|
66
75
|
|
|
67
|
-
//
|
|
76
|
+
// Add to registry
|
|
68
77
|
const registry = createRegistry();
|
|
69
78
|
await registry.add(rxr);
|
|
70
79
|
|
|
71
|
-
//
|
|
80
|
+
// Or add directly from path
|
|
81
|
+
await registry.add("./my-prompt");
|
|
82
|
+
|
|
83
|
+
// Now stored at: ~/.resourcex/local/my-prompt.text/1.0.0/
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Link Resource (Development)
|
|
87
|
+
|
|
88
|
+
Link creates a symlink for live development changes:
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
const registry = createRegistry();
|
|
92
|
+
|
|
93
|
+
// Link directory - changes reflect immediately
|
|
94
|
+
await registry.link("./my-prompts/assistant");
|
|
72
95
|
```
|
|
73
96
|
|
|
74
97
|
### Resolve Resource
|
|
75
98
|
|
|
76
|
-
Retrieve a resource
|
|
99
|
+
Retrieve and execute a resource:
|
|
77
100
|
|
|
78
101
|
```typescript
|
|
79
102
|
const registry = createRegistry();
|
|
80
103
|
|
|
81
|
-
// Resolve
|
|
82
|
-
const
|
|
104
|
+
// Resolve returns ResolvedResource with execute()
|
|
105
|
+
const resolved = await registry.resolve("localhost/my-prompt.text@1.0.0");
|
|
106
|
+
|
|
107
|
+
// Execute to get content
|
|
108
|
+
const text = await resolved.execute();
|
|
109
|
+
console.log(text);
|
|
110
|
+
|
|
111
|
+
// Check schema (for types with arguments)
|
|
112
|
+
console.log(resolved.schema); // undefined for text type
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Get Raw Resource
|
|
116
|
+
|
|
117
|
+
Get the RXR without resolving:
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
const rxr = await registry.get("localhost/my-prompt.text@1.0.0");
|
|
83
121
|
|
|
84
122
|
console.log(rxr.manifest.name); // "my-prompt"
|
|
85
|
-
console.log(
|
|
123
|
+
console.log(rxr.manifest.type); // "text"
|
|
86
124
|
```
|
|
87
125
|
|
|
88
126
|
### Check Existence
|
|
89
127
|
|
|
90
128
|
```typescript
|
|
91
|
-
const registry = createRegistry();
|
|
92
|
-
|
|
93
129
|
if (await registry.exists("localhost/my-prompt.text@1.0.0")) {
|
|
94
130
|
console.log("Resource exists");
|
|
95
131
|
}
|
|
@@ -98,9 +134,39 @@ if (await registry.exists("localhost/my-prompt.text@1.0.0")) {
|
|
|
98
134
|
### Delete Resource
|
|
99
135
|
|
|
100
136
|
```typescript
|
|
137
|
+
await registry.delete("localhost/my-prompt.text@1.0.0");
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Search Resources
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
// List all resources
|
|
144
|
+
const all = await registry.search();
|
|
145
|
+
|
|
146
|
+
// Search by name
|
|
147
|
+
const results = await registry.search({ query: "assistant" });
|
|
148
|
+
|
|
149
|
+
// With pagination
|
|
150
|
+
const page = await registry.search({
|
|
151
|
+
query: "prompt",
|
|
152
|
+
limit: 10,
|
|
153
|
+
offset: 20,
|
|
154
|
+
});
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Support Custom Types
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
import { bundleResourceType } from "@resourcexjs/type";
|
|
161
|
+
|
|
101
162
|
const registry = createRegistry();
|
|
102
163
|
|
|
103
|
-
|
|
164
|
+
// Bundle and add type at runtime
|
|
165
|
+
const promptType = await bundleResourceType("./prompt.type.ts");
|
|
166
|
+
registry.supportType(promptType);
|
|
167
|
+
|
|
168
|
+
// Now can resolve prompt resources
|
|
169
|
+
const resolved = await registry.resolve("localhost/assistant.prompt@1.0.0");
|
|
104
170
|
```
|
|
105
171
|
|
|
106
172
|
## API Reference
|
|
@@ -111,207 +177,208 @@ Create a new registry instance.
|
|
|
111
177
|
|
|
112
178
|
**Parameters:**
|
|
113
179
|
|
|
114
|
-
- `config?:
|
|
115
|
-
|
|
116
|
-
|
|
180
|
+
- `config?: ClientRegistryConfig | ServerRegistryConfig`
|
|
181
|
+
|
|
182
|
+
**Client mode (default):**
|
|
183
|
+
|
|
184
|
+
- `path?: string` - Local cache path (default: `~/.resourcex`)
|
|
185
|
+
- `mirror?: string` - Mirror URL for remote fetch
|
|
186
|
+
- `types?: BundledType[]` - Custom resource types
|
|
187
|
+
- `isolator?: IsolatorType` - Sandbox isolation level
|
|
188
|
+
|
|
189
|
+
**Server mode:**
|
|
190
|
+
|
|
191
|
+
- `storage: Storage` - Custom storage implementation
|
|
192
|
+
- `types?: BundledType[]` - Custom resource types
|
|
193
|
+
- `isolator?: IsolatorType` - Sandbox isolation level
|
|
117
194
|
|
|
118
195
|
**Returns**: `Registry`
|
|
119
196
|
|
|
120
197
|
```typescript
|
|
198
|
+
// Client mode
|
|
121
199
|
const registry = createRegistry({
|
|
122
|
-
path: "
|
|
123
|
-
|
|
200
|
+
path: "~/.resourcex",
|
|
201
|
+
mirror: "https://registry.deepractice.ai/v1",
|
|
202
|
+
types: [promptType],
|
|
203
|
+
isolator: "srt",
|
|
124
204
|
});
|
|
125
|
-
```
|
|
126
205
|
|
|
127
|
-
|
|
206
|
+
// Server mode
|
|
207
|
+
const registry = createRegistry({
|
|
208
|
+
storage: new LocalStorage({ path: "./data" }),
|
|
209
|
+
types: [promptType],
|
|
210
|
+
});
|
|
211
|
+
```
|
|
128
212
|
|
|
129
|
-
|
|
213
|
+
### `discoverRegistry(domain)`
|
|
130
214
|
|
|
131
|
-
|
|
215
|
+
Discover registry endpoints for a domain via well-known.
|
|
132
216
|
|
|
133
217
|
**Parameters:**
|
|
134
218
|
|
|
135
|
-
- `
|
|
219
|
+
- `domain: string` - Domain to discover (e.g., "deepractice.ai")
|
|
220
|
+
|
|
221
|
+
**Returns**: `Promise<DiscoveryResult>`
|
|
136
222
|
|
|
137
223
|
```typescript
|
|
138
|
-
await
|
|
224
|
+
const result = await discoverRegistry("deepractice.ai");
|
|
225
|
+
// { domain: "deepractice.ai", registries: ["https://..."] }
|
|
139
226
|
```
|
|
140
227
|
|
|
141
|
-
|
|
228
|
+
### Registry Interface
|
|
142
229
|
|
|
143
|
-
|
|
230
|
+
#### `supportType(type: BundledType): void`
|
|
144
231
|
|
|
145
|
-
|
|
232
|
+
Add support for a custom resource type at runtime.
|
|
146
233
|
|
|
147
|
-
|
|
234
|
+
#### `link(path: string): Promise<void>`
|
|
148
235
|
|
|
149
|
-
|
|
236
|
+
Create a symlink for development. Changes in the source directory are immediately reflected.
|
|
150
237
|
|
|
151
|
-
|
|
238
|
+
#### `add(source: string | RXR): Promise<void>`
|
|
152
239
|
|
|
153
|
-
|
|
154
|
-
const rxr = await registry.resolve("localhost/my-prompt.text@1.0.0");
|
|
155
|
-
```
|
|
240
|
+
Add resource to storage. Accepts a folder path or RXR object.
|
|
156
241
|
|
|
157
|
-
#### `
|
|
242
|
+
#### `get(locator: string): Promise<RXR>`
|
|
158
243
|
|
|
159
|
-
|
|
244
|
+
Get raw RXR by locator without resolving.
|
|
160
245
|
|
|
161
|
-
|
|
246
|
+
#### `resolve<TArgs, TResult>(locator: string): Promise<ResolvedResource<TArgs, TResult>>`
|
|
162
247
|
|
|
163
|
-
|
|
248
|
+
Resolve resource and return structured result with execute function.
|
|
164
249
|
|
|
165
|
-
|
|
250
|
+
#### `exists(locator: string): Promise<boolean>`
|
|
166
251
|
|
|
167
|
-
|
|
168
|
-
if (await registry.exists("localhost/my-prompt.text@1.0.0")) {
|
|
169
|
-
// Resource exists
|
|
170
|
-
}
|
|
171
|
-
```
|
|
252
|
+
Check if resource exists.
|
|
172
253
|
|
|
173
254
|
#### `delete(locator: string): Promise<void>`
|
|
174
255
|
|
|
175
|
-
Delete resource from
|
|
256
|
+
Delete resource from storage.
|
|
176
257
|
|
|
177
|
-
|
|
258
|
+
#### `search(options?: SearchOptions): Promise<RXL[]>`
|
|
178
259
|
|
|
179
|
-
|
|
260
|
+
Search for resources.
|
|
180
261
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
262
|
+
- `query?: string` - Filter by locator substring
|
|
263
|
+
- `limit?: number` - Max results
|
|
264
|
+
- `offset?: number` - Skip first N results
|
|
184
265
|
|
|
185
|
-
|
|
266
|
+
### Storage Interface
|
|
186
267
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
268
|
+
```typescript
|
|
269
|
+
interface Storage {
|
|
270
|
+
readonly type: string;
|
|
271
|
+
get(locator: string): Promise<RXR>;
|
|
272
|
+
put(rxr: RXR): Promise<void>;
|
|
273
|
+
exists(locator: string): Promise<boolean>;
|
|
274
|
+
delete(locator: string): Promise<void>;
|
|
275
|
+
search(options?: SearchOptions): Promise<RXL[]>;
|
|
276
|
+
}
|
|
277
|
+
```
|
|
194
278
|
|
|
195
|
-
|
|
196
|
-
- `query?: string` - Filter by locator substring
|
|
197
|
-
- `limit?: number` - Max results to return
|
|
198
|
-
- `offset?: number` - Skip first N results
|
|
279
|
+
### LocalStorage
|
|
199
280
|
|
|
200
|
-
|
|
281
|
+
Filesystem-based storage implementation.
|
|
201
282
|
|
|
202
283
|
```typescript
|
|
203
|
-
|
|
204
|
-
const results = await registry.search({ query: "assistant" });
|
|
205
|
-
|
|
206
|
-
// With pagination
|
|
207
|
-
const page = await registry.search({ query: "prompt", limit: 10, offset: 20 });
|
|
284
|
+
import { LocalStorage } from "@resourcexjs/registry";
|
|
208
285
|
|
|
209
|
-
|
|
210
|
-
|
|
286
|
+
const storage = new LocalStorage({
|
|
287
|
+
path: "~/.resourcex", // optional, defaults to ~/.resourcex
|
|
288
|
+
});
|
|
211
289
|
```
|
|
212
290
|
|
|
213
291
|
## Storage Structure
|
|
214
292
|
|
|
215
|
-
Resources are stored in two
|
|
216
|
-
|
|
217
|
-
- **local/** - Development resources (organized by name.type/version)
|
|
218
|
-
- **cache/** - Remote cached resources (organized by domain/path/name.type/version)
|
|
293
|
+
Resources are stored in two areas:
|
|
219
294
|
|
|
220
295
|
```
|
|
221
296
|
~/.resourcex/
|
|
222
|
-
├── local/ # Development
|
|
297
|
+
├── local/ # Development resources
|
|
223
298
|
│ └── {name}.{type}/
|
|
224
299
|
│ └── {version}/
|
|
225
300
|
│ ├── manifest.json
|
|
226
|
-
│ └──
|
|
301
|
+
│ └── archive.tar.gz
|
|
227
302
|
│
|
|
228
|
-
└── cache/ # Remote
|
|
303
|
+
└── cache/ # Remote cached resources
|
|
229
304
|
└── {domain}/
|
|
230
305
|
└── {path}/
|
|
231
306
|
└── {name}.{type}/
|
|
232
307
|
└── {version}/
|
|
233
308
|
├── manifest.json
|
|
234
|
-
└──
|
|
309
|
+
└── archive.tar.gz
|
|
235
310
|
```
|
|
236
311
|
|
|
237
|
-
###
|
|
312
|
+
### Resolution Order
|
|
238
313
|
|
|
239
|
-
|
|
314
|
+
1. **local/** is checked first (development resources)
|
|
315
|
+
2. **cache/** is checked second (remote cached resources)
|
|
316
|
+
3. If not found and domain is not localhost, fetches from remote
|
|
240
317
|
|
|
241
|
-
|
|
242
|
-
~/.resourcex/
|
|
243
|
-
└── local/
|
|
244
|
-
└── my-prompt.text/
|
|
245
|
-
└── 1.0.0/
|
|
246
|
-
├── manifest.json # domain can be "deepractice.ai" or "localhost"
|
|
247
|
-
└── content.tar.gz
|
|
248
|
-
```
|
|
318
|
+
## Remote Fetch Flow
|
|
249
319
|
|
|
250
|
-
For
|
|
320
|
+
For non-localhost domains:
|
|
251
321
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
322
|
+
1. Check local storage (cache)
|
|
323
|
+
2. If mirror configured, try mirror first
|
|
324
|
+
3. Discover source via `https://{domain}/.well-known/resourcex`
|
|
325
|
+
4. Fetch from discovered endpoint
|
|
326
|
+
5. Cache to local storage
|
|
327
|
+
|
|
328
|
+
**Well-known format:**
|
|
329
|
+
|
|
330
|
+
```json
|
|
331
|
+
{
|
|
332
|
+
"version": "1.0",
|
|
333
|
+
"registries": ["https://registry.example.com/v1"]
|
|
334
|
+
}
|
|
261
335
|
```
|
|
262
336
|
|
|
263
|
-
|
|
337
|
+
## Middleware
|
|
264
338
|
|
|
265
|
-
|
|
266
|
-
2. **cache/** is checked second (remote cached resources)
|
|
339
|
+
### RegistryMiddleware
|
|
267
340
|
|
|
268
|
-
|
|
341
|
+
Base class for creating custom middleware:
|
|
269
342
|
|
|
270
|
-
```
|
|
271
|
-
{
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
343
|
+
```typescript
|
|
344
|
+
import { RegistryMiddleware } from "@resourcexjs/registry";
|
|
345
|
+
|
|
346
|
+
class LoggingMiddleware extends RegistryMiddleware {
|
|
347
|
+
async get(locator: string) {
|
|
348
|
+
console.log("Getting:", locator);
|
|
349
|
+
return this.inner.get(locator);
|
|
350
|
+
}
|
|
277
351
|
}
|
|
278
352
|
```
|
|
279
353
|
|
|
280
|
-
|
|
354
|
+
### DomainValidation
|
|
281
355
|
|
|
282
|
-
|
|
356
|
+
Built-in middleware for validating resource domains:
|
|
357
|
+
|
|
358
|
+
```typescript
|
|
359
|
+
import { withDomainValidation } from "@resourcexjs/registry";
|
|
360
|
+
|
|
361
|
+
const validatedRegistry = withDomainValidation(registry, "deepractice.ai");
|
|
362
|
+
|
|
363
|
+
// Throws if resource.manifest.domain !== "deepractice.ai"
|
|
364
|
+
await validatedRegistry.get("deepractice.ai/assistant.text@1.0.0");
|
|
365
|
+
```
|
|
283
366
|
|
|
284
|
-
|
|
367
|
+
## Isolator Types
|
|
368
|
+
|
|
369
|
+
Sandbox isolation for resolver execution:
|
|
370
|
+
|
|
371
|
+
| Type | Description | Latency |
|
|
372
|
+
| -------------- | -------------------------- | ------- |
|
|
373
|
+
| `"none"` | No isolation (development) | ~10ms |
|
|
374
|
+
| `"srt"` | OS-level isolation | ~50ms |
|
|
375
|
+
| `"cloudflare"` | Container isolation | ~100ms |
|
|
376
|
+
| `"e2b"` | MicroVM isolation | ~150ms |
|
|
285
377
|
|
|
286
378
|
```typescript
|
|
287
|
-
import { createRegistry } from "@resourcexjs/registry";
|
|
288
|
-
import type { ResourceType } from "@resourcexjs/type";
|
|
289
|
-
|
|
290
|
-
const promptType: ResourceType<string> = {
|
|
291
|
-
name: "prompt",
|
|
292
|
-
description: "AI Prompt template",
|
|
293
|
-
serializer: {
|
|
294
|
-
async serialize(rxr) {
|
|
295
|
-
const text = await rxr.content.text();
|
|
296
|
-
return Buffer.from(text, "utf-8");
|
|
297
|
-
},
|
|
298
|
-
async deserialize(data, manifest) {
|
|
299
|
-
// ... implementation
|
|
300
|
-
},
|
|
301
|
-
},
|
|
302
|
-
resolver: {
|
|
303
|
-
async resolve(rxr) {
|
|
304
|
-
return rxr.content.text();
|
|
305
|
-
},
|
|
306
|
-
},
|
|
307
|
-
};
|
|
308
|
-
|
|
309
|
-
// Register when creating registry
|
|
310
379
|
const registry = createRegistry({
|
|
311
|
-
|
|
380
|
+
isolator: "srt",
|
|
312
381
|
});
|
|
313
|
-
|
|
314
|
-
// Now can link/resolve prompt resources
|
|
315
382
|
```
|
|
316
383
|
|
|
317
384
|
## Error Handling
|
|
@@ -320,28 +387,20 @@ const registry = createRegistry({
|
|
|
320
387
|
import { RegistryError } from "@resourcexjs/registry";
|
|
321
388
|
|
|
322
389
|
try {
|
|
323
|
-
const rxr = await registry.
|
|
390
|
+
const rxr = await registry.get("localhost/not-exist.text@1.0.0");
|
|
324
391
|
} catch (error) {
|
|
325
392
|
if (error instanceof RegistryError) {
|
|
326
393
|
console.error("Registry error:", error.message);
|
|
327
|
-
// "Resource not found: localhost/not-exist.text@1.0.0"
|
|
328
394
|
}
|
|
329
395
|
}
|
|
330
396
|
```
|
|
331
397
|
|
|
332
398
|
### Common Errors
|
|
333
399
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
```
|
|
339
|
-
|
|
340
|
-
**Unsupported type:**
|
|
341
|
-
|
|
342
|
-
```
|
|
343
|
-
RegistryError: Unsupported resource type 'unknown'
|
|
344
|
-
```
|
|
400
|
+
- `Resource not found: {locator}`
|
|
401
|
+
- `Unsupported resource type: {type}`
|
|
402
|
+
- `Well-known discovery failed for {domain}: {status}`
|
|
403
|
+
- `{storage} is read-only: {operation} not supported`
|
|
345
404
|
|
|
346
405
|
## Examples
|
|
347
406
|
|
|
@@ -351,120 +410,37 @@ RegistryError: Unsupported resource type 'unknown'
|
|
|
351
410
|
import { loadResource } from "@resourcexjs/loader";
|
|
352
411
|
import { createRegistry } from "@resourcexjs/registry";
|
|
353
412
|
|
|
354
|
-
// 1.
|
|
355
|
-
const rxr = await loadResource("./my-prompts/assistant");
|
|
356
|
-
|
|
357
|
-
// 2. Create registry
|
|
413
|
+
// 1. Create registry
|
|
358
414
|
const registry = createRegistry();
|
|
359
415
|
|
|
360
|
-
//
|
|
416
|
+
// 2. Load and add resource
|
|
417
|
+
const rxr = await loadResource("./my-prompts/assistant");
|
|
361
418
|
await registry.add(rxr);
|
|
362
419
|
|
|
363
|
-
//
|
|
364
|
-
const resolved = await registry.resolve("localhost/assistant.
|
|
365
|
-
|
|
366
|
-
// 5. Use content
|
|
367
|
-
const text = await resolved.content.text();
|
|
420
|
+
// 3. Resolve and execute
|
|
421
|
+
const resolved = await registry.resolve("localhost/assistant.text@1.0.0");
|
|
422
|
+
const text = await resolved.execute();
|
|
368
423
|
console.log(text);
|
|
369
424
|
```
|
|
370
425
|
|
|
371
|
-
### Versioning
|
|
372
|
-
|
|
373
|
-
```typescript
|
|
374
|
-
const registry = createRegistry();
|
|
375
|
-
|
|
376
|
-
// Link multiple versions
|
|
377
|
-
await registry.add(promptV1); // v1.0.0
|
|
378
|
-
await registry.add(promptV2); // v2.0.0
|
|
379
|
-
await registry.add(promptV3); // v3.0.0
|
|
380
|
-
|
|
381
|
-
// Resolve specific version
|
|
382
|
-
const v1 = await registry.resolve("localhost/prompt.text@1.0.0");
|
|
383
|
-
const v2 = await registry.resolve("localhost/prompt.text@2.0.0");
|
|
384
|
-
const latest = await registry.resolve("localhost/prompt.text@3.0.0");
|
|
385
|
-
```
|
|
386
|
-
|
|
387
|
-
### Custom Storage Path
|
|
388
|
-
|
|
389
|
-
```typescript
|
|
390
|
-
// Project-local registry
|
|
391
|
-
const registry = createRegistry({
|
|
392
|
-
path: "./project-registry",
|
|
393
|
-
});
|
|
394
|
-
|
|
395
|
-
await registry.add(rxr);
|
|
396
|
-
// Stored at: ./project-registry/localhost/...
|
|
397
|
-
```
|
|
398
|
-
|
|
399
426
|
### With Custom Types
|
|
400
427
|
|
|
401
428
|
```typescript
|
|
402
|
-
import {
|
|
429
|
+
import { createRegistry } from "@resourcexjs/registry";
|
|
430
|
+
import { bundleResourceType } from "@resourcexjs/type";
|
|
431
|
+
|
|
432
|
+
// Bundle custom type
|
|
433
|
+
const promptType = await bundleResourceType("./prompt.type.ts");
|
|
403
434
|
|
|
435
|
+
// Create registry with type
|
|
404
436
|
const registry = createRegistry({
|
|
405
|
-
types: [promptType
|
|
437
|
+
types: [promptType],
|
|
406
438
|
});
|
|
407
439
|
|
|
408
|
-
//
|
|
409
|
-
await registry.add(
|
|
410
|
-
await registry.
|
|
411
|
-
await
|
|
412
|
-
```
|
|
413
|
-
|
|
414
|
-
## Resolution Strategy
|
|
415
|
-
|
|
416
|
-
### LocalRegistry
|
|
417
|
-
|
|
418
|
-
1. **Check local filesystem** (`~/.resourcex` or custom path)
|
|
419
|
-
2. **If not found**: Throw RegistryError
|
|
420
|
-
3. **Return** RXR
|
|
421
|
-
|
|
422
|
-
### RemoteRegistry
|
|
423
|
-
|
|
424
|
-
1. **Fetch from HTTP API** (`GET /resource` + `GET /content`)
|
|
425
|
-
2. **Return** RXR (no local caching)
|
|
426
|
-
|
|
427
|
-
### Future: Hybrid Strategy (TODO)
|
|
428
|
-
|
|
429
|
-
1. Check local cache first
|
|
430
|
-
2. If not found, fetch from remote based on domain
|
|
431
|
-
3. Cache locally
|
|
432
|
-
4. Return RXR
|
|
433
|
-
|
|
434
|
-
## Architecture
|
|
435
|
-
|
|
436
|
-
```
|
|
437
|
-
┌─────────────────────────────────────────┐
|
|
438
|
-
│ Registry Interface │
|
|
439
|
-
└────────────┬────────────────────────────┘
|
|
440
|
-
│
|
|
441
|
-
┌────────┴────────┐
|
|
442
|
-
│ │
|
|
443
|
-
┌───▼──────────┐ ┌──▼──────────────┐
|
|
444
|
-
│LocalRegistry │ │RemoteRegistry │
|
|
445
|
-
│(filesystem) │ │(HTTP API) │
|
|
446
|
-
└───┬──────────┘ └──┬──────────────┘
|
|
447
|
-
│ │
|
|
448
|
-
┌───▼───────┐ ┌──▼──────┐
|
|
449
|
-
│ Node.js │ │ fetch │
|
|
450
|
-
│ fs module │ │ │
|
|
451
|
-
└───────────┘ └─────────┘
|
|
452
|
-
│ │
|
|
453
|
-
┌────▼────────────────▼─────┐
|
|
454
|
-
│ TypeHandlerChain │
|
|
455
|
-
│ (serialization logic) │
|
|
456
|
-
└───────────────────────────┘
|
|
457
|
-
```
|
|
458
|
-
|
|
459
|
-
## Type Safety
|
|
460
|
-
|
|
461
|
-
All operations are fully typed:
|
|
462
|
-
|
|
463
|
-
```typescript
|
|
464
|
-
import type { RXR, Registry } from "@resourcexjs/registry";
|
|
465
|
-
|
|
466
|
-
const registry: Registry = createRegistry();
|
|
467
|
-
const rxr: RXR = await registry.resolve("localhost/test.text@1.0.0");
|
|
440
|
+
// Add and resolve
|
|
441
|
+
await registry.add("./my-prompt");
|
|
442
|
+
const resolved = await registry.resolve<void, string>("localhost/my-prompt.prompt@1.0.0");
|
|
443
|
+
const text = await resolved.execute();
|
|
468
444
|
```
|
|
469
445
|
|
|
470
446
|
## License
|