@resourcexjs/registry 2.5.0 → 2.5.2

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # @resourcexjs/registry
2
2
 
3
- Resource registry for ResourceX - storage and retrieval of resources.
3
+ Registry layer for ResourceX. Provides business logic for RXR (ResourceX Resource) operations on top of the storage layer.
4
4
 
5
5
  ## Installation
6
6
 
@@ -10,439 +10,413 @@ 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:
14
14
 
15
- ### Key Concepts
15
+ - **Three registry types** for different use cases
16
+ - **Access chain** for read-through cache pattern
17
+ - **Middleware** for cross-cutting concerns
18
+ - **Discovery** for well-known registry endpoints
16
19
 
17
- - **Registry**: Interface for resource storage and retrieval
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
20
+ All registries implement a common `Registry` interface and use `@resourcexjs/storage` for persistence.
23
21
 
24
- ## Usage
22
+ ## Registry Types
25
23
 
26
- ### Create Registry
24
+ ### LocalRegistry
27
25
 
28
- ```typescript
29
- import { createRegistry } from "@resourcexjs/registry";
30
-
31
- // Default registry (uses LocalStorage at ~/.resourcex)
32
- const registry = createRegistry();
33
-
34
- // Custom local path
35
- const registry2 = createRegistry({
36
- path: "./my-registry",
37
- });
38
-
39
- // With custom resource types
40
- import { bundleResourceType } from "@resourcexjs/type";
41
- const promptType = await bundleResourceType("./prompt.type.ts");
26
+ For local/owned resources without a registry domain in the path.
42
27
 
43
- const registry3 = createRegistry({
44
- types: [promptType],
45
- });
28
+ ```typescript
29
+ import { LocalRegistry } from "@resourcexjs/registry";
30
+ import { FileSystemStorage } from "@resourcexjs/storage";
46
31
 
47
- // With sandbox isolation
48
- const registry4 = createRegistry({
49
- isolator: "srt", // "none" | "srt" | "cloudflare" | "e2b"
50
- });
32
+ const storage = new FileSystemStorage("~/.resourcex/local");
33
+ const registry = new LocalRegistry(storage);
51
34
 
52
- // With remote mirror
53
- const registry5 = createRegistry({
54
- mirror: "https://registry.deepractice.ai/v1",
55
- });
35
+ // Storage structure: {name}/{tag}/manifest.json + archive.tar.gz
36
+ await registry.put(rxr);
37
+ const resource = await registry.get(rxl);
38
+ ```
56
39
 
57
- // Server mode with custom storage
58
- import { LocalStorage } from "@resourcexjs/registry";
40
+ **Use cases:**
59
41
 
60
- const registry6 = createRegistry({
61
- storage: new LocalStorage({ path: "./data" }),
62
- });
63
- ```
42
+ - Client local storage (`~/.resourcex/local/`)
43
+ - Server authoritative storage (`./data/`)
64
44
 
65
- ### Add Resource
45
+ ### MirrorRegistry
66
46
 
67
- Add a resource to the registry:
47
+ For cached/mirrored remote resources. Includes registry domain in the path.
68
48
 
69
49
  ```typescript
70
- import { loadResource } from "@resourcexjs/loader";
71
- import { createRegistry } from "@resourcexjs/registry";
72
-
73
- // Load resource from folder
74
- const rxr = await loadResource("./my-prompt");
50
+ import { MirrorRegistry } from "@resourcexjs/registry";
51
+ import { FileSystemStorage } from "@resourcexjs/storage";
75
52
 
76
- // Add to registry
77
- const registry = createRegistry();
78
- await registry.add(rxr);
53
+ const storage = new FileSystemStorage("~/.resourcex/cache");
54
+ const registry = new MirrorRegistry(storage);
79
55
 
80
- // Or add directly from path
81
- await registry.add("./my-prompt");
56
+ // Storage structure: {registry}/{name}/{tag}/manifest.json + archive.tar.gz
57
+ await registry.put(rxr);
58
+ const resource = await registry.get(rxl);
82
59
 
83
- // Now stored at: ~/.resourcex/local/my-prompt.text/1.0.0/
60
+ // Cache-specific: clear cached resources
61
+ await registry.clear(); // Clear all
62
+ await registry.clear("deepractice.ai"); // Clear specific registry
84
63
  ```
85
64
 
86
- ### Link Resource (Development)
65
+ **Use cases:**
87
66
 
88
- Link creates a symlink for live development changes:
67
+ - Caching remote resources locally
68
+ - Offline access to previously fetched resources
89
69
 
90
- ```typescript
91
- const registry = createRegistry();
92
-
93
- // Link directory - changes reflect immediately
94
- await registry.link("./my-prompts/assistant");
95
- ```
96
-
97
- ### Resolve Resource
70
+ ### LinkedRegistry
98
71
 
99
- Retrieve and execute a resource:
72
+ For development symlinks. Changes in the source directory are reflected immediately.
100
73
 
101
74
  ```typescript
102
- const registry = createRegistry();
75
+ import { LinkedRegistry } from "@resourcexjs/registry";
103
76
 
104
- // Resolve returns ResolvedResource with execute()
105
- const resolved = await registry.resolve("localhost/my-prompt.text@1.0.0");
77
+ const registry = new LinkedRegistry("~/.resourcex/linked");
106
78
 
107
- // Execute to get content
108
- const text = await resolved.execute();
109
- console.log(text);
79
+ // Create symlink to development directory
80
+ const rxl = await registry.link("./my-prompt");
110
81
 
111
- // Check schema (for types with arguments)
112
- console.log(resolved.schema); // undefined for text type
113
- ```
82
+ // Get resource (reads from symlink target)
83
+ const resource = await registry.get(rxl);
114
84
 
115
- ### Get Raw Resource
85
+ // Remove symlink
86
+ await registry.unlink(rxl);
87
+ ```
116
88
 
117
- Get the RXR without resolving:
89
+ **Use cases:**
118
90
 
119
- ```typescript
120
- const rxr = await registry.get("localhost/my-prompt.text@1.0.0");
91
+ - Live development without re-adding resources
92
+ - Testing local changes before publishing
121
93
 
122
- console.log(rxr.manifest.name); // "my-prompt"
123
- console.log(rxr.manifest.type); // "text"
124
- ```
94
+ ## Registry Interface
125
95
 
126
- ### Check Existence
96
+ All registries implement:
127
97
 
128
98
  ```typescript
129
- if (await registry.exists("localhost/my-prompt.text@1.0.0")) {
130
- console.log("Resource exists");
99
+ interface Registry {
100
+ get(rxl: RXL): Promise<RXR>;
101
+ put(rxr: RXR): Promise<void>;
102
+ has(rxl: RXL): Promise<boolean>;
103
+ remove(rxl: RXL): Promise<void>;
104
+ list(options?: SearchOptions): Promise<RXL[]>;
105
+ }
106
+
107
+ interface SearchOptions {
108
+ query?: string; // Filter by name/path substring
109
+ limit?: number; // Max results
110
+ offset?: number; // Skip first N (pagination)
131
111
  }
132
112
  ```
133
113
 
134
- ### Delete Resource
114
+ ## Access Chain
135
115
 
136
- ```typescript
137
- await registry.delete("localhost/my-prompt.text@1.0.0");
138
- ```
116
+ The access chain implements a read-through cache pattern for unified resource access.
117
+
118
+ ### RegistryAccessChain
139
119
 
140
- ### Search Resources
120
+ Iterates through accessors in order. First accessor that can handle returns the result.
141
121
 
142
122
  ```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
- });
123
+ import {
124
+ RegistryAccessChain,
125
+ LinkedAccessor,
126
+ LocalAccessor,
127
+ CacheAccessor,
128
+ RemoteAccessor,
129
+ LocalRegistry,
130
+ MirrorRegistry,
131
+ LinkedRegistry,
132
+ } from "@resourcexjs/registry";
133
+ import { FileSystemStorage } from "@resourcexjs/storage";
134
+
135
+ // Create registries
136
+ const linkedRegistry = new LinkedRegistry("~/.resourcex/linked");
137
+ const localRegistry = new LocalRegistry(new FileSystemStorage("~/.resourcex/local"));
138
+ const cacheRegistry = new MirrorRegistry(new FileSystemStorage("~/.resourcex/cache"));
139
+
140
+ // Create accessor chain
141
+ const chain = new RegistryAccessChain(
142
+ [
143
+ new LinkedAccessor(linkedRegistry), // 1. Dev symlinks (highest priority)
144
+ new LocalAccessor(localRegistry), // 2. Local resources (no domain)
145
+ new CacheAccessor(cacheRegistry), // 3. Cached remote resources
146
+ new RemoteAccessor(fetcher, cacheRegistry), // 4. Fetch + auto-cache
147
+ ],
148
+ { memCache: true } // Optional in-memory cache
149
+ );
150
+
151
+ // Get resource (tries each accessor in order)
152
+ const rxr = await chain.get(rxl);
153
+
154
+ // Check existence
155
+ const exists = await chain.has(rxl);
156
+
157
+ // Cache management
158
+ chain.invalidate(rxl); // Remove specific resource from memory cache
159
+ chain.clearCache(); // Clear entire memory cache
155
160
  ```
156
161
 
157
- ### Support Custom Types
162
+ ### Accessor Types
158
163
 
159
- ```typescript
160
- import { bundleResourceType } from "@resourcexjs/type";
164
+ | Accessor | Handles | Description |
165
+ | ---------------- | -------------------------- | ------------------------------ |
166
+ | `LinkedAccessor` | All (if linked) | Dev symlinks, highest priority |
167
+ | `LocalAccessor` | Resources without registry | Local storage |
168
+ | `CacheAccessor` | Resources with registry | Cached remote resources |
169
+ | `RemoteAccessor` | Resources with registry | Fetch + auto-cache |
170
+
171
+ ### RemoteFetcher Interface
161
172
 
162
- const registry = createRegistry();
173
+ `RemoteAccessor` requires a fetcher implementation:
163
174
 
164
- // Bundle and add type at runtime
165
- const promptType = await bundleResourceType("./prompt.type.ts");
166
- registry.supportType(promptType);
175
+ ```typescript
176
+ interface RemoteFetcher {
177
+ fetch(rxl: RXL): Promise<RXR>;
178
+ }
167
179
 
168
- // Now can resolve prompt resources
169
- const resolved = await registry.resolve("localhost/assistant.prompt@1.0.0");
180
+ // Example implementation
181
+ const fetcher: RemoteFetcher = {
182
+ async fetch(rxl) {
183
+ const url = `https://${rxl.registry}/api/v1/resources/${rxl.name}/${rxl.tag}`;
184
+ const response = await fetch(url);
185
+ // ... parse response to RXR
186
+ return rxr;
187
+ },
188
+ };
170
189
  ```
171
190
 
172
- ## API Reference
191
+ ## Middleware
173
192
 
174
- ### `createRegistry(config?)`
193
+ ### RegistryMiddleware
175
194
 
176
- Create a new registry instance.
195
+ Base class for creating custom middleware. Delegates all operations to the inner registry.
177
196
 
178
- **Parameters:**
197
+ ```typescript
198
+ import { RegistryMiddleware } from "@resourcexjs/registry";
199
+ import type { RXL, RXR } from "@resourcexjs/core";
179
200
 
180
- - `config?: ClientRegistryConfig | ServerRegistryConfig`
201
+ class LoggingMiddleware extends RegistryMiddleware {
202
+ async get(rxl: RXL): Promise<RXR> {
203
+ console.log("Getting:", rxl);
204
+ const rxr = await this.inner.get(rxl);
205
+ console.log("Got:", rxr.manifest.name);
206
+ return rxr;
207
+ }
208
+ }
181
209
 
182
- **Client mode (default):**
210
+ const logged = new LoggingMiddleware(registry);
211
+ ```
183
212
 
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
213
+ ### DomainValidation
188
214
 
189
- **Server mode:**
215
+ Built-in middleware that validates resource registry matches a trusted registry.
190
216
 
191
- - `storage: Storage` - Custom storage implementation
192
- - `types?: BundledType[]` - Custom resource types
193
- - `isolator?: IsolatorType` - Sandbox isolation level
217
+ ```typescript
218
+ import { withDomainValidation } from "@resourcexjs/registry";
194
219
 
195
- **Returns**: `Registry`
220
+ const validated = withDomainValidation(registry, "deepractice.ai");
196
221
 
197
- ```typescript
198
- // Client mode
199
- const registry = createRegistry({
200
- path: "~/.resourcex",
201
- mirror: "https://registry.deepractice.ai/v1",
202
- types: [promptType],
203
- isolator: "srt",
204
- });
205
-
206
- // Server mode
207
- const registry = createRegistry({
208
- storage: new LocalStorage({ path: "./data" }),
209
- types: [promptType],
210
- });
222
+ // Throws RegistryError if resource.manifest.registry !== "deepractice.ai"
223
+ await validated.get(rxl);
211
224
  ```
212
225
 
213
- ### `discoverRegistry(domain)`
214
-
215
- Discover registry endpoints for a domain via well-known.
226
+ **Use cases:**
216
227
 
217
- **Parameters:**
228
+ - Server-side validation to prevent registry impersonation
229
+ - Ensuring resources are from trusted sources
218
230
 
219
- - `domain: string` - Domain to discover (e.g., "deepractice.ai")
231
+ ## Discovery
220
232
 
221
- **Returns**: `Promise<DiscoveryResult>`
233
+ Discover registry endpoints via well-known URL.
222
234
 
223
235
  ```typescript
236
+ import { discoverRegistry } from "@resourcexjs/registry";
237
+
224
238
  const result = await discoverRegistry("deepractice.ai");
225
- // { domain: "deepractice.ai", registries: ["https://..."] }
239
+ // {
240
+ // domain: "deepractice.ai",
241
+ // registries: ["https://registry.deepractice.ai/api/v1"]
242
+ // }
226
243
  ```
227
244
 
228
- ### Registry Interface
229
-
230
- #### `supportType(type: BundledType): void`
231
-
232
- Add support for a custom resource type at runtime.
233
-
234
- #### `link(path: string): Promise<void>`
235
-
236
- Create a symlink for development. Changes in the source directory are immediately reflected.
237
-
238
- #### `add(source: string | RXR): Promise<void>`
239
-
240
- Add resource to storage. Accepts a folder path or RXR object.
241
-
242
- #### `get(locator: string): Promise<RXR>`
245
+ **Well-known format** (`https://{domain}/.well-known/resourcex`):
243
246
 
244
- Get raw RXR by locator without resolving.
247
+ ```json
248
+ {
249
+ "version": "1.0",
250
+ "registries": ["https://registry.example.com/api/v1"]
251
+ }
252
+ ```
245
253
 
246
- #### `resolve<TArgs, TResult>(locator: string): Promise<ResolvedResource<TArgs, TResult>>`
254
+ ## Storage Structure
247
255
 
248
- Resolve resource and return structured result with execute function.
256
+ ```
257
+ ~/.resourcex/
258
+ ├── local/ # LocalRegistry - local resources
259
+ │ └── {path/}{name}/
260
+ │ └── {tag}/
261
+ │ ├── manifest.json
262
+ │ └── archive.tar.gz
263
+
264
+ ├── cache/ # MirrorRegistry - cached remote
265
+ │ └── {registry}/
266
+ │ └── {path/}{name}/
267
+ │ └── {tag}/
268
+ │ ├── manifest.json
269
+ │ └── archive.tar.gz
270
+
271
+ └── linked/ # LinkedRegistry - dev symlinks
272
+ └── {registry}/
273
+ └── {path/}{name}/
274
+ └── {tag} -> /path/to/dev/folder
275
+ ```
249
276
 
250
- #### `exists(locator: string): Promise<boolean>`
277
+ ## Error Handling
251
278
 
252
- Check if resource exists.
279
+ ```typescript
280
+ import { RegistryError } from "@resourcexjs/registry";
253
281
 
254
- #### `delete(locator: string): Promise<void>`
282
+ try {
283
+ await registry.get(rxl);
284
+ } catch (error) {
285
+ if (error instanceof RegistryError) {
286
+ console.error("Registry error:", error.message);
287
+ }
288
+ }
289
+ ```
255
290
 
256
- Delete resource from storage.
291
+ **Common errors:**
257
292
 
258
- #### `search(options?: SearchOptions): Promise<RXL[]>`
293
+ - `Resource not found: {locator}`
294
+ - `Resource not found in cache: {locator}`
295
+ - `Linked resource not found: {locator}`
296
+ - `LinkedRegistry does not support put(). Use link() instead.`
297
+ - `Well-known discovery failed for {domain}: {status}`
298
+ - `Untrusted registry: resource claims "{claimed}" but registry only trusts "{trusted}"`
259
299
 
260
- Search for resources.
300
+ ## API Reference
261
301
 
262
- - `query?: string` - Filter by locator substring
263
- - `limit?: number` - Max results
264
- - `offset?: number` - Skip first N results
302
+ ### Registries
265
303
 
266
- ### Storage Interface
304
+ #### `LocalRegistry`
267
305
 
268
306
  ```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
- }
307
+ new LocalRegistry(storage: Storage)
277
308
  ```
278
309
 
279
- ### LocalStorage
310
+ Registry for local resources without registry domain.
280
311
 
281
- Filesystem-based storage implementation.
312
+ #### `MirrorRegistry`
282
313
 
283
314
  ```typescript
284
- import { LocalStorage } from "@resourcexjs/registry";
285
-
286
- const storage = new LocalStorage({
287
- path: "~/.resourcex", // optional, defaults to ~/.resourcex
288
- });
315
+ new MirrorRegistry(storage: Storage)
289
316
  ```
290
317
 
291
- ## Storage Structure
318
+ Registry for cached remote resources with registry domain.
292
319
 
293
- Resources are stored in two areas:
320
+ **Additional methods:**
294
321
 
295
- ```
296
- ~/.resourcex/
297
- ├── local/ # Development resources
298
- │ └── {name}.{type}/
299
- │ └── {version}/
300
- │ ├── manifest.json
301
- │ └── archive.tar.gz
302
-
303
- └── cache/ # Remote cached resources
304
- └── {domain}/
305
- └── {path}/
306
- └── {name}.{type}/
307
- └── {version}/
308
- ├── manifest.json
309
- └── archive.tar.gz
310
- ```
322
+ - `clear(registry?: string): Promise<void>` - Clear cached resources
311
323
 
312
- ### Resolution Order
324
+ #### `LinkedRegistry`
313
325
 
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
326
+ ```typescript
327
+ new LinkedRegistry(basePath: string)
328
+ ```
317
329
 
318
- ## Remote Fetch Flow
330
+ Registry for development symlinks.
319
331
 
320
- For non-localhost domains:
332
+ **Additional methods:**
321
333
 
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
334
+ - `link(devPath: string): Promise<RXL>` - Create symlink to development directory
335
+ - `unlink(rxl: RXL): Promise<void>` - Remove symlink (alias for `remove`)
327
336
 
328
- **Well-known format:**
337
+ ### Access Chain
329
338
 
330
- ```json
331
- {
332
- "version": "1.0",
333
- "registries": ["https://registry.example.com/v1"]
334
- }
339
+ #### `RegistryAccessChain`
340
+
341
+ ```typescript
342
+ new RegistryAccessChain(accessors: RegistryAccessor[], options?: { memCache?: boolean })
335
343
  ```
336
344
 
337
- ## Middleware
345
+ **Methods:**
338
346
 
339
- ### RegistryMiddleware
347
+ - `get(rxl: RXL): Promise<RXR>` - Get resource through chain
348
+ - `has(rxl: RXL): Promise<boolean>` - Check existence
349
+ - `clearCache(): void` - Clear memory cache
350
+ - `invalidate(rxl: RXL): void` - Remove specific resource from memory cache
340
351
 
341
- Base class for creating custom middleware:
352
+ #### `RegistryAccessor`
342
353
 
343
354
  ```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
- }
355
+ interface RegistryAccessor {
356
+ readonly name: string;
357
+ canHandle(rxl: RXL): Promise<boolean>;
358
+ get(rxl: RXL): Promise<RXR>;
351
359
  }
352
360
  ```
353
361
 
354
- ### DomainValidation
362
+ ### Middleware
355
363
 
356
- Built-in middleware for validating resource domains:
364
+ #### `RegistryMiddleware`
357
365
 
358
366
  ```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");
367
+ abstract class RegistryMiddleware implements Registry {
368
+ constructor(protected readonly inner: Registry)
369
+ }
365
370
  ```
366
371
 
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 |
372
+ #### `DomainValidation`
377
373
 
378
374
  ```typescript
379
- const registry = createRegistry({
380
- isolator: "srt",
381
- });
375
+ new DomainValidation(inner: Registry, trustedRegistry: string)
382
376
  ```
383
377
 
384
- ## Error Handling
378
+ Middleware class that validates resource registry matches the trusted registry.
385
379
 
386
- ```typescript
387
- import { RegistryError } from "@resourcexjs/registry";
380
+ #### `withDomainValidation`
388
381
 
389
- try {
390
- const rxr = await registry.get("localhost/not-exist.text@1.0.0");
391
- } catch (error) {
392
- if (error instanceof RegistryError) {
393
- console.error("Registry error:", error.message);
394
- }
395
- }
382
+ ```typescript
383
+ withDomainValidation(registry: Registry, trustedRegistry: string): Registry
396
384
  ```
397
385
 
398
- ### Common Errors
399
-
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`
386
+ Factory function to create `DomainValidation` middleware.
404
387
 
405
- ## Examples
388
+ ### Discovery
406
389
 
407
- ### Complete Workflow
390
+ #### `discoverRegistry`
408
391
 
409
392
  ```typescript
410
- import { loadResource } from "@resourcexjs/loader";
411
- import { createRegistry } from "@resourcexjs/registry";
412
-
413
- // 1. Create registry
414
- const registry = createRegistry();
415
-
416
- // 2. Load and add resource
417
- const rxr = await loadResource("./my-prompts/assistant");
418
- await registry.add(rxr);
419
-
420
- // 3. Resolve and execute
421
- const resolved = await registry.resolve("localhost/assistant.text@1.0.0");
422
- const text = await resolved.execute();
423
- console.log(text);
393
+ discoverRegistry(domain: string): Promise<DiscoveryResult>
424
394
  ```
425
395
 
426
- ### With Custom Types
396
+ **Types:**
427
397
 
428
398
  ```typescript
429
- import { createRegistry } from "@resourcexjs/registry";
430
- import { bundleResourceType } from "@resourcexjs/type";
399
+ interface DiscoveryResult {
400
+ domain: string;
401
+ registries: string[];
402
+ }
431
403
 
432
- // Bundle custom type
433
- const promptType = await bundleResourceType("./prompt.type.ts");
404
+ interface WellKnownResponse {
405
+ version?: string;
406
+ registries: string[];
407
+ }
408
+ ```
434
409
 
435
- // Create registry with type
436
- const registry = createRegistry({
437
- types: [promptType],
438
- });
410
+ ### Error
439
411
 
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();
412
+ #### `RegistryError`
413
+
414
+ ```typescript
415
+ class RegistryError extends ResourceXError {
416
+ constructor(message: string, options?: ErrorOptions);
417
+ }
444
418
  ```
445
419
 
446
420
  ## License
447
421
 
448
- MIT
422
+ Apache-2.0