@resourcexjs/core 2.4.1 → 2.5.1

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
@@ -28,135 +28,56 @@ class ContentError extends ResourceXError {
28
28
  this.name = "ContentError";
29
29
  }
30
30
  }
31
- // src/locator/parseRXL.ts
32
- class RXLImpl {
33
- domain;
34
- path;
35
- name;
36
- type;
37
- version;
38
- constructor(parts) {
39
- this.domain = parts.domain;
40
- this.path = parts.path;
41
- this.name = parts.name;
42
- this.type = parts.type;
43
- this.version = parts.version;
44
- }
45
- toString() {
46
- let result = "";
47
- if (this.domain) {
48
- result += this.domain + "/";
49
- if (this.path) {
50
- result += this.path + "/";
51
- }
52
- }
53
- result += this.name;
54
- if (this.type) {
55
- result += "." + this.type;
56
- }
57
- if (this.version) {
58
- result += "@" + this.version;
59
- }
60
- return result;
31
+
32
+ class DefinitionError extends ResourceXError {
33
+ constructor(message) {
34
+ super(message);
35
+ this.name = "DefinitionError";
61
36
  }
62
37
  }
63
- function isDomain(str) {
64
- if (str === "localhost")
65
- return true;
66
- return str.includes(".");
67
- }
68
- function parseRXL(locator) {
69
- let remaining = locator;
70
- let version;
71
- let type;
72
- let domain;
73
- let path;
74
- let name;
75
- const atIndex = remaining.indexOf("@");
76
- if (atIndex !== -1) {
77
- version = remaining.slice(atIndex + 1);
78
- remaining = remaining.slice(0, atIndex);
79
- }
80
- const segments = remaining.split("/");
81
- if (segments.length > 1 && isDomain(segments[0])) {
82
- domain = segments[0];
83
- const lastSegment = segments[segments.length - 1];
84
- if (segments.length > 2) {
85
- path = segments.slice(1, -1).join("/");
86
- }
87
- remaining = lastSegment;
88
- } else {
89
- remaining = segments.join("/");
38
+ // src/primitives/define.ts
39
+ function define(input) {
40
+ if (input === null || typeof input !== "object") {
41
+ throw new DefinitionError("definition must be an object");
90
42
  }
91
- const dotIndex = remaining.lastIndexOf(".");
92
- if (dotIndex !== -1) {
93
- type = remaining.slice(dotIndex + 1);
94
- name = remaining.slice(0, dotIndex);
95
- } else {
96
- name = remaining;
43
+ const obj = input;
44
+ if (!obj.name || typeof obj.name !== "string") {
45
+ throw new DefinitionError("name is required");
97
46
  }
98
- return new RXLImpl({ domain, path, name, type, version });
99
- }
100
- // src/manifest/createRXM.ts
101
- class RXMImpl {
102
- domain;
103
- path;
104
- name;
105
- type;
106
- version;
107
- constructor(data) {
108
- this.domain = data.domain;
109
- this.path = data.path;
110
- this.name = data.name;
111
- this.type = data.type;
112
- this.version = data.version;
47
+ if (!obj.type || typeof obj.type !== "string") {
48
+ throw new DefinitionError("type is required");
113
49
  }
114
- toLocator() {
115
- let result = this.domain + "/";
116
- if (this.path) {
117
- result += this.path + "/";
118
- }
119
- result += this.name;
120
- result += "." + this.type;
121
- result += "@" + this.version;
122
- return result;
123
- }
124
- toJSON() {
125
- const json = {
126
- domain: this.domain,
127
- name: this.name,
128
- type: this.type,
129
- version: this.version
130
- };
131
- if (this.path !== undefined) {
132
- json.path = this.path;
133
- }
134
- return json;
50
+ const tagValue = obj.tag ?? obj.version;
51
+ if (tagValue !== undefined && typeof tagValue !== "string") {
52
+ throw new DefinitionError("tag must be a string");
135
53
  }
54
+ const rxd = {
55
+ ...obj,
56
+ name: obj.name,
57
+ type: obj.type,
58
+ tag: typeof tagValue === "string" ? tagValue : undefined,
59
+ registry: typeof obj.registry === "string" ? obj.registry : undefined,
60
+ path: typeof obj.path === "string" ? obj.path : undefined,
61
+ description: typeof obj.description === "string" ? obj.description : undefined,
62
+ author: typeof obj.author === "string" ? obj.author : undefined,
63
+ license: typeof obj.license === "string" ? obj.license : undefined,
64
+ keywords: Array.isArray(obj.keywords) ? obj.keywords : undefined,
65
+ repository: typeof obj.repository === "string" ? obj.repository : undefined
66
+ };
67
+ return rxd;
136
68
  }
137
- function createRXM(data) {
138
- if (!data.domain) {
139
- throw new ManifestError("domain is required");
140
- }
141
- if (!data.name) {
142
- throw new ManifestError("name is required");
143
- }
144
- if (!data.type) {
145
- throw new ManifestError("type is required");
146
- }
147
- if (!data.version) {
148
- throw new ManifestError("version is required");
149
- }
150
- return new RXMImpl({
151
- domain: data.domain,
152
- path: data.path,
153
- name: data.name,
154
- type: data.type,
155
- version: data.version
156
- });
69
+ // src/primitives/manifest.ts
70
+ function manifest(rxd) {
71
+ return {
72
+ registry: rxd.registry,
73
+ path: rxd.path,
74
+ name: rxd.name,
75
+ type: rxd.type,
76
+ tag: rxd.tag ?? "latest"
77
+ };
157
78
  }
158
- // src/archive/createRXA.ts
159
- import { gzip, gunzip } from "node:zlib";
79
+ // src/primitives/archive.ts
80
+ import { gzip } from "node:zlib";
160
81
  import { promisify } from "node:util";
161
82
 
162
83
  // ../../node_modules/.bun/modern-tar@0.7.3/node_modules/modern-tar/dist/unpacker-BpPBxY8N.js
@@ -1136,85 +1057,159 @@ async function unpackTar(archive, options = {}) {
1136
1057
  return results;
1137
1058
  }
1138
1059
 
1139
- // src/archive/createRXA.ts
1060
+ // src/primitives/archive.ts
1140
1061
  var gzipAsync = promisify(gzip);
1141
- var gunzipAsync = promisify(gunzip);
1142
1062
 
1143
- class RXPImpl {
1144
- _files;
1145
- _pathsCache = null;
1146
- _treeCache = null;
1147
- constructor(files) {
1148
- this._files = files;
1149
- }
1150
- paths() {
1151
- if (this._pathsCache) {
1152
- return this._pathsCache;
1153
- }
1154
- this._pathsCache = Array.from(this._files.keys()).sort();
1155
- return this._pathsCache;
1063
+ class RXAImpl {
1064
+ _buffer;
1065
+ constructor(buffer) {
1066
+ this._buffer = buffer;
1156
1067
  }
1157
- tree() {
1158
- if (this._treeCache) {
1159
- return this._treeCache;
1160
- }
1161
- const root = new Map;
1162
- for (const path of this._files.keys()) {
1163
- const parts = path.split("/");
1164
- let currentLevel = root;
1165
- for (let i = 0;i < parts.length; i++) {
1166
- const part = parts[i];
1167
- const isFile = i === parts.length - 1;
1168
- if (!currentLevel.has(part)) {
1169
- const treeNode2 = {
1170
- node: {
1171
- name: part,
1172
- type: isFile ? "file" : "directory",
1173
- children: isFile ? undefined : []
1174
- },
1175
- children: new Map
1176
- };
1177
- currentLevel.set(part, treeNode2);
1178
- }
1179
- const treeNode = currentLevel.get(part);
1180
- if (!isFile) {
1181
- currentLevel = treeNode.children;
1182
- }
1068
+ get stream() {
1069
+ const buffer = this._buffer;
1070
+ return new ReadableStream({
1071
+ start(controller) {
1072
+ controller.enqueue(new Uint8Array(buffer));
1073
+ controller.close();
1183
1074
  }
1184
- }
1185
- const convertToPathNodes = (level) => {
1186
- return Array.from(level.values()).map((treeNode) => {
1187
- if (treeNode.node.type === "directory" && treeNode.children.size > 0) {
1188
- treeNode.node.children = convertToPathNodes(treeNode.children);
1189
- }
1190
- return treeNode.node;
1191
- });
1192
- };
1193
- this._treeCache = convertToPathNodes(root);
1194
- return this._treeCache;
1075
+ });
1076
+ }
1077
+ async buffer() {
1078
+ return this._buffer;
1195
1079
  }
1196
- async file(path) {
1197
- const content = this._files.get(path);
1198
- if (!content) {
1199
- throw new ContentError(`file not found: ${path}`);
1080
+ }
1081
+ async function archive(files) {
1082
+ const entries = Object.entries(files).map(([name, content]) => {
1083
+ return {
1084
+ header: { name, size: content.length, type: "file" },
1085
+ body: new Uint8Array(content)
1086
+ };
1087
+ });
1088
+ const tarBuffer = await packTar(entries);
1089
+ const gzipBuffer = await gzipAsync(Buffer.from(tarBuffer));
1090
+ return new RXAImpl(gzipBuffer);
1091
+ }
1092
+ // src/primitives/locate.ts
1093
+ function locate(rxm) {
1094
+ return {
1095
+ registry: rxm.registry,
1096
+ path: rxm.path,
1097
+ name: rxm.name,
1098
+ tag: rxm.tag
1099
+ };
1100
+ }
1101
+ // src/primitives/resource.ts
1102
+ function resource(rxm, rxa) {
1103
+ const rxl = locate(rxm);
1104
+ return {
1105
+ locator: rxl,
1106
+ manifest: rxm,
1107
+ archive: rxa
1108
+ };
1109
+ }
1110
+ // src/primitives/extract.ts
1111
+ import { gunzip } from "node:zlib";
1112
+ import { promisify as promisify2 } from "node:util";
1113
+ var gunzipAsync = promisify2(gunzip);
1114
+ async function extract(rxa) {
1115
+ const buffer = await rxa.buffer();
1116
+ const tarBuffer = await gunzipAsync(buffer);
1117
+ const entries = await unpackTar(tarBuffer);
1118
+ const files = {};
1119
+ for (const entry of entries) {
1120
+ if ((entry.header.type === "file" || entry.header.type === undefined) && entry.data) {
1121
+ files[entry.header.name] = Buffer.from(entry.data);
1200
1122
  }
1201
- return content;
1202
1123
  }
1203
- async files() {
1204
- return new Map(this._files);
1124
+ return files;
1125
+ }
1126
+ // src/primitives/format.ts
1127
+ function format(rxl) {
1128
+ let result = "";
1129
+ if (rxl.registry) {
1130
+ result += rxl.registry + "/";
1205
1131
  }
1206
- async pack() {
1207
- const filesRecord = {};
1208
- for (const [path, content] of this._files) {
1209
- filesRecord[path] = content;
1210
- }
1211
- return createRXA(filesRecord);
1132
+ if (rxl.path) {
1133
+ result += rxl.path + "/";
1212
1134
  }
1135
+ result += rxl.name;
1136
+ if (rxl.tag && rxl.tag !== "latest") {
1137
+ result += ":" + rxl.tag;
1138
+ }
1139
+ return result;
1213
1140
  }
1214
-
1215
- class RXAImpl {
1141
+ // src/primitives/parse.ts
1142
+ function looksLikeRegistry(str) {
1143
+ if (str.includes(":") && !str.includes("/")) {
1144
+ return true;
1145
+ }
1146
+ if (str.includes(".")) {
1147
+ return true;
1148
+ }
1149
+ if (str === "localhost") {
1150
+ return true;
1151
+ }
1152
+ return false;
1153
+ }
1154
+ function parse(locator) {
1155
+ if (!locator || typeof locator !== "string") {
1156
+ throw new LocatorError("Locator must be a non-empty string", locator);
1157
+ }
1158
+ if (locator.includes("@")) {
1159
+ throw new LocatorError("Invalid locator format. Use name:tag instead of name@version", locator);
1160
+ }
1161
+ const lastSlashIndex = locator.lastIndexOf("/");
1162
+ let beforeSlash = "";
1163
+ let afterSlash = locator;
1164
+ if (lastSlashIndex !== -1) {
1165
+ beforeSlash = locator.substring(0, lastSlashIndex);
1166
+ afterSlash = locator.substring(lastSlashIndex + 1);
1167
+ }
1168
+ const colonIndex = afterSlash.lastIndexOf(":");
1169
+ let name;
1170
+ let tag;
1171
+ if (colonIndex === -1) {
1172
+ name = afterSlash;
1173
+ tag = "latest";
1174
+ } else {
1175
+ name = afterSlash.substring(0, colonIndex);
1176
+ tag = afterSlash.substring(colonIndex + 1);
1177
+ }
1178
+ if (!name) {
1179
+ throw new LocatorError("Name is required", locator);
1180
+ }
1181
+ if (!tag) {
1182
+ throw new LocatorError("Tag cannot be empty. Use name:tag format or omit tag for :latest", locator);
1183
+ }
1184
+ if (lastSlashIndex === -1) {
1185
+ return {
1186
+ registry: undefined,
1187
+ path: undefined,
1188
+ name,
1189
+ tag
1190
+ };
1191
+ }
1192
+ const parts = beforeSlash.split("/");
1193
+ if (looksLikeRegistry(parts[0])) {
1194
+ const registry = parts[0];
1195
+ const path = parts.length > 1 ? parts.slice(1).join("/") : undefined;
1196
+ return {
1197
+ registry,
1198
+ path,
1199
+ name,
1200
+ tag
1201
+ };
1202
+ }
1203
+ return {
1204
+ registry: undefined,
1205
+ path: beforeSlash,
1206
+ name,
1207
+ tag
1208
+ };
1209
+ }
1210
+ // src/primitives/wrap.ts
1211
+ class RXAImpl2 {
1216
1212
  _buffer;
1217
- _rxpCache = null;
1218
1213
  constructor(buffer) {
1219
1214
  this._buffer = buffer;
1220
1215
  }
@@ -1230,49 +1225,25 @@ class RXAImpl {
1230
1225
  async buffer() {
1231
1226
  return this._buffer;
1232
1227
  }
1233
- async extract() {
1234
- if (this._rxpCache) {
1235
- return this._rxpCache;
1236
- }
1237
- const tarBuffer = await gunzipAsync(this._buffer);
1238
- const entries = await unpackTar(tarBuffer);
1239
- const filesMap = new Map;
1240
- for (const entry of entries) {
1241
- if ((entry.header.type === "file" || entry.header.type === undefined) && entry.data) {
1242
- filesMap.set(entry.header.name, Buffer.from(entry.data));
1243
- }
1244
- }
1245
- this._rxpCache = new RXPImpl(filesMap);
1246
- return this._rxpCache;
1247
- }
1248
- }
1249
- function isBufferInput(input) {
1250
- return "buffer" in input && Buffer.isBuffer(input.buffer);
1251
1228
  }
1252
- async function createRXA(input) {
1253
- if (isBufferInput(input)) {
1254
- return new RXAImpl(input.buffer);
1255
- }
1256
- const entries = Object.entries(input).map(([name, content]) => {
1257
- const body = typeof content === "string" ? content : content instanceof Uint8Array ? content : new Uint8Array(content);
1258
- const size = typeof content === "string" ? Buffer.byteLength(content) : content.length;
1259
- return {
1260
- header: { name, size, type: "file" },
1261
- body
1262
- };
1263
- });
1264
- const tarBuffer = await packTar(entries);
1265
- const gzipBuffer = await gzipAsync(Buffer.from(tarBuffer));
1266
- return new RXAImpl(gzipBuffer);
1229
+ function wrap(buffer) {
1230
+ return new RXAImpl2(buffer);
1267
1231
  }
1268
1232
  export {
1269
- parseRXL,
1270
- createRXM,
1271
- createRXA,
1233
+ wrap,
1234
+ resource,
1235
+ parse,
1236
+ manifest,
1237
+ locate,
1238
+ format,
1239
+ extract,
1240
+ define,
1241
+ archive,
1272
1242
  ResourceXError,
1273
1243
  ManifestError,
1274
1244
  LocatorError,
1245
+ DefinitionError,
1275
1246
  ContentError
1276
1247
  };
1277
1248
 
1278
- //# debugId=AFABB314B72836D164756E2164756E21
1249
+ //# debugId=E36D0778C816F02964756E2164756E21