@easel-sh/cli 0.1.0-alpha.0 → 0.1.0-alpha.10
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/cli.js +9 -4
- package/dist/cli.js.map +1 -1
- package/dist/commands/create-lambda-gateway.d.ts.map +1 -1
- package/dist/commands/create-lambda-gateway.js +3 -181
- package/dist/commands/create-lambda-gateway.js.map +1 -1
- package/dist/commands/generate-manifest.d.ts.map +1 -1
- package/dist/commands/generate-manifest.js +14 -1
- package/dist/commands/generate-manifest.js.map +1 -1
- package/dist/commands/package-functions.d.ts.map +1 -1
- package/dist/commands/package-functions.js +73 -202
- package/dist/commands/package-functions.js.map +1 -1
- package/dist/commands/upload-manifest.d.ts.map +1 -1
- package/dist/commands/upload-manifest.js +1 -1
- package/dist/commands/upload-manifest.js.map +1 -1
- package/dist/commands/upload-static.d.ts +2 -0
- package/dist/commands/upload-static.d.ts.map +1 -1
- package/dist/commands/upload-static.js +49 -21
- package/dist/commands/upload-static.js.map +1 -1
- package/dist/handler-wrapper.d.ts +8 -0
- package/dist/handler-wrapper.d.ts.map +1 -0
- package/dist/handler-wrapper.js +288 -0
- package/dist/handler-wrapper.js.map +1 -0
- package/dist/handler-wrapper.test.d.ts +2 -0
- package/dist/handler-wrapper.test.d.ts.map +1 -0
- package/dist/handler-wrapper.test.js +53 -0
- package/dist/handler-wrapper.test.js.map +1 -0
- package/dist/utils/types.d.ts +30 -0
- package/dist/utils/types.d.ts.map +1 -1
- package/dist/utils/vercel-config.d.ts +7 -1
- package/dist/utils/vercel-config.d.ts.map +1 -1
- package/dist/utils/vercel-config.js +19 -0
- package/dist/utils/vercel-config.js.map +1 -1
- package/dist/utils.d.ts +4 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +65 -10
- package/dist/utils.js.map +1 -1
- package/package.json +5 -3
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Handler wrapper compatible with Vercel Node.js runtime:
|
|
3
|
+
* - Fetch Web Standard: export default { fetch(request) { return new Response(...); } };
|
|
4
|
+
* - HTTP method exports: export function GET(request) { return new Response(...); }
|
|
5
|
+
* - Node-style: export default (req, res) => { ... } with Vercel-like helpers (query, cookies, body, status, send, json, redirect).
|
|
6
|
+
*/
|
|
7
|
+
export function generateHandlerWrapper(handlerFile) {
|
|
8
|
+
const handlerPath = JSON.stringify("./" + handlerFile.replace(/\\/g, "/"));
|
|
9
|
+
return `/* eslint-disable @typescript-eslint/no-require-imports */
|
|
10
|
+
|
|
11
|
+
const { Readable } = require("stream");
|
|
12
|
+
const { EventEmitter } = require("events");
|
|
13
|
+
|
|
14
|
+
const HTTP_METHODS = ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD"];
|
|
15
|
+
|
|
16
|
+
let userModulePromise = null;
|
|
17
|
+
function getModule() {
|
|
18
|
+
if (!userModulePromise) {
|
|
19
|
+
userModulePromise = import(${handlerPath}).then(function (m) { return m || {}; });
|
|
20
|
+
}
|
|
21
|
+
return userModulePromise;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function normalizeStatus(status) {
|
|
25
|
+
// Valid HTTP status is 100-599. Response.status can be 0 for error/opaque (Fetch API).
|
|
26
|
+
if (typeof status === "number" && status >= 100 && status < 600) return status;
|
|
27
|
+
if (status === 0) return 502; // error/opaque response
|
|
28
|
+
return 200;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function responseToLambda(response) {
|
|
32
|
+
const responseHeaders = {};
|
|
33
|
+
response.headers.forEach((value, key) => {
|
|
34
|
+
responseHeaders[key.toLowerCase()] = value;
|
|
35
|
+
});
|
|
36
|
+
const body = await response.text();
|
|
37
|
+
return {
|
|
38
|
+
statusCode: normalizeStatus(response.status),
|
|
39
|
+
headers: responseHeaders,
|
|
40
|
+
body: body,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
module.exports.handler = async (event, _context) => {
|
|
45
|
+
const mod = await getModule();
|
|
46
|
+
const handler = mod.default !== undefined ? mod.default : mod;
|
|
47
|
+
|
|
48
|
+
const isV2 = event.requestContext && event.requestContext.http;
|
|
49
|
+
const method = isV2 ? event.requestContext.http.method : event.httpMethod || "GET";
|
|
50
|
+
|
|
51
|
+
const normalizedHeaders = {};
|
|
52
|
+
if (event.headers) {
|
|
53
|
+
Object.entries(event.headers).forEach(([key, value]) => {
|
|
54
|
+
normalizedHeaders[key.toLowerCase()] = value;
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const queryParams = { ...(event.queryStringParameters || {}) };
|
|
59
|
+
// Prefer original client path from router when present so Lambda sees the same URL the client requested (event.rawPath may be wrong if event was built by API Gateway or an older gateway)
|
|
60
|
+
const originalPath = normalizedHeaders["x-router-original-path"];
|
|
61
|
+
const pathFromEvent = isV2 ? event.rawPath || event.path || "/" : event.path || "/";
|
|
62
|
+
const path = (originalPath && originalPath.trim())
|
|
63
|
+
? (originalPath.trim().startsWith("/") ? originalPath.trim() : "/" + originalPath.trim())
|
|
64
|
+
: pathFromEvent;
|
|
65
|
+
const host = event.headers?.host || event.headers?.["host"] || "localhost";
|
|
66
|
+
const url = new URL(path, "http://" + host);
|
|
67
|
+
Object.entries(queryParams).forEach(([key, value]) => {
|
|
68
|
+
url.searchParams.set(key, value);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
let bodyBuffer = null;
|
|
72
|
+
if (event.body) {
|
|
73
|
+
bodyBuffer = event.isBase64Encoded
|
|
74
|
+
? Buffer.from(event.body, "base64")
|
|
75
|
+
: Buffer.from(event.body, "utf8");
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const requestUrl = "http://" + host + url.pathname + url.search;
|
|
79
|
+
const webRequest = new Request(requestUrl, {
|
|
80
|
+
method: method,
|
|
81
|
+
headers: normalizedHeaders,
|
|
82
|
+
body: bodyBuffer && bodyBuffer.length > 0 ? bodyBuffer : undefined,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const requestDetails = {
|
|
86
|
+
method: method,
|
|
87
|
+
url: requestUrl,
|
|
88
|
+
path: url.pathname,
|
|
89
|
+
query: queryParams,
|
|
90
|
+
headers: normalizedHeaders,
|
|
91
|
+
bodyLength: bodyBuffer ? bodyBuffer.length : 0,
|
|
92
|
+
};
|
|
93
|
+
console.log("[handler] reconstructed request:", JSON.stringify(requestDetails));
|
|
94
|
+
|
|
95
|
+
// Vercel: named method export (e.g. export function GET(request) { ... })
|
|
96
|
+
if (HTTP_METHODS.includes(method) && typeof mod[method] === "function") {
|
|
97
|
+
const response = await Promise.resolve(mod[method](webRequest));
|
|
98
|
+
return responseToLambda(response);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Vercel/Nitro: default export with fetch(request)
|
|
102
|
+
if (handler && typeof handler.fetch === "function") {
|
|
103
|
+
const response = await handler.fetch(webRequest, _context);
|
|
104
|
+
return responseToLambda(response);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Node-style: default export as function (req, res), with Vercel-like helpers
|
|
108
|
+
if (typeof handler !== "function") {
|
|
109
|
+
throw new TypeError(
|
|
110
|
+
"Handler must export a function (req, res), an object with fetch(request), or named GET/POST/etc. Got: " + typeof handler
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return new Promise((resolve, reject) => {
|
|
115
|
+
let _bodyParsed = undefined;
|
|
116
|
+
function getParsedBody() {
|
|
117
|
+
if (_bodyParsed !== undefined) return _bodyParsed;
|
|
118
|
+
if (!bodyBuffer || bodyBuffer.length === 0) {
|
|
119
|
+
_bodyParsed = undefined;
|
|
120
|
+
return _bodyParsed;
|
|
121
|
+
}
|
|
122
|
+
const ct = (normalizedHeaders["content-type"] || "").toLowerCase();
|
|
123
|
+
const text = bodyBuffer.toString("utf8");
|
|
124
|
+
try {
|
|
125
|
+
if (ct.includes("application/json")) _bodyParsed = JSON.parse(text);
|
|
126
|
+
else if (ct.includes("application/x-www-form-urlencoded")) {
|
|
127
|
+
_bodyParsed = Object.fromEntries(new URLSearchParams(text));
|
|
128
|
+
}
|
|
129
|
+
else if (ct.includes("text/plain")) _bodyParsed = text;
|
|
130
|
+
else if (ct.includes("application/octet-stream")) _bodyParsed = bodyBuffer;
|
|
131
|
+
else _bodyParsed = undefined;
|
|
132
|
+
} catch (e) {
|
|
133
|
+
if (ct.includes("application/json")) throw e;
|
|
134
|
+
_bodyParsed = undefined;
|
|
135
|
+
}
|
|
136
|
+
return _bodyParsed;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
let cookiesObj = undefined;
|
|
140
|
+
function getCookies() {
|
|
141
|
+
if (cookiesObj !== undefined) return cookiesObj;
|
|
142
|
+
cookiesObj = {};
|
|
143
|
+
const cookieHeader = normalizedHeaders["cookie"];
|
|
144
|
+
if (cookieHeader) {
|
|
145
|
+
cookieHeader.split(";").forEach(function (part) {
|
|
146
|
+
const eq = part.indexOf("=");
|
|
147
|
+
if (eq > 0) {
|
|
148
|
+
const key = part.slice(0, eq).trim();
|
|
149
|
+
const val = part.slice(eq + 1).trim();
|
|
150
|
+
cookiesObj[key] = val;
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
return cookiesObj;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const req = Object.assign(
|
|
158
|
+
new Readable({
|
|
159
|
+
read() {
|
|
160
|
+
if (bodyBuffer) this.push(bodyBuffer);
|
|
161
|
+
this.push(null);
|
|
162
|
+
},
|
|
163
|
+
}),
|
|
164
|
+
{
|
|
165
|
+
method: method,
|
|
166
|
+
url: url.pathname + url.search,
|
|
167
|
+
headers: normalizedHeaders,
|
|
168
|
+
query: queryParams,
|
|
169
|
+
}
|
|
170
|
+
);
|
|
171
|
+
Object.defineProperty(req, "body", {
|
|
172
|
+
get: getParsedBody,
|
|
173
|
+
set: function (val) { _bodyParsed = val; },
|
|
174
|
+
enumerable: true,
|
|
175
|
+
configurable: true,
|
|
176
|
+
});
|
|
177
|
+
Object.defineProperty(req, "cookies", {
|
|
178
|
+
get: getCookies,
|
|
179
|
+
set: function (val) { cookiesObj = val; },
|
|
180
|
+
enumerable: true,
|
|
181
|
+
configurable: true,
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
let statusCode = 200;
|
|
185
|
+
const headers = {};
|
|
186
|
+
let body = "";
|
|
187
|
+
let headersSent = false;
|
|
188
|
+
let resolved = false;
|
|
189
|
+
|
|
190
|
+
function finishRes() {
|
|
191
|
+
if (resolved) return;
|
|
192
|
+
resolved = true;
|
|
193
|
+
const out = {};
|
|
194
|
+
Object.entries(headers).forEach(([k, v]) => {
|
|
195
|
+
out[k] = Array.isArray(v) ? v.join(", ") : v;
|
|
196
|
+
});
|
|
197
|
+
resolve({ statusCode: statusCode || 200, headers: out, body: body });
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const res = Object.assign(new EventEmitter(), {
|
|
201
|
+
setHeader: (key, value) => {
|
|
202
|
+
if (!headersSent) headers[key.toLowerCase()] = value;
|
|
203
|
+
},
|
|
204
|
+
getHeader: (key) => headers[key.toLowerCase()],
|
|
205
|
+
removeHeader: (key) => { delete headers[key.toLowerCase()]; },
|
|
206
|
+
appendHeader: (key, value) => {
|
|
207
|
+
if (!headersSent) {
|
|
208
|
+
const lowerKey = key.toLowerCase();
|
|
209
|
+
const existing = headers[lowerKey];
|
|
210
|
+
headers[lowerKey] = existing
|
|
211
|
+
? (Array.isArray(existing) ? existing.concat(value) : [existing, value])
|
|
212
|
+
: value;
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
hasHeader: (key) => key.toLowerCase() in headers,
|
|
216
|
+
getHeaderNames: () => Object.keys(headers),
|
|
217
|
+
writeHead: (code, responseHeaders) => {
|
|
218
|
+
if (!headersSent) {
|
|
219
|
+
statusCode = code;
|
|
220
|
+
if (responseHeaders) {
|
|
221
|
+
Object.entries(responseHeaders).forEach(([key, value]) => {
|
|
222
|
+
headers[key.toLowerCase()] = value;
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
headersSent = true;
|
|
226
|
+
}
|
|
227
|
+
return res;
|
|
228
|
+
},
|
|
229
|
+
write: (chunk) => {
|
|
230
|
+
if (!headersSent) headersSent = true;
|
|
231
|
+
body += chunk.toString();
|
|
232
|
+
return true;
|
|
233
|
+
},
|
|
234
|
+
end: (chunk) => {
|
|
235
|
+
if (chunk) body += chunk.toString();
|
|
236
|
+
finishRes();
|
|
237
|
+
},
|
|
238
|
+
status: (code) => {
|
|
239
|
+
statusCode = code;
|
|
240
|
+
return res;
|
|
241
|
+
},
|
|
242
|
+
send: (val) => {
|
|
243
|
+
if (typeof val === "object" && val !== null && !Buffer.isBuffer(val)) {
|
|
244
|
+
if (!headers["content-type"]) headers["content-type"] = "application/json";
|
|
245
|
+
body = JSON.stringify(val);
|
|
246
|
+
} else {
|
|
247
|
+
body = val == null ? "" : String(val);
|
|
248
|
+
}
|
|
249
|
+
finishRes();
|
|
250
|
+
return res;
|
|
251
|
+
},
|
|
252
|
+
json: (obj) => {
|
|
253
|
+
headers["content-type"] = "application/json";
|
|
254
|
+
body = JSON.stringify(obj);
|
|
255
|
+
finishRes();
|
|
256
|
+
return res;
|
|
257
|
+
},
|
|
258
|
+
redirect: (a, b) => {
|
|
259
|
+
const code = typeof a === "number" ? a : 307;
|
|
260
|
+
const loc = typeof a === "number" ? b : a;
|
|
261
|
+
statusCode = code;
|
|
262
|
+
headers["location"] = loc;
|
|
263
|
+
finishRes();
|
|
264
|
+
return res;
|
|
265
|
+
},
|
|
266
|
+
headersSent: false,
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
Object.defineProperty(res, "statusCode", {
|
|
270
|
+
get: () => statusCode,
|
|
271
|
+
set: (value) => { statusCode = value; },
|
|
272
|
+
enumerable: true,
|
|
273
|
+
configurable: true,
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
req.on("error", reject);
|
|
277
|
+
res.on("error", reject);
|
|
278
|
+
|
|
279
|
+
try {
|
|
280
|
+
handler(req, res);
|
|
281
|
+
} catch (error) {
|
|
282
|
+
reject(error);
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
};
|
|
286
|
+
`;
|
|
287
|
+
}
|
|
288
|
+
//# sourceMappingURL=handler-wrapper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler-wrapper.js","sourceRoot":"","sources":["../src/handler-wrapper.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CAAC,WAAmB;IACxD,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,GAAG,WAAW,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC;IAC3E,OAAO;;;;;;;;;;iCAUwB,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2Q3C,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler-wrapper.test.d.ts","sourceRoot":"","sources":["../src/handler-wrapper.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
6
|
+
import { generateHandlerWrapper } from "./handler-wrapper.js";
|
|
7
|
+
describe("handler-wrapper", () => {
|
|
8
|
+
let tmpDir;
|
|
9
|
+
const require = createRequire(import.meta.url);
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "handler-wrapper-test-"));
|
|
12
|
+
});
|
|
13
|
+
afterEach(() => {
|
|
14
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
15
|
+
});
|
|
16
|
+
it("allows assigning to req.cookies without throwing (Node-style handler)", async () => {
|
|
17
|
+
const wrapperCode = generateHandlerWrapper("index.mjs");
|
|
18
|
+
fs.writeFileSync(path.join(tmpDir, "handler.js"), wrapperCode, "utf8");
|
|
19
|
+
fs.writeFileSync(path.join(tmpDir, "index.mjs"), `export default function (req, res) {
|
|
20
|
+
req.cookies = {};
|
|
21
|
+
res.end("ok");
|
|
22
|
+
}`, "utf8");
|
|
23
|
+
const handler = require(path.join(tmpDir, "handler.js")).handler;
|
|
24
|
+
const mockEvent = {
|
|
25
|
+
requestContext: { http: { method: "GET" } },
|
|
26
|
+
headers: { host: "localhost" },
|
|
27
|
+
rawPath: "/",
|
|
28
|
+
};
|
|
29
|
+
const result = await handler(mockEvent, {});
|
|
30
|
+
expect(result).toBeDefined();
|
|
31
|
+
expect(result.statusCode).toBe(200);
|
|
32
|
+
expect(result.body).toBe("ok");
|
|
33
|
+
});
|
|
34
|
+
it("allows assigning to req.body without throwing (Node-style handler)", async () => {
|
|
35
|
+
const wrapperCode = generateHandlerWrapper("index.mjs");
|
|
36
|
+
fs.writeFileSync(path.join(tmpDir, "handler.js"), wrapperCode, "utf8");
|
|
37
|
+
fs.writeFileSync(path.join(tmpDir, "index.mjs"), `export default function (req, res) {
|
|
38
|
+
req.body = {};
|
|
39
|
+
res.end("ok");
|
|
40
|
+
}`, "utf8");
|
|
41
|
+
const handler = require(path.join(tmpDir, "handler.js")).handler;
|
|
42
|
+
const mockEvent = {
|
|
43
|
+
requestContext: { http: { method: "GET" } },
|
|
44
|
+
headers: { host: "localhost" },
|
|
45
|
+
rawPath: "/",
|
|
46
|
+
};
|
|
47
|
+
const result = await handler(mockEvent, {});
|
|
48
|
+
expect(result).toBeDefined();
|
|
49
|
+
expect(result.statusCode).toBe(200);
|
|
50
|
+
expect(result.body).toBe("ok");
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
//# sourceMappingURL=handler-wrapper.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler-wrapper.test.js","sourceRoot":"","sources":["../src/handler-wrapper.test.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/types.d.ts
CHANGED
|
@@ -27,11 +27,41 @@ export interface FileManifestEntry {
|
|
|
27
27
|
contentType?: string;
|
|
28
28
|
}
|
|
29
29
|
export type FileManifestItem = string | FileManifestEntry;
|
|
30
|
+
/** Build Output API image format */
|
|
31
|
+
export type ImageFormat = "image/avif" | "image/webp";
|
|
32
|
+
/** Remote pattern for image optimization (regex for hostname, pathname, etc.) */
|
|
33
|
+
export interface RemotePattern {
|
|
34
|
+
protocol?: "http" | "https";
|
|
35
|
+
hostname: string;
|
|
36
|
+
port?: string;
|
|
37
|
+
pathname?: string;
|
|
38
|
+
search?: string;
|
|
39
|
+
}
|
|
40
|
+
/** Local pattern for image optimization (regex for pathname, search) */
|
|
41
|
+
export interface LocalPattern {
|
|
42
|
+
pathname?: string;
|
|
43
|
+
search?: string;
|
|
44
|
+
}
|
|
45
|
+
/** Images config from .vercel/output/config.json (Build Output API) */
|
|
46
|
+
export interface ImagesConfig {
|
|
47
|
+
sizes: number[];
|
|
48
|
+
domains: string[];
|
|
49
|
+
remotePatterns?: RemotePattern[];
|
|
50
|
+
localPatterns?: LocalPattern[];
|
|
51
|
+
qualities?: number[];
|
|
52
|
+
minimumCacheTTL?: number;
|
|
53
|
+
formats?: ImageFormat[];
|
|
54
|
+
dangerouslyAllowSVG?: boolean;
|
|
55
|
+
contentSecurityPolicy?: string;
|
|
56
|
+
contentDispositionType?: string;
|
|
57
|
+
}
|
|
30
58
|
export interface DeploymentManifest {
|
|
31
59
|
routes: Route[];
|
|
32
60
|
fileManifest: FileManifestItem[];
|
|
33
61
|
resourceManifest: string[];
|
|
34
62
|
resourceHashes?: Record<string, string>;
|
|
63
|
+
fileHashes?: Record<string, string>;
|
|
64
|
+
images?: ImagesConfig;
|
|
35
65
|
version?: string;
|
|
36
66
|
createdAt?: string;
|
|
37
67
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/utils/types.ts"],"names":[],"mappings":"AACA,MAAM,WAAW,KAAK;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC;IACZ,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC;IAChB,MAAM,CAAC,EAAE;QACP,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAClC,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,QAAQ,CAAC,EAAE;QACT,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,UAAU,CAAC,EAAE,GAAG,EAAE,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,iBAAiB,CAAC;AAE1D,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,YAAY,EAAE,gBAAgB,EAAE,CAAC;IACjC,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/utils/types.ts"],"names":[],"mappings":"AACA,MAAM,WAAW,KAAK;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC;IACZ,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC;IAChB,MAAM,CAAC,EAAE;QACP,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAClC,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,QAAQ,CAAC,EAAE;QACT,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,UAAU,CAAC,EAAE,GAAG,EAAE,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,iBAAiB,CAAC;AAE1D,oCAAoC;AACpC,MAAM,MAAM,WAAW,GAAG,YAAY,GAAG,YAAY,CAAC;AAEtD,iFAAiF;AACjF,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wEAAwE;AACxE,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,uEAAuE;AACvE,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,cAAc,CAAC,EAAE,aAAa,EAAE,CAAC;IACjC,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,WAAW,EAAE,CAAC;IACxB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,YAAY,EAAE,gBAAgB,EAAE,CAAC;IACjC,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Route } from
|
|
1
|
+
import type { Route, ImagesConfig } from "./types.js";
|
|
2
2
|
export interface FileOverride {
|
|
3
3
|
path?: string;
|
|
4
4
|
contentType?: string;
|
|
@@ -6,6 +6,7 @@ export interface FileOverride {
|
|
|
6
6
|
export interface VercelConfig {
|
|
7
7
|
routes?: VercelRoute[];
|
|
8
8
|
overrides?: Record<string, FileOverride>;
|
|
9
|
+
images?: ImagesConfig;
|
|
9
10
|
[key: string]: any;
|
|
10
11
|
}
|
|
11
12
|
export interface VercelRoute {
|
|
@@ -53,6 +54,11 @@ export declare function parseOverrides(configPath: string): Record<string, {
|
|
|
53
54
|
path?: string;
|
|
54
55
|
contentType?: string;
|
|
55
56
|
}>;
|
|
57
|
+
/**
|
|
58
|
+
* Parse images config from config.json (Build Output API).
|
|
59
|
+
* Returns undefined if file missing or images property not defined.
|
|
60
|
+
*/
|
|
61
|
+
export declare function parseImagesConfig(configPath: string): ImagesConfig | undefined;
|
|
56
62
|
/**
|
|
57
63
|
* Scan static files directory to build file manifest
|
|
58
64
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vercel-config.d.ts","sourceRoot":"","sources":["../../src/utils/vercel-config.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"vercel-config.d.ts","sourceRoot":"","sources":["../../src/utils/vercel-config.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEtD,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,WAAW,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACzC,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC3B,OAAO,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC/B,MAAM,CAAC,EAAE;QACP,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAClC,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,QAAQ,CAAC,EAAE;QACT,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,UAAU,CAAC,EAAE,eAAe,EAAE,CAAC;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,GAAG,CAAC;IACZ,IAAI,CAAC,EAAE,GAAG,CAAC;CACZ;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,KAAK,EAAE,CAa7D;AA0ED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,UAAU,EAAE,MAAM,GACjB,MAAM,CAAC,MAAM,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CASzD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,GACjB,YAAY,GAAG,SAAS,CAkB1B;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CA0B7D"}
|
|
@@ -92,6 +92,25 @@ export function parseOverrides(configPath) {
|
|
|
92
92
|
const config = JSON.parse(configContent);
|
|
93
93
|
return config.overrides || {};
|
|
94
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Parse images config from config.json (Build Output API).
|
|
97
|
+
* Returns undefined if file missing or images property not defined.
|
|
98
|
+
*/
|
|
99
|
+
export function parseImagesConfig(configPath) {
|
|
100
|
+
if (!fs.existsSync(configPath)) {
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
const configContent = fs.readFileSync(configPath, "utf8");
|
|
104
|
+
const config = JSON.parse(configContent);
|
|
105
|
+
if (!config.images || typeof config.images !== "object") {
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
108
|
+
const img = config.images;
|
|
109
|
+
if (!Array.isArray(img.sizes) || !Array.isArray(img.domains)) {
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
112
|
+
return img;
|
|
113
|
+
}
|
|
95
114
|
/**
|
|
96
115
|
* Scan static files directory to build file manifest
|
|
97
116
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vercel-config.js","sourceRoot":"","sources":["../../src/utils/vercel-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"vercel-config.js","sourceRoot":"","sources":["../../src/utils/vercel-config.ts"],"names":[],"mappings":"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"}
|
package/dist/utils.d.ts
CHANGED
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
* Handles cases where the path points to:
|
|
4
4
|
* - .vercel/output (use as-is)
|
|
5
5
|
* - .vercel (append 'output')
|
|
6
|
-
* -
|
|
6
|
+
* - .next/output (use as-is)
|
|
7
|
+
* - .next (append 'output')
|
|
8
|
+
* - project root or other (check for .vercel/output first, then .next/output)
|
|
9
|
+
* Expands leading ~ to homedir so build steps using ~/workspace write to the correct location.
|
|
7
10
|
*/
|
|
8
11
|
export declare function resolveVercelOutputDir(inputDir: string): string;
|
|
9
12
|
/**
|
package/dist/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AASA;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAkC/D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAyC1C;AAED,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,YAAY,EAAE,CA0I1E;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAmG7D"}
|
package/dist/utils.js
CHANGED
|
@@ -1,28 +1,55 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
2
|
import * as path from 'path';
|
|
3
|
+
import * as os from "os";
|
|
3
4
|
import * as crypto from 'crypto';
|
|
4
5
|
import { fileURLToPath } from 'url';
|
|
6
|
+
import { generateHandlerWrapper } from "./handler-wrapper.js";
|
|
5
7
|
/**
|
|
6
8
|
* Resolve the Vercel output directory from a given path
|
|
7
9
|
* Handles cases where the path points to:
|
|
8
10
|
* - .vercel/output (use as-is)
|
|
9
11
|
* - .vercel (append 'output')
|
|
10
|
-
* -
|
|
12
|
+
* - .next/output (use as-is)
|
|
13
|
+
* - .next (append 'output')
|
|
14
|
+
* - project root or other (check for .vercel/output first, then .next/output)
|
|
15
|
+
* Expands leading ~ to homedir so build steps using ~/workspace write to the correct location.
|
|
11
16
|
*/
|
|
12
17
|
export function resolveVercelOutputDir(inputDir) {
|
|
13
|
-
const
|
|
18
|
+
const expandedDir = inputDir === "~" || inputDir.startsWith("~/") || inputDir.startsWith("~\\")
|
|
19
|
+
? path.join(os.homedir(), inputDir.slice(1))
|
|
20
|
+
: inputDir;
|
|
21
|
+
const resolvedDir = path.resolve(expandedDir);
|
|
14
22
|
const normalized = resolvedDir.replace(/\\/g, '/'); // Normalize for cross-platform
|
|
15
23
|
if (normalized.endsWith('/.vercel/output') || normalized.endsWith('\\.vercel\\output')) {
|
|
16
24
|
// Already pointing to .vercel/output, use as-is
|
|
17
25
|
return resolvedDir;
|
|
18
26
|
}
|
|
27
|
+
else if (normalized.endsWith('/.next/output') || normalized.endsWith('\\.next\\output')) {
|
|
28
|
+
// Already pointing to .next/output, use as-is
|
|
29
|
+
return resolvedDir;
|
|
30
|
+
}
|
|
19
31
|
else if (normalized.endsWith('/.vercel') || normalized.endsWith('\\.vercel')) {
|
|
20
32
|
// Points to .vercel directory, append 'output'
|
|
21
33
|
return path.join(resolvedDir, 'output');
|
|
22
34
|
}
|
|
35
|
+
else if (normalized.endsWith('/.next') || normalized.endsWith('\\.next')) {
|
|
36
|
+
// Points to .next directory, append 'output'
|
|
37
|
+
return path.join(resolvedDir, 'output');
|
|
38
|
+
}
|
|
23
39
|
else {
|
|
24
|
-
// Points to project root or something else,
|
|
25
|
-
|
|
40
|
+
// Points to project root or something else, check for .vercel/output first, then .next/output
|
|
41
|
+
const vercelOutputPath = path.join(resolvedDir, '.vercel', 'output');
|
|
42
|
+
const nextOutputPath = path.join(resolvedDir, '.next', 'output');
|
|
43
|
+
if (fs.existsSync(vercelOutputPath)) {
|
|
44
|
+
return vercelOutputPath;
|
|
45
|
+
}
|
|
46
|
+
else if (fs.existsSync(nextOutputPath)) {
|
|
47
|
+
return nextOutputPath;
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
// Default to .vercel/output if neither exists (for backwards compatibility)
|
|
51
|
+
return vercelOutputPath;
|
|
52
|
+
}
|
|
26
53
|
}
|
|
27
54
|
}
|
|
28
55
|
/**
|
|
@@ -201,7 +228,7 @@ export function scanFunctions(dir, baseDir) {
|
|
|
201
228
|
* Similar to the bash script: uses sorted file names and contents
|
|
202
229
|
*/
|
|
203
230
|
export function hashFunctionDirectory(funcDir) {
|
|
204
|
-
const hash = crypto.createHash(
|
|
231
|
+
const hash = crypto.createHash("sha256");
|
|
205
232
|
const files = [];
|
|
206
233
|
function walkDir(dir, baseDir) {
|
|
207
234
|
if (!fs.existsSync(dir)) {
|
|
@@ -209,12 +236,15 @@ export function hashFunctionDirectory(funcDir) {
|
|
|
209
236
|
}
|
|
210
237
|
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
211
238
|
// Sort entries by name for deterministic ordering
|
|
212
|
-
entries.sort((a, b) => a.name.localeCompare(b.name,
|
|
239
|
+
entries.sort((a, b) => a.name.localeCompare(b.name, "en", { numeric: true }));
|
|
213
240
|
for (const entry of entries) {
|
|
214
241
|
const fullPath = path.join(dir, entry.name);
|
|
215
242
|
const relativePath = path.relative(baseDir, fullPath);
|
|
216
243
|
// Skip .DS_Store and __MACOSX
|
|
217
|
-
if (entry.name ===
|
|
244
|
+
if (entry.name === ".DS_Store" ||
|
|
245
|
+
entry.name === "__MACOSX" ||
|
|
246
|
+
relativePath.includes("/.DS_Store") ||
|
|
247
|
+
relativePath.includes("/__MACOSX")) {
|
|
218
248
|
continue;
|
|
219
249
|
}
|
|
220
250
|
if (entry.isFile()) {
|
|
@@ -249,15 +279,40 @@ export function hashFunctionDirectory(funcDir) {
|
|
|
249
279
|
}
|
|
250
280
|
// Walk the directory and collect all files
|
|
251
281
|
walkDir(funcDir, funcDir);
|
|
282
|
+
// Include the injected handler wrapper in the hash so that changes to the wrapper
|
|
283
|
+
// (e.g. dynamic import for ESM) produce fresh hashes and deployments.
|
|
284
|
+
let handlerFile = "handler.js";
|
|
285
|
+
const vcConfigPath = path.join(funcDir, ".vc-config.json");
|
|
286
|
+
if (fs.existsSync(vcConfigPath)) {
|
|
287
|
+
try {
|
|
288
|
+
const vcConfig = JSON.parse(fs.readFileSync(vcConfigPath, "utf8"));
|
|
289
|
+
if (vcConfig.handler) {
|
|
290
|
+
handlerFile = vcConfig.handler;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
catch {
|
|
294
|
+
// Use default handler file if config is missing or invalid
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
const wrapperContent = Buffer.from(generateHandlerWrapper(handlerFile), "utf8");
|
|
298
|
+
// Replace any existing handler.js in the dir with our wrapper (zip contents match hash)
|
|
299
|
+
const normalized = (p) => p.split(path.sep).join("/");
|
|
300
|
+
const filtered = files.filter((f) => normalized(f.path) !== "handler.js");
|
|
301
|
+
filtered.push({ path: "handler.js", content: wrapperContent });
|
|
302
|
+
files.length = 0;
|
|
303
|
+
files.push(...filtered);
|
|
252
304
|
// Sort files by path for deterministic ordering
|
|
253
|
-
files.sort((a, b) => a.path.localeCompare(b.path,
|
|
305
|
+
files.sort((a, b) => a.path.localeCompare(b.path, "en", { numeric: true }));
|
|
254
306
|
// Create a deterministic representation
|
|
255
307
|
// Format: path:size:content_hash\n
|
|
256
308
|
for (const file of files) {
|
|
257
|
-
const fileHash = crypto
|
|
309
|
+
const fileHash = crypto
|
|
310
|
+
.createHash("sha256")
|
|
311
|
+
.update(file.content)
|
|
312
|
+
.digest("hex");
|
|
258
313
|
const line = `${file.path}:${file.content.length}:${fileHash}\n`;
|
|
259
314
|
hash.update(line);
|
|
260
315
|
}
|
|
261
|
-
return hash.digest(
|
|
316
|
+
return hash.digest("hex");
|
|
262
317
|
}
|
|
263
318
|
//# sourceMappingURL=utils.js.map
|