@resourcexjs/core 0.4.0 → 0.7.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/dist/index.js CHANGED
@@ -6,521 +6,406 @@ class ResourceXError extends Error {
6
6
  }
7
7
  }
8
8
 
9
- class ParseError extends ResourceXError {
10
- url;
11
- constructor(message, url) {
9
+ class LocatorError extends ResourceXError {
10
+ locator;
11
+ constructor(message, locator) {
12
12
  super(message);
13
- this.url = url;
14
- this.name = "ParseError";
13
+ this.locator = locator;
14
+ this.name = "LocatorError";
15
15
  }
16
16
  }
17
17
 
18
- class TransportError extends ResourceXError {
19
- transport;
20
- constructor(message, transport, options) {
21
- super(message, options);
22
- this.transport = transport;
23
- this.name = "TransportError";
18
+ class ManifestError extends ResourceXError {
19
+ constructor(message) {
20
+ super(message);
21
+ this.name = "ManifestError";
24
22
  }
25
23
  }
26
24
 
27
- class SemanticError extends ResourceXError {
28
- semantic;
29
- constructor(message, semantic, options) {
30
- super(message, options);
31
- this.semantic = semantic;
32
- this.name = "SemanticError";
25
+ class ContentError extends ResourceXError {
26
+ constructor(message) {
27
+ super(message);
28
+ this.name = "ContentError";
33
29
  }
34
30
  }
35
- // src/parser.ts
36
- function parseARP(url) {
37
- if (!url.startsWith("arp:")) {
38
- throw new ParseError(`Invalid ARP URL: must start with "arp:"`, url);
39
- }
40
- const content = url.substring(4);
41
- const separatorIndex = content.indexOf("://");
42
- if (separatorIndex === -1) {
43
- throw new ParseError(`Invalid ARP URL: missing "://"`, url);
44
- }
45
- const typePart = content.substring(0, separatorIndex);
46
- const location = content.substring(separatorIndex + 3);
47
- const colonIndex = typePart.indexOf(":");
48
- if (colonIndex === -1) {
49
- throw new ParseError(`Invalid ARP URL: must have exactly 2 types (semantic:transport)`, url);
50
- }
51
- const semantic = typePart.substring(0, colonIndex);
52
- const transport = typePart.substring(colonIndex + 1);
53
- if (!semantic) {
54
- throw new ParseError(`Invalid ARP URL: semantic type cannot be empty`, url);
55
- }
56
- if (!transport) {
57
- throw new ParseError(`Invalid ARP URL: transport type cannot be empty`, url);
58
- }
59
- if (!location) {
60
- throw new ParseError(`Invalid ARP URL: location cannot be empty`, url);
61
- }
62
- return { semantic, transport, location };
31
+
32
+ class ResourceTypeError extends ResourceXError {
33
+ constructor(message) {
34
+ super(message);
35
+ this.name = "ResourceTypeError";
36
+ }
63
37
  }
64
- // src/transport/http.ts
65
- class HttpTransportHandler {
38
+ // src/locator/parseRXL.ts
39
+ class RXLImpl {
40
+ domain;
41
+ path;
66
42
  name;
67
- protocol;
68
- capabilities = {
69
- canRead: true,
70
- canWrite: false,
71
- canList: false,
72
- canDelete: false,
73
- canStat: false
74
- };
75
- constructor(protocol = "https") {
76
- this.protocol = protocol;
77
- this.name = protocol;
78
- }
79
- async read(location) {
80
- const url = `${this.protocol}://${location}`;
81
- try {
82
- const response = await fetch(url);
83
- if (!response.ok) {
84
- throw new TransportError(`HTTP ${response.status}: ${response.statusText} - ${url}`, this.name);
43
+ type;
44
+ version;
45
+ constructor(parts) {
46
+ this.domain = parts.domain;
47
+ this.path = parts.path;
48
+ this.name = parts.name;
49
+ this.type = parts.type;
50
+ this.version = parts.version;
51
+ }
52
+ toString() {
53
+ let result = "";
54
+ if (this.domain) {
55
+ result += this.domain + "/";
56
+ if (this.path) {
57
+ result += this.path + "/";
85
58
  }
86
- const arrayBuffer = await response.arrayBuffer();
87
- return Buffer.from(arrayBuffer);
88
- } catch (error) {
89
- if (error instanceof TransportError) {
90
- throw error;
91
- }
92
- throw new TransportError(`Network error: ${url}`, this.name, {
93
- cause: error
94
- });
95
59
  }
60
+ result += this.name;
61
+ if (this.type) {
62
+ result += "." + this.type;
63
+ }
64
+ if (this.version) {
65
+ result += "@" + this.version;
66
+ }
67
+ return result;
96
68
  }
97
69
  }
98
- var httpsHandler = new HttpTransportHandler("https");
99
- var httpHandler = new HttpTransportHandler("http");
100
- // src/transport/file.ts
101
- import { readFile, writeFile, readdir, mkdir, rm, access, stat as fsStat } from "node:fs/promises";
102
- import { resolve, dirname } from "node:path";
103
- class FileTransportHandler {
104
- name = "file";
105
- capabilities = {
106
- canRead: true,
107
- canWrite: true,
108
- canList: true,
109
- canDelete: true,
110
- canStat: true
111
- };
112
- resolvePath(location) {
113
- return resolve(process.cwd(), location);
114
- }
115
- async read(location) {
116
- const filePath = this.resolvePath(location);
117
- try {
118
- return await readFile(filePath);
119
- } catch (error) {
120
- const err = error;
121
- throw new TransportError(`File read error: ${err.code} - ${filePath}`, this.name, {
122
- cause: err
123
- });
70
+ function isDomain(str) {
71
+ if (str === "localhost")
72
+ return true;
73
+ return str.includes(".");
74
+ }
75
+ function parseRXL(locator) {
76
+ let remaining = locator;
77
+ let version;
78
+ let type;
79
+ let domain;
80
+ let path;
81
+ let name;
82
+ const atIndex = remaining.indexOf("@");
83
+ if (atIndex !== -1) {
84
+ version = remaining.slice(atIndex + 1);
85
+ remaining = remaining.slice(0, atIndex);
86
+ }
87
+ const segments = remaining.split("/");
88
+ if (segments.length > 1 && isDomain(segments[0])) {
89
+ domain = segments[0];
90
+ const lastSegment = segments[segments.length - 1];
91
+ if (segments.length > 2) {
92
+ path = segments.slice(1, -1).join("/");
124
93
  }
125
- }
126
- async write(location, content) {
127
- const filePath = this.resolvePath(location);
128
- try {
129
- await mkdir(dirname(filePath), { recursive: true });
130
- await writeFile(filePath, content);
131
- } catch (error) {
132
- const err = error;
133
- throw new TransportError(`File write error: ${err.code} - ${filePath}`, this.name, {
134
- cause: err
135
- });
94
+ remaining = lastSegment;
95
+ } else {
96
+ remaining = segments.join("/");
97
+ }
98
+ const dotIndex = remaining.lastIndexOf(".");
99
+ if (dotIndex !== -1) {
100
+ type = remaining.slice(dotIndex + 1);
101
+ name = remaining.slice(0, dotIndex);
102
+ } else {
103
+ name = remaining;
104
+ }
105
+ return new RXLImpl({ domain, path, name, type, version });
106
+ }
107
+ // src/manifest/createRXM.ts
108
+ class RXMImpl {
109
+ domain;
110
+ path;
111
+ name;
112
+ type;
113
+ version;
114
+ constructor(data) {
115
+ this.domain = data.domain;
116
+ this.path = data.path;
117
+ this.name = data.name;
118
+ this.type = data.type;
119
+ this.version = data.version;
120
+ }
121
+ toLocator() {
122
+ let result = this.domain + "/";
123
+ if (this.path) {
124
+ result += this.path + "/";
136
125
  }
137
- }
138
- async list(location) {
139
- const dirPath = this.resolvePath(location);
140
- try {
141
- return await readdir(dirPath);
142
- } catch (error) {
143
- const err = error;
144
- throw new TransportError(`Directory list error: ${err.code} - ${dirPath}`, this.name, {
145
- cause: err
146
- });
126
+ result += this.name;
127
+ result += "." + this.type;
128
+ result += "@" + this.version;
129
+ return result;
130
+ }
131
+ toJSON() {
132
+ const json = {
133
+ domain: this.domain,
134
+ name: this.name,
135
+ type: this.type,
136
+ version: this.version
137
+ };
138
+ if (this.path !== undefined) {
139
+ json.path = this.path;
147
140
  }
141
+ return json;
148
142
  }
149
- async mkdir(location) {
150
- const dirPath = this.resolvePath(location);
151
- try {
152
- await mkdir(dirPath, { recursive: true });
153
- } catch (error) {
154
- const err = error;
155
- throw new TransportError(`Directory create error: ${err.code} - ${dirPath}`, this.name, {
156
- cause: err
157
- });
143
+ }
144
+ function createRXM(data) {
145
+ if (!data.domain) {
146
+ throw new ManifestError("domain is required");
147
+ }
148
+ if (!data.name) {
149
+ throw new ManifestError("name is required");
150
+ }
151
+ if (!data.type) {
152
+ throw new ManifestError("type is required");
153
+ }
154
+ if (!data.version) {
155
+ throw new ManifestError("version is required");
156
+ }
157
+ return new RXMImpl({
158
+ domain: data.domain,
159
+ path: data.path,
160
+ name: data.name,
161
+ type: data.type,
162
+ version: data.version
163
+ });
164
+ }
165
+ // src/content/createRXC.ts
166
+ class RXCImpl {
167
+ _stream;
168
+ _consumed = false;
169
+ constructor(stream) {
170
+ this._stream = stream;
171
+ }
172
+ get stream() {
173
+ if (this._consumed) {
174
+ throw new ContentError("Content has already been consumed");
158
175
  }
176
+ this._consumed = true;
177
+ return this._stream;
159
178
  }
160
- async exists(location) {
161
- const filePath = this.resolvePath(location);
162
- try {
163
- await access(filePath);
164
- return true;
165
- } catch {
166
- return false;
167
- }
179
+ async text() {
180
+ const buffer = await this.buffer();
181
+ return buffer.toString("utf-8");
168
182
  }
169
- async stat(location) {
170
- const filePath = this.resolvePath(location);
171
- try {
172
- const stats = await fsStat(filePath);
173
- return {
174
- size: stats.size,
175
- modifiedAt: stats.mtime,
176
- isDirectory: stats.isDirectory()
177
- };
178
- } catch (error) {
179
- const err = error;
180
- throw new TransportError(`File stat error: ${err.code} - ${filePath}`, this.name, {
181
- cause: err
182
- });
183
+ async buffer() {
184
+ if (this._consumed) {
185
+ throw new ContentError("Content has already been consumed");
183
186
  }
184
- }
185
- async delete(location) {
186
- const filePath = this.resolvePath(location);
187
- try {
188
- await rm(filePath, { recursive: true });
189
- } catch (error) {
190
- const err = error;
191
- throw new TransportError(`File delete error: ${err.code} - ${filePath}`, this.name, {
192
- cause: err
193
- });
187
+ this._consumed = true;
188
+ const reader = this._stream.getReader();
189
+ const chunks = [];
190
+ while (true) {
191
+ const { done, value } = await reader.read();
192
+ if (done)
193
+ break;
194
+ chunks.push(value);
194
195
  }
196
+ return Buffer.concat(chunks);
197
+ }
198
+ async json() {
199
+ const text = await this.text();
200
+ return JSON.parse(text);
195
201
  }
196
202
  }
197
- var fileHandler = new FileTransportHandler;
198
- // src/transport/deepractice.ts
199
- import { homedir } from "node:os";
200
- import { join } from "node:path";
201
- import { readFile as readFile2, writeFile as writeFile2, readdir as readdir2, access as access2, unlink, mkdir as mkdir2, stat, rm as rm2 } from "node:fs/promises";
202
- function deepracticeHandler(config = {}) {
203
- const parentDir = config.parentDir || homedir();
204
- const baseDir = join(parentDir, ".deepractice");
205
- function resolvePath(location) {
206
- return join(baseDir, location);
207
- }
208
- return {
209
- name: "deepractice",
210
- capabilities: {
211
- canRead: true,
212
- canWrite: true,
213
- canList: true,
214
- canDelete: true,
215
- canStat: true
216
- },
217
- async read(location) {
218
- const fullPath = resolvePath(location);
219
- try {
220
- return await readFile2(fullPath);
221
- } catch (error) {
222
- throw new TransportError(`Failed to read from deepractice: ${error.message}`, "deepractice", { cause: error });
223
- }
224
- },
225
- async write(location, content) {
226
- const fullPath = resolvePath(location);
227
- try {
228
- await mkdir2(join(fullPath, ".."), { recursive: true });
229
- await writeFile2(fullPath, content);
230
- } catch (error) {
231
- throw new TransportError(`Failed to write to deepractice: ${error.message}`, "deepractice", { cause: error });
203
+ function createRXC(data) {
204
+ let stream;
205
+ if (typeof data === "string") {
206
+ const encoded = new TextEncoder().encode(data);
207
+ stream = new ReadableStream({
208
+ start(controller) {
209
+ controller.enqueue(encoded);
210
+ controller.close();
232
211
  }
233
- },
234
- async list(location) {
235
- const fullPath = resolvePath(location);
236
- try {
237
- return await readdir2(fullPath);
238
- } catch (error) {
239
- throw new TransportError(`Failed to list deepractice directory: ${error.message}`, "deepractice", { cause: error });
240
- }
241
- },
242
- async exists(location) {
243
- const fullPath = resolvePath(location);
244
- try {
245
- await access2(fullPath);
246
- return true;
247
- } catch {
248
- return false;
249
- }
250
- },
251
- async stat(location) {
252
- const fullPath = resolvePath(location);
253
- try {
254
- const stats = await stat(fullPath);
255
- return {
256
- size: stats.size,
257
- isDirectory: stats.isDirectory(),
258
- modifiedAt: stats.mtime
259
- };
260
- } catch (error) {
261
- throw new TransportError(`Failed to stat deepractice resource: ${error.message}`, "deepractice", { cause: error });
262
- }
263
- },
264
- async delete(location) {
265
- const fullPath = resolvePath(location);
266
- try {
267
- const stats = await stat(fullPath);
268
- if (stats.isDirectory()) {
269
- await rm2(fullPath, { recursive: true, force: true });
270
- } else {
271
- await unlink(fullPath);
272
- }
273
- } catch (error) {
274
- throw new TransportError(`Failed to delete from deepractice: ${error.message}`, "deepractice", { cause: error });
212
+ });
213
+ } else if (Buffer.isBuffer(data)) {
214
+ stream = new ReadableStream({
215
+ start(controller) {
216
+ controller.enqueue(new Uint8Array(data));
217
+ controller.close();
275
218
  }
219
+ });
220
+ } else {
221
+ stream = data;
222
+ }
223
+ return new RXCImpl(stream);
224
+ }
225
+ // src/content/loadRXC.ts
226
+ import { createReadStream } from "node:fs";
227
+ import { Readable } from "node:stream";
228
+ async function loadRXC(source) {
229
+ if (source.startsWith("http://") || source.startsWith("https://")) {
230
+ const response = await fetch(source);
231
+ if (!response.ok) {
232
+ throw new Error(`Failed to fetch ${source}: ${response.statusText}`);
233
+ }
234
+ if (!response.body) {
235
+ throw new Error(`No body in response from ${source}`);
276
236
  }
277
- };
237
+ return createRXC(response.body);
238
+ }
239
+ const nodeStream = createReadStream(source);
240
+ const webStream = Readable.toWeb(nodeStream);
241
+ return createRXC(webStream);
278
242
  }
279
- // src/transport/index.ts
280
- var handlers = new Map([
281
- ["https", httpsHandler],
282
- ["http", httpHandler],
283
- ["file", fileHandler]
284
- ]);
285
- function getTransportHandler(name) {
286
- const handler = handlers.get(name);
287
- if (!handler) {
288
- throw new TransportError(`Unsupported transport type: ${name}`, name);
289
- }
290
- return handler;
243
+ // src/resource/defineResourceType.ts
244
+ var resourceTypes = new Map;
245
+ function defineResourceType(config) {
246
+ if (resourceTypes.has(config.name)) {
247
+ throw new ResourceTypeError(`Resource type "${config.name}" is already registered`);
248
+ }
249
+ resourceTypes.set(config.name, config);
250
+ return config;
291
251
  }
292
- function registerTransportHandler(handler) {
293
- handlers.set(handler.name, handler);
252
+ function getResourceType(name) {
253
+ return resourceTypes.get(name);
294
254
  }
295
- // src/semantic/text.ts
296
- class TextSemanticHandler {
297
- name = "text";
298
- async resolve(transport, location, context) {
299
- const buffer = await transport.read(location);
300
- const text = buffer.toString("utf-8");
301
- const meta = {
302
- url: context.url,
303
- semantic: context.semantic,
304
- transport: context.transport,
305
- location: context.location,
306
- size: buffer.length,
307
- encoding: "utf-8",
308
- mimeType: "text/plain",
309
- resolvedAt: context.timestamp.toISOString()
310
- };
255
+ function clearResourceTypes() {
256
+ resourceTypes.clear();
257
+ }
258
+ // src/resource/builtinTypes.ts
259
+ var textSerializer = {
260
+ async serialize(rxr) {
261
+ const text = await rxr.content.text();
262
+ return Buffer.from(text, "utf-8");
263
+ },
264
+ async deserialize(data, manifest) {
265
+ const text = data.toString("utf-8");
311
266
  return {
312
- type: "text",
313
- content: text,
314
- meta
267
+ locator: parseRXL(manifest.toLocator()),
268
+ manifest,
269
+ content: createRXC(text)
315
270
  };
316
271
  }
317
- async deposit(transport, location, data, _context) {
318
- if (!transport.write) {
319
- throw new SemanticError(`Transport "${transport.name}" does not support write operation`, this.name);
320
- }
321
- const buffer = Buffer.from(data, "utf-8");
322
- await transport.write(location, buffer);
272
+ };
273
+ var textResolver = {
274
+ async resolve(rxr) {
275
+ return rxr.content.text();
323
276
  }
324
- async exists(transport, location, _context) {
325
- if (transport.exists) {
326
- return transport.exists(location);
327
- }
328
- try {
329
- await transport.read(location);
330
- return true;
331
- } catch {
332
- return false;
333
- }
277
+ };
278
+ var textType = {
279
+ name: "text",
280
+ aliases: ["txt", "plaintext"],
281
+ description: "Plain text content",
282
+ serializer: textSerializer,
283
+ resolver: textResolver
284
+ };
285
+ var jsonSerializer = {
286
+ async serialize(rxr) {
287
+ const json = await rxr.content.json();
288
+ return Buffer.from(JSON.stringify(json, null, 2), "utf-8");
289
+ },
290
+ async deserialize(data, manifest) {
291
+ const text = data.toString("utf-8");
292
+ return {
293
+ locator: parseRXL(manifest.toLocator()),
294
+ manifest,
295
+ content: createRXC(text)
296
+ };
334
297
  }
335
- async delete(transport, location, _context) {
336
- if (!transport.delete) {
337
- throw new SemanticError(`Transport "${transport.name}" does not support delete operation`, this.name);
338
- }
339
- await transport.delete(location);
298
+ };
299
+ var jsonResolver = {
300
+ async resolve(rxr) {
301
+ return rxr.content.json();
340
302
  }
341
- }
342
- var textHandler = new TextSemanticHandler;
343
- // src/semantic/binary.ts
344
- function toBuffer(data) {
345
- if (Buffer.isBuffer(data)) {
346
- return data;
303
+ };
304
+ var jsonType = {
305
+ name: "json",
306
+ aliases: ["config", "manifest"],
307
+ description: "JSON content",
308
+ serializer: jsonSerializer,
309
+ resolver: jsonResolver
310
+ };
311
+ var binarySerializer = {
312
+ async serialize(rxr) {
313
+ return rxr.content.buffer();
314
+ },
315
+ async deserialize(data, manifest) {
316
+ return {
317
+ locator: parseRXL(manifest.toLocator()),
318
+ manifest,
319
+ content: createRXC(data)
320
+ };
347
321
  }
348
- if (data instanceof Uint8Array) {
349
- return Buffer.from(data);
322
+ };
323
+ var binaryResolver = {
324
+ async resolve(rxr) {
325
+ return rxr.content.buffer();
350
326
  }
351
- if (data instanceof ArrayBuffer) {
352
- return Buffer.from(data);
327
+ };
328
+ var binaryType = {
329
+ name: "binary",
330
+ aliases: ["bin", "blob", "raw"],
331
+ description: "Binary content",
332
+ serializer: binarySerializer,
333
+ resolver: binaryResolver
334
+ };
335
+ var builtinTypes = [textType, jsonType, binaryType];
336
+ // src/resource/TypeHandlerChain.ts
337
+ class TypeHandlerChain {
338
+ handlers = new Map;
339
+ register(type) {
340
+ this.handlers.set(type.name, type);
341
+ if (type.aliases) {
342
+ for (const alias of type.aliases) {
343
+ this.handlers.set(alias, type);
344
+ }
345
+ }
353
346
  }
354
- if (Array.isArray(data)) {
355
- return Buffer.from(data);
347
+ registerAll(types) {
348
+ for (const type of types) {
349
+ this.register(type);
350
+ }
356
351
  }
357
- throw new SemanticError(`Unsupported binary input type`, "binary");
358
- }
359
-
360
- class BinarySemanticHandler {
361
- name = "binary";
362
- async resolve(transport, location, context) {
363
- const buffer = await transport.read(location);
364
- const meta = {
365
- url: context.url,
366
- semantic: context.semantic,
367
- transport: context.transport,
368
- location: context.location,
369
- size: buffer.length,
370
- resolvedAt: context.timestamp.toISOString()
371
- };
372
- return {
373
- type: "binary",
374
- content: buffer,
375
- meta
376
- };
352
+ canHandle(typeName) {
353
+ return this.handlers.has(typeName);
377
354
  }
378
- async deposit(transport, location, data, _context) {
379
- if (!transport.write) {
380
- throw new SemanticError(`Transport "${transport.name}" does not support write operation`, this.name);
381
- }
382
- const buffer = toBuffer(data);
383
- await transport.write(location, buffer);
355
+ getHandler(typeName) {
356
+ return this.handlers.get(typeName);
384
357
  }
385
- async exists(transport, location, _context) {
386
- if (transport.exists) {
387
- return transport.exists(location);
358
+ async serialize(rxr) {
359
+ const typeName = rxr.manifest.type;
360
+ const handler = this.handlers.get(typeName);
361
+ if (!handler) {
362
+ throw new ResourceTypeError(`Unsupported resource type: ${typeName}`);
388
363
  }
389
- try {
390
- await transport.read(location);
391
- return true;
392
- } catch {
393
- return false;
364
+ return handler.serializer.serialize(rxr);
365
+ }
366
+ async deserialize(data, manifest) {
367
+ const typeName = manifest.type;
368
+ const handler = this.handlers.get(typeName);
369
+ if (!handler) {
370
+ throw new ResourceTypeError(`Unsupported resource type: ${typeName}`);
394
371
  }
372
+ return handler.serializer.deserialize(data, manifest);
395
373
  }
396
- async delete(transport, location, _context) {
397
- if (!transport.delete) {
398
- throw new SemanticError(`Transport "${transport.name}" does not support delete operation`, this.name);
374
+ async resolve(rxr) {
375
+ const typeName = rxr.manifest.type;
376
+ const handler = this.handlers.get(typeName);
377
+ if (!handler) {
378
+ throw new ResourceTypeError(`Unsupported resource type: ${typeName}`);
399
379
  }
400
- await transport.delete(location);
380
+ return handler.resolver.resolve(rxr);
401
381
  }
402
382
  }
403
- var binaryHandler = new BinarySemanticHandler;
404
- // src/semantic/index.ts
405
- var handlers2 = new Map([
406
- ["text", textHandler],
407
- ["binary", binaryHandler]
408
- ]);
409
- function getSemanticHandler(name) {
410
- const handler = handlers2.get(name);
411
- if (!handler) {
412
- throw new SemanticError(`Unsupported semantic type: ${name}`, name);
413
- }
414
- return handler;
415
- }
416
- function registerSemanticHandler(handler) {
417
- handlers2.set(handler.name, handler);
418
- }
419
- // src/resolve.ts
420
- function createContext(url, semantic, transport, location) {
421
- return {
422
- url,
423
- semantic,
424
- transport,
425
- location,
426
- timestamp: new Date
427
- };
428
- }
429
- async function resolve2(url) {
430
- const parsed = parseARP(url);
431
- const transport = getTransportHandler(parsed.transport);
432
- const semantic = getSemanticHandler(parsed.semantic);
433
- const context = createContext(url, parsed.semantic, parsed.transport, parsed.location);
434
- return semantic.resolve(transport, parsed.location, context);
435
- }
436
- async function deposit(url, data) {
437
- const parsed = parseARP(url);
438
- const transport = getTransportHandler(parsed.transport);
439
- const semantic = getSemanticHandler(parsed.semantic);
440
- if (!semantic.deposit) {
441
- throw new SemanticError(`Semantic "${semantic.name}" does not support deposit operation`, parsed.semantic);
442
- }
443
- const context = createContext(url, parsed.semantic, parsed.transport, parsed.location);
444
- await semantic.deposit(transport, parsed.location, data, context);
445
- }
446
- async function resourceExists(url) {
447
- const parsed = parseARP(url);
448
- const transport = getTransportHandler(parsed.transport);
449
- const semantic = getSemanticHandler(parsed.semantic);
450
- const context = createContext(url, parsed.semantic, parsed.transport, parsed.location);
451
- if (semantic.exists) {
452
- return semantic.exists(transport, parsed.location, context);
453
- }
454
- if (transport.exists) {
455
- return transport.exists(parsed.location);
456
- }
457
- try {
458
- await transport.read(parsed.location);
459
- return true;
460
- } catch {
461
- return false;
383
+ function createTypeHandlerChain(types) {
384
+ const chain = new TypeHandlerChain;
385
+ if (types) {
386
+ chain.registerAll(types);
462
387
  }
388
+ return chain;
463
389
  }
464
- async function resourceDelete(url) {
465
- const parsed = parseARP(url);
466
- const transport = getTransportHandler(parsed.transport);
467
- const semantic = getSemanticHandler(parsed.semantic);
468
- const context = createContext(url, parsed.semantic, parsed.transport, parsed.location);
469
- if (semantic.delete) {
470
- return semantic.delete(transport, parsed.location, context);
471
- }
472
- if (!transport.delete) {
473
- throw new SemanticError(`Neither semantic "${semantic.name}" nor transport "${transport.name}" supports delete operation`, parsed.semantic);
474
- }
475
- await transport.delete(parsed.location);
476
- }
477
- // src/resource/registry.ts
478
- function createResourceRegistry() {
479
- const registry = new Map;
480
- return {
481
- register(definition) {
482
- if (!/^[a-z][a-z0-9-]*$/.test(definition.name)) {
483
- throw new ParseError(`Invalid resource name: "${definition.name}". Must start with lowercase letter and contain only lowercase letters, numbers, and hyphens.`, definition.name);
484
- }
485
- getSemanticHandler(definition.semantic);
486
- getTransportHandler(definition.transport);
487
- registry.set(definition.name, definition);
488
- },
489
- get(name) {
490
- return registry.get(name);
491
- },
492
- has(name) {
493
- return registry.has(name);
494
- },
495
- clear() {
496
- registry.clear();
497
- }
498
- };
499
- }
500
- // src/index.ts
501
- var VERSION = "0.4.0";
502
390
  export {
503
- textHandler,
504
- resourceExists,
505
- resourceDelete,
506
- resolve2 as resolve,
507
- registerTransportHandler,
508
- registerSemanticHandler,
509
- parseARP,
510
- httpsHandler,
511
- httpHandler,
512
- getTransportHandler,
513
- getSemanticHandler,
514
- fileHandler,
515
- deposit,
516
- deepracticeHandler,
517
- createResourceRegistry,
518
- binaryHandler,
519
- VERSION,
520
- TransportError,
521
- SemanticError,
391
+ textType,
392
+ parseRXL,
393
+ loadRXC,
394
+ jsonType,
395
+ getResourceType,
396
+ defineResourceType,
397
+ createTypeHandlerChain,
398
+ createRXM,
399
+ createRXC,
400
+ clearResourceTypes,
401
+ builtinTypes,
402
+ binaryType,
403
+ TypeHandlerChain,
522
404
  ResourceXError,
523
- ParseError
405
+ ResourceTypeError,
406
+ ManifestError,
407
+ LocatorError,
408
+ ContentError
524
409
  };
525
410
 
526
- //# debugId=7CEC90BE3B5822A664756E2164756E21
411
+ //# debugId=B9B3CCB31ADA300B64756E2164756E21