@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/README.md +279 -178
- package/dist/index.d.ts +127 -90
- package/dist/index.js +197 -226
- package/dist/index.js.map +14 -8
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -28,135 +28,56 @@ class ContentError extends ResourceXError {
|
|
|
28
28
|
this.name = "ContentError";
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
|
-
|
|
32
|
-
class
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
|
92
|
-
if (
|
|
93
|
-
|
|
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
|
-
|
|
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
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
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
|
|
159
|
-
import { gzip
|
|
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
|
|
1060
|
+
// src/primitives/archive.ts
|
|
1140
1061
|
var gzipAsync = promisify(gzip);
|
|
1141
|
-
var gunzipAsync = promisify(gunzip);
|
|
1142
1062
|
|
|
1143
|
-
class
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
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
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
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
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
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
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
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
|
-
|
|
1204
|
-
|
|
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
|
-
|
|
1207
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1253
|
-
|
|
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
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
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=
|
|
1249
|
+
//# debugId=E36D0778C816F02964756E2164756E21
|