run402-mcp 2.2.0 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/tools/assets-put.d.ts.map +1 -1
- package/dist/tools/assets-put.js +27 -0
- package/dist/tools/assets-put.js.map +1 -1
- package/package.json +4 -5
- package/sdk/README.md +70 -0
- package/sdk/dist/namespaces/assets.d.ts.map +1 -1
- package/sdk/dist/namespaces/assets.js +129 -2
- package/sdk/dist/namespaces/assets.js.map +1 -1
- package/sdk/dist/namespaces/assets.types.d.ts +116 -0
- package/sdk/dist/namespaces/assets.types.d.ts.map +1 -1
- package/sdk/dist/namespaces/deploy.d.ts +5 -0
- package/sdk/dist/namespaces/deploy.d.ts.map +1 -1
- package/sdk/dist/namespaces/deploy.js +165 -27
- package/sdk/dist/namespaces/deploy.js.map +1 -1
- package/sdk/dist/namespaces/deploy.types.d.ts +44 -0
- package/sdk/dist/namespaces/deploy.types.d.ts.map +1 -1
|
@@ -137,6 +137,27 @@ export interface BlobCdnEnvelope {
|
|
|
137
137
|
* Tag emitters require the SHA-256 (only computed when uploaded with
|
|
138
138
|
* `immutable: true`). On non-immutable uploads, calling them throws.
|
|
139
139
|
*/
|
|
140
|
+
/**
|
|
141
|
+
* One image variant generated by the gateway (v1.49+) on `assets.put` for
|
|
142
|
+
* image MIMEs. Three sizes are produced (`thumb` 320w, `medium` 800w,
|
|
143
|
+
* `large` 1920w) plus a full-resolution `display_jpeg` for HEIC/HEIF
|
|
144
|
+
* sources. WebP-only in v1; AVIF is deferred (see `imgTagWithSrcSet`'s
|
|
145
|
+
* JSDoc for the `<picture>` type-precedence footgun).
|
|
146
|
+
*/
|
|
147
|
+
export interface AssetVariant {
|
|
148
|
+
/** Mutable URL of the variant (preferred-host form). */
|
|
149
|
+
url: string;
|
|
150
|
+
/** Content-addressed CDN URL of the variant. Recommended for HTML/CSS. */
|
|
151
|
+
cdn_url: string;
|
|
152
|
+
/** Pixel width of the variant in display orientation. */
|
|
153
|
+
width_px: number;
|
|
154
|
+
/** Pixel height of the variant in display orientation. */
|
|
155
|
+
height_px: number;
|
|
156
|
+
/** Encoded format of the variant. */
|
|
157
|
+
format: "webp" | "jpeg";
|
|
158
|
+
/** Hex SHA-256 of the variant bytes. */
|
|
159
|
+
sha256: string;
|
|
160
|
+
}
|
|
140
161
|
export interface AssetRef {
|
|
141
162
|
key: string;
|
|
142
163
|
size_bytes: number;
|
|
@@ -176,6 +197,42 @@ export interface AssetRef {
|
|
|
176
197
|
/** CloudFront invalidation envelope. For immutable uploads `cdn.ready ===
|
|
177
198
|
* true` and no further action is needed. */
|
|
178
199
|
cdn: BlobCdnEnvelope;
|
|
200
|
+
/** Display-oriented width (post-EXIF rotation) of the source image, in
|
|
201
|
+
* pixels. Present only for image MIMEs against a v1.49+ gateway. */
|
|
202
|
+
width_px?: number;
|
|
203
|
+
/** Display-oriented height (post-EXIF rotation) of the source image, in
|
|
204
|
+
* pixels. Present only for image MIMEs against a v1.49+ gateway. */
|
|
205
|
+
height_px?: number;
|
|
206
|
+
/** Blurhash string suitable for a low-quality image placeholder (LQIP).
|
|
207
|
+
* Present only for image MIMEs against a v1.49+ gateway. */
|
|
208
|
+
blurhash?: string;
|
|
209
|
+
/** Variant spec version. v1 in the v1.49 gateway release. Future
|
|
210
|
+
* spec-version bumps produce different variant bytes at different URLs. */
|
|
211
|
+
variant_spec_version?: string;
|
|
212
|
+
/** Browser-renderable URL for the source. For jpeg/png/webp/avif this
|
|
213
|
+
* equals `cdn_url`. For HEIC/HEIF this points to a generated JPEG
|
|
214
|
+
* display variant so apps render correctly without HEIC-aware code. */
|
|
215
|
+
display_url?: string;
|
|
216
|
+
/** Immutable (content-addressed) form of `display_url`. */
|
|
217
|
+
display_immutable_url?: string;
|
|
218
|
+
/** Generated variant set for image MIMEs ≥320×320. Sub-320 images skip
|
|
219
|
+
* the WebP set (the source IS the thumbnail at that size). `display_jpeg`
|
|
220
|
+
* is present only for HEIC/HEIF sources (full-resolution JPEG transcode). */
|
|
221
|
+
variants?: {
|
|
222
|
+
thumb?: AssetVariant;
|
|
223
|
+
medium?: AssetVariant;
|
|
224
|
+
large?: AssetVariant;
|
|
225
|
+
display_jpeg?: AssetVariant;
|
|
226
|
+
};
|
|
227
|
+
/** Convenience: `variants.thumb.cdn_url` if a thumb variant exists,
|
|
228
|
+
* else `display_url` (acts as the thumbnail for sub-320 images). **Undefined
|
|
229
|
+
* for non-image AssetRefs** — TypeScript narrows accordingly; see also
|
|
230
|
+
* `imgTag()`. */
|
|
231
|
+
thumbUrl?: string;
|
|
232
|
+
/** Convenience: `display_url` falling back to `cdn_url` for images.
|
|
233
|
+
* **Undefined for non-image AssetRefs** — TypeScript narrows accordingly;
|
|
234
|
+
* see also `imgTag()`. */
|
|
235
|
+
displayUrl?: string;
|
|
179
236
|
/**
|
|
180
237
|
* Returns a ready-to-paste `<script>` tag with the content-addressed
|
|
181
238
|
* URL + Subresource Integrity + `crossorigin`. The browser will refuse
|
|
@@ -234,8 +291,67 @@ export interface AssetRef {
|
|
|
234
291
|
* @example
|
|
235
292
|
* asset.imgTag("Company logo")
|
|
236
293
|
* // → <img src="https://pr-abc.run402.com/_blob/logo-a1b2c3d4.png" alt="Company logo" loading="lazy" decoding="async">
|
|
294
|
+
*
|
|
295
|
+
* **v1.49+ HEIC handling:** when the source is HEIC/HEIF, the gateway sets
|
|
296
|
+
* `display_url` to a generated JPEG transcode of the source and `cdn_url`
|
|
297
|
+
* to the original HEIC bytes (which browsers can't render). `imgTag()`
|
|
298
|
+
* defaults `<img src>` to `display_url ?? cdn_url`, so HEIC uploads render
|
|
299
|
+
* correctly without HEIC-specific code in the caller. When the ref carries
|
|
300
|
+
* `width_px` and `height_px`, the emitter also adds `width`/`height`
|
|
301
|
+
* attributes to eliminate Cumulative Layout Shift. Non-image refs omit
|
|
302
|
+
* those attributes silently — `imgTag()` never throws on absence.
|
|
237
303
|
*/
|
|
238
304
|
imgTag(alt?: string): string;
|
|
305
|
+
/**
|
|
306
|
+
* Returns a `<picture>` element with a responsive WebP `<source>` (three
|
|
307
|
+
* sizes: 320w / 800w / 1920w) and the gateway's `display_url` as the
|
|
308
|
+
* `<img>` fallback. Designed for hero images and any layout where the
|
|
309
|
+
* browser should pick the right resolution per viewport.
|
|
310
|
+
*
|
|
311
|
+
* **Both throw conditions fail loud — no silent fallbacks:**
|
|
312
|
+
*
|
|
313
|
+
* - **`opts.sizes` is required.** Without `sizes`, browsers conservatively
|
|
314
|
+
* download the largest candidate in `srcset` (defeating the variant
|
|
315
|
+
* set). The helper throws `LocalError` with a message that names the
|
|
316
|
+
* issue and gives a copy-pasteable example.
|
|
317
|
+
* - **`variants` must be present.** This helper assumes the gateway
|
|
318
|
+
* generated the three WebP variants (image source ≥320×320, encoded
|
|
319
|
+
* successfully). On non-image refs, sub-320 images, or older gateway
|
|
320
|
+
* responses without variants, the helper throws `LocalError` and tells
|
|
321
|
+
* the caller to use `imgTag()` instead. Silent fallback would render a
|
|
322
|
+
* broken layout (no srcset, no responsive benefit) with no diagnostic.
|
|
323
|
+
*
|
|
324
|
+
* **AVIF footgun — why no `<source type="image/avif">`:** `<picture>`
|
|
325
|
+
* browsers select sources by `type` precedence, not best size. A single
|
|
326
|
+
* AVIF source at 1920w would be picked for thumbnails by AVIF-capable
|
|
327
|
+
* browsers, defeating the variant set. AVIF support, if it returns, must
|
|
328
|
+
* land at all three sizes simultaneously OR via a separate `imgTagHero()`
|
|
329
|
+
* helper that opts in explicitly for above-the-fold heroes.
|
|
330
|
+
*
|
|
331
|
+
* @example
|
|
332
|
+
* ref.imgTagWithSrcSet({
|
|
333
|
+
* alt: "Hero",
|
|
334
|
+
* sizes: "(max-width: 800px) 100vw, 1920px",
|
|
335
|
+
* });
|
|
336
|
+
* // → <picture>
|
|
337
|
+
* // <source type="image/webp"
|
|
338
|
+
* // srcset="<thumb-cdn-url> 320w, <medium-cdn-url> 800w, <large-cdn-url> 1920w"
|
|
339
|
+
* // sizes="(max-width: 800px) 100vw, 1920px">
|
|
340
|
+
* // <img src="<display_url>"
|
|
341
|
+
* // alt="Hero"
|
|
342
|
+
* // width="4032" height="3024"
|
|
343
|
+
* // loading="lazy"
|
|
344
|
+
* // decoding="async">
|
|
345
|
+
* // </picture>
|
|
346
|
+
*/
|
|
347
|
+
imgTagWithSrcSet(opts: {
|
|
348
|
+
alt?: string;
|
|
349
|
+
/** REQUIRED. Browser `sizes` attribute (e.g. `"100vw"` or
|
|
350
|
+
* `"(max-width: 800px) 100vw, 1920px"`). Throws when missing/empty. */
|
|
351
|
+
sizes: string;
|
|
352
|
+
/** Default `"lazy"`. Pass `"eager"` for above-the-fold heroes. */
|
|
353
|
+
loading?: "lazy" | "eager";
|
|
354
|
+
}): string;
|
|
239
355
|
}
|
|
240
356
|
/**
|
|
241
357
|
* Return type of `client.blobs.put`. v1.45 widens this to AssetRef; the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assets.types.d.ts","sourceRoot":"","sources":["../../src/namespaces/assets.types.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"assets.types.d.ts","sourceRoot":"","sources":["../../src/namespaces/assets.types.ts"],"names":[],"mappings":"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"}
|
|
@@ -145,5 +145,10 @@ export interface ByteReader {
|
|
|
145
145
|
(): Promise<Uint8Array>;
|
|
146
146
|
label?: string;
|
|
147
147
|
contentType?: string;
|
|
148
|
+
/** Which spec slice category registered this byte reader. Set by the
|
|
149
|
+
* slice-tagged `remember` in `normalizeReleaseSpec` and surfaces on
|
|
150
|
+
* `content.upload.*` events so callers can group telemetry by slice.
|
|
151
|
+
* Cross-kind CAS dedup escalates the value to `"mixed"`. */
|
|
152
|
+
slice?: "release" | "asset" | "mixed";
|
|
148
153
|
}
|
|
149
154
|
//# sourceMappingURL=deploy.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/namespaces/deploy.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/namespaces/deploy.ts"],"names":[],"mappings":"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"}
|
|
@@ -362,8 +362,29 @@ function requireNonEmptyStringQueryOption(value, label, context) {
|
|
|
362
362
|
return value;
|
|
363
363
|
}
|
|
364
364
|
// ─── Internal pipeline ───────────────────────────────────────────────────────
|
|
365
|
+
/**
|
|
366
|
+
* Compute the sorted set of slice kinds the spec carried. Surfaces on
|
|
367
|
+
* `commit.phase` and `ready` events so agents can group per-phase
|
|
368
|
+
* telemetry by slice category. `assets` slice → `"asset"`; any of
|
|
369
|
+
* `database` / `functions` / `site` → `"release"`. Order is stable
|
|
370
|
+
* (release before asset).
|
|
371
|
+
*/
|
|
372
|
+
function deriveSliceKinds(spec) {
|
|
373
|
+
// Guard against non-object spec — the validate phase throws below
|
|
374
|
+
// (INVALID_SPEC), but this is called before validation in applyOnce so
|
|
375
|
+
// we must not blow up first.
|
|
376
|
+
if (!spec || typeof spec !== "object")
|
|
377
|
+
return [];
|
|
378
|
+
const set = new Set();
|
|
379
|
+
if (spec.database || spec.functions || spec.site)
|
|
380
|
+
set.add("release");
|
|
381
|
+
if (spec.assets)
|
|
382
|
+
set.add("asset");
|
|
383
|
+
return [...set].sort((a, b) => (a === "release" ? -1 : 1));
|
|
384
|
+
}
|
|
365
385
|
async function applyOnce(client, spec, opts, emit) {
|
|
366
386
|
const allowWarningCodes = normalizeAllowWarningCodes(opts.allowWarningCodes);
|
|
387
|
+
const sliceKinds = deriveSliceKinds(spec);
|
|
367
388
|
emit({ type: "plan.started" });
|
|
368
389
|
const { plan, byteReaders } = await planInternal(client, spec, opts.idempotencyKey);
|
|
369
390
|
emit({ type: "plan.diff", diff: plan.diff });
|
|
@@ -383,16 +404,79 @@ async function applyOnce(client, spec, opts, emit) {
|
|
|
383
404
|
// event and resolve before we hit upload.
|
|
384
405
|
}
|
|
385
406
|
await uploadMissing(client, spec.project, plan.missing_content, byteReaders, emit);
|
|
386
|
-
emit({
|
|
407
|
+
emit({
|
|
408
|
+
type: "commit.phase",
|
|
409
|
+
phase: "validate",
|
|
410
|
+
status: "started",
|
|
411
|
+
...(sliceKinds.length > 0 ? { slice_kinds: sliceKinds } : {}),
|
|
412
|
+
});
|
|
387
413
|
const { planId } = requirePersistedPlan(plan, "applying deploy");
|
|
388
414
|
const commit = await commitInternal(client, planId, opts.idempotencyKey);
|
|
389
|
-
const result = await pollUntilReady(client, commit, plan.diff, plan.warnings, emit, spec.project);
|
|
415
|
+
const result = await pollUntilReady(client, commit, plan.diff, plan.warnings, emit, spec.project, sliceKinds);
|
|
390
416
|
// v1.48 unified-apply: thread the plan response's `asset_entries[]` back
|
|
391
417
|
// into DeployResult.assets so callers reading `result.assets.byKey[key]`
|
|
392
418
|
// get the gateway-authoritative `AssetRef` envelope (URLs, SRI, etag).
|
|
393
419
|
// Release-only applies leave `result.assets` undefined.
|
|
394
420
|
if (plan.asset_entries && plan.asset_entries.length > 0) {
|
|
395
421
|
result.assets = buildAssetManifestFromPlanEntries(plan.asset_entries);
|
|
422
|
+
// v1.49 image-variant follow-up: variants are generated AT COMMIT TIME
|
|
423
|
+
// (parent gateway change Section 5 — `prepareStagedAssetVariants` runs
|
|
424
|
+
// before the activation txn opens). The plan that funded `result.assets`
|
|
425
|
+
// was built BEFORE commit, so its `asset_entries[].asset_ref` doesn't
|
|
426
|
+
// include the variant fields (the gateway only threads `image_data`
|
|
427
|
+
// through `buildAssetRefForPlan` for SHAs that ALREADY have variants
|
|
428
|
+
// in `internal.blob_image_variants`).
|
|
429
|
+
//
|
|
430
|
+
// For image puts, do a dry-run re-plan with the same spec. Bytes are
|
|
431
|
+
// now in CAS (the commit just landed) AND variant rows exist in the
|
|
432
|
+
// DB. The new plan response surfaces the variants. Dry-run keeps it
|
|
433
|
+
// cheap: no new plan_id or operation_id rows are created.
|
|
434
|
+
//
|
|
435
|
+
// Best-effort: a re-plan failure shouldn't fail the apply. The bytes
|
|
436
|
+
// are committed, the release is live, and the variant fields are
|
|
437
|
+
// strictly additive — leaving them empty when the recheck errors is
|
|
438
|
+
// worse than failing the apply.
|
|
439
|
+
const hasImagePut = spec.assets?.put?.some((entry) => {
|
|
440
|
+
const ct = ("content_type" in entry && typeof entry.content_type === "string")
|
|
441
|
+
? entry.content_type
|
|
442
|
+
: "";
|
|
443
|
+
return ct.startsWith("image/");
|
|
444
|
+
});
|
|
445
|
+
if (hasImagePut) {
|
|
446
|
+
try {
|
|
447
|
+
const { plan: recheck } = await planInternal(client, spec, undefined, true);
|
|
448
|
+
if (recheck.asset_entries && recheck.asset_entries.length > 0) {
|
|
449
|
+
for (const recheckEntry of recheck.asset_entries) {
|
|
450
|
+
const existing = result.assets.byKey[recheckEntry.key];
|
|
451
|
+
if (!existing)
|
|
452
|
+
continue;
|
|
453
|
+
const ref = recheckEntry.asset_ref;
|
|
454
|
+
if (ref.width_px !== undefined)
|
|
455
|
+
existing.width_px = ref.width_px;
|
|
456
|
+
if (ref.height_px !== undefined)
|
|
457
|
+
existing.height_px = ref.height_px;
|
|
458
|
+
if (ref.blurhash !== undefined)
|
|
459
|
+
existing.blurhash = ref.blurhash;
|
|
460
|
+
if (ref.variant_spec_version !== undefined) {
|
|
461
|
+
existing.variant_spec_version = ref.variant_spec_version;
|
|
462
|
+
}
|
|
463
|
+
if (ref.display_url !== undefined)
|
|
464
|
+
existing.display_url = ref.display_url;
|
|
465
|
+
if (ref.display_immutable_url !== undefined) {
|
|
466
|
+
existing.display_immutable_url = ref.display_immutable_url;
|
|
467
|
+
}
|
|
468
|
+
if (ref.variants !== undefined)
|
|
469
|
+
existing.variants = ref.variants;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
catch {
|
|
474
|
+
// Best-effort: leave variant fields unpopulated rather than
|
|
475
|
+
// failing a successful apply. Consumers can re-call
|
|
476
|
+
// `r.assets.put` with the same bytes (dedup) to trigger the
|
|
477
|
+
// plan-time surfacing if variants are missing.
|
|
478
|
+
}
|
|
479
|
+
}
|
|
396
480
|
}
|
|
397
481
|
return result;
|
|
398
482
|
}
|
|
@@ -873,6 +957,7 @@ async function uploadMissing(client, projectId, presence, byteReaders, emit) {
|
|
|
873
957
|
label: reader?.label ?? p.sha256,
|
|
874
958
|
sha256: p.sha256,
|
|
875
959
|
reason: "present",
|
|
960
|
+
...(reader?.slice ? { slice_kind: reader.slice } : {}),
|
|
876
961
|
});
|
|
877
962
|
}
|
|
878
963
|
// Filter to refs the gateway reported as missing for this project.
|
|
@@ -925,6 +1010,7 @@ async function uploadMissing(client, projectId, presence, byteReaders, emit) {
|
|
|
925
1010
|
sha256: session.sha256,
|
|
926
1011
|
done,
|
|
927
1012
|
total,
|
|
1013
|
+
...(reader.slice ? { slice_kind: reader.slice } : {}),
|
|
928
1014
|
});
|
|
929
1015
|
}
|
|
930
1016
|
// Plan-level finalize — marks the plan committed in the deploy_plans
|
|
@@ -1040,7 +1126,7 @@ async function putToS3(fetchFn, url, body, checksumBase64, partNumber) {
|
|
|
1040
1126
|
}
|
|
1041
1127
|
return res.headers.get("etag");
|
|
1042
1128
|
}
|
|
1043
|
-
async function pollUntilReady(client, commit, diff, warnings, emit, projectId) {
|
|
1129
|
+
async function pollUntilReady(client, commit, diff, warnings, emit, projectId, sliceKinds = []) {
|
|
1044
1130
|
if (commit.status === "failed") {
|
|
1045
1131
|
throw translateGatewayError(commit.error, "commit", null, commit.operation_id);
|
|
1046
1132
|
}
|
|
@@ -1054,7 +1140,12 @@ async function pollUntilReady(client, commit, diff, warnings, emit, projectId) {
|
|
|
1054
1140
|
context: "committing deploy",
|
|
1055
1141
|
});
|
|
1056
1142
|
}
|
|
1057
|
-
emit({
|
|
1143
|
+
emit({
|
|
1144
|
+
type: "ready",
|
|
1145
|
+
releaseId: commit.release_id,
|
|
1146
|
+
urls: commit.urls,
|
|
1147
|
+
...(sliceKinds.length > 0 ? { slice_kinds: sliceKinds } : {}),
|
|
1148
|
+
});
|
|
1058
1149
|
return {
|
|
1059
1150
|
release_id: commit.release_id,
|
|
1060
1151
|
operation_id: commit.operation_id,
|
|
@@ -1065,9 +1156,16 @@ async function pollUntilReady(client, commit, diff, warnings, emit, projectId) {
|
|
|
1065
1156
|
}
|
|
1066
1157
|
const opHeaders = projectId ? await apikeyHeaders(client, projectId) : {};
|
|
1067
1158
|
const initialSnapshot = await client.request(`/apply/v1/operations/${encodeURIComponent(commit.operation_id)}`, { headers: opHeaders, context: "fetching deploy operation" });
|
|
1068
|
-
return await pollSnapshotUntilReady(client, initialSnapshot, diff, warnings, emit, projectId);
|
|
1069
|
-
}
|
|
1070
|
-
async function pollSnapshotUntilReady(client, initial, diff, warnings, emit, projectId) {
|
|
1159
|
+
return await pollSnapshotUntilReady(client, initialSnapshot, diff, warnings, emit, projectId, sliceKinds);
|
|
1160
|
+
}
|
|
1161
|
+
async function pollSnapshotUntilReady(client, initial, diff, warnings, emit, projectId, sliceKinds = []) {
|
|
1162
|
+
// Helper to spread slice_kinds onto every commit.phase / ready emit so
|
|
1163
|
+
// agents grouping per-slice telemetry don't need to track the apply's
|
|
1164
|
+
// spec separately. The low-level commit/upload helpers that pass no
|
|
1165
|
+
// sliceKinds get an empty array → field is omitted from events.
|
|
1166
|
+
const withSliceKinds = (ev) => sliceKinds.length > 0
|
|
1167
|
+
? { ...ev, slice_kinds: sliceKinds }
|
|
1168
|
+
: ev;
|
|
1071
1169
|
let snapshot = initial;
|
|
1072
1170
|
const opHeaders = projectId ? await apikeyHeaders(client, projectId) : {};
|
|
1073
1171
|
let lastPhaseEmitted = null;
|
|
@@ -1107,7 +1205,7 @@ async function pollSnapshotUntilReady(client, initial, diff, warnings, emit, pro
|
|
|
1107
1205
|
return;
|
|
1108
1206
|
if (nextPhase !== undefined && prev.phase === nextPhase)
|
|
1109
1207
|
return;
|
|
1110
|
-
emit({ type: "commit.phase", phase: prev.phase, status: closeStatus });
|
|
1208
|
+
emit(withSliceKinds({ type: "commit.phase", phase: prev.phase, status: closeStatus }));
|
|
1111
1209
|
};
|
|
1112
1210
|
while (true) {
|
|
1113
1211
|
if (lastPhaseEmitted !== snapshot.status) {
|
|
@@ -1115,7 +1213,7 @@ async function pollSnapshotUntilReady(client, initial, diff, warnings, emit, pro
|
|
|
1115
1213
|
if (ev) {
|
|
1116
1214
|
if (ev.type === "commit.phase")
|
|
1117
1215
|
closePreviousPhase(ev.phase);
|
|
1118
|
-
emit(ev);
|
|
1216
|
+
emit(withSliceKinds(ev));
|
|
1119
1217
|
lastPhaseEmitted = snapshot.status;
|
|
1120
1218
|
}
|
|
1121
1219
|
// If `ev` is null (status not in the phase map, e.g. "ready"), leave
|
|
@@ -1133,7 +1231,7 @@ async function pollSnapshotUntilReady(client, initial, diff, warnings, emit, pro
|
|
|
1133
1231
|
});
|
|
1134
1232
|
}
|
|
1135
1233
|
closePreviousPhase();
|
|
1136
|
-
emit({ type: "ready", releaseId: snapshot.release_id, urls: snapshot.urls });
|
|
1234
|
+
emit(withSliceKinds({ type: "ready", releaseId: snapshot.release_id, urls: snapshot.urls }));
|
|
1137
1235
|
return {
|
|
1138
1236
|
release_id: snapshot.release_id,
|
|
1139
1237
|
operation_id: snapshot.operation_id,
|
|
@@ -1215,12 +1313,18 @@ async function startInternal(client, spec, opts) {
|
|
|
1215
1313
|
reason: plan.payment_required.reason,
|
|
1216
1314
|
});
|
|
1217
1315
|
}
|
|
1316
|
+
const sliceKinds = deriveSliceKinds(spec);
|
|
1218
1317
|
const resultPromise = (async () => {
|
|
1219
1318
|
await uploadMissing(client, spec.project, plan.missing_content, byteReaders, emit);
|
|
1220
|
-
emit({
|
|
1319
|
+
emit({
|
|
1320
|
+
type: "commit.phase",
|
|
1321
|
+
phase: "validate",
|
|
1322
|
+
status: "started",
|
|
1323
|
+
...(sliceKinds.length > 0 ? { slice_kinds: sliceKinds } : {}),
|
|
1324
|
+
});
|
|
1221
1325
|
const { planId } = requirePersistedPlan(plan, "starting deploy");
|
|
1222
1326
|
const commit = await commitInternal(client, planId, opts.idempotencyKey);
|
|
1223
|
-
return await pollUntilReady(client, commit, plan.diff, plan.warnings, emit, spec.project);
|
|
1327
|
+
return await pollUntilReady(client, commit, plan.diff, plan.warnings, emit, spec.project, sliceKinds);
|
|
1224
1328
|
})();
|
|
1225
1329
|
// Avoid an unhandled-rejection at construction time. Consumers must call
|
|
1226
1330
|
// .result() to actually observe the error.
|
|
@@ -2033,7 +2137,13 @@ function invalidSecretSpec(message, resource) {
|
|
|
2033
2137
|
}
|
|
2034
2138
|
async function normalizeReleaseSpec(client, spec) {
|
|
2035
2139
|
const byteReaders = new Map();
|
|
2036
|
-
|
|
2140
|
+
// Slice-tagged `remember`. Each slice category creates its own remember
|
|
2141
|
+
// closure so the registered reader carries `reader.slice = "release" |
|
|
2142
|
+
// "asset"`. On cross-kind dedup (same SHA from both a release-bound
|
|
2143
|
+
// slice and the asset slice) the value escalates to `"mixed"`. This
|
|
2144
|
+
// value surfaces on `content.upload.*` events so agents can group
|
|
2145
|
+
// upload telemetry by slice kind.
|
|
2146
|
+
const makeRemember = (slice) => (resolved) => {
|
|
2037
2147
|
// Propagate the final content-type onto the deferred reader so the CAS
|
|
2038
2148
|
// upload session can declare it correctly. Callers may set
|
|
2039
2149
|
// ref.contentType *after* resolveContent returns (e.g. normalizeFileSet
|
|
@@ -2042,18 +2152,25 @@ async function normalizeReleaseSpec(client, spec) {
|
|
|
2042
2152
|
resolved.reader.contentType = resolved.ref.contentType;
|
|
2043
2153
|
}
|
|
2044
2154
|
if (!byteReaders.has(resolved.ref.sha256)) {
|
|
2155
|
+
resolved.reader.slice = slice;
|
|
2045
2156
|
byteReaders.set(resolved.ref.sha256, resolved.reader);
|
|
2046
2157
|
}
|
|
2047
2158
|
else {
|
|
2048
2159
|
// Already remembered — but if the existing reader has no contentType
|
|
2049
|
-
// and we just learned it, fill it in.
|
|
2160
|
+
// and we just learned it, fill it in. Also escalate slice tag when
|
|
2161
|
+
// the second registration comes from a different kind.
|
|
2050
2162
|
const existing = byteReaders.get(resolved.ref.sha256);
|
|
2051
2163
|
if (resolved.ref.contentType && !existing.contentType) {
|
|
2052
2164
|
existing.contentType = resolved.ref.contentType;
|
|
2053
2165
|
}
|
|
2166
|
+
if (existing.slice && existing.slice !== slice && existing.slice !== "mixed") {
|
|
2167
|
+
existing.slice = "mixed";
|
|
2168
|
+
}
|
|
2054
2169
|
}
|
|
2055
2170
|
return resolved.ref;
|
|
2056
2171
|
};
|
|
2172
|
+
const rememberRelease = makeRemember("release");
|
|
2173
|
+
const rememberAsset = makeRemember("asset");
|
|
2057
2174
|
const normalized = { project: spec.project };
|
|
2058
2175
|
if (spec.base)
|
|
2059
2176
|
normalized.base = spec.base;
|
|
@@ -2074,19 +2191,19 @@ async function normalizeReleaseSpec(client, spec) {
|
|
|
2074
2191
|
db.zero_downtime = spec.database.zero_downtime;
|
|
2075
2192
|
}
|
|
2076
2193
|
if (spec.database.migrations && spec.database.migrations.length > 0) {
|
|
2077
|
-
db.migrations = await Promise.all(spec.database.migrations.map(async (m) => normalizeMigration(client, spec.project, m,
|
|
2194
|
+
db.migrations = await Promise.all(spec.database.migrations.map(async (m) => normalizeMigration(client, spec.project, m, rememberRelease)));
|
|
2078
2195
|
}
|
|
2079
2196
|
normalized.database = db;
|
|
2080
2197
|
}
|
|
2081
2198
|
if (spec.functions) {
|
|
2082
2199
|
const fns = {};
|
|
2083
2200
|
if (spec.functions.replace) {
|
|
2084
|
-
fns.replace = await normalizeFunctionMap(spec.functions.replace,
|
|
2201
|
+
fns.replace = await normalizeFunctionMap(spec.functions.replace, rememberRelease);
|
|
2085
2202
|
}
|
|
2086
2203
|
if (spec.functions.patch) {
|
|
2087
2204
|
fns.patch = {};
|
|
2088
2205
|
if (spec.functions.patch.set) {
|
|
2089
|
-
fns.patch.set = await normalizeFunctionMap(spec.functions.patch.set,
|
|
2206
|
+
fns.patch.set = await normalizeFunctionMap(spec.functions.patch.set, rememberRelease);
|
|
2090
2207
|
}
|
|
2091
2208
|
if (spec.functions.patch.delete)
|
|
2092
2209
|
fns.patch.delete = spec.functions.patch.delete;
|
|
@@ -2096,7 +2213,7 @@ async function normalizeReleaseSpec(client, spec) {
|
|
|
2096
2213
|
if (spec.site) {
|
|
2097
2214
|
const publicPaths = "public_paths" in spec.site ? spec.site.public_paths : undefined;
|
|
2098
2215
|
if ("replace" in spec.site && spec.site.replace) {
|
|
2099
|
-
const map = await normalizeFileSet(spec.site.replace,
|
|
2216
|
+
const map = await normalizeFileSet(spec.site.replace, rememberRelease);
|
|
2100
2217
|
normalized.site = {
|
|
2101
2218
|
replace: map,
|
|
2102
2219
|
...(publicPaths ? { public_paths: publicPaths } : {}),
|
|
@@ -2105,7 +2222,7 @@ async function normalizeReleaseSpec(client, spec) {
|
|
|
2105
2222
|
else if ("patch" in spec.site && spec.site.patch) {
|
|
2106
2223
|
const patch = {};
|
|
2107
2224
|
if (spec.site.patch.put) {
|
|
2108
|
-
patch.put = await normalizeFileSet(spec.site.patch.put,
|
|
2225
|
+
patch.put = await normalizeFileSet(spec.site.patch.put, rememberRelease);
|
|
2109
2226
|
}
|
|
2110
2227
|
if (spec.site.patch.delete)
|
|
2111
2228
|
patch.delete = spec.site.patch.delete;
|
|
@@ -2123,7 +2240,7 @@ async function normalizeReleaseSpec(client, spec) {
|
|
|
2123
2240
|
// register a byte-reader; emit the wire-shaped `AssetPutEntry[]`.
|
|
2124
2241
|
// Cross-kind SHA dedup is automatic via the shared `byteReaders` map.
|
|
2125
2242
|
if (spec.assets) {
|
|
2126
|
-
normalized.assets = await normalizeAssetSlice(spec.assets,
|
|
2243
|
+
normalized.assets = await normalizeAssetSlice(spec.assets, rememberAsset);
|
|
2127
2244
|
}
|
|
2128
2245
|
return { normalized, byteReaders };
|
|
2129
2246
|
}
|
|
@@ -2186,20 +2303,41 @@ function buildAssetManifestFromPlanEntries(entries) {
|
|
|
2186
2303
|
let bytesUploaded = 0;
|
|
2187
2304
|
let bytesReused = 0;
|
|
2188
2305
|
for (const entry of entries) {
|
|
2306
|
+
const ref = entry.asset_ref;
|
|
2189
2307
|
const e = {
|
|
2190
2308
|
key: entry.key,
|
|
2191
2309
|
sha256: entry.sha256,
|
|
2192
2310
|
size_bytes: entry.size_bytes,
|
|
2193
2311
|
content_type: entry.content_type,
|
|
2194
2312
|
visibility: entry.visibility,
|
|
2195
|
-
url:
|
|
2196
|
-
immutable_url:
|
|
2197
|
-
cdn_url:
|
|
2198
|
-
cdn_immutable_url:
|
|
2199
|
-
sri:
|
|
2200
|
-
etag:
|
|
2201
|
-
content_digest:
|
|
2313
|
+
url: ref.url,
|
|
2314
|
+
immutable_url: ref.immutable_url,
|
|
2315
|
+
cdn_url: ref.cdn_url,
|
|
2316
|
+
cdn_immutable_url: ref.cdn_immutable_url,
|
|
2317
|
+
sri: ref.sri,
|
|
2318
|
+
etag: ref.etag,
|
|
2319
|
+
content_digest: ref.content_digest,
|
|
2202
2320
|
};
|
|
2321
|
+
// v1.49+ image-variant pass-through. Only emitted when the gateway
|
|
2322
|
+
// returned them (image MIMEs ≥320×320; HEIC/HEIF sources also include
|
|
2323
|
+
// `display_jpeg`). Pre-v1.49 plan responses omit these fields entirely
|
|
2324
|
+
// and the manifest entry stays bytewise-identical to before.
|
|
2325
|
+
if (ref.width_px !== undefined)
|
|
2326
|
+
e.width_px = ref.width_px;
|
|
2327
|
+
if (ref.height_px !== undefined)
|
|
2328
|
+
e.height_px = ref.height_px;
|
|
2329
|
+
if (ref.blurhash !== undefined)
|
|
2330
|
+
e.blurhash = ref.blurhash;
|
|
2331
|
+
if (ref.variant_spec_version !== undefined) {
|
|
2332
|
+
e.variant_spec_version = ref.variant_spec_version;
|
|
2333
|
+
}
|
|
2334
|
+
if (ref.display_url !== undefined)
|
|
2335
|
+
e.display_url = ref.display_url;
|
|
2336
|
+
if (ref.display_immutable_url !== undefined) {
|
|
2337
|
+
e.display_immutable_url = ref.display_immutable_url;
|
|
2338
|
+
}
|
|
2339
|
+
if (ref.variants !== undefined)
|
|
2340
|
+
e.variants = ref.variants;
|
|
2203
2341
|
list.push(e);
|
|
2204
2342
|
byKey[entry.key] = e;
|
|
2205
2343
|
manifest[entry.key] = e;
|