@gradial/aci 0.1.52-rc.34-e2e.1 → 0.1.52-rc.34

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.
Files changed (27) hide show
  1. package/CHANGELOG.md +4 -18
  2. package/README.md +4 -4
  3. package/dist/cli/compile-registry.mjs +2 -0
  4. package/dist/react/VideoPlayer.js +2 -2
  5. package/dist/react/index.d.ts +1 -1
  6. package/dist/react/index.js +3 -2
  7. package/dist/types/image.d.ts +17 -54
  8. package/dist/types/image.js +18 -102
  9. package/dist/types/media.d.ts +6 -14
  10. package/dist/types/video.d.ts +3 -7
  11. package/package.json +7 -7
  12. package/src/cli/compile-registry.mjs +2 -0
  13. package/src/types/image.ts +29 -133
  14. package/src/types/video.ts +1 -1
  15. package/templates/astro/starter-content/src/fixtures/sections.ts +1 -0
  16. package/templates/common/.agents/skills/dam-delivery/SKILL.md +18 -19
  17. package/templates/common/starter-content/.content/dam/folders/seed/000000000000000000000000101/governance.json +1 -2
  18. package/templates/common/starter-content/.content/dam/folders/seed/000000000000000000000000102/governance.json +1 -2
  19. package/templates/common/starter-content/.content/patterns/components/button.json +2 -2
  20. package/templates/common/starter-content/.content/patterns/components/container.json +2 -2
  21. package/templates/common/starter-content/.content/patterns/components/feature_card.json +2 -2
  22. package/templates/common/starter-content/.content/patterns/components/feature_grid.json +2 -2
  23. package/templates/common/starter-content/.content/patterns/components/home_hero.json +7 -16
  24. package/templates/common/starter-content/.content/patterns/components/personalization_choice.json +2 -2
  25. package/templates/common/starter-content/.content/patterns/components/site-footer.json +2 -2
  26. package/templates/common/starter-content/.content/patterns/components/site-navigation.json +2 -2
  27. package/templates/common/starter-content/.content/patterns/components/stats_bar.json +2 -2
package/CHANGELOG.md CHANGED
@@ -1,26 +1,12 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.52-rc.34-e2e.1
4
-
5
- Experimental staging build (ADR 0062 assetId-only contract). Not for
6
- customer use; dist-tagged `rc-e2e`.
7
-
8
- ### Migration required
9
-
10
- - Compiled DAM images no longer carry `src`/`srcset` on their sources: they
11
- carry the asset id plus the slot's declared presentation (`widths`, `fit`,
12
- format). Sites must render images through the SDK helpers (`imageAttrs()`,
13
- `<Picture>`, `<Image>`), which construct the `/dam/{assetId}` permalink and
14
- srcset at render time. Reading `image.sources[0].src` directly no longer
15
- works for DAM images; static (`static:`) assets are unchanged.
3
+ ## 0.1.52-rc.34
16
4
 
17
5
  ### Changed
18
6
 
19
- - `imageAttrs()` constructs `src`/`srcset` from the closed
20
- `{w,h,fit,fm,q}` set (quality default 82, per-width `h` for `fit=crop`).
21
- - New `configureDamAssets({ baseUrl })` sets an absolute permalink origin
22
- for off-origin consumers; default is relative same-origin.
23
- - `DAMDeliveryEnabled`/`DAM_DELIVERY_ENABLED` handling removed everywhere.
7
+ - The `dam-delivery` agent skill now says a future `expiresAt` is admitted to
8
+ public delivery and can be set, moved, or cleared on a public version; only
9
+ a past expiry vetoes approval or is refused on a public version.
24
10
 
25
11
  ## 0.1.52-rc.33
26
12
 
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Agentic Content Infrastructure SDK
2
2
 
3
- `@gradial/aci` `0.1.52-rc.34-e2e.1` is a pre-1.0 public-surface reset for the ACI
3
+ `@gradial/aci` `0.1.52-rc.34` is a pre-1.0 public-surface reset for the ACI
4
4
  client SDK. Breaking changes from the old `0.1.x` accidental surface are
5
5
  intentional: the root import is framework-neutral, framework runtime behavior is
6
6
  behind explicit subpaths, and the first required customer path is React/Next.
@@ -8,7 +8,7 @@ behind explicit subpaths, and the first required customer path is React/Next.
8
8
  ## Install
9
9
 
10
10
  ```bash
11
- npm install @gradial/aci@0.1.52-rc.34-e2e.1 zod@^4
11
+ npm install @gradial/aci@0.1.52-rc.34 zod@^4
12
12
  ```
13
13
 
14
14
  ## Root Import
@@ -137,13 +137,13 @@ host bundles select and serve immutable release artifacts.
137
137
  The first RC scaffold path is Next:
138
138
 
139
139
  ```bash
140
- npx @gradial/aci@0.1.52-rc.34-e2e.1 init my-site --template next-starter
140
+ npx @gradial/aci@0.1.52-rc.34 init my-site --template next-starter
141
141
  ```
142
142
 
143
143
  List available templates:
144
144
 
145
145
  ```bash
146
- npx @gradial/aci@0.1.52-rc.34-e2e.1 init --list
146
+ npx @gradial/aci@0.1.52-rc.34 init --list
147
147
  ```
148
148
 
149
149
  ## Personalization: The One-Tag Install
@@ -352,10 +352,12 @@ function isImageSchema(schema) {
352
352
  return compiled?.type === 'object'
353
353
  && properties.$type?.const === 'gradial.image'
354
354
  && properties.assetId?.type === 'string'
355
+ && properties.versionId?.type === 'string'
355
356
  && properties.alt?.type === 'string'
356
357
  && properties.sources?.type === 'array'
357
358
  && required.has('$type')
358
359
  && required.has('assetId')
360
+ && required.has('versionId')
359
361
  && required.has('alt')
360
362
  && required.has('sources');
361
363
  }
@@ -1,5 +1,5 @@
1
1
  import { createElement } from 'react';
2
- import { imageAttrs } from '../types/image.js';
2
+ import { primaryImageSource } from '../types/image.js';
3
3
  function isEmbed(video) {
4
4
  return video.type === 'text/html';
5
5
  }
@@ -23,7 +23,7 @@ export function VideoPlayer({ video, ...attrs }) {
23
23
  ...attrs,
24
24
  });
25
25
  }
26
- const posterSrc = video.poster ? String(imageAttrs(video.poster).src ?? '') : undefined;
26
+ const posterSrc = video.poster ? primaryImageSource(video.poster).src : undefined;
27
27
  const hasSources = video.sources && video.sources.length > 0;
28
28
  const videoAttrs = {
29
29
  poster: posterSrc,
@@ -19,9 +19,9 @@ export declare function Image({ image, value, ...attrs }: ImageProps): import("r
19
19
  width?: number | string | undefined | undefined;
20
20
  height?: number | string | undefined | undefined;
21
21
  sizes?: string | undefined | undefined;
22
+ srcSet?: string | undefined | undefined;
22
23
  loading?: "eager" | "lazy" | undefined | undefined;
23
24
  decoding?: "async" | "auto" | "sync" | undefined | undefined;
24
- srcSet?: string | undefined | undefined;
25
25
  rel?: string | undefined | undefined;
26
26
  content?: string | undefined | undefined;
27
27
  referrerPolicy?: import("react").HTMLAttributeReferrerPolicy | undefined;
@@ -9,11 +9,12 @@ export { VideoPlayer } from './VideoPlayer.js';
9
9
  export function Image({ image, value, ...attrs }) {
10
10
  const resolved = image ?? value ?? {
11
11
  $type: 'gradial.image',
12
- assetId: 'static:',
12
+ assetId: '',
13
+ versionId: '',
13
14
  alt: '',
14
15
  sources: [],
15
16
  };
16
- if (!resolved.sources[0]) {
17
+ if (!resolved.sources[0]?.src) {
17
18
  return createElement('img', {
18
19
  src: '',
19
20
  alt: resolved.alt,
@@ -1,19 +1,13 @@
1
1
  import { z } from 'zod';
2
2
  export interface ImageSource {
3
- /** Authored asset path — static sources only; DAM sources never set it. */
4
- src?: string;
5
- /** Declared candidate widths for the srcset (DAM sources). Empty or absent
6
- * when the slot declares no outputs: the SDK renders the bare permalink
7
- * (no params, original bytes). */
8
- widths?: number[];
9
- /** Layout width in pixels — the largest declared width, or the intrinsic
10
- * width for static/original-aspect sources. */
3
+ /** Primary derivative URL for this rendition candidate. */
4
+ src: string;
5
+ /** Intrinsic width in pixels (0 when the format carries none, e.g. SVG). */
11
6
  width?: number;
12
- /** Layout height in pixels — the height at `width` (aspect carrier). */
7
+ /** Intrinsic height in pixels (0 when the format carries none). */
13
8
  height?: number;
14
- /** Transform fit for DAM sources: 'max' fits inside the box; 'crop' fills
15
- * the declared aspect and emits an h param per srcset width. */
16
- fit?: 'max' | 'crop';
9
+ /** Optional width-descriptor rendition candidates. */
10
+ srcset?: string;
17
11
  /** sizes attribute from the slot contract. */
18
12
  sizes?: string;
19
13
  /** Media query scoping this source (art direction). */
@@ -26,9 +20,8 @@ export interface Image {
26
20
  $type: 'gradial.image';
27
21
  /** DAM asset identifier (or "static:<path>" for non-DAM assets). */
28
22
  assetId: string;
29
- /** DAM version identifier — absent for DAM images, which compile to the
30
- * versionless live URL /dam/{assetId}; never set for static images. */
31
- versionId?: string;
23
+ /** DAM version identifier (or "static" for non-DAM assets). */
24
+ versionId: string;
32
25
  /** Accessible description of the image content. */
33
26
  alt: string;
34
27
  /** <source> candidates produced for the asset slot. */
@@ -45,14 +38,10 @@ export interface SlotOutput {
45
38
  media?: string;
46
39
  }
47
40
  export declare const ImageSourceSchema: z.ZodObject<{
48
- src: z.ZodOptional<z.ZodString>;
49
- widths: z.ZodOptional<z.ZodArray<z.ZodNumber>>;
41
+ src: z.ZodString;
42
+ srcset: z.ZodOptional<z.ZodString>;
50
43
  width: z.ZodOptional<z.ZodNumber>;
51
44
  height: z.ZodOptional<z.ZodNumber>;
52
- fit: z.ZodOptional<z.ZodEnum<{
53
- max: "max";
54
- crop: "crop";
55
- }>>;
56
45
  sizes: z.ZodOptional<z.ZodString>;
57
46
  media: z.ZodOptional<z.ZodString>;
58
47
  type: z.ZodString;
@@ -60,43 +49,19 @@ export declare const ImageSourceSchema: z.ZodObject<{
60
49
  export declare const ImageSchema: z.ZodObject<{
61
50
  $type: z.ZodLiteral<"gradial.image">;
62
51
  assetId: z.ZodString;
63
- versionId: z.ZodOptional<z.ZodString>;
52
+ versionId: z.ZodString;
64
53
  alt: z.ZodString;
65
54
  sources: z.ZodArray<z.ZodObject<{
66
- src: z.ZodOptional<z.ZodString>;
67
- widths: z.ZodOptional<z.ZodArray<z.ZodNumber>>;
55
+ src: z.ZodString;
56
+ srcset: z.ZodOptional<z.ZodString>;
68
57
  width: z.ZodOptional<z.ZodNumber>;
69
58
  height: z.ZodOptional<z.ZodNumber>;
70
- fit: z.ZodOptional<z.ZodEnum<{
71
- max: "max";
72
- crop: "crop";
73
- }>>;
74
59
  sizes: z.ZodOptional<z.ZodString>;
75
60
  media: z.ZodOptional<z.ZodString>;
76
61
  type: z.ZodString;
77
62
  }, z.core.$strip>>;
78
63
  }, z.core.$strip>;
79
- /** Default DAM delivery quality, matching the edge's DEFAULT_QUALITY. */
80
- export declare const DAM_IMAGE_QUALITY = 82;
81
- /**
82
- * Configures the origin for DAM permalinks. The default is the empty string:
83
- * relative same-origin URLs (`/dam/{assetId}`), served by the site's own
84
- * hosting edge. Set a base (e.g. `https://assets.example.com`) when images
85
- * are consumed off-origin — email, external CMS fields, social cards — or
86
- * when delivery is hosted on a dedicated domain. Call once during app setup,
87
- * before the first render.
88
- */
89
- export declare function configureDamAssets(options?: {
90
- baseUrl?: string;
91
- }): void;
92
- /**
93
- * The DAM permalink for an asset: `{base}/dam/{assetId}`. No params means
94
- * original bytes.
95
- */
96
- export declare function damAssetUrl(assetId: string): string;
97
64
  export type ImageAttrs = Record<string, unknown>;
98
- /** True when the image resolves to authored static bytes, not a DAM asset. */
99
- export declare function isStaticImage(image: Image): boolean;
100
65
  /**
101
66
  * The primary rendition of an image — its first source entry.
102
67
  */
@@ -105,11 +70,9 @@ export declare function primaryImageSource(image: Image): ImageSource;
105
70
  * Computes the full set of <img> attributes for an Image.
106
71
  *
107
72
  * Framework components (React <Picture>, Astro <img>, Svelte <img>) call this
108
- * and spread the result into the native element. No HTML string
109
- * serialization. DAM images construct their /dam/{assetId} permalink and
110
- * srcset here from the slot-declared widths; static images pass their
111
- * authored src through. Media-scoped sources need a <picture> wrapper and
112
- * are not representable as plain <img> attributes, so srcset/sizes are taken
113
- * from the first unscoped source only.
73
+ * and spread the result into their native element. No HTML string
74
+ * serialization. Media-scoped sources need a <picture> wrapper and are not
75
+ * representable as plain <img> attributes, so srcset/sizes are taken from the
76
+ * first unscoped source only.
114
77
  */
115
78
  export declare function imageAttrs(image: Image, overrides?: ImageAttrs): ImageAttrs;
@@ -3,11 +3,10 @@ import { z } from 'zod';
3
3
  // Zod schema
4
4
  // ---------------------------------------------------------------------------
5
5
  export const ImageSourceSchema = z.object({
6
- src: z.string().min(1).optional(),
7
- widths: z.array(z.number().int().positive()).optional(),
6
+ src: z.string().min(1),
7
+ srcset: z.string().min(1).optional(),
8
8
  width: z.number().int().nonnegative().optional(),
9
9
  height: z.number().int().nonnegative().optional(),
10
- fit: z.enum(['max', 'crop']).optional(),
11
10
  sizes: z.string().min(1).optional(),
12
11
  media: z.string().min(1).optional(),
13
12
  type: z.string().min(1),
@@ -15,97 +14,10 @@ export const ImageSourceSchema = z.object({
15
14
  export const ImageSchema = z.object({
16
15
  $type: z.literal('gradial.image'),
17
16
  assetId: z.string().min(1),
18
- versionId: z.string().min(1).optional(),
17
+ versionId: z.string().min(1),
19
18
  alt: z.string(),
20
19
  sources: z.array(ImageSourceSchema).min(1),
21
20
  });
22
- // ---------------------------------------------------------------------------
23
- // DAM permalink construction (ADR 0062)
24
- // ---------------------------------------------------------------------------
25
- /** Default DAM delivery quality, matching the edge's DEFAULT_QUALITY. */
26
- export const DAM_IMAGE_QUALITY = 82;
27
- let damAssetBase = '';
28
- /**
29
- * Configures the origin for DAM permalinks. The default is the empty string:
30
- * relative same-origin URLs (`/dam/{assetId}`), served by the site's own
31
- * hosting edge. Set a base (e.g. `https://assets.example.com`) when images
32
- * are consumed off-origin — email, external CMS fields, social cards — or
33
- * when delivery is hosted on a dedicated domain. Call once during app setup,
34
- * before the first render.
35
- */
36
- export function configureDamAssets(options = {}) {
37
- damAssetBase = (options.baseUrl ?? '').replace(/\/+$/, '');
38
- }
39
- /**
40
- * The DAM permalink for an asset: `{base}/dam/{assetId}`. No params means
41
- * original bytes.
42
- */
43
- export function damAssetUrl(assetId) {
44
- return `${damAssetBase}/dam/${assetId}`;
45
- }
46
- const FORMAT_PARAMS = {
47
- 'image/avif': 'avif',
48
- 'image/webp': 'webp',
49
- 'image/jpeg': 'jpg',
50
- 'image/png': 'png',
51
- };
52
- function sourceFormatParams(source) {
53
- const fm = FORMAT_PARAMS[source.type] ?? 'webp';
54
- return `fm=${fm}&q=${DAM_IMAGE_QUALITY}`;
55
- }
56
- function srcsetWidth(assetId, source, width) {
57
- const params = [`w=${width}`];
58
- if (source.fit === 'crop' && source.width && source.height) {
59
- const height = Math.round((width * source.height) / source.width);
60
- params.push(`h=${height}`, 'fit=crop');
61
- }
62
- else {
63
- params.push('fit=max');
64
- }
65
- params.push(sourceFormatParams(source));
66
- return `${damAssetUrl(assetId)}?${params.join('&')} ${width}w`;
67
- }
68
- function damImageAttrs(image, primary) {
69
- const base = {
70
- src: damAssetUrl(image.assetId),
71
- alt: image.alt,
72
- width: primary.width && primary.width > 0 ? primary.width : undefined,
73
- height: primary.height && primary.height > 0 ? primary.height : undefined,
74
- loading: 'lazy',
75
- decoding: 'async',
76
- };
77
- if (primary.widths && primary.widths.length > 0) {
78
- // Primary src at the largest declared width; srcset covers them all.
79
- const largest = primary.widths[primary.widths.length - 1];
80
- const params = [`w=${largest}`];
81
- if (primary.fit === 'crop' && primary.width && primary.height) {
82
- params.push(`h=${Math.round((largest * primary.height) / primary.width)}`, 'fit=crop');
83
- }
84
- else {
85
- params.push('fit=max');
86
- }
87
- params.push(sourceFormatParams(primary));
88
- base.src = `${damAssetUrl(image.assetId)}?${params.join('&')}`;
89
- if (primary.widths.length > 1) {
90
- base.srcSet = primary.widths.map((w) => srcsetWidth(image.assetId, primary, w)).join(', ');
91
- }
92
- }
93
- return base;
94
- }
95
- function staticImageAttrs(image, primary) {
96
- return {
97
- src: primary.src ?? '',
98
- alt: image.alt,
99
- width: primary.width && primary.width > 0 ? primary.width : undefined,
100
- height: primary.height && primary.height > 0 ? primary.height : undefined,
101
- loading: 'lazy',
102
- decoding: 'async',
103
- };
104
- }
105
- /** True when the image resolves to authored static bytes, not a DAM asset. */
106
- export function isStaticImage(image) {
107
- return image.assetId.startsWith('static:');
108
- }
109
21
  /**
110
22
  * The primary rendition of an image — its first source entry.
111
23
  */
@@ -116,19 +28,23 @@ export function primaryImageSource(image) {
116
28
  * Computes the full set of <img> attributes for an Image.
117
29
  *
118
30
  * Framework components (React <Picture>, Astro <img>, Svelte <img>) call this
119
- * and spread the result into the native element. No HTML string
120
- * serialization. DAM images construct their /dam/{assetId} permalink and
121
- * srcset here from the slot-declared widths; static images pass their
122
- * authored src through. Media-scoped sources need a <picture> wrapper and
123
- * are not representable as plain <img> attributes, so srcset/sizes are taken
124
- * from the first unscoped source only.
31
+ * and spread the result into their native element. No HTML string
32
+ * serialization. Media-scoped sources need a <picture> wrapper and are not
33
+ * representable as plain <img> attributes, so srcset/sizes are taken from the
34
+ * first unscoped source only.
125
35
  */
126
36
  export function imageAttrs(image, overrides = {}) {
127
37
  const primary = image.sources[0];
128
38
  const unscoped = image.sources.find((s) => !s.media) ?? primary;
129
- const base = isStaticImage(image) ? staticImageAttrs(image, primary) : damImageAttrs(image, primary);
130
- if (unscoped?.sizes) {
131
- base.sizes = unscoped.sizes;
132
- }
133
- return { ...base, ...overrides };
39
+ return {
40
+ src: primary.src,
41
+ alt: image.alt,
42
+ width: primary.width && primary.width > 0 ? primary.width : undefined,
43
+ height: primary.height && primary.height > 0 ? primary.height : undefined,
44
+ srcSet: unscoped?.srcset || undefined,
45
+ sizes: unscoped?.sizes || undefined,
46
+ loading: 'lazy',
47
+ decoding: 'async',
48
+ ...overrides,
49
+ };
134
50
  }
@@ -7,17 +7,13 @@ export type Asset = Image | Video;
7
7
  export declare const AssetSchema: z.ZodUnion<readonly [z.ZodObject<{
8
8
  $type: z.ZodLiteral<"gradial.image">;
9
9
  assetId: z.ZodString;
10
- versionId: z.ZodOptional<z.ZodString>;
10
+ versionId: z.ZodString;
11
11
  alt: z.ZodString;
12
12
  sources: z.ZodArray<z.ZodObject<{
13
- src: z.ZodOptional<z.ZodString>;
14
- widths: z.ZodOptional<z.ZodArray<z.ZodNumber>>;
13
+ src: z.ZodString;
14
+ srcset: z.ZodOptional<z.ZodString>;
15
15
  width: z.ZodOptional<z.ZodNumber>;
16
16
  height: z.ZodOptional<z.ZodNumber>;
17
- fit: z.ZodOptional<z.ZodEnum<{
18
- max: "max";
19
- crop: "crop";
20
- }>>;
21
17
  sizes: z.ZodOptional<z.ZodString>;
22
18
  media: z.ZodOptional<z.ZodString>;
23
19
  type: z.ZodString;
@@ -34,17 +30,13 @@ export declare const AssetSchema: z.ZodUnion<readonly [z.ZodObject<{
34
30
  poster: z.ZodOptional<z.ZodObject<{
35
31
  $type: z.ZodLiteral<"gradial.image">;
36
32
  assetId: z.ZodString;
37
- versionId: z.ZodOptional<z.ZodString>;
33
+ versionId: z.ZodString;
38
34
  alt: z.ZodString;
39
35
  sources: z.ZodArray<z.ZodObject<{
40
- src: z.ZodOptional<z.ZodString>;
41
- widths: z.ZodOptional<z.ZodArray<z.ZodNumber>>;
36
+ src: z.ZodString;
37
+ srcset: z.ZodOptional<z.ZodString>;
42
38
  width: z.ZodOptional<z.ZodNumber>;
43
39
  height: z.ZodOptional<z.ZodNumber>;
44
- fit: z.ZodOptional<z.ZodEnum<{
45
- max: "max";
46
- crop: "crop";
47
- }>>;
48
40
  sizes: z.ZodOptional<z.ZodString>;
49
41
  media: z.ZodOptional<z.ZodString>;
50
42
  type: z.ZodString;
@@ -50,17 +50,13 @@ export declare const VideoSchema: z.ZodObject<{
50
50
  poster: z.ZodOptional<z.ZodObject<{
51
51
  $type: z.ZodLiteral<"gradial.image">;
52
52
  assetId: z.ZodString;
53
- versionId: z.ZodOptional<z.ZodString>;
53
+ versionId: z.ZodString;
54
54
  alt: z.ZodString;
55
55
  sources: z.ZodArray<z.ZodObject<{
56
- src: z.ZodOptional<z.ZodString>;
57
- widths: z.ZodOptional<z.ZodArray<z.ZodNumber>>;
56
+ src: z.ZodString;
57
+ srcset: z.ZodOptional<z.ZodString>;
58
58
  width: z.ZodOptional<z.ZodNumber>;
59
59
  height: z.ZodOptional<z.ZodNumber>;
60
- fit: z.ZodOptional<z.ZodEnum<{
61
- max: "max";
62
- crop: "crop";
63
- }>>;
64
60
  sizes: z.ZodOptional<z.ZodString>;
65
61
  media: z.ZodOptional<z.ZodString>;
66
62
  type: z.ZodString;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gradial/aci",
3
- "version": "0.1.52-rc.34-e2e.1",
3
+ "version": "0.1.52-rc.34",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/gradial/bare-metal-go.git",
@@ -160,11 +160,11 @@
160
160
  "zod": "^4.0.0"
161
161
  },
162
162
  "optionalDependencies": {
163
- "@gradial/aci-cli-darwin-arm64": "0.1.52-rc.34-e2e.1",
164
- "@gradial/aci-cli-darwin-x64": "0.1.52-rc.34-e2e.1",
165
- "@gradial/aci-cli-linux-arm64": "0.1.52-rc.34-e2e.1",
166
- "@gradial/aci-cli-linux-x64": "0.1.52-rc.34-e2e.1",
167
- "@gradial/aci-cli-win32-arm64": "0.1.52-rc.34-e2e.1",
168
- "@gradial/aci-cli-win32-x64": "0.1.52-rc.34-e2e.1"
163
+ "@gradial/aci-cli-darwin-arm64": "0.1.52-rc.34",
164
+ "@gradial/aci-cli-darwin-x64": "0.1.52-rc.34",
165
+ "@gradial/aci-cli-linux-arm64": "0.1.52-rc.34",
166
+ "@gradial/aci-cli-linux-x64": "0.1.52-rc.34",
167
+ "@gradial/aci-cli-win32-arm64": "0.1.52-rc.34",
168
+ "@gradial/aci-cli-win32-x64": "0.1.52-rc.34"
169
169
  }
170
170
  }
@@ -346,10 +346,12 @@ function isImageSchema(schema) {
346
346
  return compiled?.type === 'object'
347
347
  && properties.$type?.const === 'gradial.image'
348
348
  && properties.assetId?.type === 'string'
349
+ && properties.versionId?.type === 'string'
349
350
  && properties.alt?.type === 'string'
350
351
  && properties.sources?.type === 'array'
351
352
  && required.has('$type')
352
353
  && required.has('assetId')
354
+ && required.has('versionId')
353
355
  && required.has('alt')
354
356
  && required.has('sources');
355
357
  } catch {
@@ -3,28 +3,19 @@ import { z } from 'zod';
3
3
  // ---------------------------------------------------------------------------
4
4
  // Image source variants
5
5
  //
6
- // A DAM source carries the asset identity's slot presentation — the declared
7
- // candidate widths, the fit, and the MIME format — and NEVER a URL: the SDK
8
- // constructs the /dam/{assetId} permalink and its srcset at render time
9
- // (ADR 0062: the compiler emits asset ids only). Static assets keep their
10
- // authored src passthrough.
6
+ // Each source provides a primary src and may include a ready-made srcset
7
+ // scoped by the optional media/sizes of the slot output that produced it.
11
8
  // ---------------------------------------------------------------------------
12
9
 
13
10
  export interface ImageSource {
14
- /** Authored asset path — static sources only; DAM sources never set it. */
15
- src?: string;
16
- /** Declared candidate widths for the srcset (DAM sources). Empty or absent
17
- * when the slot declares no outputs: the SDK renders the bare permalink
18
- * (no params, original bytes). */
19
- widths?: number[];
20
- /** Layout width in pixels — the largest declared width, or the intrinsic
21
- * width for static/original-aspect sources. */
11
+ /** Primary derivative URL for this rendition candidate. */
12
+ src: string;
13
+ /** Intrinsic width in pixels (0 when the format carries none, e.g. SVG). */
22
14
  width?: number;
23
- /** Layout height in pixels — the height at `width` (aspect carrier). */
15
+ /** Intrinsic height in pixels (0 when the format carries none). */
24
16
  height?: number;
25
- /** Transform fit for DAM sources: 'max' fits inside the box; 'crop' fills
26
- * the declared aspect and emits an h param per srcset width. */
27
- fit?: 'max' | 'crop';
17
+ /** Optional width-descriptor rendition candidates. */
18
+ srcset?: string;
28
19
  /** sizes attribute from the slot contract. */
29
20
  sizes?: string;
30
21
  /** Media query scoping this source (art direction). */
@@ -34,7 +25,7 @@ export interface ImageSource {
34
25
  }
35
26
 
36
27
  // ---------------------------------------------------------------------------
37
- // Image — DAM-backed image asset with compiler-resolved live asset URLs
28
+ // Image — DAM-backed image asset with compiler-resolved derivatives
38
29
  //
39
30
  // Content authors write an asset reference: { "$type": "dam.assetRef", ... }
40
31
  // or for static files: { "$type": "static.assetRef", "src": "/path" }
@@ -46,9 +37,8 @@ export interface Image {
46
37
  $type: 'gradial.image';
47
38
  /** DAM asset identifier (or "static:<path>" for non-DAM assets). */
48
39
  assetId: string;
49
- /** DAM version identifier — absent for DAM images, which compile to the
50
- * versionless live URL /dam/{assetId}; never set for static images. */
51
- versionId?: string;
40
+ /** DAM version identifier (or "static" for non-DAM assets). */
41
+ versionId: string;
52
42
  /** Accessible description of the image content. */
53
43
  alt: string;
54
44
  /** <source> candidates produced for the asset slot. */
@@ -76,11 +66,10 @@ export interface SlotOutput {
76
66
  // ---------------------------------------------------------------------------
77
67
 
78
68
  export const ImageSourceSchema = z.object({
79
- src: z.string().min(1).optional(),
80
- widths: z.array(z.number().int().positive()).optional(),
69
+ src: z.string().min(1),
70
+ srcset: z.string().min(1).optional(),
81
71
  width: z.number().int().nonnegative().optional(),
82
72
  height: z.number().int().nonnegative().optional(),
83
- fit: z.enum(['max', 'crop']).optional(),
84
73
  sizes: z.string().min(1).optional(),
85
74
  media: z.string().min(1).optional(),
86
75
  type: z.string().min(1),
@@ -89,113 +78,17 @@ export const ImageSourceSchema = z.object({
89
78
  export const ImageSchema = z.object({
90
79
  $type: z.literal('gradial.image'),
91
80
  assetId: z.string().min(1),
92
- versionId: z.string().min(1).optional(),
81
+ versionId: z.string().min(1),
93
82
  alt: z.string(),
94
83
  sources: z.array(ImageSourceSchema).min(1),
95
84
  });
96
85
 
97
- // ---------------------------------------------------------------------------
98
- // DAM permalink construction (ADR 0062)
99
- // ---------------------------------------------------------------------------
100
-
101
- /** Default DAM delivery quality, matching the edge's DEFAULT_QUALITY. */
102
- export const DAM_IMAGE_QUALITY = 82;
103
-
104
- let damAssetBase = '';
105
-
106
- /**
107
- * Configures the origin for DAM permalinks. The default is the empty string:
108
- * relative same-origin URLs (`/dam/{assetId}`), served by the site's own
109
- * hosting edge. Set a base (e.g. `https://assets.example.com`) when images
110
- * are consumed off-origin — email, external CMS fields, social cards — or
111
- * when delivery is hosted on a dedicated domain. Call once during app setup,
112
- * before the first render.
113
- */
114
- export function configureDamAssets(options: { baseUrl?: string } = {}): void {
115
- damAssetBase = (options.baseUrl ?? '').replace(/\/+$/, '');
116
- }
117
-
118
- /**
119
- * The DAM permalink for an asset: `{base}/dam/{assetId}`. No params means
120
- * original bytes.
121
- */
122
- export function damAssetUrl(assetId: string): string {
123
- return `${damAssetBase}/dam/${assetId}`;
124
- }
125
-
126
- const FORMAT_PARAMS: Record<string, string> = {
127
- 'image/avif': 'avif',
128
- 'image/webp': 'webp',
129
- 'image/jpeg': 'jpg',
130
- 'image/png': 'png',
131
- };
132
-
133
- function sourceFormatParams(source: ImageSource): string {
134
- const fm = FORMAT_PARAMS[source.type] ?? 'webp';
135
- return `fm=${fm}&q=${DAM_IMAGE_QUALITY}`;
136
- }
137
-
138
- function srcsetWidth(assetId: string, source: ImageSource, width: number): string {
139
- const params = [`w=${width}`];
140
- if (source.fit === 'crop' && source.width && source.height) {
141
- const height = Math.round((width * source.height) / source.width);
142
- params.push(`h=${height}`, 'fit=crop');
143
- } else {
144
- params.push('fit=max');
145
- }
146
- params.push(sourceFormatParams(source));
147
- return `${damAssetUrl(assetId)}?${params.join('&')} ${width}w`;
148
- }
149
-
150
- function damImageAttrs(image: Image, primary: ImageSource): ImageAttrs {
151
- const base: ImageAttrs = {
152
- src: damAssetUrl(image.assetId),
153
- alt: image.alt,
154
- width: primary.width && primary.width > 0 ? primary.width : undefined,
155
- height: primary.height && primary.height > 0 ? primary.height : undefined,
156
- loading: 'lazy',
157
- decoding: 'async',
158
- };
159
- if (primary.widths && primary.widths.length > 0) {
160
- // Primary src at the largest declared width; srcset covers them all.
161
- const largest = primary.widths[primary.widths.length - 1];
162
- const params = [`w=${largest}`];
163
- if (primary.fit === 'crop' && primary.width && primary.height) {
164
- params.push(`h=${Math.round((largest * primary.height) / primary.width)}`, 'fit=crop');
165
- } else {
166
- params.push('fit=max');
167
- }
168
- params.push(sourceFormatParams(primary));
169
- base.src = `${damAssetUrl(image.assetId)}?${params.join('&')}`;
170
- if (primary.widths.length > 1) {
171
- base.srcSet = primary.widths.map((w) => srcsetWidth(image.assetId, primary, w)).join(', ');
172
- }
173
- }
174
- return base;
175
- }
176
-
177
- function staticImageAttrs(image: Image, primary: ImageSource): ImageAttrs {
178
- return {
179
- src: primary.src ?? '',
180
- alt: image.alt,
181
- width: primary.width && primary.width > 0 ? primary.width : undefined,
182
- height: primary.height && primary.height > 0 ? primary.height : undefined,
183
- loading: 'lazy',
184
- decoding: 'async',
185
- };
186
- }
187
-
188
86
  // ---------------------------------------------------------------------------
189
87
  // Shared attrs helper — consumed by React, Astro, and Svelte components
190
88
  // ---------------------------------------------------------------------------
191
89
 
192
90
  export type ImageAttrs = Record<string, unknown>;
193
91
 
194
- /** True when the image resolves to authored static bytes, not a DAM asset. */
195
- export function isStaticImage(image: Image): boolean {
196
- return image.assetId.startsWith('static:');
197
- }
198
-
199
92
  /**
200
93
  * The primary rendition of an image — its first source entry.
201
94
  */
@@ -207,21 +100,24 @@ export function primaryImageSource(image: Image): ImageSource {
207
100
  * Computes the full set of <img> attributes for an Image.
208
101
  *
209
102
  * Framework components (React <Picture>, Astro <img>, Svelte <img>) call this
210
- * and spread the result into the native element. No HTML string
211
- * serialization. DAM images construct their /dam/{assetId} permalink and
212
- * srcset here from the slot-declared widths; static images pass their
213
- * authored src through. Media-scoped sources need a <picture> wrapper and
214
- * are not representable as plain <img> attributes, so srcset/sizes are taken
215
- * from the first unscoped source only.
103
+ * and spread the result into their native element. No HTML string
104
+ * serialization. Media-scoped sources need a <picture> wrapper and are not
105
+ * representable as plain <img> attributes, so srcset/sizes are taken from the
106
+ * first unscoped source only.
216
107
  */
217
108
  export function imageAttrs(image: Image, overrides: ImageAttrs = {}): ImageAttrs {
218
109
  const primary = image.sources[0];
219
110
  const unscoped = image.sources.find((s) => !s.media) ?? primary;
220
111
 
221
- const base = isStaticImage(image) ? staticImageAttrs(image, primary) : damImageAttrs(image, primary);
222
-
223
- if (unscoped?.sizes) {
224
- base.sizes = unscoped.sizes;
225
- }
226
- return { ...base, ...overrides };
112
+ return {
113
+ src: primary.src,
114
+ alt: image.alt,
115
+ width: primary.width && primary.width > 0 ? primary.width : undefined,
116
+ height: primary.height && primary.height > 0 ? primary.height : undefined,
117
+ srcSet: unscoped?.srcset || undefined,
118
+ sizes: unscoped?.sizes || undefined,
119
+ loading: 'lazy',
120
+ decoding: 'async',
121
+ ...overrides,
122
+ };
227
123
  }
@@ -11,7 +11,7 @@ export interface VideoSource {
11
11
  }
12
12
 
13
13
  // ---------------------------------------------------------------------------
14
- // Video — DAM-backed video asset with compiler-resolved live asset URLs
14
+ // Video — DAM-backed video asset with compiler-resolved derivatives
15
15
  //
16
16
  // Content authors write: { "$type": "dam.assetRef", ... }
17
17
  // or for static files: { "$type": "static.assetRef", "src": "/path" }
@@ -26,6 +26,7 @@ export const sectionStoryFixtures: SectionStoryFixture[] = [
26
26
  image: {
27
27
  $type: 'gradial.image',
28
28
  assetId: '3Ih26etWBTYfnAd0EjD0pP2h902',
29
+ versionId: 'v0001',
29
30
  alt: 'Seattle skyline at dusk',
30
31
  sources: [
31
32
  { src: '/assets/seattle.avif', width: 1920, height: 1280, sizes: '100vw', type: 'image/avif' }
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: dam-delivery
3
- description: Build and use public DAM asset links (`/dam/{assetId}`) with on-the-fly image shaping (resize, crop, format, quality). Use when a page, a CMS field, or an email needs a URL for an approved DAM asset, when choosing between a compiled content link and a shaped public link, when making an asset public or taking it down, or when a `/dam/…` URL answers 301, 403, or 404 unexpectedly.
3
+ description: Build and use public DAM asset links (`/dam/{assetId}`) with on-the-fly image shaping (resize, crop, format, quality). Use when a page, a CMS field, or an email needs a URL for an approved DAM asset, when choosing between pre-baked derivatives and a shaped public link, when making an asset public or taking it down, or when a `/dam/…` URL answers 301, 403, or 404 unexpectedly.
4
4
  ---
5
5
 
6
6
  # DAM Delivery — Public Asset Links
@@ -59,9 +59,9 @@ the link above. They are not served and they do not redirect.
59
59
  ```
60
60
 
61
61
  The route is served by the deployed site's hosting edge. The site's own
62
- dev server (`npm run dev`) serves `/dam/…` links for assets seeded in the
63
- local `.content/dam/` tree; anything else answers 404 there — test it
64
- against the deployed domain.
62
+ dev server (`npm run dev`) only serves compiled derivatives under
63
+ `/dam/…`, so a public link answers 404 there — test it against the
64
+ deployed domain.
65
65
 
66
66
  ## Shaping an Image
67
67
 
@@ -70,7 +70,7 @@ Five query parameters, and only these. Full rules and worked examples:
70
70
 
71
71
  | Param | Values | Default | Notes |
72
72
  | --- | --- | --- | --- |
73
- | `w`, `h` | whole numbers | none | 1–4096, honored exactly — no snapping or size ladder |
73
+ | `w`, `h` | whole numbers | none | held to 16–3840, then snapped down to a fixed ladder of sizes |
74
74
  | `fit` | `max` \| `crop` | `max` | `max` fits inside the box; `crop` fills it and needs both `w` and `h` |
75
75
  | `fm` | `webp` \| `avif` \| `jpg` \| `png` | `webp` | the format is always this parameter, never the browser's `Accept` header |
76
76
  | `q` | 5–100 | 80 | snapped down to steps of 5 |
@@ -120,7 +120,7 @@ Read `effects` in the response to see what happened:
120
120
  | Effect | Meaning |
121
121
  | --- | --- |
122
122
  | `live_published` | the link now serves this version |
123
- | `public_admission_vetoed:<cause>` | the version is approved but **not public**: it carries an expiry date, an embargo still in force, a usage block, or a license that does not allow publication. The link keeps serving the previous public version, if there is one |
123
+ | `public_admission_vetoed:<cause>` | the version is approved but **not public**: its expiry date has already passed, an embargo is still in force, a usage block, or a license that does not allow publication. A future expiry date does not veto; the link serves until that date. The link keeps serving the previous public version, if there is one |
124
124
  | `live_plane_unconfigured` | a local or dev stack with no delivery wired; nothing was made public |
125
125
 
126
126
  On the asset record (`GET /v1/dam/assets/{assetId}`), a public version
@@ -133,9 +133,11 @@ shows `deliveryTier: "public"` in its governance, and a refused one shows
133
133
  the previous public version, or stops serving if there is none) or
134
134
  `archive` the asset. Both use the same lifecycle endpoint.
135
135
  - **Governance that would have blocked the approval cannot be added while
136
- a version is public.** A patch adding an expiry date, an embargo, a
136
+ a version is public.** A patch adding a past expiry date, an embargo, a
137
137
  usage block, or a license without publication is refused with a
138
- conflict that tells you to demote first.
138
+ conflict that tells you to demote first. A future expiry date can be
139
+ set, moved, or cleared on a public version; the link stops serving the
140
+ version when that date arrives.
139
141
  - **Changes take up to five minutes to show everywhere.** Responses are
140
142
  `Cache-Control: public, max-age=300`, so a new version or a take-down
141
143
  can lag by that long in browsers and CDN caches. On AWS CloudFront,
@@ -145,22 +147,19 @@ shows `deliveryTier: "public"` in its governance, and a refused one shows
145
147
  not treat a public link as instantly revocable, and do not re-cache it
146
148
  for longer downstream.
147
149
 
148
- ## Compiled Content Link or a Public Link?
150
+ ## Pre-Baked Derivatives or a Public Link?
149
151
 
150
- - **Images a page renders from content: use the compiled live link.**
151
- Author a `dam.assetRef` (asset id + alt); the compiler emits the
152
- versionless permalink and the SDK asset component builds the `srcset`
153
- from the slot's declared widths at render time. Declare `imageSlots` in
154
- the contract and render with `imageAttrs()` or `Picture`; you never
155
- construct a URL. There is no pre-baked derivative pipeline — publish
156
- stages no asset bytes.
152
+ - **Images a page renders from content: keep using the pre-baked
153
+ pipeline.** Declare `imageSlots` in the contract and render with
154
+ `imageAttrs()` or `Picture`. The build produces fixed sizes per slot and
155
+ you never construct a URL. See the authoring skill.
157
156
  - **A URL that lives outside the build: use the public link.** A field in
158
157
  an external CMS, an email, a social card, a partner page, or a one-off
159
158
  size that no slot declares.
160
159
 
161
- The difference that matters: a compiled link follows approval and take-down
162
- through each publish, while a public link follows them on its own, within
163
- the five-minute window.
160
+ The difference that matters: a pre-baked image is fixed at publish time
161
+ and changes with the next publish. A public link follows approval and
162
+ take-down on its own, within the five-minute window.
164
163
 
165
164
  Published content may carry `/dam/{assetId}` links. The publish check
166
165
  rejects a payload that contains a raw source path (`dam/blobs/…`) or a
@@ -17,8 +17,7 @@
17
17
  "license": {
18
18
  "kind": "unsplash-local-fixture"
19
19
  },
20
- "publicationRestriction": "none",
21
- "deliveryTier": "public"
20
+ "publicationRestriction": "none"
22
21
  }
23
22
  }
24
23
  }
@@ -17,8 +17,7 @@
17
17
  "license": {
18
18
  "kind": "unsplash-local-fixture"
19
19
  },
20
- "publicationRestriction": "none",
21
- "deliveryTier": "public"
20
+ "publicationRestriction": "none"
22
21
  }
23
22
  }
24
23
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$type": "componentPattern",
3
- "buildId": "codebuild_01a12331-b86d-7d20-8a35-a7a71d96e8be",
4
- "codeDigest": "sha256:f1246860864e55359c7ad442a7a956b61a835a4826cd6229cc9971db1fe29a67",
3
+ "buildId": "codebuild_01a0d03d-1243-7f49-9ead-8599ed577882",
4
+ "codeDigest": "sha256:44327370dc42bcabe39daf8b86fca1fe191e19dbd8dd39db71df2109c11b3635",
5
5
  "name": "button",
6
6
  "schema": {
7
7
  "$schema": "https://json-schema.org/draft/2020-12/schema",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$type": "componentPattern",
3
- "buildId": "codebuild_01a12331-b86d-7d20-8a35-a7a71d96e8be",
4
- "codeDigest": "sha256:f1246860864e55359c7ad442a7a956b61a835a4826cd6229cc9971db1fe29a67",
3
+ "buildId": "codebuild_01a0d03d-1243-7f49-9ead-8599ed577882",
4
+ "codeDigest": "sha256:44327370dc42bcabe39daf8b86fca1fe191e19dbd8dd39db71df2109c11b3635",
5
5
  "name": "container",
6
6
  "schema": {
7
7
  "$schema": "https://json-schema.org/draft/2020-12/schema",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$type": "componentPattern",
3
- "buildId": "codebuild_01a12331-b86d-7d20-8a35-a7a71d96e8be",
4
- "codeDigest": "sha256:f1246860864e55359c7ad442a7a956b61a835a4826cd6229cc9971db1fe29a67",
3
+ "buildId": "codebuild_01a0d03d-1243-7f49-9ead-8599ed577882",
4
+ "codeDigest": "sha256:44327370dc42bcabe39daf8b86fca1fe191e19dbd8dd39db71df2109c11b3635",
5
5
  "name": "feature_card",
6
6
  "schema": {
7
7
  "$schema": "https://json-schema.org/draft/2020-12/schema",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$type": "componentPattern",
3
- "buildId": "codebuild_01a12331-b86d-7d20-8a35-a7a71d96e8be",
4
- "codeDigest": "sha256:f1246860864e55359c7ad442a7a956b61a835a4826cd6229cc9971db1fe29a67",
3
+ "buildId": "codebuild_01a0d03d-1243-7f49-9ead-8599ed577882",
4
+ "codeDigest": "sha256:44327370dc42bcabe39daf8b86fca1fe191e19dbd8dd39db71df2109c11b3635",
5
5
  "name": "feature_grid",
6
6
  "schema": {
7
7
  "$schema": "https://json-schema.org/draft/2020-12/schema",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$type": "componentPattern",
3
- "buildId": "codebuild_01a12331-b86d-7d20-8a35-a7a71d96e8be",
4
- "codeDigest": "sha256:f1246860864e55359c7ad442a7a956b61a835a4826cd6229cc9971db1fe29a67",
3
+ "buildId": "codebuild_01a0d03d-1243-7f49-9ead-8599ed577882",
4
+ "codeDigest": "sha256:44327370dc42bcabe39daf8b86fca1fe191e19dbd8dd39db71df2109c11b3635",
5
5
  "name": "home_hero",
6
6
  "schema": {
7
7
  "$schema": "https://json-schema.org/draft/2020-12/schema",
@@ -54,13 +54,9 @@
54
54
  "type": "string",
55
55
  "minLength": 1
56
56
  },
57
- "widths": {
58
- "type": "array",
59
- "items": {
60
- "type": "integer",
61
- "exclusiveMinimum": 0,
62
- "maximum": 9007199254740991
63
- }
57
+ "srcset": {
58
+ "type": "string",
59
+ "minLength": 1
64
60
  },
65
61
  "width": {
66
62
  "type": "integer",
@@ -72,13 +68,6 @@
72
68
  "minimum": 0,
73
69
  "maximum": 9007199254740991
74
70
  },
75
- "fit": {
76
- "type": "string",
77
- "enum": [
78
- "max",
79
- "crop"
80
- ]
81
- },
82
71
  "sizes": {
83
72
  "type": "string",
84
73
  "minLength": 1
@@ -93,6 +82,7 @@
93
82
  }
94
83
  },
95
84
  "required": [
85
+ "src",
96
86
  "type"
97
87
  ],
98
88
  "additionalProperties": false
@@ -102,6 +92,7 @@
102
92
  "required": [
103
93
  "$type",
104
94
  "assetId",
95
+ "versionId",
105
96
  "alt",
106
97
  "sources"
107
98
  ],
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$type": "componentPattern",
3
- "buildId": "codebuild_01a12331-b86d-7d20-8a35-a7a71d96e8be",
4
- "codeDigest": "sha256:f1246860864e55359c7ad442a7a956b61a835a4826cd6229cc9971db1fe29a67",
3
+ "buildId": "codebuild_01a0d03d-1243-7f49-9ead-8599ed577882",
4
+ "codeDigest": "sha256:44327370dc42bcabe39daf8b86fca1fe191e19dbd8dd39db71df2109c11b3635",
5
5
  "name": "personalization_choice",
6
6
  "schema": {
7
7
  "$schema": "https://json-schema.org/draft/2020-12/schema",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$type": "componentPattern",
3
- "buildId": "codebuild_01a12331-b86d-7d20-8a35-a7a71d96e8be",
4
- "codeDigest": "sha256:f1246860864e55359c7ad442a7a956b61a835a4826cd6229cc9971db1fe29a67",
3
+ "buildId": "codebuild_01a0d03d-1243-7f49-9ead-8599ed577882",
4
+ "codeDigest": "sha256:44327370dc42bcabe39daf8b86fca1fe191e19dbd8dd39db71df2109c11b3635",
5
5
  "name": "site-footer",
6
6
  "schema": {
7
7
  "$schema": "https://json-schema.org/draft/2020-12/schema",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$type": "componentPattern",
3
- "buildId": "codebuild_01a12331-b86d-7d20-8a35-a7a71d96e8be",
4
- "codeDigest": "sha256:f1246860864e55359c7ad442a7a956b61a835a4826cd6229cc9971db1fe29a67",
3
+ "buildId": "codebuild_01a0d03d-1243-7f49-9ead-8599ed577882",
4
+ "codeDigest": "sha256:44327370dc42bcabe39daf8b86fca1fe191e19dbd8dd39db71df2109c11b3635",
5
5
  "name": "site-navigation",
6
6
  "schema": {
7
7
  "$schema": "https://json-schema.org/draft/2020-12/schema",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$type": "componentPattern",
3
- "buildId": "codebuild_01a12331-b86d-7d20-8a35-a7a71d96e8be",
4
- "codeDigest": "sha256:f1246860864e55359c7ad442a7a956b61a835a4826cd6229cc9971db1fe29a67",
3
+ "buildId": "codebuild_01a0d03d-1243-7f49-9ead-8599ed577882",
4
+ "codeDigest": "sha256:44327370dc42bcabe39daf8b86fca1fe191e19dbd8dd39db71df2109c11b3635",
5
5
  "name": "stats_bar",
6
6
  "schema": {
7
7
  "$schema": "https://json-schema.org/draft/2020-12/schema",