blogwright 0.4.0-beta.3 → 0.4.0-beta.5

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/agent/server.js CHANGED
@@ -2,7 +2,7 @@ import { createRequire } from "node:module";
2
2
  import { createServer } from "node:http";
3
3
  import { spawn } from "node:child_process";
4
4
  import { createHash, createHmac, getRandomValues } from "node:crypto";
5
- import { mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
5
+ import { lstat, mkdir, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
6
6
  import { tmpdir } from "node:os";
7
7
  import { dirname, join, relative, sep } from "node:path";
8
8
  import { ReadStream, fstatSync, lstatSync } from "node:fs";
@@ -64,14 +64,35 @@ var AwsError = class extends Error {
64
64
  get isNotFound() {
65
65
  return this.statusCode === 404 || /NotFound|NoSuchEntity|NoSuchBucket|NoSuchKey|ResourceNotFoundException/i.test(this.code);
66
66
  }
67
+ /**
68
+ * True when AWS refused the request for its rate: the request was rejected
69
+ * before it was acted on, so retrying it is safe for any method - a create
70
+ * included. See {@link THROTTLING_CODE}.
71
+ */
72
+ get isThrottling() {
73
+ return this.statusCode === 429 || THROTTLING_CODE.test(this.code);
74
+ }
67
75
  /** True for "already exists" style conflicts that bootstrap can treat as success. */
68
76
  get isAlreadyExists() {
69
77
  return /AlreadyExists|BucketAlreadyOwnedByYou|EntityAlreadyExists|Conflict/i.test(this.code);
70
78
  }
71
79
  };
80
+ /**
81
+ * The error codes AWS services use for a request refused for its rate, across
82
+ * the protocols this repo speaks: CloudFront's and IAM's `Throttling` (HTTP
83
+ * 400), the JSON services' `ThrottlingException` and `TooManyRequestsException`,
84
+ * S3's `SlowDown` (HTTP 503), Route 53's `PriorRequestNotComplete`, and the
85
+ * rest of the family. Matched whole, so a quota error such as
86
+ * `LimitExceededException` - which waiting does not clear - is not retried.
87
+ */
88
+ const THROTTLING_CODE = /^(?:Throttling|ThrottlingException|ThrottledException|Throttled|TooManyRequests|TooManyRequestsException|RequestLimitExceeded|RequestThrottled|RequestThrottledException|SlowDown|PriorRequestNotComplete|ProvisionedThroughputExceededException|BandwidthLimitExceeded|EC2ThrottledException)$/i;
89
+ /** True when an error is AWS refusing a request for its rate. */
90
+ function isThrottling(err) {
91
+ return err instanceof AwsError && err.isThrottling;
92
+ }
72
93
  /** True for transient errors worth retrying with backoff. */
73
94
  function isRetryable(err) {
74
- if (err instanceof AwsError) return err.statusCode >= 500 || err.statusCode === 429 || /Throttling|TooManyRequests|InternalError|ServiceUnavailable/i.test(err.code);
95
+ if (err instanceof AwsError) return err.isThrottling || err.statusCode >= 500 || /InternalError|ServiceUnavailable/i.test(err.code);
75
96
  return err instanceof TypeError;
76
97
  }
77
98
  //#endregion
@@ -5711,6 +5732,7 @@ const SIGNING_NAMES = {
5711
5732
  cloudfront: "cloudfront",
5712
5733
  route53: "route53",
5713
5734
  microvms: "lambda",
5735
+ lambdaweb: "lambda",
5714
5736
  secretsmanager: "secretsmanager"
5715
5737
  };
5716
5738
  /** Services that are global; they always sign in us-east-1. */
@@ -5761,6 +5783,7 @@ function canonicalHost(service, region) {
5761
5783
  case "route53": return "route53.amazonaws.com";
5762
5784
  case "s3": return `s3.${region}.amazonaws.com`;
5763
5785
  case "microvms": return `lambda.${region}.amazonaws.com`;
5786
+ case "lambdaweb": return `lambda.${region}.amazonaws.com`;
5764
5787
  default: return `${service}.${region}.amazonaws.com`;
5765
5788
  }
5766
5789
  }
@@ -5781,6 +5804,10 @@ function encodeTagQuery(tags) {
5781
5804
  function bodyChecksum(body) {
5782
5805
  return createHash("sha256").update(body).digest("base64");
5783
5806
  }
5807
+ /** Base64 MD5 of a request body - DeleteObjects' required integrity header. */
5808
+ function bodyMd5(body) {
5809
+ return createHash("md5").update(body).digest("base64");
5810
+ }
5784
5811
  /** Percent-encode an object key for a path-style URL, preserving '/' separators. */
5785
5812
  function encodeKey(key) {
5786
5813
  return key.split("/").map((seg) => encodeURIComponent(seg).replace(/[!'()*]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`)).join("/");
@@ -5853,7 +5880,7 @@ var S3Client = class {
5853
5880
  });
5854
5881
  }
5855
5882
  async putObject(bucket, key, body, contentType = "application/octet-stream", tags) {
5856
- await this.client.send({
5883
+ return (await this.client.send({
5857
5884
  service: "s3",
5858
5885
  method: "PUT",
5859
5886
  path: this.objectPath(bucket, key),
@@ -5862,8 +5889,38 @@ var S3Client = class {
5862
5889
  ...tags && Object.keys(tags).length > 0 ? { "x-amz-tagging": encodeTagQuery(tags) } : {}
5863
5890
  },
5864
5891
  body
5892
+ })).headers["x-amz-version-id"];
5893
+ }
5894
+ /** Enable or suspend bucket versioning. Never suspended once enabled (see the SSR contract). */
5895
+ async putBucketVersioning(bucket, status) {
5896
+ const body = `<?xml version="1.0" encoding="UTF-8"?><VersioningConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Status>${status}</Status></VersioningConfiguration>`;
5897
+ await this.client.send({
5898
+ service: "s3",
5899
+ method: "PUT",
5900
+ path: `/${bucket}`,
5901
+ query: { versioning: "" },
5902
+ headers: {
5903
+ "content-type": "application/xml",
5904
+ "x-amz-checksum-sha256": bodyChecksum(body)
5905
+ },
5906
+ body
5865
5907
  });
5866
5908
  }
5909
+ /** Current versioning status of a bucket, or undefined when the API reports none. */
5910
+ async getBucketVersioning(bucket) {
5911
+ try {
5912
+ const status = textTag((await this.client.send({
5913
+ service: "s3",
5914
+ method: "GET",
5915
+ path: `/${bucket}`,
5916
+ query: { versioning: "" }
5917
+ })).text(), "Status");
5918
+ return status === "Enabled" || status === "Suspended" ? status : void 0;
5919
+ } catch (err) {
5920
+ if (err instanceof AwsError && err.isNotFound) return void 0;
5921
+ throw err;
5922
+ }
5923
+ }
5867
5924
  /** Apply bucket tags (idempotent full replace). */
5868
5925
  async putBucketTagging(bucket, tags) {
5869
5926
  const body = `<?xml version="1.0" encoding="UTF-8"?><Tagging xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><TagSet>${Object.entries(tags).map(([k, v]) => `<Tag><Key>${encodeEntities(k)}</Key><Value>${encodeEntities(v)}</Value></Tag>`).join("")}</TagSet></Tagging>`;
@@ -5908,6 +5965,21 @@ var S3Client = class {
5908
5965
  throw err;
5909
5966
  }
5910
5967
  }
5968
+ /** True when one specific object version still exists (rollback's artifact check). */
5969
+ async objectVersionExists(bucket, key, versionId) {
5970
+ try {
5971
+ await this.client.send({
5972
+ service: "s3",
5973
+ method: "HEAD",
5974
+ path: this.objectPath(bucket, key),
5975
+ query: { versionId }
5976
+ });
5977
+ return true;
5978
+ } catch (err) {
5979
+ if (err instanceof AwsError && err.isNotFound) return false;
5980
+ throw err;
5981
+ }
5982
+ }
5911
5983
  async deleteObject(bucket, key) {
5912
5984
  await this.client.send({
5913
5985
  service: "s3",
@@ -5963,6 +6035,88 @@ var S3Client = class {
5963
6035
  body: policy
5964
6036
  });
5965
6037
  }
6038
+ /** The bucket's current policy document, or undefined when it has none. */
6039
+ async getBucketPolicy(bucket) {
6040
+ try {
6041
+ return (await this.client.send({
6042
+ service: "s3",
6043
+ method: "GET",
6044
+ path: `/${bucket}`,
6045
+ query: { policy: "" }
6046
+ })).text();
6047
+ } catch (err) {
6048
+ if (err instanceof AwsError && err.isNotFound) return void 0;
6049
+ throw err;
6050
+ }
6051
+ }
6052
+ /**
6053
+ * Every object version (and delete marker) under a prefix, following the
6054
+ * ListObjectVersions key/version-id markers. Only the bucket node's teardown
6055
+ * reads this - a plain `deletePrefix` cannot empty a versioned bucket.
6056
+ */
6057
+ async listObjectVersions(bucket, prefix) {
6058
+ const out = [];
6059
+ let keyMarker;
6060
+ let versionIdMarker;
6061
+ for (;;) {
6062
+ const xml = (await this.client.send({
6063
+ service: "s3",
6064
+ method: "GET",
6065
+ path: `/${bucket}`,
6066
+ query: {
6067
+ versions: "",
6068
+ prefix,
6069
+ ...keyMarker ? { "key-marker": keyMarker } : {},
6070
+ ...versionIdMarker ? { "version-id-marker": versionIdMarker } : {}
6071
+ }
6072
+ })).text();
6073
+ for (const tag of ["Version", "DeleteMarker"]) for (const block of allTags(xml, tag)) {
6074
+ const key = rawTextTag(block, "Key");
6075
+ const versionId = textTag(block, "VersionId") ?? "";
6076
+ if (key === void 0 || versionId === "") continue;
6077
+ out.push({
6078
+ key,
6079
+ versionId,
6080
+ isDeleteMarker: tag === "DeleteMarker",
6081
+ size: Number(textTag(block, "Size") ?? "0")
6082
+ });
6083
+ }
6084
+ if (textTag(xml, "IsTruncated") !== "true") break;
6085
+ const nextKey = textTag(xml, "NextKeyMarker");
6086
+ const nextVersion = textTag(xml, "NextVersionIdMarker");
6087
+ if (!nextKey) break;
6088
+ keyMarker = nextKey;
6089
+ versionIdMarker = nextVersion;
6090
+ }
6091
+ return out;
6092
+ }
6093
+ /**
6094
+ * Remove every version and delete marker under a prefix with batched
6095
+ * DeleteObjects requests. Version-aware removal is deliberately NOT what
6096
+ * `deletePrefix` does: no role that deletes a prefix today holds
6097
+ * `s3:ListBucketVersions`/`s3:DeleteObjectVersion`, so only the bucket's own
6098
+ * teardown may call this. Returns the number of entries removed.
6099
+ */
6100
+ async deleteAllVersions(bucket, prefix) {
6101
+ const versions = await this.listObjectVersions(bucket, prefix);
6102
+ for (let i = 0; i < versions.length; i += 1e3) {
6103
+ const body = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Delete xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">" + versions.slice(i, i + 1e3).map((v) => `<Object><Key>${encodeEntities(v.key)}</Key><VersionId>${encodeEntities(v.versionId)}</VersionId></Object>`).join("") + "<Quiet>true</Quiet></Delete>";
6104
+ const failures = allTags((await this.client.send({
6105
+ service: "s3",
6106
+ method: "POST",
6107
+ path: `/${bucket}`,
6108
+ query: { delete: "" },
6109
+ headers: {
6110
+ "content-type": "application/xml",
6111
+ "content-md5": bodyMd5(body)
6112
+ },
6113
+ body
6114
+ })).text(), "Error");
6115
+ const first = failures[0];
6116
+ if (first !== void 0) throw new Error(`could not delete ${failures.length} object version(s) under s3://${bucket}/${prefix}: ${textTag(first, "Code") ?? "error"} on ${rawTextTag(first, "Key") ?? "an entry"}${textTag(first, "Message") ? ` (${textTag(first, "Message")})` : ""}`);
6117
+ }
6118
+ return versions.length;
6119
+ }
5966
6120
  /** Build an S3 REST-XML error-free marker; exported for callers needing entity-safe values. */
5967
6121
  static xmlValue(value) {
5968
6122
  return encodeEntities(value);
@@ -7060,6 +7214,29 @@ var require_dist_cjs = /* @__PURE__ */ __commonJSMin(((exports) => {
7060
7214
  }));
7061
7215
  //#endregion
7062
7216
  //#region ../core/dist/util.js
7217
+ /**
7218
+ * The fixed timestamp every reproducible zip in this repo stamps its entries
7219
+ * with, so identical input bytes always produce identical archive bytes.
7220
+ *
7221
+ * **Constructed from local parts on purpose, and the obvious `Date.UTC` form is
7222
+ * a bug.** A zip's DOS timestamp is *local* time, and `fflate` reads it with
7223
+ * `getFullYear()`/`getMonth()`/`getDate()`, so a `Date` fixed in UTC lands on a
7224
+ * different local date in every zone. Two things follow, and this repo shipped
7225
+ * both:
7226
+ *
7227
+ * - `new Date('1980-01-01T00:00:00Z')` is 1979-12-31 local anywhere west of
7228
+ * Greenwich, and `fflate` throws `date not in range 1980-2099` outright -
7229
+ * so `blogwright bootstrap`, `deploy` and `analytics bootstrap` all failed
7230
+ * for most of the Americas while passing in CI, which runs `TZ=UTC`.
7231
+ * - Even where it did not throw, the encoded timestamp differed by zone, so
7232
+ * the archive was *not* reproducible - the property the constant exists to
7233
+ * provide. The crash was hiding that.
7234
+ *
7235
+ * A local-constructed 1980-01-02 is 1980-01-02 in every zone by construction:
7236
+ * in range everywhere, and byte-identical everywhere. The second of January
7237
+ * rather than the first so that no offset can push it below the 1980 floor.
7238
+ */
7239
+ const REPRODUCIBLE_ZIP_MTIME = new Date(1980, 0, 2);
7063
7240
  function sleep(ms) {
7064
7241
  return new Promise((resolve) => setTimeout(resolve, ms));
7065
7242
  }
@@ -7075,7 +7252,8 @@ async function withRetry(fn, opts = {}) {
7075
7252
  } catch (err) {
7076
7253
  lastErr = err;
7077
7254
  if (i === attempts - 1 || !retryable(err)) throw err;
7078
- await sleep(Math.min(max, base * 2 ** i));
7255
+ const ceiling = Math.min(max, base * 2 ** i);
7256
+ await sleep(opts.jitter ? ceiling / 2 + Math.random() * (ceiling / 2) : ceiling);
7079
7257
  }
7080
7258
  throw lastErr;
7081
7259
  }
@@ -7084,6 +7262,19 @@ async function withRetry(fn, opts = {}) {
7084
7262
  var import_main = require_main();
7085
7263
  var import_dist_cjs = require_dist_cjs();
7086
7264
  var import_dist_cjs$1 = require_dist_cjs$4();
7265
+ /**
7266
+ * Backoff for a request AWS refused for its rate. Eight attempts, doubling from
7267
+ * 1 second to a 20-second ceiling with jitter, wait roughly 36-71 seconds in all -
7268
+ * long enough to outlast a burst of throttling from parallel bootstraps against
7269
+ * one account. Other transient failures (5xx, network errors) keep the default
7270
+ * {@link withRetry} budget.
7271
+ */
7272
+ const THROTTLE_RETRY = {
7273
+ attempts: 8,
7274
+ baseDelayMs: 1e3,
7275
+ maxDelayMs: 2e4,
7276
+ jitter: true
7277
+ };
7087
7278
  /** Default transport backed by the global fetch. */
7088
7279
  const fetchTransport = async (req) => {
7089
7280
  const init = {
@@ -7168,7 +7359,13 @@ var SigningClient = class {
7168
7359
  }).sign(request);
7169
7360
  const qs = Object.keys(query).map((k) => `${escape(k)}=${escape(query[k])}`).join("&");
7170
7361
  const url = `${ep.protocol}//${ep.host}${opts.path}${qs ? `?${qs}` : ""}`;
7171
- return withRetry(async () => {
7362
+ const transient = [
7363
+ "GET",
7364
+ "HEAD",
7365
+ "PUT",
7366
+ "DELETE"
7367
+ ].includes(opts.method) ? isRetryable : (err) => err instanceof TypeError;
7368
+ const attempt = async () => {
7172
7369
  const response = await this.transport({
7173
7370
  url,
7174
7371
  method: opts.method,
@@ -7177,12 +7374,59 @@ var SigningClient = class {
7177
7374
  });
7178
7375
  if (response.statusCode >= 300) throw parseError(resolved.name, response);
7179
7376
  return response;
7180
- }, { retryable: [
7181
- "GET",
7182
- "HEAD",
7183
- "PUT",
7184
- "DELETE"
7185
- ].includes(opts.method) ? isRetryable : (err) => err instanceof TypeError });
7377
+ };
7378
+ return withRetry(() => withRetry(attempt, {
7379
+ ...THROTTLE_RETRY,
7380
+ retryable: isThrottling
7381
+ }), { retryable: (err) => !isThrottling(err) && transient(err) });
7382
+ }
7383
+ /**
7384
+ * Sign and send a request to an explicit URL - an application endpoint, not
7385
+ * an AWS service endpoint - with `x-amz-content-sha256` always present (a
7386
+ * Lambda Web Function endpoint rejects a signed request without it).
7387
+ *
7388
+ * Unlike {@link send}, an HTTP error status is RETURNED rather than thrown:
7389
+ * the Web Function probe needs the status and headers of a 403 or 5xx to
7390
+ * tell an application answer from an authorization refusal, and neither is
7391
+ * a transport failure. Network errors still throw.
7392
+ */
7393
+ async sendToUrl(opts) {
7394
+ const url = new URL(opts.url);
7395
+ const contentHash = await sha256Hex(opts.body);
7396
+ const headers = {
7397
+ host: url.host,
7398
+ "x-amz-content-sha256": contentHash,
7399
+ ...opts.headers
7400
+ };
7401
+ const request = new import_dist_cjs.HttpRequest({
7402
+ protocol: url.protocol === "http:" ? "http:" : "https:",
7403
+ hostname: url.hostname,
7404
+ ...url.port ? { port: Number(url.port) } : {},
7405
+ method: opts.method,
7406
+ path: url.pathname,
7407
+ query: Object.fromEntries(url.searchParams.entries()),
7408
+ headers,
7409
+ ...opts.body !== void 0 ? { body: opts.body } : {}
7410
+ });
7411
+ const signed = await new import_dist_cjs$1.SignatureV4({
7412
+ service: opts.service,
7413
+ region: this.region,
7414
+ credentials: async () => {
7415
+ const c = await this.credentials();
7416
+ return {
7417
+ accessKeyId: c.accessKeyId,
7418
+ secretAccessKey: c.secretAccessKey,
7419
+ ...c.sessionToken ? { sessionToken: c.sessionToken } : {}
7420
+ };
7421
+ },
7422
+ sha256: import_main.Sha256
7423
+ }).sign(request);
7424
+ return this.transport({
7425
+ url: url.toString(),
7426
+ method: opts.method,
7427
+ headers: signed.headers,
7428
+ body: opts.body
7429
+ });
7186
7430
  }
7187
7431
  };
7188
7432
  function parseError(service, response) {
@@ -7325,7 +7569,7 @@ var revfl = _a.r;
7325
7569
  fl[28] = 258, revfl[258] = 28;
7326
7570
  var _b = freb(fdeb, 0);
7327
7571
  var fd = _b.b;
7328
- _b.r;
7572
+ var revfd = _b.r;
7329
7573
  var rev = new u16(32768);
7330
7574
  for (var i = 0; i < 32768; ++i) {
7331
7575
  var x = (i & 43690) >> 1 | (i & 21845) << 1;
@@ -7363,7 +7607,9 @@ for (var i = 256; i < 280; ++i) flt[i] = 7;
7363
7607
  for (var i = 280; i < 288; ++i) flt[i] = 8;
7364
7608
  var fdt = new u8(32);
7365
7609
  for (var i = 0; i < 32; ++i) fdt[i] = 5;
7610
+ var flm = /*#__PURE__*/ hMap(flt, 9, 0);
7366
7611
  var flrm = /*#__PURE__*/ hMap(flt, 9, 1);
7612
+ var fdm = /*#__PURE__*/ hMap(fdt, 5, 0);
7367
7613
  var fdrm = /*#__PURE__*/ hMap(fdt, 5, 1);
7368
7614
  var max = function(a) {
7369
7615
  var m = a[0];
@@ -7525,7 +7771,348 @@ var inflt = function(dat, st, buf, dict) {
7525
7771
  } while (!final);
7526
7772
  return bt != buf.length && noBuf ? slc(buf, 0, bt) : buf.subarray(0, bt);
7527
7773
  };
7774
+ var wbits = function(d, p, v) {
7775
+ v <<= p & 7;
7776
+ var o = p / 8 | 0;
7777
+ d[o] |= v;
7778
+ d[o + 1] |= v >> 8;
7779
+ };
7780
+ var wbits16 = function(d, p, v) {
7781
+ v <<= p & 7;
7782
+ var o = p / 8 | 0;
7783
+ d[o] |= v;
7784
+ d[o + 1] |= v >> 8;
7785
+ d[o + 2] |= v >> 16;
7786
+ };
7787
+ var hTree = function(d, mb) {
7788
+ var t = [];
7789
+ for (var i = 0; i < d.length; ++i) if (d[i]) t.push({
7790
+ s: i,
7791
+ f: d[i]
7792
+ });
7793
+ var s = t.length;
7794
+ var t2 = t.slice();
7795
+ if (!s) return {
7796
+ t: et,
7797
+ l: 0
7798
+ };
7799
+ if (s == 1) {
7800
+ var v = new u8(t[0].s + 1);
7801
+ v[t[0].s] = 1;
7802
+ return {
7803
+ t: v,
7804
+ l: 1
7805
+ };
7806
+ }
7807
+ t.sort(function(a, b) {
7808
+ return a.f - b.f;
7809
+ });
7810
+ t.push({
7811
+ s: -1,
7812
+ f: 25001
7813
+ });
7814
+ var l = t[0], r = t[1], i0 = 0, i1 = 1, i2 = 2;
7815
+ t[0] = {
7816
+ s: -1,
7817
+ f: l.f + r.f,
7818
+ l,
7819
+ r
7820
+ };
7821
+ while (i1 != s - 1) {
7822
+ l = t[t[i0].f < t[i2].f ? i0++ : i2++];
7823
+ r = t[i0 != i1 && t[i0].f < t[i2].f ? i0++ : i2++];
7824
+ t[i1++] = {
7825
+ s: -1,
7826
+ f: l.f + r.f,
7827
+ l,
7828
+ r
7829
+ };
7830
+ }
7831
+ var maxSym = t2[0].s;
7832
+ for (var i = 1; i < s; ++i) if (t2[i].s > maxSym) maxSym = t2[i].s;
7833
+ var tr = new u16(maxSym + 1);
7834
+ var mbt = ln(t[i1 - 1], tr, 0);
7835
+ if (mbt > mb) {
7836
+ var i = 0, dt = 0;
7837
+ var lft = mbt - mb, cst = 1 << lft;
7838
+ t2.sort(function(a, b) {
7839
+ return tr[b.s] - tr[a.s] || a.f - b.f;
7840
+ });
7841
+ for (; i < s; ++i) {
7842
+ var i2_1 = t2[i].s;
7843
+ if (tr[i2_1] > mb) {
7844
+ dt += cst - (1 << mbt - tr[i2_1]);
7845
+ tr[i2_1] = mb;
7846
+ } else break;
7847
+ }
7848
+ dt >>= lft;
7849
+ while (dt > 0) {
7850
+ var i2_2 = t2[i].s;
7851
+ if (tr[i2_2] < mb) dt -= 1 << mb - tr[i2_2]++ - 1;
7852
+ else ++i;
7853
+ }
7854
+ for (; i >= 0 && dt; --i) {
7855
+ var i2_3 = t2[i].s;
7856
+ if (tr[i2_3] == mb) {
7857
+ --tr[i2_3];
7858
+ ++dt;
7859
+ }
7860
+ }
7861
+ mbt = mb;
7862
+ }
7863
+ return {
7864
+ t: new u8(tr),
7865
+ l: mbt
7866
+ };
7867
+ };
7868
+ var ln = function(n, l, d) {
7869
+ return n.s == -1 ? Math.max(ln(n.l, l, d + 1), ln(n.r, l, d + 1)) : l[n.s] = d;
7870
+ };
7871
+ var lc = function(c) {
7872
+ var s = c.length;
7873
+ while (s && !c[--s]);
7874
+ var cl = new u16(++s);
7875
+ var cli = 0, cln = c[0], cls = 1;
7876
+ var w = function(v) {
7877
+ cl[cli++] = v;
7878
+ };
7879
+ for (var i = 1; i <= s; ++i) if (c[i] == cln && i != s) ++cls;
7880
+ else {
7881
+ if (!cln && cls > 2) {
7882
+ for (; cls > 138; cls -= 138) w(32754);
7883
+ if (cls > 2) {
7884
+ w(cls > 10 ? cls - 11 << 5 | 28690 : cls - 3 << 5 | 12305);
7885
+ cls = 0;
7886
+ }
7887
+ } else if (cls > 3) {
7888
+ w(cln), --cls;
7889
+ for (; cls > 6; cls -= 6) w(8304);
7890
+ if (cls > 2) w(cls - 3 << 5 | 8208), cls = 0;
7891
+ }
7892
+ while (cls--) w(cln);
7893
+ cls = 1;
7894
+ cln = c[i];
7895
+ }
7896
+ return {
7897
+ c: cl.subarray(0, cli),
7898
+ n: s
7899
+ };
7900
+ };
7901
+ var clen = function(cf, cl) {
7902
+ var l = 0;
7903
+ for (var i = 0; i < cl.length; ++i) l += cf[i] * cl[i];
7904
+ return l;
7905
+ };
7906
+ var wfblk = function(out, pos, dat) {
7907
+ var s = dat.length;
7908
+ var o = shft(pos + 2);
7909
+ out[o] = s & 255;
7910
+ out[o + 1] = s >> 8;
7911
+ out[o + 2] = out[o] ^ 255;
7912
+ out[o + 3] = out[o + 1] ^ 255;
7913
+ for (var i = 0; i < s; ++i) out[o + i + 4] = dat[i];
7914
+ return (o + 4 + s) * 8;
7915
+ };
7916
+ var wblk = function(dat, out, final, syms, lf, df, eb, li, bs, bl, p) {
7917
+ wbits(out, p++, final);
7918
+ ++lf[256];
7919
+ var _a = hTree(lf, 15), dlt = _a.t, mlb = _a.l;
7920
+ var _b = hTree(df, 15), ddt = _b.t, mdb = _b.l;
7921
+ var _c = lc(dlt), lclt = _c.c, nlc = _c.n;
7922
+ var _d = lc(ddt), lcdt = _d.c, ndc = _d.n;
7923
+ var lcfreq = new u16(19);
7924
+ for (var i = 0; i < lclt.length; ++i) ++lcfreq[lclt[i] & 31];
7925
+ for (var i = 0; i < lcdt.length; ++i) ++lcfreq[lcdt[i] & 31];
7926
+ var _e = hTree(lcfreq, 7), lct = _e.t, mlcb = _e.l;
7927
+ var nlcc = 19;
7928
+ for (; nlcc > 4 && !lct[clim[nlcc - 1]]; --nlcc);
7929
+ var flen = bl + 5 << 3;
7930
+ var ftlen = clen(lf, flt) + clen(df, fdt) + eb;
7931
+ var dtlen = clen(lf, dlt) + clen(df, ddt) + eb + 14 + 3 * nlcc + clen(lcfreq, lct) + 2 * lcfreq[16] + 3 * lcfreq[17] + 7 * lcfreq[18];
7932
+ if (bs >= 0 && flen <= ftlen && flen <= dtlen) return wfblk(out, p, dat.subarray(bs, bs + bl));
7933
+ var lm, ll, dm, dl;
7934
+ wbits(out, p, 1 + (dtlen < ftlen)), p += 2;
7935
+ if (dtlen < ftlen) {
7936
+ lm = hMap(dlt, mlb, 0), ll = dlt, dm = hMap(ddt, mdb, 0), dl = ddt;
7937
+ var llm = hMap(lct, mlcb, 0);
7938
+ wbits(out, p, nlc - 257);
7939
+ wbits(out, p + 5, ndc - 1);
7940
+ wbits(out, p + 10, nlcc - 4);
7941
+ p += 14;
7942
+ for (var i = 0; i < nlcc; ++i) wbits(out, p + 3 * i, lct[clim[i]]);
7943
+ p += 3 * nlcc;
7944
+ var lcts = [lclt, lcdt];
7945
+ for (var it = 0; it < 2; ++it) {
7946
+ var clct = lcts[it];
7947
+ for (var i = 0; i < clct.length; ++i) {
7948
+ var len = clct[i] & 31;
7949
+ wbits(out, p, llm[len]), p += lct[len];
7950
+ if (len > 15) wbits(out, p, clct[i] >> 5 & 127), p += clct[i] >> 12;
7951
+ }
7952
+ }
7953
+ } else lm = flm, ll = flt, dm = fdm, dl = fdt;
7954
+ for (var i = 0; i < li; ++i) {
7955
+ var sym = syms[i];
7956
+ if (sym > 255) {
7957
+ var len = sym >> 18 & 31;
7958
+ wbits16(out, p, lm[len + 257]), p += ll[len + 257];
7959
+ if (len > 7) wbits(out, p, sym >> 23 & 31), p += fleb[len];
7960
+ var dst = sym & 31;
7961
+ wbits16(out, p, dm[dst]), p += dl[dst];
7962
+ if (dst > 3) wbits16(out, p, sym >> 5 & 8191), p += fdeb[dst];
7963
+ } else wbits16(out, p, lm[sym]), p += ll[sym];
7964
+ }
7965
+ wbits16(out, p, lm[256]);
7966
+ return p + ll[256];
7967
+ };
7968
+ var deo = /*#__PURE__*/ new i32([
7969
+ 65540,
7970
+ 131080,
7971
+ 131088,
7972
+ 131104,
7973
+ 262176,
7974
+ 1048704,
7975
+ 1048832,
7976
+ 2114560,
7977
+ 2117632
7978
+ ]);
7528
7979
  var et = /*#__PURE__*/ new u8(0);
7980
+ var dflt = function(dat, lvl, plvl, pre, post, st) {
7981
+ var s = st.z || dat.length;
7982
+ var o = new u8(pre + s + 5 * (1 + Math.ceil(s / 7e3)) + post);
7983
+ var w = o.subarray(pre, o.length - post);
7984
+ var lst = st.l;
7985
+ var pos = (st.r || 0) & 7;
7986
+ if (lvl) {
7987
+ if (pos) w[0] = st.r >> 3;
7988
+ var opt = deo[lvl - 1];
7989
+ var n = opt >> 13, c = opt & 8191;
7990
+ var msk_1 = (1 << plvl) - 1;
7991
+ var prev = st.p || new u16(32768), head = st.h || new u16(msk_1 + 1);
7992
+ var bs1_1 = Math.ceil(plvl / 3), bs2_1 = 2 * bs1_1;
7993
+ var hsh = function(i) {
7994
+ return (dat[i] ^ dat[i + 1] << bs1_1 ^ dat[i + 2] << bs2_1) & msk_1;
7995
+ };
7996
+ var syms = new i32(25e3);
7997
+ var lf = new u16(288), df = new u16(32);
7998
+ var lc_1 = 0, eb = 0, i = st.i || 0, li = 0, wi = st.w || 0, bs = 0;
7999
+ for (; i + 2 < s; ++i) {
8000
+ var hv = hsh(i);
8001
+ var imod = i & 32767, pimod = head[hv];
8002
+ prev[imod] = pimod;
8003
+ head[hv] = imod;
8004
+ if (wi <= i) {
8005
+ var rem = s - i;
8006
+ if ((lc_1 > 7e3 || li > 24576) && (rem > 423 || !lst)) {
8007
+ pos = wblk(dat, w, 0, syms, lf, df, eb, li, bs, i - bs, pos);
8008
+ li = lc_1 = eb = 0, bs = i;
8009
+ for (var j = 0; j < 286; ++j) lf[j] = 0;
8010
+ for (var j = 0; j < 30; ++j) df[j] = 0;
8011
+ }
8012
+ var l = 2, d = 0, ch_1 = c, dif = imod - pimod & 32767;
8013
+ if (rem > 2 && hv == hsh(i - dif)) {
8014
+ var maxn = Math.min(n, rem) - 1;
8015
+ var maxd = Math.min(32767, i);
8016
+ var ml = Math.min(258, rem);
8017
+ while (dif <= maxd && --ch_1 && imod != pimod) {
8018
+ if (dat[i + l] == dat[i + l - dif]) {
8019
+ var nl = 0;
8020
+ for (; nl < ml && dat[i + nl] == dat[i + nl - dif]; ++nl);
8021
+ if (nl > l) {
8022
+ l = nl, d = dif;
8023
+ if (nl > maxn) break;
8024
+ var mmd = Math.min(dif, nl - 2);
8025
+ var md = 0;
8026
+ for (var j = 0; j < mmd; ++j) {
8027
+ var ti = i - dif + j & 32767;
8028
+ var cd = ti - prev[ti] & 32767;
8029
+ if (cd > md) md = cd, pimod = ti;
8030
+ }
8031
+ }
8032
+ }
8033
+ imod = pimod, pimod = prev[imod];
8034
+ dif += imod - pimod & 32767;
8035
+ }
8036
+ }
8037
+ if (d) {
8038
+ syms[li++] = 268435456 | revfl[l] << 18 | revfd[d];
8039
+ var lin = revfl[l] & 31, din = revfd[d] & 31;
8040
+ eb += fleb[lin] + fdeb[din];
8041
+ ++lf[257 + lin];
8042
+ ++df[din];
8043
+ wi = i + l;
8044
+ ++lc_1;
8045
+ } else {
8046
+ syms[li++] = dat[i];
8047
+ ++lf[dat[i]];
8048
+ }
8049
+ }
8050
+ }
8051
+ for (i = Math.max(i, wi); i < s; ++i) {
8052
+ syms[li++] = dat[i];
8053
+ ++lf[dat[i]];
8054
+ }
8055
+ pos = wblk(dat, w, lst, syms, lf, df, eb, li, bs, i - bs, pos);
8056
+ if (!lst) {
8057
+ st.r = pos & 7 | w[pos / 8 | 0] << 3;
8058
+ pos -= 7;
8059
+ st.h = head, st.p = prev, st.i = i, st.w = wi;
8060
+ }
8061
+ } else {
8062
+ for (var i = st.w || 0; i < s + lst; i += 65535) {
8063
+ var e = i + 65535;
8064
+ if (e >= s) {
8065
+ w[pos / 8 | 0] = lst;
8066
+ e = s;
8067
+ }
8068
+ pos = wfblk(w, pos + 1, dat.subarray(i, e));
8069
+ }
8070
+ st.i = s;
8071
+ }
8072
+ return slc(o, 0, pre + shft(pos) + post);
8073
+ };
8074
+ var crct = /*#__PURE__*/ (function() {
8075
+ var t = /* @__PURE__ */ new Int32Array(256);
8076
+ for (var i = 0; i < 256; ++i) {
8077
+ var c = i, k = 9;
8078
+ while (--k) c = (c & 1 && -306674912) ^ c >>> 1;
8079
+ t[i] = c;
8080
+ }
8081
+ return t;
8082
+ })();
8083
+ var crc = function() {
8084
+ var c = -1;
8085
+ return {
8086
+ p: function(d) {
8087
+ var cr = c;
8088
+ for (var i = 0; i < d.length; ++i) cr = crct[cr & 255 ^ d[i]] ^ cr >>> 8;
8089
+ c = cr;
8090
+ },
8091
+ d: function() {
8092
+ return ~c;
8093
+ }
8094
+ };
8095
+ };
8096
+ var dopt = function(dat, opt, pre, post, st) {
8097
+ if (!st) {
8098
+ st = { l: 1 };
8099
+ if (opt.dictionary) {
8100
+ var dict = opt.dictionary.subarray(-32768);
8101
+ var newDat = new u8(dict.length + dat.length);
8102
+ newDat.set(dict);
8103
+ newDat.set(dat, dict.length);
8104
+ dat = newDat;
8105
+ st.w = dict.length;
8106
+ }
8107
+ }
8108
+ return dflt(dat, opt.level == null ? 6 : opt.level, opt.mem == null ? st.l ? Math.ceil(Math.max(8, Math.min(13, Math.log(dat.length))) * 1.5) : 20 : 12 + opt.mem, pre, post, st);
8109
+ };
8110
+ var mrg = function(a, b) {
8111
+ var o = {};
8112
+ for (var k in a) o[k] = a[k];
8113
+ for (var k in b) o[k] = b[k];
8114
+ return o;
8115
+ };
7529
8116
  var b2 = function(d, b) {
7530
8117
  return d[b] | d[b + 1] << 8;
7531
8118
  };
@@ -7535,9 +8122,33 @@ var b4 = function(d, b) {
7535
8122
  var b8 = function(d, b) {
7536
8123
  return b4(d, b) + b4(d, b + 4) * 4294967296;
7537
8124
  };
8125
+ var wbytes = function(d, b, v) {
8126
+ for (; v; ++b) d[b] = v, v >>>= 8;
8127
+ };
8128
+ /**
8129
+ * Compresses data with DEFLATE without any wrapper
8130
+ * @param data The data to compress
8131
+ * @param opts The compression options
8132
+ * @returns The deflated version of the data
8133
+ */
8134
+ function deflateSync(data, opts) {
8135
+ return dopt(data, opts || {}, 0, 0);
8136
+ }
7538
8137
  function inflateSync(data, opts) {
7539
8138
  return inflt(data, { i: 2 }, opts && opts.out, opts && opts.dictionary);
7540
8139
  }
8140
+ var fltn = function(d, p, t, o) {
8141
+ for (var k in d) {
8142
+ var val = d[k], n = p + k, op = o;
8143
+ if (Array.isArray(val)) op = mrg(o, val[1]), val = val[0];
8144
+ if (ArrayBuffer.isView(val)) t[n] = [val, op];
8145
+ else {
8146
+ t[n += "/"] = [new u8(0), op];
8147
+ fltn(val, n, t, o);
8148
+ }
8149
+ }
8150
+ };
8151
+ var te = typeof TextEncoder != "undefined" && /*#__PURE__*/ new TextEncoder();
7541
8152
  var td = typeof TextDecoder != "undefined" && /*#__PURE__*/ new TextDecoder();
7542
8153
  try {
7543
8154
  td.decode(et, { stream: true });
@@ -7557,6 +8168,40 @@ var dutf8 = function(d) {
7557
8168
  }
7558
8169
  };
7559
8170
  /**
8171
+ * Converts a string into a Uint8Array for use with compression/decompression methods
8172
+ * @param str The string to encode
8173
+ * @param latin1 Whether or not to interpret the data as Latin-1. This should
8174
+ * not need to be true unless decoding a binary string.
8175
+ * @returns The string encoded in UTF-8/Latin-1 binary
8176
+ */
8177
+ function strToU8(str, latin1) {
8178
+ if (latin1) {
8179
+ var ar_1 = new u8(str.length);
8180
+ for (var i = 0; i < str.length; ++i) ar_1[i] = str.charCodeAt(i);
8181
+ return ar_1;
8182
+ }
8183
+ if (te) return te.encode(str);
8184
+ var l = str.length;
8185
+ var ar = new u8(str.length + (str.length >> 1));
8186
+ var ai = 0;
8187
+ var w = function(v) {
8188
+ ar[ai++] = v;
8189
+ };
8190
+ for (var i = 0; i < l; ++i) {
8191
+ if (ai + 5 > ar.length) {
8192
+ var n = new u8(ai + 8 + (l - i << 1));
8193
+ n.set(ar);
8194
+ ar = n;
8195
+ }
8196
+ var c = str.charCodeAt(i);
8197
+ if (c < 128 || latin1) w(c);
8198
+ else if (c < 2048) w(192 | c >> 6), w(128 | c & 63);
8199
+ else if (c > 55295 && c < 57344) c = 65536 + (c & 1047552) | str.charCodeAt(++i) & 1023, w(240 | c >> 18), w(128 | c >> 12 & 63), w(128 | c >> 6 & 63), w(128 | c & 63);
8200
+ else w(224 | c >> 12), w(128 | c >> 6 & 63), w(128 | c & 63);
8201
+ }
8202
+ return slc(ar, 0, ai);
8203
+ }
8204
+ /**
7560
8205
  * Converts a Uint8Array to a string
7561
8206
  * @param dat The data to decode to string
7562
8207
  * @param latin1 Whether or not to interpret the data as Latin-1. This should
@@ -7609,6 +8254,104 @@ var z64hs = function(d, b, l, z, sc, su, off) {
7609
8254
  0
7610
8255
  ];
7611
8256
  };
8257
+ var exfl = function(ex) {
8258
+ var le = 0;
8259
+ if (ex) for (var k in ex) {
8260
+ var l = ex[k].length;
8261
+ if (l > 65535) err(9);
8262
+ le += l + 4;
8263
+ }
8264
+ return le;
8265
+ };
8266
+ var wzh = function(d, b, f, fn, u, c, ce, co) {
8267
+ var fl = fn.length, ex = f.extra, col = co && co.length;
8268
+ var exl = exfl(ex);
8269
+ wbytes(d, b, ce != null ? 33639248 : 67324752), b += 4;
8270
+ if (ce != null) d[b++] = 20, d[b++] = f.os;
8271
+ d[b] = 20, b += 2;
8272
+ d[b++] = f.flag << 1 | (c < 0 && 8), d[b++] = u && 8;
8273
+ d[b++] = f.compression & 255, d[b++] = f.compression >> 8;
8274
+ var dt = new Date(f.mtime == null ? Date.now() : f.mtime), y = dt.getFullYear() - 1980;
8275
+ if (y < 0 || y > 119) err(10);
8276
+ wbytes(d, b, y << 25 | dt.getMonth() + 1 << 21 | dt.getDate() << 16 | dt.getHours() << 11 | dt.getMinutes() << 5 | dt.getSeconds() >> 1), b += 4;
8277
+ if (c != -1) {
8278
+ wbytes(d, b, f.crc);
8279
+ wbytes(d, b + 4, c < 0 ? -c - 2 : c);
8280
+ wbytes(d, b + 8, f.size);
8281
+ }
8282
+ wbytes(d, b + 12, fl);
8283
+ wbytes(d, b + 14, exl), b += 16;
8284
+ if (ce != null) {
8285
+ wbytes(d, b, col);
8286
+ wbytes(d, b + 6, f.attrs);
8287
+ wbytes(d, b + 10, ce), b += 14;
8288
+ }
8289
+ d.set(fn, b);
8290
+ b += fl;
8291
+ if (exl) for (var k in ex) {
8292
+ var exf = ex[k], l = exf.length;
8293
+ wbytes(d, b, +k);
8294
+ wbytes(d, b + 2, l);
8295
+ d.set(exf, b + 4), b += 4 + l;
8296
+ }
8297
+ if (col) d.set(co, b), b += col;
8298
+ return b;
8299
+ };
8300
+ var wzf = function(o, b, c, d, e) {
8301
+ wbytes(o, b, 101010256);
8302
+ wbytes(o, b + 8, c);
8303
+ wbytes(o, b + 10, c);
8304
+ wbytes(o, b + 12, d);
8305
+ wbytes(o, b + 16, e);
8306
+ };
8307
+ /**
8308
+ * Synchronously creates a ZIP file. Prefer using `zip` for better performance
8309
+ * with more than one file.
8310
+ * @param data The directory structure for the ZIP archive
8311
+ * @param opts The main options, merged with per-file options
8312
+ * @returns The generated ZIP archive
8313
+ */
8314
+ function zipSync(data, opts) {
8315
+ if (!opts) opts = {};
8316
+ var r = {};
8317
+ var files = [];
8318
+ fltn(data, "", r, opts);
8319
+ var o = 0;
8320
+ var tot = 0;
8321
+ for (var fn in r) {
8322
+ var _a = r[fn], file = _a[0], p = _a[1];
8323
+ var compression = p.level == 0 ? 0 : 8;
8324
+ var f = strToU8(fn), s = f.length;
8325
+ var com = p.comment, m = com && strToU8(com), ms = m && m.length;
8326
+ var exl = exfl(p.extra);
8327
+ if (s > 65535) err(11);
8328
+ var d = compression ? deflateSync(file, p) : file, l = d.length;
8329
+ var c = crc();
8330
+ c.p(file);
8331
+ files.push(mrg(p, {
8332
+ size: file.length,
8333
+ crc: c.d(),
8334
+ c: d,
8335
+ f,
8336
+ m,
8337
+ u: s != fn.length || m && com.length != ms,
8338
+ o,
8339
+ compression
8340
+ }));
8341
+ o += 30 + s + exl + l;
8342
+ tot += 76 + 2 * (s + exl) + (ms || 0) + l;
8343
+ }
8344
+ var out = new u8(tot + 22), oe = o, cdl = tot - o;
8345
+ for (var i = 0; i < files.length; ++i) {
8346
+ var f = files[i];
8347
+ wzh(out, f.o, f, f.f, f.u, f.c.length);
8348
+ var badd = 30 + f.f.length + exfl(f.extra);
8349
+ out.set(f.c, f.o + badd);
8350
+ wzh(out, o, f, f.f, f.u, f.c.length, f.o, f.m), o += 16 + badd + (f.m ? f.m.length : 0);
8351
+ }
8352
+ wzf(out, o, files.length, cdl, oe);
8353
+ return out;
8354
+ }
7612
8355
  /**
7613
8356
  * Synchronously decompresses a ZIP archive. Prefer using `unzip` for better
7614
8357
  * performance with more than one file.
@@ -7875,6 +8618,177 @@ async function walkFiles(dir) {
7875
8618
  }
7876
8619
  return out;
7877
8620
  }
8621
+ /** The unzipped package size bound Lambda enforces. */
8622
+ const MAX_PACKAGE_BYTES = 512 * 1024 * 1024;
8623
+ /**
8624
+ * A package that must be self-contained: Lambda loads nothing outside the
8625
+ * archive, and pnpm's default `node_modules` is a symlink tree, so a symlink
8626
+ * anywhere in the package means the app cannot load once deployed. Fail the
8627
+ * build naming the path rather than archiving a tree that cannot run.
8628
+ */
8629
+ async function walkPackageFiles(dir, prefix = "") {
8630
+ const out = [];
8631
+ const entries = await readdir(dir, { withFileTypes: true });
8632
+ entries.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
8633
+ for (const entry of entries) {
8634
+ const full = join(dir, entry.name);
8635
+ const rel = `${prefix}${entry.name}`;
8636
+ if (entry.isSymbolicLink()) throw new Error(`SSR package contains a symbolic link at ${rel}: Lambda loads nothing that is not in the archive, so the package must be self-contained (copy production dependencies in as real files instead of relying on pnpm's symlinked node_modules)`);
8637
+ if (entry.isDirectory()) out.push(...await walkPackageFiles(full, `${rel}/`));
8638
+ else if (entry.isFile()) out.push({
8639
+ path: full,
8640
+ rel,
8641
+ size: (await stat(full)).size
8642
+ });
8643
+ }
8644
+ return out;
8645
+ }
8646
+ /**
8647
+ * Zip the built package with its contents at the archive root and a fixed
8648
+ * timestamp, so identical output produces identical bytes. A generated entry
8649
+ * shim is added to the archive only; the build output on disk is untouched.
8650
+ */
8651
+ async function packageWebFunction(packageDir, entryPoint, shim) {
8652
+ const entryPath = join(packageDir, ...entryPoint.split("/"));
8653
+ let entry;
8654
+ try {
8655
+ entry = await lstat(entryPath);
8656
+ } catch {
8657
+ throw new Error(`SSR package entry point "${entryPoint}" does not exist under ${packageDir}; ` + (shim ? "the build must emit it (with ssr.shim set, it is the framework's server entry the generated shim imports)" : "the build must emit it (a consumer-owned entry shim, or ssr.shim, is the usual way)"));
8658
+ }
8659
+ if (!entry.isFile()) throw new Error(`SSR package entry point "${entryPoint}" is not a file`);
8660
+ const files = await walkPackageFiles(packageDir);
8661
+ const shimBytes = shim ? new TextEncoder().encode(shim.source) : void 0;
8662
+ if (shim && files.some((file) => file.rel === shim.path)) throw new Error(`SSR package already contains ${shim.path}, the path of the entry shim generated from config.ssr.shim: remove the build step that emits it, or drop ssr.shim and point ssr.entryPoint at your own shim`);
8663
+ const unzipped = files.reduce((total, file) => total + file.size, 0) + (shimBytes?.byteLength ?? 0);
8664
+ if (unzipped > 536870912) throw new Error(`SSR package is ${(unzipped / (1024 * 1024)).toFixed(1)} MB unzipped, over Lambda's ${MAX_PACKAGE_BYTES / (1024 * 1024)} MB limit`);
8665
+ const entries = {};
8666
+ for (const file of files) entries[file.rel] = new Uint8Array(await readFile(file.path));
8667
+ if (shim && shimBytes) entries[shim.path] = shimBytes;
8668
+ return {
8669
+ zip: zipSync(entries, {
8670
+ level: 6,
8671
+ mtime: REPRODUCIBLE_ZIP_MTIME
8672
+ }),
8673
+ size: unzipped
8674
+ };
8675
+ }
8676
+ /**
8677
+ * Upload the files under `rootDir` to the site prefix, comparing each file's
8678
+ * MD5 to the existing object's ETag so only genuinely changed content is
8679
+ * re-uploaded. Returns the keys this build wrote and - when `deleteStale` is
8680
+ * false, which is the SSR mode - the keys left behind, which only the CLI may
8681
+ * remove, after a revision is verified.
8682
+ */
8683
+ async function publishFiles(opts) {
8684
+ const { s3, log } = opts;
8685
+ const existing = new Map((await s3.listObjects(opts.bucket, opts.prefix)).map((o) => [o.key, o.etag]));
8686
+ const uploadSiteFile = createSiteUploader(s3, log);
8687
+ const uploaded = /* @__PURE__ */ new Set();
8688
+ const changedKeys = /* @__PURE__ */ new Set();
8689
+ const unmapped = /* @__PURE__ */ new Set();
8690
+ if (opts.refresh) log("refresh: re-uploading every file (metadata - content type, tags - may have changed)");
8691
+ for (const file of opts.files) {
8692
+ const key = opts.prefix + relative(opts.rootDir, file).split("\\").join("/");
8693
+ uploaded.add(key);
8694
+ const content = await readFile(file);
8695
+ const md5 = createHash("md5").update(content).digest("hex");
8696
+ const type = contentType(key);
8697
+ const ext = extensionOf(key);
8698
+ if (type === "application/octet-stream" && ext !== void 0) unmapped.add(ext);
8699
+ if (!shouldUpload(existing.get(key), md5, opts.refresh)) continue;
8700
+ await uploadSiteFile(opts.bucket, key, content, type, opts.objectTags);
8701
+ changedKeys.add(key);
8702
+ }
8703
+ if (unmapped.size > 0) log(`warning: no content type mapped for extension(s) ${[...unmapped].sort().join(", ")} - serving them as ${DEFAULT_CONTENT_TYPE}`);
8704
+ const staleKeys = [];
8705
+ for (const key of existing.keys()) {
8706
+ if (uploaded.has(key)) continue;
8707
+ if (opts.deleteStale) {
8708
+ await s3.deleteObject(opts.bucket, key);
8709
+ changedKeys.add(key);
8710
+ } else staleKeys.push(key);
8711
+ }
8712
+ return {
8713
+ changedKeys,
8714
+ staleKeys,
8715
+ count: opts.files.length
8716
+ };
8717
+ }
8718
+ /** Write the changed-paths manifest the CLI reads for a targeted invalidation. */
8719
+ async function writeChangedPaths(s3, log, bucket, hash, changedKeys, prefix) {
8720
+ const changedPaths = [...new Set([...changedKeys].flatMap((k) => invalidationPaths(k, prefix)))];
8721
+ try {
8722
+ await s3.putObject(bucket, `build/changed/${hash}.json`, JSON.stringify({ paths: changedPaths }), "application/json");
8723
+ } catch (err) {
8724
+ log(`warning: could not write changed-paths manifest (${err.message})`);
8725
+ }
8726
+ }
8727
+ /**
8728
+ * Publish the built static assets and, for an SSR environment, package the
8729
+ * server output and upload it as the revision artifact. Returns the number of
8730
+ * published static files and the changed keys.
8731
+ */
8732
+ async function publishBuild(s3, payload, workDir, distDir, log) {
8733
+ const prefix = payload.sitePrefix.endsWith("/") ? payload.sitePrefix : `${payload.sitePrefix}/`;
8734
+ const job = payload.webFunction;
8735
+ if (!job) {
8736
+ const built = await walkFiles(distDir);
8737
+ log(`uploading ${built.length} files to site/`);
8738
+ const published = await publishFiles({
8739
+ s3,
8740
+ log,
8741
+ bucket: payload.bucket,
8742
+ prefix,
8743
+ rootDir: distDir,
8744
+ files: built,
8745
+ objectTags: payload.objectTags,
8746
+ refresh: payload.refresh,
8747
+ deleteStale: true
8748
+ });
8749
+ log(`published ${built.length} files (${published.changedKeys.size} changed) to s3://${payload.bucket}/${prefix}`);
8750
+ return published;
8751
+ }
8752
+ const { zip, size } = await packageWebFunction(resolveWithin(workDir, job.packageDir, "packageDir"), job.entryPoint, job.shim);
8753
+ if (job.shim) log(`added entry shim ${job.shim.path} (starts ${job.entryPoint})`);
8754
+ const digest = createHash("sha256").update(zip).digest("hex");
8755
+ const versionId = await s3.putObject(payload.bucket, job.artifactKey, zip, "application/zip");
8756
+ log(`uploaded SSR package ${job.artifactKey} (${(zip.byteLength / 1024).toFixed(0)} KiB zipped, ${(size / (1024 * 1024)).toFixed(1)} MB unzipped, sha256 ${digest.slice(0, 12)}…)`);
8757
+ let changedKeys = /* @__PURE__ */ new Set();
8758
+ let staleKeys = [];
8759
+ if (job.staticDir) {
8760
+ const staticDir = resolveWithin(workDir, job.staticDir, "staticDir");
8761
+ const assets = await walkFiles(staticDir);
8762
+ log(`publishing ${assets.length} static asset(s) from ${job.staticDir} to site/`);
8763
+ const published = await publishFiles({
8764
+ s3,
8765
+ log,
8766
+ bucket: payload.bucket,
8767
+ prefix,
8768
+ rootDir: staticDir,
8769
+ files: assets,
8770
+ objectTags: payload.objectTags,
8771
+ refresh: payload.refresh,
8772
+ deleteStale: false
8773
+ });
8774
+ changedKeys = published.changedKeys;
8775
+ staleKeys = published.staleKeys;
8776
+ log(`published ${assets.length} static asset(s) (${changedKeys.size} changed) to s3://${payload.bucket}/${prefix}`);
8777
+ } else log("no ssr.staticDir configured - leaving site/ untouched");
8778
+ const result = {
8779
+ artifactKey: job.artifactKey,
8780
+ artifactVersionId: versionId ?? "null",
8781
+ artifactSha256: digest,
8782
+ artifactSize: zip.byteLength,
8783
+ staleStaticKeys: staleKeys
8784
+ };
8785
+ await s3.putObject(payload.bucket, job.resultKey, JSON.stringify(result, null, 2), "application/json");
8786
+ log(`wrote ${job.resultKey} (${staleKeys.length} stale site key(s) left for the CLI)`);
8787
+ return {
8788
+ changedKeys,
8789
+ count: 0
8790
+ };
8791
+ }
7878
8792
  function escapeXml(s) {
7879
8793
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
7880
8794
  }
@@ -7899,7 +8813,10 @@ async function generateSitemap(distDir, base) {
7899
8813
  }
7900
8814
  /**
7901
8815
  * The build pipeline that runs inside the MicroVM: download the source zip, install
7902
- * dependencies, build the Astro site, and sync dist/ to the bucket's site/ prefix.
8816
+ * dependencies, build the site, and publish it. In SSR mode the built package is
8817
+ * zipped and uploaded as a revision artifact, `site/` receives only `staticDir`, and
8818
+ * robots.txt/sitemap.xml generation is skipped because the application owns those
8819
+ * routes.
7903
8820
  */
7904
8821
  async function runBuild(s3, payload, log) {
7905
8822
  const workDir = join(tmpdir(), `build-${payload.hash}`);
@@ -7926,48 +8843,20 @@ async function runBuild(s3, payload, log) {
7926
8843
  ], appDir, log);
7927
8844
  await exec("pnpm", ["run", "build"], appDir, log);
7928
8845
  const distDir = resolveWithin(workDir, payload.distDir ?? "dist", "distDir");
7929
- if (payload.robots !== void 0) {
7930
- await writeFile(join(distDir, "robots.txt"), payload.robots);
7931
- log("wrote robots.txt");
7932
- }
7933
- if (payload.sitemapBaseUrl) {
7934
- const xml = await generateSitemap(distDir, payload.sitemapBaseUrl);
7935
- await writeFile(join(distDir, "sitemap.xml"), xml);
7936
- log("wrote sitemap.xml");
8846
+ if (!payload.webFunction) {
8847
+ if (payload.robots !== void 0) {
8848
+ await writeFile(join(distDir, "robots.txt"), payload.robots);
8849
+ log("wrote robots.txt");
8850
+ }
8851
+ if (payload.sitemapBaseUrl) {
8852
+ const xml = await generateSitemap(distDir, payload.sitemapBaseUrl);
8853
+ await writeFile(join(distDir, "sitemap.xml"), xml);
8854
+ log("wrote sitemap.xml");
8855
+ }
7937
8856
  }
7938
- const built = await walkFiles(distDir);
7939
- log(`uploading ${built.length} files to site/`);
7940
8857
  const prefix = payload.sitePrefix.endsWith("/") ? payload.sitePrefix : `${payload.sitePrefix}/`;
7941
- const existing = new Map((await s3.listObjects(payload.bucket, prefix)).map((o) => [o.key, o.etag]));
7942
- const uploadSiteFile = createSiteUploader(s3, log);
7943
- const uploaded = /* @__PURE__ */ new Set();
7944
- const changedKeys = /* @__PURE__ */ new Set();
7945
- const unmapped = /* @__PURE__ */ new Set();
7946
- if (payload.refresh) log("refresh: re-uploading every file (metadata - content type, tags - may have changed)");
7947
- for (const file of built) {
7948
- const key = prefix + relative(distDir, file).split("\\").join("/");
7949
- uploaded.add(key);
7950
- const content = await readFile(file);
7951
- const md5 = createHash("md5").update(content).digest("hex");
7952
- const type = contentType(key);
7953
- const ext = extensionOf(key);
7954
- if (type === "application/octet-stream" && ext !== void 0) unmapped.add(ext);
7955
- if (!shouldUpload(existing.get(key), md5, payload.refresh)) continue;
7956
- await uploadSiteFile(payload.bucket, key, content, type, payload.objectTags);
7957
- changedKeys.add(key);
7958
- }
7959
- if (unmapped.size > 0) log(`warning: no content type mapped for extension(s) ${[...unmapped].sort().join(", ")} - serving them as ${DEFAULT_CONTENT_TYPE}`);
7960
- for (const key of existing.keys()) if (!uploaded.has(key)) {
7961
- await s3.deleteObject(payload.bucket, key);
7962
- changedKeys.add(key);
7963
- }
7964
- const changedPaths = [...new Set([...changedKeys].flatMap((k) => invalidationPaths(k, prefix)))];
7965
- try {
7966
- await s3.putObject(payload.bucket, `build/changed/${payload.hash}.json`, JSON.stringify({ paths: changedPaths }), "application/json");
7967
- } catch (err) {
7968
- log(`warning: could not write changed-paths manifest (${err.message})`);
7969
- }
7970
- log(`published ${built.length} files (${changedKeys.size} changed) to s3://${payload.bucket}/${prefix}`);
8858
+ const published = await publishBuild(s3, payload, workDir, distDir, log);
8859
+ await writeChangedPaths(s3, log, payload.bucket, payload.hash, published.changedKeys, prefix);
7971
8860
  await rm(workDir, {
7972
8861
  recursive: true,
7973
8862
  force: true
@@ -8048,7 +8937,8 @@ async function poll() {
8048
8937
  robots: next.robots,
8049
8938
  sitemapBaseUrl: next.sitemapBaseUrl,
8050
8939
  objectTags: next.objectTags,
8051
- refresh: next.refresh
8940
+ refresh: next.refresh,
8941
+ ...next.webFunction ? { webFunction: next.webFunction } : {}
8052
8942
  });
8053
8943
  } finally {
8054
8944
  polling = false;