@fnndsc/salsa 4.4.4 → 4.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.
@@ -0,0 +1,46 @@
1
+ /**
2
+ * @file Run a list of tasks a few at a time.
3
+ *
4
+ * Plugin uploads and registry lookups each run four at a time: enough to
5
+ * finish 175 in seconds, few enough not to hammer a CUBE or a registry. Each
6
+ * task's failure stays its own; the pool never stops early.
7
+ *
8
+ * Key components:
9
+ * - POOL_WIDTH: the number of tasks run at once.
10
+ * - items_mapPooled: map items through an async function, a few at a time, in order.
11
+ *
12
+ * Typical usage:
13
+ * ```ts
14
+ * const sizes: number[] = await items_mapPooled(urls, POOL_WIDTH, async (url: string): Promise<number> => size_get(url));
15
+ * ```
16
+ *
17
+ * Dependencies: none.
18
+ *
19
+ * @module
20
+ */
21
+ /** Tasks run at once by the plugin verbs. */
22
+ export declare const POOL_WIDTH: number;
23
+ /**
24
+ * Maps items through an async function, at most `width` at a time.
25
+ *
26
+ * Results come back in the items' order, whatever order the tasks finish in.
27
+ * A task that throws is not caught here: map to a value that records the
28
+ * failure when each failure must stay its own.
29
+ *
30
+ * A stop (the signal aborting) lets the tasks already running finish and
31
+ * starts no more, so what was sent is all accounted for; the items never
32
+ * started have no result.
33
+ *
34
+ * @param items - The items.
35
+ * @param width - Tasks run at once; at least 1.
36
+ * @param task - The work for one item.
37
+ * @param signal - Stops the map; absent, it runs to the end.
38
+ * @returns The started items' results, in the items' order: every item's
39
+ * unless stopped.
40
+ *
41
+ * @example
42
+ * ```ts
43
+ * await items_mapPooled([1, 2, 3], 2, async (n: number): Promise<number> => n * 2); // [2, 4, 6]
44
+ * ```
45
+ */
46
+ export declare function items_mapPooled<T, R>(items: readonly T[], width: number, task: (item: T, index: number) => Promise<R>, signal?: AbortSignal): Promise<R[]>;
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ /**
3
+ * @file Run a list of tasks a few at a time.
4
+ *
5
+ * Plugin uploads and registry lookups each run four at a time: enough to
6
+ * finish 175 in seconds, few enough not to hammer a CUBE or a registry. Each
7
+ * task's failure stays its own; the pool never stops early.
8
+ *
9
+ * Key components:
10
+ * - POOL_WIDTH: the number of tasks run at once.
11
+ * - items_mapPooled: map items through an async function, a few at a time, in order.
12
+ *
13
+ * Typical usage:
14
+ * ```ts
15
+ * const sizes: number[] = await items_mapPooled(urls, POOL_WIDTH, async (url: string): Promise<number> => size_get(url));
16
+ * ```
17
+ *
18
+ * Dependencies: none.
19
+ *
20
+ * @module
21
+ */
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.POOL_WIDTH = void 0;
24
+ exports.items_mapPooled = items_mapPooled;
25
+ /** Tasks run at once by the plugin verbs. */
26
+ exports.POOL_WIDTH = 4;
27
+ /**
28
+ * Maps items through an async function, at most `width` at a time.
29
+ *
30
+ * Results come back in the items' order, whatever order the tasks finish in.
31
+ * A task that throws is not caught here: map to a value that records the
32
+ * failure when each failure must stay its own.
33
+ *
34
+ * A stop (the signal aborting) lets the tasks already running finish and
35
+ * starts no more, so what was sent is all accounted for; the items never
36
+ * started have no result.
37
+ *
38
+ * @param items - The items.
39
+ * @param width - Tasks run at once; at least 1.
40
+ * @param task - The work for one item.
41
+ * @param signal - Stops the map; absent, it runs to the end.
42
+ * @returns The started items' results, in the items' order: every item's
43
+ * unless stopped.
44
+ *
45
+ * @example
46
+ * ```ts
47
+ * await items_mapPooled([1, 2, 3], 2, async (n: number): Promise<number> => n * 2); // [2, 4, 6]
48
+ * ```
49
+ */
50
+ async function items_mapPooled(items, width, task, signal) {
51
+ const results = new Array(items.length);
52
+ let next = 0;
53
+ const worker = async () => {
54
+ while (next < items.length && signal?.aborted !== true) {
55
+ const index = next;
56
+ next += 1;
57
+ results[index] = await task(items[index], index);
58
+ }
59
+ };
60
+ await Promise.all(Array.from({ length: Math.max(1, Math.min(width, items.length)) }, worker));
61
+ return results.slice(0, next);
62
+ }
63
+ //# sourceMappingURL=pool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pool.js","sourceRoot":"","sources":["../../src/plugins/pool.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;GAmBG;;;AA4BH,0CAiBC;AA3CD,6CAA6C;AAChC,QAAA,UAAU,GAAW,CAAC,CAAC;AAEpC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACI,KAAK,UAAU,eAAe,CACnC,KAAmB,EACnB,KAAa,EACb,IAA4C,EAC5C,MAAoB;IAEpB,MAAM,OAAO,GAAQ,IAAI,KAAK,CAAI,KAAK,CAAC,MAAM,CAAC,CAAC;IAChD,IAAI,IAAI,GAAW,CAAC,CAAC;IACrB,MAAM,MAAM,GAAG,KAAK,IAAmB,EAAE;QACvC,OAAO,IAAI,GAAG,KAAK,CAAC,MAAM,IAAI,MAAM,EAAE,OAAO,KAAK,IAAI,EAAE,CAAC;YACvD,MAAM,KAAK,GAAW,IAAI,CAAC;YAC3B,IAAI,IAAI,CAAC,CAAC;YACV,OAAO,CAAC,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAM,EAAE,KAAK,CAAC,CAAC;QACxD,CAAC;IACH,CAAC,CAAC;IACF,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC;IAC9F,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;AAChC,CAAC"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * @file A small reader for ustar archives, gzipped or not.
3
+ *
4
+ * A plugin index arrives as GitHub's archive of a ref (a gzipped ustar file
5
+ * with a pax global header naming the commit) or as a `.tar.gz` an operator
6
+ * uploaded. Both need only regular files and pax headers read, so this is a
7
+ * reader for that much of the format and no more: no links, no devices, no
8
+ * sparse files. Entries are returned in archive order with their paths as
9
+ * the archive names them.
10
+ *
11
+ * A path that climbs out of the archive (`..`) or starts at the root is
12
+ * refused outright rather than skipped: an archive that carries one is not
13
+ * one this reader should be trusted to have read correctly.
14
+ *
15
+ * Key components:
16
+ * - TarFile: one regular file of the archive, its path and bytes.
17
+ * - TarArchive: the files and the pax global header's records.
18
+ * - tarArchive_read: read an archive's regular files and global header.
19
+ *
20
+ * Typical usage:
21
+ * ```ts
22
+ * const archive: TarArchive = tarArchive_read(bytes);
23
+ * const commit: string | undefined = archive.globals['comment'];
24
+ * ```
25
+ *
26
+ * Dependencies: Node.js built-ins only (`node:zlib` for gzip).
27
+ *
28
+ * @module
29
+ */
30
+ /**
31
+ * One regular file read from an archive.
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * const file: TarFile = { path: 'repo-abc/plugins/pl-x.json', content: Buffer.from('{}') };
36
+ * ```
37
+ */
38
+ export interface TarFile {
39
+ /** The file's path as the archive names it, prefix and pax `path` applied. */
40
+ readonly path: string;
41
+ /** The file's bytes. */
42
+ readonly content: Buffer;
43
+ }
44
+ /**
45
+ * What an archive holds that a reader of plugin indexes needs.
46
+ *
47
+ * @example
48
+ * ```ts
49
+ * const archive: TarArchive = tarArchive_read(bytes);
50
+ * archive.files.length;
51
+ * ```
52
+ */
53
+ export interface TarArchive {
54
+ /** Every regular file, in archive order. */
55
+ readonly files: TarFile[];
56
+ /** The pax global header's records (GitHub writes the commit under `comment`). */
57
+ readonly globals: Record<string, string>;
58
+ }
59
+ /**
60
+ * Reads an archive's regular files and its pax global header.
61
+ *
62
+ * @param bytes - The archive, gzipped or plain ustar.
63
+ * @returns The regular files in archive order and the global records.
64
+ * @throws {Error} When the bytes are not a readable archive, or an entry's
65
+ * path is absolute or climbs out with `..`.
66
+ *
67
+ * @example
68
+ * ```ts
69
+ * const archive: TarArchive = tarArchive_read(readFileSync('index.tar.gz'));
70
+ * archive.files.map((file: TarFile): string => file.path);
71
+ * ```
72
+ */
73
+ export declare function tarArchive_read(bytes: Buffer): TarArchive;
@@ -0,0 +1,190 @@
1
+ "use strict";
2
+ /**
3
+ * @file A small reader for ustar archives, gzipped or not.
4
+ *
5
+ * A plugin index arrives as GitHub's archive of a ref (a gzipped ustar file
6
+ * with a pax global header naming the commit) or as a `.tar.gz` an operator
7
+ * uploaded. Both need only regular files and pax headers read, so this is a
8
+ * reader for that much of the format and no more: no links, no devices, no
9
+ * sparse files. Entries are returned in archive order with their paths as
10
+ * the archive names them.
11
+ *
12
+ * A path that climbs out of the archive (`..`) or starts at the root is
13
+ * refused outright rather than skipped: an archive that carries one is not
14
+ * one this reader should be trusted to have read correctly.
15
+ *
16
+ * Key components:
17
+ * - TarFile: one regular file of the archive, its path and bytes.
18
+ * - TarArchive: the files and the pax global header's records.
19
+ * - tarArchive_read: read an archive's regular files and global header.
20
+ *
21
+ * Typical usage:
22
+ * ```ts
23
+ * const archive: TarArchive = tarArchive_read(bytes);
24
+ * const commit: string | undefined = archive.globals['comment'];
25
+ * ```
26
+ *
27
+ * Dependencies: Node.js built-ins only (`node:zlib` for gzip).
28
+ *
29
+ * @module
30
+ */
31
+ Object.defineProperty(exports, "__esModule", { value: true });
32
+ exports.tarArchive_read = tarArchive_read;
33
+ const node_zlib_1 = require("node:zlib");
34
+ /** The tar block size: headers and padded data both come in these. */
35
+ const BLOCK_BYTES = 512;
36
+ /** The first two bytes of a gzip stream. */
37
+ const GZIP_MAGIC = [0x1f, 0x8b];
38
+ /** Header field offsets and widths, as the ustar format fixes them. */
39
+ const FIELD = {
40
+ name: [0, 100],
41
+ size: [124, 12],
42
+ typeflag: [156, 1],
43
+ magic: [257, 6],
44
+ prefix: [345, 155],
45
+ };
46
+ /**
47
+ * Reads an archive's regular files and its pax global header.
48
+ *
49
+ * @param bytes - The archive, gzipped or plain ustar.
50
+ * @returns The regular files in archive order and the global records.
51
+ * @throws {Error} When the bytes are not a readable archive, or an entry's
52
+ * path is absolute or climbs out with `..`.
53
+ *
54
+ * @example
55
+ * ```ts
56
+ * const archive: TarArchive = tarArchive_read(readFileSync('index.tar.gz'));
57
+ * archive.files.map((file: TarFile): string => file.path);
58
+ * ```
59
+ */
60
+ function tarArchive_read(bytes) {
61
+ const tar = gzip_is(bytes) ? (0, node_zlib_1.gunzipSync)(bytes) : bytes;
62
+ const files = [];
63
+ const globals = {};
64
+ let pending = {};
65
+ let offset = 0;
66
+ while (offset + BLOCK_BYTES <= tar.length) {
67
+ const header = tar.subarray(offset, offset + BLOCK_BYTES);
68
+ if (block_isZero(header))
69
+ break;
70
+ if (!header.subarray(FIELD.magic[0], FIELD.magic[0] + 5).equals(Buffer.from('ustar'))) {
71
+ throw new Error(`not a ustar archive (no ustar magic at byte ${offset})`);
72
+ }
73
+ const size = headerSize_parse(header);
74
+ const type = field_read(header, FIELD.typeflag);
75
+ const body = tar.subarray(offset + BLOCK_BYTES, offset + BLOCK_BYTES + size);
76
+ if (body.length < size)
77
+ throw new Error('archive ends inside an entry');
78
+ offset += BLOCK_BYTES + Math.ceil(size / BLOCK_BYTES) * BLOCK_BYTES;
79
+ if (type === 'g') {
80
+ Object.assign(globals, paxRecords_parse(body));
81
+ }
82
+ else if (type === 'x') {
83
+ pending = paxRecords_parse(body);
84
+ }
85
+ else {
86
+ const named = headerPath_read(header);
87
+ const path = pending['path'] ?? named;
88
+ pending = {};
89
+ path_check(path);
90
+ if (type === '0' || type === '' || type === '\0')
91
+ files.push({ path, content: Buffer.from(body) });
92
+ }
93
+ }
94
+ return { files, globals };
95
+ }
96
+ /**
97
+ * Reports whether bytes start a gzip stream.
98
+ *
99
+ * @param bytes - The candidate bytes.
100
+ * @returns True on the gzip magic number.
101
+ */
102
+ function gzip_is(bytes) {
103
+ return bytes[0] === GZIP_MAGIC[0] && bytes[1] === GZIP_MAGIC[1];
104
+ }
105
+ /**
106
+ * Reports whether a block is all zero bytes (the archive's end marker).
107
+ *
108
+ * @param block - One 512-byte block.
109
+ * @returns True when every byte is zero.
110
+ */
111
+ function block_isZero(block) {
112
+ return block.every((byte) => byte === 0);
113
+ }
114
+ /**
115
+ * Reads a NUL-terminated header field as text.
116
+ *
117
+ * @param header - The header block.
118
+ * @param field - The field's offset and width.
119
+ * @returns The field's text, up to its first NUL.
120
+ */
121
+ function field_read(header, field) {
122
+ const raw = header.subarray(field[0], field[0] + field[1]).toString('utf8');
123
+ const nul = raw.indexOf('\0');
124
+ return nul === -1 ? raw : raw.slice(0, nul);
125
+ }
126
+ /**
127
+ * Reads an entry's size from its octal header field.
128
+ *
129
+ * @param header - The header block.
130
+ * @returns The size in bytes.
131
+ * @throws {Error} When the field is not octal (base-256 sizes are not read).
132
+ */
133
+ function headerSize_parse(header) {
134
+ const text = field_read(header, FIELD.size).trim();
135
+ if (!/^[0-7]*$/.test(text))
136
+ throw new Error(`unreadable entry size '${text}'`);
137
+ return text === '' ? 0 : parseInt(text, 8);
138
+ }
139
+ /**
140
+ * Reads an entry's path from the header's prefix and name fields.
141
+ *
142
+ * @param header - The header block.
143
+ * @returns The joined path.
144
+ */
145
+ function headerPath_read(header) {
146
+ const name = field_read(header, FIELD.name);
147
+ const prefix = field_read(header, FIELD.prefix);
148
+ return prefix === '' ? name : `${prefix}/${name}`;
149
+ }
150
+ /**
151
+ * Parses pax extended-header records (`<len> <key>=<value>\n`).
152
+ *
153
+ * @param body - The header's data.
154
+ * @returns The records by key.
155
+ * @throws {Error} When a record's length does not fit the data.
156
+ */
157
+ function paxRecords_parse(body) {
158
+ const records = {};
159
+ let at = 0;
160
+ while (at < body.length) {
161
+ const space = body.indexOf(0x20, at);
162
+ if (space === -1)
163
+ break;
164
+ const length = parseInt(body.subarray(at, space).toString('utf8'), 10);
165
+ if (!Number.isInteger(length) || length <= 0 || at + length > body.length) {
166
+ throw new Error('unreadable pax header record');
167
+ }
168
+ const record = body.subarray(space + 1, at + length - 1).toString('utf8');
169
+ const equals = record.indexOf('=');
170
+ if (equals !== -1)
171
+ records[record.slice(0, equals)] = record.slice(equals + 1);
172
+ at += length;
173
+ }
174
+ return records;
175
+ }
176
+ /**
177
+ * Refuses a path that is absolute or climbs out of the archive.
178
+ *
179
+ * @param path - The entry's path.
180
+ * @throws {Error} When the path starts at the root or holds a `..` segment.
181
+ */
182
+ function path_check(path) {
183
+ if (path.startsWith('/') || /^[A-Za-z]:[\\/]/.test(path)) {
184
+ throw new Error(`archive entry '${path}' is an absolute path`);
185
+ }
186
+ if (path.split(/[\\/]/).includes('..')) {
187
+ throw new Error(`archive entry '${path}' climbs out of the archive`);
188
+ }
189
+ }
190
+ //# sourceMappingURL=tar_read.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tar_read.js","sourceRoot":"","sources":["../../src/plugins/tar_read.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fnndsc/salsa",
3
- "version": "4.4.4",
3
+ "version": "4.5.1",
4
4
  "description": "Shared Application Logic and Service Assets for ChRIS",
5
5
  "repository": {
6
6
  "type": "git",
@@ -60,8 +60,9 @@
60
60
  "adm-zip": "npm:empty-npm-package@1.0.0"
61
61
  },
62
62
  "dependencies": {
63
+ "@fnndsc/cumin": "^3.30.0",
63
64
  "@fnndsc/fond": "^0.6.0",
64
- "@fnndsc/cumin": "^3.29.4",
65
+ "ajv": "^8.17.1",
65
66
  "axios": "^1.6.8",
66
67
  "dcmjs": "^0.52.0",
67
68
  "ws": "^8.21.0"