@resourcexjs/core 0.9.0 → 1.1.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # @resourcexjs/core
2
2
 
3
- Core types and implementations for ResourceX.
3
+ Core data structures for ResourceX.
4
4
 
5
5
  > **Note**: For most use cases, use the main [`resourcexjs`](https://www.npmjs.com/package/resourcexjs) package. This package is for advanced usage.
6
6
 
@@ -14,14 +14,12 @@ bun add @resourcexjs/core
14
14
 
15
15
  ## What's Inside
16
16
 
17
- Core building blocks for ResourceX:
17
+ Core building blocks - pure data structures:
18
18
 
19
- - **RXL** (Locator) - Parse locator strings
20
- - **RXM** (Manifest) - Create resource metadata
19
+ - **RXL** (Locator) - Resource locator string parser
20
+ - **RXM** (Manifest) - Resource metadata
21
21
  - **RXC** (Content) - Stream-based content
22
22
  - **RXR** (Resource) - Complete resource type
23
- - **ResourceType** - Type system with serializer & resolver
24
- - **TypeHandlerChain** - Responsibility chain for type handling
25
23
  - **Errors** - Error hierarchy
26
24
 
27
25
  ## API
@@ -43,6 +41,13 @@ rxl.version; // "1.0.0"
43
41
  rxl.toString(); // "deepractice.ai/sean/assistant.prompt@1.0.0"
44
42
  ```
45
43
 
44
+ **Minimal locator:**
45
+
46
+ ```typescript
47
+ parseRXL("name.text@1.0.0");
48
+ // → domain: "localhost", path: undefined, name: "name", type: "text", version: "1.0.0"
49
+ ```
50
+
46
51
  ### RXM - Resource Manifest
47
52
 
48
53
  Create and validate resource metadata:
@@ -56,40 +61,54 @@ const manifest = createRXM({
56
61
  name: "assistant",
57
62
  type: "prompt",
58
63
  version: "1.0.0",
64
+ description: "Optional description", // optional
65
+ tags: ["optional", "tags"], // optional
59
66
  });
60
67
 
61
68
  manifest.toLocator(); // → "deepractice.ai/sean/assistant.prompt@1.0.0"
62
69
  manifest.toJSON(); // → plain object
63
70
  ```
64
71
 
65
- Required fields: domain, name, type, version
72
+ **Required fields**: `name`, `type`, `version`
73
+
74
+ **Optional fields**: `domain` (default: "localhost"), `path`, `description`, `tags`
66
75
 
67
76
  ### RXC - Resource Content
68
77
 
69
- Stream-based content (can only be consumed once, like fetch Response):
78
+ Archive-based content (internally tar.gz), supports single or multi-file resources:
70
79
 
71
80
  ```typescript
72
- import { createRXC, loadRXC } from "@resourcexjs/core";
73
-
74
- // Create from memory
75
- const content = createRXC("Hello, World!");
76
- const content = createRXC(Buffer.from([1, 2, 3]));
77
- const content = createRXC(readableStream);
78
-
79
- // Load from file or URL (async)
80
- const content = await loadRXC("./file.txt");
81
- const content = await loadRXC("https://example.com/data.txt");
82
-
83
- // Consume (choose one, can only use once)
84
- const text = await content.text(); // → string
85
- const buffer = await content.buffer(); // → Buffer
86
- const json = await content.json<T>(); // → T
87
- const stream = content.stream; // → ReadableStream<Uint8Array>
81
+ import { createRXC } from "@resourcexjs/core";
82
+
83
+ // Single file
84
+ const content = await createRXC({ content: "Hello, World!" });
85
+
86
+ // Multiple files
87
+ const content = await createRXC({
88
+ "index.ts": "export default 1",
89
+ "styles.css": "body {}",
90
+ });
91
+
92
+ // Nested directories
93
+ const content = await createRXC({
94
+ "src/index.ts": "main code",
95
+ "src/utils/helper.ts": "helper code",
96
+ });
97
+
98
+ // From existing tar.gz archive (for deserialization)
99
+ const content = await createRXC({ archive: tarGzBuffer });
100
+
101
+ // Read files
102
+ const buffer = await content.file("content"); // → Buffer
103
+ const buffer = await content.file("src/index.ts"); // → Buffer
104
+ const files = await content.files(); // → Map<string, Buffer>
105
+ const archiveBuffer = await content.buffer(); // → raw tar.gz Buffer
106
+ const stream = content.stream; // → ReadableStream (tar.gz)
88
107
  ```
89
108
 
90
109
  ### RXR - Resource
91
110
 
92
- Complete resource object (pure interface, no factory):
111
+ Complete resource object (pure interface):
93
112
 
94
113
  ```typescript
95
114
  import type { RXR } from "@resourcexjs/core";
@@ -101,156 +120,149 @@ interface RXR {
101
120
  }
102
121
 
103
122
  // Create from literals
104
- const rxr: RXR = {
105
- locator: parseRXL("localhost/test.text@1.0.0"),
106
- manifest: createRXM({ domain: "localhost", name: "test", type: "text", version: "1.0.0" }),
107
- content: createRXC("content"),
108
- };
123
+ const rxr: RXR = { locator, manifest, content };
109
124
  ```
110
125
 
111
- ### Resource Types
126
+ RXR is a pure DTO (Data Transfer Object) - no factory function needed.
112
127
 
113
- Built-in types:
128
+ ## Error Handling
114
129
 
115
130
  ```typescript
116
- import { textType, jsonType, binaryType, builtinTypes } from "@resourcexjs/core";
131
+ import { ResourceXError, LocatorError, ManifestError, ContentError } from "@resourcexjs/core";
117
132
 
118
- console.log(textType.name); // "text"
119
- console.log(textType.aliases); // ["txt", "plaintext"]
120
- console.log(jsonType.aliases); // ["config", "manifest"]
121
- console.log(binaryType.aliases); // ["bin", "blob", "raw"]
122
- ```
133
+ try {
134
+ parseRXL("invalid-locator");
135
+ } catch (error) {
136
+ if (error instanceof LocatorError) {
137
+ console.error("Invalid locator format");
138
+ }
139
+ }
123
140
 
124
- Define custom types:
141
+ try {
142
+ createRXM({ name: "test" }); // Missing required fields
143
+ } catch (error) {
144
+ if (error instanceof ManifestError) {
145
+ console.error("Invalid manifest");
146
+ }
147
+ }
125
148
 
126
- ```typescript
127
- import { defineResourceType } from "@resourcexjs/core";
128
-
129
- defineResourceType({
130
- name: "prompt",
131
- aliases: ["deepractice-prompt"],
132
- description: "AI Prompt template",
133
- serializer: {
134
- async serialize(rxr: RXR): Promise<Buffer> {
135
- // Convert RXR to Buffer for storage
136
- const text = await rxr.content.text();
137
- return Buffer.from(JSON.stringify({ template: text }));
138
- },
139
- async deserialize(data: Buffer, manifest: RXM): Promise<RXR> {
140
- // Convert Buffer back to RXR
141
- const obj = JSON.parse(data.toString());
142
- return {
143
- locator: parseRXL(manifest.toLocator()),
144
- manifest,
145
- content: createRXC(obj.template),
146
- };
147
- },
148
- },
149
- resolver: {
150
- async resolve(rxr: RXR): Promise<PromptTemplate> {
151
- // Convert RXR to usable object
152
- return {
153
- template: await rxr.content.text(),
154
- compile: (vars) => {
155
- /* ... */
156
- },
157
- };
158
- },
159
- },
160
- });
149
+ try {
150
+ await content.text();
151
+ await content.text(); // Second consumption
152
+ } catch (error) {
153
+ if (error instanceof ContentError) {
154
+ console.error("Content already consumed");
155
+ }
156
+ }
161
157
  ```
162
158
 
163
- Query registered types:
164
-
165
- ```typescript
166
- import { getResourceType, clearResourceTypes } from "@resourcexjs/core";
167
-
168
- const type = getResourceType("text");
169
- const type = getResourceType("txt"); // Works with aliases
159
+ ### Error Hierarchy
170
160
 
171
- clearResourceTypes(); // For testing
161
+ ```
162
+ ResourceXError (base)
163
+ ├── LocatorError
164
+ ├── ManifestError
165
+ └── ContentError
172
166
  ```
173
167
 
174
- ### TypeHandlerChain
168
+ ## Examples
175
169
 
176
- Responsibility chain for type handling (used internally by Registry):
170
+ ### Complete Resource Creation
177
171
 
178
172
  ```typescript
179
- import { createTypeHandlerChain, builtinTypes } from "@resourcexjs/core";
173
+ import { parseRXL, createRXM, createRXC } from "@resourcexjs/core";
174
+ import type { RXR } from "@resourcexjs/core";
180
175
 
181
- // Create with initial types
182
- const chain = createTypeHandlerChain(builtinTypes);
176
+ // Create manifest
177
+ const manifest = createRXM({
178
+ domain: "deepractice.ai",
179
+ name: "assistant",
180
+ type: "prompt",
181
+ version: "1.0.0",
182
+ });
183
183
 
184
- // Or start empty
185
- const chain = createTypeHandlerChain();
186
- chain.register(customType);
187
- chain.registerAll([type1, type2]);
184
+ // Create locator from manifest
185
+ const locator = parseRXL(manifest.toLocator());
188
186
 
189
- // Use the chain
190
- chain.canHandle("text"); // → boolean
191
- chain.getHandler("txt"); // → ResourceType (via alias)
187
+ // Create content (single file)
188
+ const content = await createRXC({ content: "You are a helpful assistant." });
192
189
 
193
- await chain.serialize(rxr); // Buffer
194
- await chain.deserialize(buffer, manifest); // → RXR
195
- await chain.resolve<T>(rxr); // → T (usable object)
190
+ // Assemble RXR
191
+ const rxr: RXR = {
192
+ locator,
193
+ manifest,
194
+ content,
195
+ };
196
196
  ```
197
197
 
198
- ## Error Handling
198
+ ### Multi-file Resource
199
199
 
200
200
  ```typescript
201
- import {
202
- ResourceXError,
203
- LocatorError,
204
- ManifestError,
205
- ContentError,
206
- ResourceTypeError,
207
- } from "@resourcexjs/core";
201
+ import { createRXC } from "@resourcexjs/core";
208
202
 
209
- try {
210
- const rxl = parseRXL("invalid");
211
- } catch (error) {
212
- if (error instanceof LocatorError) {
213
- console.error("Invalid locator:", error.message);
214
- }
203
+ // Create multi-file content
204
+ const content = await createRXC({
205
+ "prompt.md": "# System Prompt\nYou are...",
206
+ "config.json": '{"temperature": 0.7}',
207
+ });
208
+
209
+ // Read individual files
210
+ const promptBuffer = await content.file("prompt.md");
211
+ const configBuffer = await content.file("config.json");
212
+
213
+ // Read all files
214
+ const allFiles = await content.files();
215
+ for (const [path, buffer] of allFiles) {
216
+ console.log(path, buffer.toString());
215
217
  }
216
218
  ```
217
219
 
218
- Error hierarchy:
220
+ ### Manifest Serialization
219
221
 
220
- ```
221
- Error
222
- └── ResourceXError
223
- ├── LocatorError (RXL parsing)
224
- ├── ManifestError (RXM validation)
225
- ├── ContentError (RXC consumption)
226
- └── ResourceTypeError (Type not found/duplicate)
222
+ ```typescript
223
+ const manifest = createRXM({
224
+ name: "assistant",
225
+ type: "prompt",
226
+ version: "1.0.0",
227
+ });
228
+
229
+ // To JSON (for storage)
230
+ const json = manifest.toJSON();
231
+ /*
232
+ {
233
+ "domain": "localhost",
234
+ "name": "assistant",
235
+ "type": "prompt",
236
+ "version": "1.0.0"
237
+ }
238
+ */
239
+
240
+ // To locator string
241
+ const locator = manifest.toLocator();
242
+ // "localhost/assistant.prompt@1.0.0"
227
243
  ```
228
244
 
229
- ## Complete Exports
245
+ ## Related Packages
230
246
 
231
- ```typescript
232
- // Errors
233
- export { ResourceXError, LocatorError, ManifestError, ContentError, ResourceTypeError };
247
+ This package provides only data structures. For full functionality:
234
248
 
235
- // RXL (Locator)
236
- export { parseRXL };
237
- export type { RXL };
249
+ - **[@resourcexjs/type](../type)** - Type system and handlers
250
+ - **[@resourcexjs/loader](../loader)** - Resource loading
251
+ - **[@resourcexjs/registry](../registry)** - Storage and retrieval
252
+ - **[@resourcexjs/arp](../arp)** - Low-level I/O
253
+ - **[resourcexjs](../resourcex)** - Main package (all-in-one)
238
254
 
239
- // RXM (Manifest)
240
- export { createRXM };
241
- export type { RXM, ManifestData };
255
+ ## Type Safety
242
256
 
243
- // RXC (Content)
244
- export { createRXC, loadRXC };
245
- export type { RXC };
257
+ All types are fully typed with TypeScript:
246
258
 
247
- // RXR (Resource)
248
- export type { RXR, ResourceType, ResourceSerializer, ResourceResolver };
259
+ ```typescript
260
+ import type { RXL, RXM, RXC, RXR } from "@resourcexjs/core";
249
261
 
250
- // ResourceType
251
- export { defineResourceType, getResourceType, clearResourceTypes };
252
- export { textType, jsonType, binaryType, builtinTypes };
253
- export { TypeHandlerChain, createTypeHandlerChain };
262
+ const locator: RXL = parseRXL("...");
263
+ const manifest: RXM = createRXM({ ... });
264
+ const content: RXC = createRXC("...");
265
+ const resource: RXR = { locator, manifest, content };
254
266
  ```
255
267
 
256
268
  ## License
package/dist/index.d.ts CHANGED
@@ -14,9 +14,6 @@ declare class ManifestError extends ResourceXError {
14
14
  declare class ContentError extends ResourceXError {
15
15
  constructor(message: string);
16
16
  }
17
- declare class ResourceTypeError extends ResourceXError {
18
- constructor(message: string);
19
- }
20
17
  /**
21
18
  * RXL - ResourceX Locator
22
19
  *
@@ -62,26 +59,28 @@ declare function createRXM(data: ManifestData): RXM;
62
59
  /**
63
60
  * RXC - ResourceX Content
64
61
  *
65
- * Represents resource content as a stream.
62
+ * Archive-based content container using tar.gz format internally.
63
+ * Provides unified file access API for both single and multi-file resources.
66
64
  */
67
65
  interface RXC {
68
- /** Content as a readable stream */
66
+ /** Content as a readable stream (tar.gz format) */
69
67
  readonly stream: ReadableStream<Uint8Array>;
70
- /** Read content as text */
71
- text(): Promise<string>;
72
- /** Read content as Buffer */
68
+ /** Get raw archive buffer (tar.gz format) */
73
69
  buffer(): Promise<Buffer>;
74
- /** Read content as JSON */
75
- json<T>(): Promise<T>;
70
+ /** Read a specific file from the archive */
71
+ file(path: string): Promise<Buffer>;
72
+ /** Read all files from the archive */
73
+ files(): Promise<Map<string, Buffer>>;
76
74
  }
77
75
  /**
78
- * Create RXC from string, Buffer, or ReadableStream.
79
- */
80
- declare function createRXC(data: string | Buffer | ReadableStream<Uint8Array>): RXC;
81
- /**
82
- * Load RXC from file path or URL.
76
+ * Input type for createRXC.
77
+ * - Files record: { 'path/to/file': content }
78
+ * - Archive: { archive: tarGzBuffer }
83
79
  */
84
- declare function loadRXC(source: string): Promise<RXC>;
80
+ type RXCInput = Record<string, Buffer | Uint8Array | string> | {
81
+ archive: Buffer
82
+ };
83
+ declare function createRXC(input: RXCInput): Promise<RXC>;
85
84
  /**
86
85
  * RXR (ResourceX Resource) - Complete resource object.
87
86
  * A pure data transfer object combining locator, manifest, and content.
@@ -91,208 +90,4 @@ interface RXR {
91
90
  manifest: RXM;
92
91
  content: RXC;
93
92
  }
94
- /**
95
- * ResourceSerializer - Handles RXR serialization/deserialization for storage.
96
- */
97
- interface ResourceSerializer {
98
- /**
99
- * Serialize RXR to storage format.
100
- */
101
- serialize(rxr: RXR): Promise<Buffer>;
102
- /**
103
- * Deserialize storage data to RXR.
104
- */
105
- deserialize(data: Buffer, manifest: RXM): Promise<RXR>;
106
- }
107
- /**
108
- * ResourceResolver - Transforms RXR into usable object.
109
- */
110
- interface ResourceResolver<T = unknown> {
111
- /**
112
- * Resolve RXR content into a usable object.
113
- */
114
- resolve(rxr: RXR): Promise<T>;
115
- }
116
- /**
117
- * ResourceType - Defines how a resource type is handled.
118
- */
119
- interface ResourceType<T = unknown> {
120
- /**
121
- * Type name (e.g., "text", "json", "binary").
122
- */
123
- name: string;
124
- /**
125
- * Alternative names for this type (e.g., ["txt", "plaintext"]).
126
- */
127
- aliases?: string[];
128
- /**
129
- * Human-readable description.
130
- */
131
- description: string;
132
- /**
133
- * Serializer for storage operations.
134
- */
135
- serializer: ResourceSerializer;
136
- /**
137
- * Resolver to transform RXR into usable object.
138
- */
139
- resolver: ResourceResolver<T>;
140
- }
141
- /**
142
- * ResourceLoader - Strategy interface for loading resources from different sources.
143
- */
144
- interface ResourceLoader {
145
- /**
146
- * Check if this loader can handle the given source.
147
- *
148
- * @param source - Source path or identifier
149
- * @returns true if this loader can handle the source
150
- */
151
- canLoad(source: string): boolean | Promise<boolean>;
152
- /**
153
- * Load a resource from the given source.
154
- *
155
- * @param source - Source path or identifier
156
- * @returns Complete RXR object
157
- * @throws ResourceXError if loading fails
158
- */
159
- load(source: string): Promise<RXR>;
160
- }
161
- /**
162
- * Define and register a resource type.
163
- *
164
- * @throws ResourceTypeError if type is already registered
165
- */
166
- declare function defineResourceType<T>(config: ResourceType<T>): ResourceType<T>;
167
- /**
168
- * Get a registered resource type by name.
169
- *
170
- * @returns ResourceType or undefined if not found
171
- */
172
- declare function getResourceType<T = unknown>(name: string): ResourceType<T> | undefined;
173
- /**
174
- * Clear all registered resource types (for testing).
175
- */
176
- declare function clearResourceTypes(): void;
177
- /**
178
- * Text resource type
179
- */
180
- declare const textType: ResourceType<string>;
181
- /**
182
- * JSON resource type
183
- */
184
- declare const jsonType: ResourceType<unknown>;
185
- /**
186
- * Binary resource type
187
- */
188
- declare const binaryType: ResourceType<Buffer>;
189
- /**
190
- * All built-in types
191
- */
192
- declare const builtinTypes: ResourceType[];
193
- /**
194
- * TypeHandlerChain - Responsibility chain for resource type handling.
195
- * Manages type registration and delegates serialization/deserialization.
196
- */
197
- declare class TypeHandlerChain {
198
- private handlers;
199
- /**
200
- * Register a resource type handler.
201
- * Registers both the type name and its aliases.
202
- */
203
- register(type: ResourceType): void;
204
- /**
205
- * Register multiple type handlers.
206
- */
207
- registerAll(types: ResourceType[]): void;
208
- /**
209
- * Check if a type is supported.
210
- */
211
- canHandle(typeName: string): boolean;
212
- /**
213
- * Get handler for a type.
214
- */
215
- getHandler(typeName: string): ResourceType | undefined;
216
- /**
217
- * Serialize RXR content using the appropriate type handler.
218
- */
219
- serialize(rxr: RXR): Promise<Buffer>;
220
- /**
221
- * Deserialize content into RXR using the appropriate type handler.
222
- */
223
- deserialize(data: Buffer, manifest: RXM): Promise<RXR>;
224
- /**
225
- * Resolve RXR content into usable object using the appropriate type handler.
226
- */
227
- resolve<T = unknown>(rxr: RXR): Promise<T>;
228
- }
229
- /**
230
- * Create a new TypeHandlerChain with optional initial types.
231
- */
232
- declare function createTypeHandlerChain(types?: ResourceType[]): TypeHandlerChain;
233
- /**
234
- * Default ResourceLoader implementation for loading resources from folders.
235
- *
236
- * Expected folder structure:
237
- * ```
238
- * folder/
239
- * ├── resource.json # Resource metadata (required)
240
- * └── content # Resource content (required)
241
- * ```
242
- *
243
- * resource.json format:
244
- * ```json
245
- * {
246
- * "name": "resource-name", // required
247
- * "type": "text", // required
248
- * "version": "1.0.0", // required
249
- * "domain": "localhost", // optional, defaults to "localhost"
250
- * "path": "optional/path" // optional
251
- * }
252
- * ```
253
- */
254
- declare class FolderLoader implements ResourceLoader {
255
- canLoad(source: string): Promise<boolean>;
256
- load(folderPath: string): Promise<RXR>;
257
- }
258
- /**
259
- * Configuration options for loadResource.
260
- */
261
- interface LoadResourceConfig {
262
- /**
263
- * Custom loader to use. If not provided, defaults to FolderLoader.
264
- */
265
- loader?: ResourceLoader;
266
- }
267
- /**
268
- * Load a resource from a given source using a ResourceLoader.
269
- *
270
- * By default, uses FolderLoader which expects:
271
- * ```
272
- * folder/
273
- * ├── resource.json # Resource metadata
274
- * └── content # Resource content
275
- * ```
276
- *
277
- * You can provide a custom loader via config.loader to support other formats
278
- * (e.g., zip, tar.gz, URLs).
279
- *
280
- * @param source - Source path or identifier
281
- * @param config - Optional configuration
282
- * @returns Complete RXR object ready for registry.link()
283
- * @throws ResourceXError if the source cannot be loaded
284
- *
285
- * @example
286
- * ```typescript
287
- * // Load from folder (default)
288
- * const rxr = await loadResource("./my-resource");
289
- * await registry.link(rxr);
290
- *
291
- * // Load with custom loader
292
- * const rxr = await loadResource("resource.zip", {
293
- * loader: new ZipLoader()
294
- * });
295
- * ```
296
- */
297
- declare function loadResource(source: string, config?: LoadResourceConfig): Promise<RXR>;
298
- export { textType, parseRXL, loadResource, loadRXC, jsonType, getResourceType, defineResourceType, createTypeHandlerChain, createRXM, createRXC, clearResourceTypes, builtinTypes, binaryType, TypeHandlerChain, ResourceXError, ResourceTypeError, ResourceType, ResourceSerializer, ResourceResolver, ResourceLoader, RXR, RXM, RXL, RXC, ManifestError, ManifestData, LocatorError, LoadResourceConfig, FolderLoader, ContentError };
93
+ export { parseRXL, createRXM, createRXC, ResourceXError, RXR, RXM, RXL, RXCInput, RXC, ManifestError, ManifestData, LocatorError, ContentError };