@eik/core 2.1.71 → 2.1.73
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/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [2.1.73](https://github.com/eik-lib/core/compare/v2.1.72...v2.1.73) (2026-08-14)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* write eik.json server-side as the final committed marker for package uploads ([#632](https://github.com/eik-lib/core/issues/632)) ([4461f76](https://github.com/eik-lib/core/commit/4461f76881886992db70848d42c7d6a199397c8f)), closes [#4](https://github.com/eik-lib/core/issues/4) [#5](https://github.com/eik-lib/core/issues/5)
|
|
7
|
+
|
|
8
|
+
## [2.1.72](https://github.com/eik-lib/core/compare/v2.1.71...v2.1.72) (2026-08-14)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* upgrade size-limit log from info to warn and include package details ([#631](https://github.com/eik-lib/core/issues/631)) ([e324b5e](https://github.com/eik-lib/core/commit/e324b5e6cab52c788535d3c54b888e0514e40546))
|
|
14
|
+
|
|
1
15
|
## [2.1.71](https://github.com/eik-lib/core/compare/v2.1.70...v2.1.71) (2026-08-13)
|
|
2
16
|
|
|
3
17
|
|
package/lib/handlers/pkg.put.js
CHANGED
|
@@ -82,19 +82,22 @@ const PkgPut = class PkgPut {
|
|
|
82
82
|
.parse(incoming)
|
|
83
83
|
.then((result) => {
|
|
84
84
|
const pkg = new Package(incoming);
|
|
85
|
+
/** @type {Record<string,any>|null} */
|
|
86
|
+
let eikJson = null;
|
|
85
87
|
result.forEach((/** @type {any} */ obj) => {
|
|
86
88
|
if (obj.constructor.name === "FormField") {
|
|
87
89
|
pkg.setMeta(obj);
|
|
88
90
|
}
|
|
89
91
|
if (obj.constructor.name === "FormFile") {
|
|
92
|
+
eikJson = obj.eikJson;
|
|
90
93
|
obj.value.forEach((/** @type {any} */ o) => {
|
|
91
94
|
pkg.setAsset(o);
|
|
92
95
|
});
|
|
93
96
|
}
|
|
94
97
|
});
|
|
95
|
-
return pkg;
|
|
98
|
+
return { pkg, eikJson };
|
|
96
99
|
})
|
|
97
|
-
.then(async (pkg) => {
|
|
100
|
+
.then(async ({ pkg, eikJson }) => {
|
|
98
101
|
const path = createFilePathToPackage(pkg);
|
|
99
102
|
await writeJSON(this._sink, path, pkg, "application/json");
|
|
100
103
|
|
|
@@ -102,7 +105,7 @@ const PkgPut = class PkgPut {
|
|
|
102
105
|
`pkg:put - Successfully wrote package meta file to sink - Pathname: ${path}`,
|
|
103
106
|
);
|
|
104
107
|
|
|
105
|
-
resolve(pkg);
|
|
108
|
+
resolve({ pkg, eikJson });
|
|
106
109
|
})
|
|
107
110
|
.catch((error) => {
|
|
108
111
|
reject(error);
|
|
@@ -110,6 +113,29 @@ const PkgPut = class PkgPut {
|
|
|
110
113
|
});
|
|
111
114
|
}
|
|
112
115
|
|
|
116
|
+
/**
|
|
117
|
+
* Writes eik.json to the sink as the final committed marker for a version.
|
|
118
|
+
* Merges any fields from the client's eik.json (captured from the tar) with
|
|
119
|
+
* server-authoritative values, ensuring the file is always server-written
|
|
120
|
+
* regardless of what the client's tar contained.
|
|
121
|
+
*
|
|
122
|
+
* @param {any} incoming
|
|
123
|
+
* @param {Record<string,any>|null} capturedEikJson
|
|
124
|
+
*/
|
|
125
|
+
async _writeEikJson(incoming, capturedEikJson) {
|
|
126
|
+
const content = {
|
|
127
|
+
...capturedEikJson,
|
|
128
|
+
name: incoming.name,
|
|
129
|
+
version: incoming.version,
|
|
130
|
+
type: incoming.type,
|
|
131
|
+
};
|
|
132
|
+
const eikJsonPath = createFilePathToEikJson(incoming);
|
|
133
|
+
await writeJSON(this._sink, eikJsonPath, content, "application/json");
|
|
134
|
+
this._log.info(
|
|
135
|
+
`pkg:put - Successfully wrote eik.json to sink - Pathname: ${eikJsonPath}`,
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
|
|
113
139
|
/**
|
|
114
140
|
* @param {any} incoming
|
|
115
141
|
*/
|
|
@@ -226,7 +252,7 @@ const PkgPut = class PkgPut {
|
|
|
226
252
|
}
|
|
227
253
|
|
|
228
254
|
const versions = await this._readVersions(incoming);
|
|
229
|
-
const pkg = await this._parser(incoming);
|
|
255
|
+
const { pkg, eikJson } = await this._parser(incoming);
|
|
230
256
|
versions.setVersion(pVersion, pkg.integrity);
|
|
231
257
|
|
|
232
258
|
try {
|
|
@@ -238,6 +264,15 @@ const PkgPut = class PkgPut {
|
|
|
238
264
|
throw e;
|
|
239
265
|
}
|
|
240
266
|
|
|
267
|
+
try {
|
|
268
|
+
await this._writeEikJson(incoming, eikJson);
|
|
269
|
+
// eslint-disable-next-line no-unused-vars
|
|
270
|
+
} catch (error) {
|
|
271
|
+
const e = new HttpError.BadGateway();
|
|
272
|
+
end({ labels: { success: false, status: e.status, type } });
|
|
273
|
+
throw e;
|
|
274
|
+
}
|
|
275
|
+
|
|
241
276
|
const outgoing = new HttpOutgoing();
|
|
242
277
|
outgoing.cacheControl = this._cacheControl || "";
|
|
243
278
|
outgoing.statusCode = 303;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
const FormFile = class FormFile {
|
|
2
2
|
/**
|
|
3
|
-
* @param {{ value?: any[], name?: string }} [options]
|
|
3
|
+
* @param {{ value?: any[], name?: string, eikJson?: Record<string,any>|null }} [options]
|
|
4
4
|
*/
|
|
5
|
-
constructor({ value = [], name = "" } = {}) {
|
|
5
|
+
constructor({ value = [], name = "", eikJson = null } = {}) {
|
|
6
6
|
if (!Array.isArray(value))
|
|
7
7
|
throw new TypeError('The argument "value" must be of type Array');
|
|
8
8
|
this._value = value;
|
|
9
9
|
this._name = name;
|
|
10
|
+
this._eikJson = eikJson;
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
get value() {
|
|
@@ -17,6 +18,11 @@ const FormFile = class FormFile {
|
|
|
17
18
|
return this._name;
|
|
18
19
|
}
|
|
19
20
|
|
|
21
|
+
/** @returns {Record<string,any>|null} */
|
|
22
|
+
get eikJson() {
|
|
23
|
+
return this._eikJson;
|
|
24
|
+
}
|
|
25
|
+
|
|
20
26
|
toJSON() {
|
|
21
27
|
return {
|
|
22
28
|
value: this.value,
|
package/lib/multipart/parser.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { pipeline } from "node:stream";
|
|
2
|
+
import path from "node:path";
|
|
2
3
|
import HttpError from "http-errors";
|
|
3
4
|
import Busboy from "busboy";
|
|
4
5
|
import abslog from "abslog";
|
|
@@ -148,10 +149,12 @@ const MultipartParser = class MultipartParser {
|
|
|
148
149
|
const ac = new AbortController();
|
|
149
150
|
/** @type {Promise<any>[]} */
|
|
150
151
|
const queue = [];
|
|
152
|
+
/** @type {Record<string,any>|null} */
|
|
153
|
+
let capturedEikJson = null;
|
|
151
154
|
|
|
152
155
|
file.once("limit", () => {
|
|
153
|
-
this._log.
|
|
154
|
-
`multipart - Uploaded package exceeds
|
|
156
|
+
this._log.warn(
|
|
157
|
+
`multipart - Uploaded package exceeds the max allowed file size - Field: ${fieldname} - Filename: ${filename} - Name: ${incoming.name} - Version: ${incoming.version} - Type: ${incoming.type} - Limit: ${this._pkgMaxFileSize} bytes`,
|
|
155
158
|
);
|
|
156
159
|
ac.abort();
|
|
157
160
|
file.emit("error", new HttpError.PayloadTooLarge());
|
|
@@ -166,6 +169,30 @@ const MultipartParser = class MultipartParser {
|
|
|
166
169
|
entry.resume();
|
|
167
170
|
return;
|
|
168
171
|
}
|
|
172
|
+
|
|
173
|
+
// eik.json is captured in memory and written server-side
|
|
174
|
+
// after the upload is fully committed, so that it can serve
|
|
175
|
+
// as a reliable committed marker independent of what the
|
|
176
|
+
// client includes in the tar.
|
|
177
|
+
if (path.normalize(entry.path) === "eik.json") {
|
|
178
|
+
/** @type {Buffer[]} */
|
|
179
|
+
const chunks = [];
|
|
180
|
+
entry.on("data", (/** @type {Buffer} */ chunk) => {
|
|
181
|
+
chunks.push(chunk);
|
|
182
|
+
});
|
|
183
|
+
entry.once("end", () => {
|
|
184
|
+
try {
|
|
185
|
+
capturedEikJson = JSON.parse(
|
|
186
|
+
Buffer.concat(chunks).toString("utf8"),
|
|
187
|
+
);
|
|
188
|
+
} catch {
|
|
189
|
+
// Malformed eik.json in tar — proceed without it.
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
entry.once("error", () => {});
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
|
|
169
196
|
const persist = this._persistFile({
|
|
170
197
|
incoming,
|
|
171
198
|
entry,
|
|
@@ -205,7 +232,11 @@ const MultipartParser = class MultipartParser {
|
|
|
205
232
|
|
|
206
233
|
Promise.all(queue)
|
|
207
234
|
.then((result) => {
|
|
208
|
-
const formFile = new FormFile({
|
|
235
|
+
const formFile = new FormFile({
|
|
236
|
+
name: fieldname,
|
|
237
|
+
value: result,
|
|
238
|
+
eikJson: capturedEikJson,
|
|
239
|
+
});
|
|
209
240
|
resolve(formFile);
|
|
210
241
|
})
|
|
211
242
|
.catch((err) => {
|
package/package.json
CHANGED
|
@@ -66,6 +66,16 @@ declare const PkgPut: {
|
|
|
66
66
|
* @param {any} incoming
|
|
67
67
|
*/
|
|
68
68
|
_parser(incoming: any): Promise<any>;
|
|
69
|
+
/**
|
|
70
|
+
* Writes eik.json to the sink as the final committed marker for a version.
|
|
71
|
+
* Merges any fields from the client's eik.json (captured from the tar) with
|
|
72
|
+
* server-authoritative values, ensuring the file is always server-written
|
|
73
|
+
* regardless of what the client's tar contained.
|
|
74
|
+
*
|
|
75
|
+
* @param {any} incoming
|
|
76
|
+
* @param {Record<string,any>|null} capturedEikJson
|
|
77
|
+
*/
|
|
78
|
+
_writeEikJson(incoming: any, capturedEikJson: Record<string, any> | null): Promise<void>;
|
|
69
79
|
/**
|
|
70
80
|
* @param {any} incoming
|
|
71
81
|
*/
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
export default FormFile;
|
|
2
2
|
declare const FormFile: {
|
|
3
|
-
new ({ value, name }?: {
|
|
3
|
+
new ({ value, name, eikJson }?: {
|
|
4
4
|
value?: any[];
|
|
5
5
|
name?: string;
|
|
6
|
+
eikJson?: Record<string, any> | null;
|
|
6
7
|
}): {
|
|
7
8
|
_value: any[];
|
|
8
9
|
_name: string;
|
|
10
|
+
_eikJson: Record<string, any> | null;
|
|
9
11
|
get value(): any[];
|
|
10
12
|
get name(): string;
|
|
13
|
+
/** @returns {Record<string,any>|null} */
|
|
14
|
+
get eikJson(): Record<string, any> | null;
|
|
11
15
|
toJSON(): {
|
|
12
16
|
value: any[];
|
|
13
17
|
name: string;
|