@gradial/aci 0.1.29 → 0.1.31
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/bin/aci-darwin-arm64 +0 -0
- package/bin/aci.js +4 -1
- package/dist/assets/index.d.ts +1 -1
- package/dist/content/provider.d.ts +7 -0
- package/dist/index.d.ts +1 -1
- package/dist/next/server.js +26 -1
- package/dist/providers/s3.d.ts +7 -0
- package/dist/providers/s3.js +20 -0
- package/dist/react/index.js +1 -2
- package/dist/types/image.d.ts +16 -28
- package/dist/types/image.js +11 -14
- package/dist/types/media.d.ts +8 -14
- package/dist/types/video.d.ts +4 -7
- package/package.json +8 -9
- package/src/cli/validate-content.mjs +0 -0
- package/src/types/image.ts +21 -33
- package/templates/astro/template/src/fixtures/sections.ts +1 -2
- package/templates/nextjs/template/package.json.tmpl +0 -2
- package/templates/nextjs/template/src/app/layout.tsx +1 -3
- package/templates/nextjs/template/src/app/_components/ConsentManager.tsx +0 -132
package/bin/aci-darwin-arm64
CHANGED
|
Binary file
|
package/bin/aci.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { spawn } from 'node:child_process';
|
|
3
|
-
import { existsSync } from 'node:fs';
|
|
3
|
+
import { chmodSync, existsSync } from 'node:fs';
|
|
4
4
|
import { cp, mkdir, readdir, readFile, rename, stat, writeFile } from 'node:fs/promises';
|
|
5
5
|
import { createRequire } from 'node:module';
|
|
6
6
|
import { basename, dirname, join, relative, resolve } from 'node:path';
|
|
@@ -62,6 +62,9 @@ function resolveWorkspaceBinary() {
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
const binaryPath = resolveBundledBinary() ?? resolvePackagedBinary() ?? resolveWorkspaceBinary();
|
|
65
|
+
if (binaryPath) {
|
|
66
|
+
try { chmodSync(binaryPath, 0o755); } catch {}
|
|
67
|
+
}
|
|
65
68
|
const fallback = binaryPath ? null : resolveGoFallback();
|
|
66
69
|
|
|
67
70
|
if (!binaryPath && !fallback) {
|
package/dist/assets/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { type Image, type
|
|
1
|
+
export { type Image, type ImageSource, type ImageAttrs, ImageSchema, imageAttrs, primaryImageSource, } from '../types/image.js';
|
|
2
2
|
export { type Video, type VideoSource, VideoSchema, VideoSourceSchema, } from '../types/video.js';
|
|
3
3
|
export { type Asset, AssetSchema, isImage, isVideo, isAsset, } from '../types/media.js';
|
|
@@ -5,6 +5,13 @@ export interface RouteEntry {
|
|
|
5
5
|
payloadRef: string;
|
|
6
6
|
digest: string;
|
|
7
7
|
fragmentRefs?: string[];
|
|
8
|
+
variants?: Record<string, RouteVariantEntry>;
|
|
9
|
+
}
|
|
10
|
+
export interface RouteVariantEntry {
|
|
11
|
+
variantKey: string;
|
|
12
|
+
payloadRef: string;
|
|
13
|
+
digest?: string;
|
|
14
|
+
variantValues?: Record<string, string>;
|
|
8
15
|
}
|
|
9
16
|
export interface FragmentEntry {
|
|
10
17
|
id: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export type { Registry, RegistryEntry, AnyComponent } from './registry.js';
|
|
|
5
5
|
export { blockRef, blockRefArray } from './types/block-ref.js';
|
|
6
6
|
export type { BlockRef, BlockRefEntry, BlockRefMeta, BlockRefUnion } from './types/block-ref.js';
|
|
7
7
|
export type { ComponentContract, ComponentContractID, ComponentContractValidator, ComponentRegistry, ComponentValidationContext, ComponentValidationIssue, InferComponentProps, } from './types/component.js';
|
|
8
|
-
export { ImageSchema, imageAttrs, primaryImageSource, type Image, type
|
|
8
|
+
export { ImageSchema, imageAttrs, primaryImageSource, type Image, type ImageSource, type ImageAttrs, type ImageSlotContract, type SlotOutput, } from './types/image.js';
|
|
9
9
|
export { LinkSchema, type Link, type LinkTarget, type LinkResolverContext, resolveLink, resolveHref, assertSafeHref, normalizeLinkRel, } from './types/link.js';
|
|
10
10
|
export { HeadingSchema, InlineContentSchema, RichTextValueSchema, type Heading, type InlineContent, type RichTextValue, } from './types/rich-text.js';
|
|
11
11
|
export type { Config, RouteConfig, ExternalDependency, DAMConfig, } from './types/config.js';
|
package/dist/next/server.js
CHANGED
|
@@ -10,6 +10,9 @@ export async function getPage(route = '', config = {}) {
|
|
|
10
10
|
if (runtimeInput)
|
|
11
11
|
return runtimeInput.page;
|
|
12
12
|
const provider = await resolveProviderWithFallback(config);
|
|
13
|
+
const variantPage = await pageFromFunctionRef(provider);
|
|
14
|
+
if (variantPage !== null)
|
|
15
|
+
return variantPage;
|
|
13
16
|
return await provider.getPage(route);
|
|
14
17
|
}
|
|
15
18
|
export async function getSiteConfig(config = {}) {
|
|
@@ -53,7 +56,7 @@ export async function getRenderInput(route = '/', config = {}) {
|
|
|
53
56
|
// Cache shared resources (manifest, siteConfig) but not per-page content
|
|
54
57
|
// Page-level caching is handled by CDN
|
|
55
58
|
const [page, siteConfig] = await Promise.all([
|
|
56
|
-
provider.getPage(route),
|
|
59
|
+
pageFromFunctionRef(provider).then((variantPage) => variantPage ?? provider.getPage(route)),
|
|
57
60
|
getCachedSiteConfig(provider),
|
|
58
61
|
]);
|
|
59
62
|
return {
|
|
@@ -73,6 +76,28 @@ export async function getPageRuntimeRenderInput() {
|
|
|
73
76
|
return null;
|
|
74
77
|
}
|
|
75
78
|
}
|
|
79
|
+
// The personalization edge proxies framework-origin requests with
|
|
80
|
+
// X-Baremetal-Function-Ref naming the exact page payload its decision
|
|
81
|
+
// selected (base or variant). When present, the SSR render must use that
|
|
82
|
+
// payload — otherwise every visitor gets the base page and edge decisioning
|
|
83
|
+
// is cosmetic. The S3 provider only serves refs the release manifest
|
|
84
|
+
// declares.
|
|
85
|
+
const BAREMETAL_FUNCTION_REF_HEADER = 'x-baremetal-function-ref';
|
|
86
|
+
async function pageFromFunctionRef(provider) {
|
|
87
|
+
if (!(provider instanceof S3ContentProvider))
|
|
88
|
+
return null;
|
|
89
|
+
let ref = '';
|
|
90
|
+
try {
|
|
91
|
+
const current = await headers();
|
|
92
|
+
ref = (current.get(BAREMETAL_FUNCTION_REF_HEADER) || '').trim();
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
if (!ref)
|
|
98
|
+
return null;
|
|
99
|
+
return await provider.getPageByRef(ref);
|
|
100
|
+
}
|
|
76
101
|
export { isPreviewMode } from './preview-mode.js';
|
|
77
102
|
export async function routeFromNextParams(params) {
|
|
78
103
|
if (!params)
|
package/dist/providers/s3.d.ts
CHANGED
|
@@ -16,6 +16,13 @@ export declare class S3ContentProvider implements ContentProvider {
|
|
|
16
16
|
listRoutes(): Promise<RouteEntry[]>;
|
|
17
17
|
getSiteConfig<T = unknown>(): Promise<T>;
|
|
18
18
|
getPage<T = unknown>(route: string): Promise<T>;
|
|
19
|
+
/**
|
|
20
|
+
* getPageByRef serves the exact payload the edge selected (the
|
|
21
|
+
* X-Baremetal-Function-Ref contract): base page or variant. Only refs the
|
|
22
|
+
* release manifest declares are served — the header names published
|
|
23
|
+
* content, it cannot address arbitrary keys.
|
|
24
|
+
*/
|
|
25
|
+
getPageByRef<T = unknown>(payloadRef: string): Promise<T>;
|
|
19
26
|
getFragment<T = unknown>(id: string): Promise<T>;
|
|
20
27
|
getLayout<T = unknown>(name: string): Promise<T>;
|
|
21
28
|
manifest(): Promise<CompiledManifest>;
|
package/dist/providers/s3.js
CHANGED
|
@@ -32,6 +32,26 @@ export class S3ContentProvider {
|
|
|
32
32
|
throw new PageNotFoundError(route, error);
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* getPageByRef serves the exact payload the edge selected (the
|
|
37
|
+
* X-Baremetal-Function-Ref contract): base page or variant. Only refs the
|
|
38
|
+
* release manifest declares are served — the header names published
|
|
39
|
+
* content, it cannot address arbitrary keys.
|
|
40
|
+
*/
|
|
41
|
+
async getPageByRef(payloadRef) {
|
|
42
|
+
const manifest = await this.manifest();
|
|
43
|
+
const known = Object.values(manifest.routes).some((entry) => entry.payloadRef === payloadRef ||
|
|
44
|
+
Object.values(entry.variants ?? {}).some((variant) => variant.payloadRef === payloadRef));
|
|
45
|
+
if (!known) {
|
|
46
|
+
throw new PageNotFoundError(payloadRef);
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
return await this.getJSON(payloadRef);
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
throw new PageNotFoundError(payloadRef, error);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
35
55
|
async getFragment(id) {
|
|
36
56
|
const manifest = await this.manifest();
|
|
37
57
|
const entry = manifest.fragments[id];
|
package/dist/react/index.js
CHANGED
|
@@ -12,10 +12,9 @@ export function Image({ image, value, ...attrs }) {
|
|
|
12
12
|
assetId: '',
|
|
13
13
|
versionId: '',
|
|
14
14
|
alt: '',
|
|
15
|
-
fallback: { src: '', width: 0, height: 0 },
|
|
16
15
|
sources: [],
|
|
17
16
|
};
|
|
18
|
-
if (!resolved.
|
|
17
|
+
if (!resolved.sources[0]?.src) {
|
|
19
18
|
return createElement('img', {
|
|
20
19
|
src: '',
|
|
21
20
|
alt: resolved.alt,
|
package/dist/types/image.d.ts
CHANGED
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
export interface
|
|
3
|
-
/**
|
|
2
|
+
export interface ImageSource {
|
|
3
|
+
/** Primary derivative URL for this rendition candidate. */
|
|
4
4
|
src: string;
|
|
5
5
|
/** Intrinsic width in pixels (0 when the format carries none, e.g. SVG). */
|
|
6
|
-
width
|
|
6
|
+
width?: number;
|
|
7
7
|
/** Intrinsic height in pixels (0 when the format carries none). */
|
|
8
|
-
height
|
|
9
|
-
/**
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
export interface ImageSource {
|
|
13
|
-
/** srcset value — a single URL or a width-descriptor candidate list. */
|
|
14
|
-
srcset: string;
|
|
8
|
+
height?: number;
|
|
9
|
+
/** Optional width-descriptor rendition candidates. */
|
|
10
|
+
srcset?: string;
|
|
15
11
|
/** sizes attribute from the slot contract. */
|
|
16
12
|
sizes?: string;
|
|
17
13
|
/** Media query scoping this source (art direction). */
|
|
@@ -28,8 +24,6 @@ export interface Image {
|
|
|
28
24
|
versionId: string;
|
|
29
25
|
/** Accessible description of the image content. */
|
|
30
26
|
alt: string;
|
|
31
|
-
/** Base <img> rendition. */
|
|
32
|
-
fallback: ImageFallback;
|
|
33
27
|
/** <source> candidates produced for the asset slot. */
|
|
34
28
|
sources: ImageSource[];
|
|
35
29
|
}
|
|
@@ -43,14 +37,11 @@ export interface SlotOutput {
|
|
|
43
37
|
widths: number[];
|
|
44
38
|
media?: string;
|
|
45
39
|
}
|
|
46
|
-
export declare const ImageFallbackSchema: z.ZodObject<{
|
|
47
|
-
src: z.ZodString;
|
|
48
|
-
width: z.ZodNumber;
|
|
49
|
-
height: z.ZodNumber;
|
|
50
|
-
type: z.ZodOptional<z.ZodString>;
|
|
51
|
-
}, z.core.$strip>;
|
|
52
40
|
export declare const ImageSourceSchema: z.ZodObject<{
|
|
53
|
-
|
|
41
|
+
src: z.ZodString;
|
|
42
|
+
srcset: z.ZodOptional<z.ZodString>;
|
|
43
|
+
width: z.ZodOptional<z.ZodNumber>;
|
|
44
|
+
height: z.ZodOptional<z.ZodNumber>;
|
|
54
45
|
sizes: z.ZodOptional<z.ZodString>;
|
|
55
46
|
media: z.ZodOptional<z.ZodString>;
|
|
56
47
|
type: z.ZodString;
|
|
@@ -60,14 +51,11 @@ export declare const ImageSchema: z.ZodObject<{
|
|
|
60
51
|
assetId: z.ZodString;
|
|
61
52
|
versionId: z.ZodString;
|
|
62
53
|
alt: z.ZodString;
|
|
63
|
-
fallback: z.ZodObject<{
|
|
64
|
-
src: z.ZodString;
|
|
65
|
-
width: z.ZodNumber;
|
|
66
|
-
height: z.ZodNumber;
|
|
67
|
-
type: z.ZodOptional<z.ZodString>;
|
|
68
|
-
}, z.core.$strip>;
|
|
69
54
|
sources: z.ZodArray<z.ZodObject<{
|
|
70
|
-
|
|
55
|
+
src: z.ZodString;
|
|
56
|
+
srcset: z.ZodOptional<z.ZodString>;
|
|
57
|
+
width: z.ZodOptional<z.ZodNumber>;
|
|
58
|
+
height: z.ZodOptional<z.ZodNumber>;
|
|
71
59
|
sizes: z.ZodOptional<z.ZodString>;
|
|
72
60
|
media: z.ZodOptional<z.ZodString>;
|
|
73
61
|
type: z.ZodString;
|
|
@@ -75,9 +63,9 @@ export declare const ImageSchema: z.ZodObject<{
|
|
|
75
63
|
}, z.core.$strip>;
|
|
76
64
|
export type ImageAttrs = Record<string, unknown>;
|
|
77
65
|
/**
|
|
78
|
-
* The primary rendition of an image — its
|
|
66
|
+
* The primary rendition of an image — its first source entry.
|
|
79
67
|
*/
|
|
80
|
-
export declare function primaryImageSource(image: Image):
|
|
68
|
+
export declare function primaryImageSource(image: Image): ImageSource;
|
|
81
69
|
/**
|
|
82
70
|
* Computes the full set of <img> attributes for an Image.
|
|
83
71
|
*
|
package/dist/types/image.js
CHANGED
|
@@ -2,14 +2,11 @@ import { z } from 'zod';
|
|
|
2
2
|
// ---------------------------------------------------------------------------
|
|
3
3
|
// Zod schema
|
|
4
4
|
// ---------------------------------------------------------------------------
|
|
5
|
-
export const ImageFallbackSchema = z.object({
|
|
6
|
-
src: z.string().min(1),
|
|
7
|
-
width: z.number().int().nonnegative(),
|
|
8
|
-
height: z.number().int().nonnegative(),
|
|
9
|
-
type: z.string().min(1).optional(),
|
|
10
|
-
});
|
|
11
5
|
export const ImageSourceSchema = z.object({
|
|
12
|
-
|
|
6
|
+
src: z.string().min(1),
|
|
7
|
+
srcset: z.string().min(1).optional(),
|
|
8
|
+
width: z.number().int().nonnegative().optional(),
|
|
9
|
+
height: z.number().int().nonnegative().optional(),
|
|
13
10
|
sizes: z.string().min(1).optional(),
|
|
14
11
|
media: z.string().min(1).optional(),
|
|
15
12
|
type: z.string().min(1),
|
|
@@ -19,14 +16,13 @@ export const ImageSchema = z.object({
|
|
|
19
16
|
assetId: z.string().min(1),
|
|
20
17
|
versionId: z.string().min(1),
|
|
21
18
|
alt: z.string(),
|
|
22
|
-
fallback: ImageFallbackSchema,
|
|
23
19
|
sources: z.array(ImageSourceSchema).min(1),
|
|
24
20
|
});
|
|
25
21
|
/**
|
|
26
|
-
* The primary rendition of an image — its
|
|
22
|
+
* The primary rendition of an image — its first source entry.
|
|
27
23
|
*/
|
|
28
24
|
export function primaryImageSource(image) {
|
|
29
|
-
return image.
|
|
25
|
+
return image.sources[0];
|
|
30
26
|
}
|
|
31
27
|
/**
|
|
32
28
|
* Computes the full set of <img> attributes for an Image.
|
|
@@ -38,12 +34,13 @@ export function primaryImageSource(image) {
|
|
|
38
34
|
* first unscoped source only.
|
|
39
35
|
*/
|
|
40
36
|
export function imageAttrs(image, overrides = {}) {
|
|
41
|
-
const
|
|
37
|
+
const primary = image.sources[0];
|
|
38
|
+
const unscoped = image.sources.find((s) => !s.media) ?? primary;
|
|
42
39
|
return {
|
|
43
|
-
src:
|
|
40
|
+
src: primary.src,
|
|
44
41
|
alt: image.alt,
|
|
45
|
-
width:
|
|
46
|
-
height:
|
|
42
|
+
width: primary.width && primary.width > 0 ? primary.width : undefined,
|
|
43
|
+
height: primary.height && primary.height > 0 ? primary.height : undefined,
|
|
47
44
|
srcSet: unscoped?.srcset || undefined,
|
|
48
45
|
sizes: unscoped?.sizes || undefined,
|
|
49
46
|
loading: 'lazy',
|
package/dist/types/media.d.ts
CHANGED
|
@@ -9,14 +9,11 @@ export declare const AssetSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
9
9
|
assetId: z.ZodString;
|
|
10
10
|
versionId: z.ZodString;
|
|
11
11
|
alt: z.ZodString;
|
|
12
|
-
fallback: z.ZodObject<{
|
|
13
|
-
src: z.ZodString;
|
|
14
|
-
width: z.ZodNumber;
|
|
15
|
-
height: z.ZodNumber;
|
|
16
|
-
type: z.ZodOptional<z.ZodString>;
|
|
17
|
-
}, z.core.$strip>;
|
|
18
12
|
sources: z.ZodArray<z.ZodObject<{
|
|
19
|
-
|
|
13
|
+
src: z.ZodString;
|
|
14
|
+
srcset: z.ZodOptional<z.ZodString>;
|
|
15
|
+
width: z.ZodOptional<z.ZodNumber>;
|
|
16
|
+
height: z.ZodOptional<z.ZodNumber>;
|
|
20
17
|
sizes: z.ZodOptional<z.ZodString>;
|
|
21
18
|
media: z.ZodOptional<z.ZodString>;
|
|
22
19
|
type: z.ZodString;
|
|
@@ -35,14 +32,11 @@ export declare const AssetSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
35
32
|
assetId: z.ZodString;
|
|
36
33
|
versionId: z.ZodString;
|
|
37
34
|
alt: z.ZodString;
|
|
38
|
-
fallback: z.ZodObject<{
|
|
39
|
-
src: z.ZodString;
|
|
40
|
-
width: z.ZodNumber;
|
|
41
|
-
height: z.ZodNumber;
|
|
42
|
-
type: z.ZodOptional<z.ZodString>;
|
|
43
|
-
}, z.core.$strip>;
|
|
44
35
|
sources: z.ZodArray<z.ZodObject<{
|
|
45
|
-
|
|
36
|
+
src: z.ZodString;
|
|
37
|
+
srcset: z.ZodOptional<z.ZodString>;
|
|
38
|
+
width: z.ZodOptional<z.ZodNumber>;
|
|
39
|
+
height: z.ZodOptional<z.ZodNumber>;
|
|
46
40
|
sizes: z.ZodOptional<z.ZodString>;
|
|
47
41
|
media: z.ZodOptional<z.ZodString>;
|
|
48
42
|
type: z.ZodString;
|
package/dist/types/video.d.ts
CHANGED
|
@@ -52,14 +52,11 @@ export declare const VideoSchema: z.ZodObject<{
|
|
|
52
52
|
assetId: z.ZodString;
|
|
53
53
|
versionId: z.ZodString;
|
|
54
54
|
alt: z.ZodString;
|
|
55
|
-
fallback: z.ZodObject<{
|
|
56
|
-
src: z.ZodString;
|
|
57
|
-
width: z.ZodNumber;
|
|
58
|
-
height: z.ZodNumber;
|
|
59
|
-
type: z.ZodOptional<z.ZodString>;
|
|
60
|
-
}, z.core.$strip>;
|
|
61
55
|
sources: z.ZodArray<z.ZodObject<{
|
|
62
|
-
|
|
56
|
+
src: z.ZodString;
|
|
57
|
+
srcset: z.ZodOptional<z.ZodString>;
|
|
58
|
+
width: z.ZodOptional<z.ZodNumber>;
|
|
59
|
+
height: z.ZodOptional<z.ZodNumber>;
|
|
63
60
|
sizes: z.ZodOptional<z.ZodString>;
|
|
64
61
|
media: z.ZodOptional<z.ZodString>;
|
|
65
62
|
type: z.ZodString;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gradial/aci",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.31",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -85,13 +85,6 @@
|
|
|
85
85
|
"default": "./dist/astro/index.js"
|
|
86
86
|
}
|
|
87
87
|
},
|
|
88
|
-
"scripts": {
|
|
89
|
-
"build": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\" && tsc -p tsconfig.json",
|
|
90
|
-
"build:cli": "cd ../.. && ./scripts/build-cli.sh",
|
|
91
|
-
"generate-starters": "cd ../.. && tsx scripts/generate-starters.ts",
|
|
92
|
-
"compile-registry": "tsx src/cli/compile-registry.mjs",
|
|
93
|
-
"prepack": "npm run generate-starters && npm run build && npm run build:cli"
|
|
94
|
-
},
|
|
95
88
|
"dependencies": {
|
|
96
89
|
"markdown-it": "^14.1.0",
|
|
97
90
|
"sanitize-html": "^2.13.1",
|
|
@@ -127,5 +120,11 @@
|
|
|
127
120
|
"tsx": "^4.20.0",
|
|
128
121
|
"typescript": "^5.9.3",
|
|
129
122
|
"zod": "^4.0.0"
|
|
123
|
+
},
|
|
124
|
+
"scripts": {
|
|
125
|
+
"build": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\" && tsc -p tsconfig.json",
|
|
126
|
+
"build:cli": "cd ../.. && ./scripts/build-cli.sh",
|
|
127
|
+
"generate-starters": "cd ../.. && tsx scripts/generate-starters.ts",
|
|
128
|
+
"compile-registry": "tsx src/cli/compile-registry.mjs"
|
|
130
129
|
}
|
|
131
|
-
}
|
|
130
|
+
}
|
|
File without changes
|
package/src/types/image.ts
CHANGED
|
@@ -1,27 +1,21 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
|
|
3
3
|
// ---------------------------------------------------------------------------
|
|
4
|
-
// Image
|
|
4
|
+
// Image source variants
|
|
5
5
|
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
// the optional media/sizes of the slot output that produced it.
|
|
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.
|
|
9
8
|
// ---------------------------------------------------------------------------
|
|
10
9
|
|
|
11
|
-
export interface
|
|
12
|
-
/**
|
|
10
|
+
export interface ImageSource {
|
|
11
|
+
/** Primary derivative URL for this rendition candidate. */
|
|
13
12
|
src: string;
|
|
14
13
|
/** Intrinsic width in pixels (0 when the format carries none, e.g. SVG). */
|
|
15
|
-
width
|
|
14
|
+
width?: number;
|
|
16
15
|
/** Intrinsic height in pixels (0 when the format carries none). */
|
|
17
|
-
height
|
|
18
|
-
/**
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface ImageSource {
|
|
23
|
-
/** srcset value — a single URL or a width-descriptor candidate list. */
|
|
24
|
-
srcset: string;
|
|
16
|
+
height?: number;
|
|
17
|
+
/** Optional width-descriptor rendition candidates. */
|
|
18
|
+
srcset?: string;
|
|
25
19
|
/** sizes attribute from the slot contract. */
|
|
26
20
|
sizes?: string;
|
|
27
21
|
/** Media query scoping this source (art direction). */
|
|
@@ -47,8 +41,6 @@ export interface Image {
|
|
|
47
41
|
versionId: string;
|
|
48
42
|
/** Accessible description of the image content. */
|
|
49
43
|
alt: string;
|
|
50
|
-
/** Base <img> rendition. */
|
|
51
|
-
fallback: ImageFallback;
|
|
52
44
|
/** <source> candidates produced for the asset slot. */
|
|
53
45
|
sources: ImageSource[];
|
|
54
46
|
}
|
|
@@ -73,15 +65,11 @@ export interface SlotOutput {
|
|
|
73
65
|
// Zod schema
|
|
74
66
|
// ---------------------------------------------------------------------------
|
|
75
67
|
|
|
76
|
-
export const ImageFallbackSchema = z.object({
|
|
77
|
-
src: z.string().min(1),
|
|
78
|
-
width: z.number().int().nonnegative(),
|
|
79
|
-
height: z.number().int().nonnegative(),
|
|
80
|
-
type: z.string().min(1).optional(),
|
|
81
|
-
});
|
|
82
|
-
|
|
83
68
|
export const ImageSourceSchema = z.object({
|
|
84
|
-
|
|
69
|
+
src: z.string().min(1),
|
|
70
|
+
srcset: z.string().min(1).optional(),
|
|
71
|
+
width: z.number().int().nonnegative().optional(),
|
|
72
|
+
height: z.number().int().nonnegative().optional(),
|
|
85
73
|
sizes: z.string().min(1).optional(),
|
|
86
74
|
media: z.string().min(1).optional(),
|
|
87
75
|
type: z.string().min(1),
|
|
@@ -92,7 +80,6 @@ export const ImageSchema = z.object({
|
|
|
92
80
|
assetId: z.string().min(1),
|
|
93
81
|
versionId: z.string().min(1),
|
|
94
82
|
alt: z.string(),
|
|
95
|
-
fallback: ImageFallbackSchema,
|
|
96
83
|
sources: z.array(ImageSourceSchema).min(1),
|
|
97
84
|
});
|
|
98
85
|
|
|
@@ -103,10 +90,10 @@ export const ImageSchema = z.object({
|
|
|
103
90
|
export type ImageAttrs = Record<string, unknown>;
|
|
104
91
|
|
|
105
92
|
/**
|
|
106
|
-
* The primary rendition of an image — its
|
|
93
|
+
* The primary rendition of an image — its first source entry.
|
|
107
94
|
*/
|
|
108
|
-
export function primaryImageSource(image: Image):
|
|
109
|
-
return image.
|
|
95
|
+
export function primaryImageSource(image: Image): ImageSource {
|
|
96
|
+
return image.sources[0];
|
|
110
97
|
}
|
|
111
98
|
|
|
112
99
|
/**
|
|
@@ -119,13 +106,14 @@ export function primaryImageSource(image: Image): ImageFallback {
|
|
|
119
106
|
* first unscoped source only.
|
|
120
107
|
*/
|
|
121
108
|
export function imageAttrs(image: Image, overrides: ImageAttrs = {}): ImageAttrs {
|
|
122
|
-
const
|
|
109
|
+
const primary = image.sources[0];
|
|
110
|
+
const unscoped = image.sources.find((s) => !s.media) ?? primary;
|
|
123
111
|
|
|
124
112
|
return {
|
|
125
|
-
src:
|
|
113
|
+
src: primary.src,
|
|
126
114
|
alt: image.alt,
|
|
127
|
-
width:
|
|
128
|
-
height:
|
|
115
|
+
width: primary.width && primary.width > 0 ? primary.width : undefined,
|
|
116
|
+
height: primary.height && primary.height > 0 ? primary.height : undefined,
|
|
129
117
|
srcSet: unscoped?.srcset || undefined,
|
|
130
118
|
sizes: unscoped?.sizes || undefined,
|
|
131
119
|
loading: 'lazy',
|
|
@@ -27,9 +27,8 @@ export const sectionStoryFixtures: SectionStoryFixture[] = [
|
|
|
27
27
|
assetId: 'fixture_seattle',
|
|
28
28
|
versionId: 'v0001',
|
|
29
29
|
alt: 'Seattle skyline at dusk',
|
|
30
|
-
fallback: { src: '/assets/seattle.avif', width: 1920, height: 1280, type: 'image/avif' },
|
|
31
30
|
sources: [
|
|
32
|
-
{
|
|
31
|
+
{ src: '/assets/seattle.avif', width: 1920, height: 1280, sizes: '100vw', type: 'image/avif' }
|
|
33
32
|
]
|
|
34
33
|
}
|
|
35
34
|
}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
2
|
import { Inter, Space_Grotesk } from 'next/font/google';
|
|
3
3
|
import { DevRefresh } from '@gradial/aci/next';
|
|
4
|
-
import { ConsentManager } from '@/app/_components/ConsentManager';
|
|
5
|
-
import '@c15t/nextjs/styles.css';
|
|
6
4
|
import '@/design-system/styles.css';
|
|
7
5
|
|
|
8
6
|
const inter = Inter({
|
|
@@ -23,7 +21,7 @@ export default function Layout({ children }: { children: ReactNode }) {
|
|
|
23
21
|
return (
|
|
24
22
|
<html lang="en" className={`${inter.variable} ${spaceGrotesk.variable}`}>
|
|
25
23
|
<body>
|
|
26
|
-
|
|
24
|
+
{children}
|
|
27
25
|
<DevRefresh />
|
|
28
26
|
</body>
|
|
29
27
|
</html>
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
ConsentBanner,
|
|
5
|
-
ConsentDialog,
|
|
6
|
-
ConsentManagerProvider,
|
|
7
|
-
useConsentManager,
|
|
8
|
-
type ConsentManagerProviderProps,
|
|
9
|
-
} from '@c15t/nextjs';
|
|
10
|
-
import { useEffect, useMemo, type ReactNode } from 'react';
|
|
11
|
-
|
|
12
|
-
// Hosted c15t backend (consent.io or self-hosted). Unset = offline mode:
|
|
13
|
-
// consent is stored client-side and no network calls are made.
|
|
14
|
-
const C15T_BACKEND_URL = process.env.NEXT_PUBLIC_C15T_BACKEND_URL;
|
|
15
|
-
|
|
16
|
-
// The CMP's own categories. The mapping from categories to the Gradial
|
|
17
|
-
// personalization purpose lives in .content/config/site.json
|
|
18
|
-
// (personalization.consentCategories), not here.
|
|
19
|
-
const CONSENT_CATEGORIES = ['necessary', 'measurement', 'marketing'] as const;
|
|
20
|
-
|
|
21
|
-
// ---------------------------------------------------------------------------
|
|
22
|
-
// Gradial collect bridge
|
|
23
|
-
//
|
|
24
|
-
// The Gradial collect SDK's c15t preset (the site config's
|
|
25
|
-
// `personalization.consentPreset: "c15t"`, emitted as
|
|
26
|
-
// `data-aci-consent="c15t"` on the collect tag) reads
|
|
27
|
-
// `window.c15t = { consents, onConsentChange }`. c15t itself does not
|
|
28
|
-
// publish that shape, so this bridge mirrors the store onto it — only after
|
|
29
|
-
// a real visitor decision (`consentInfo` set), never for pre-decision
|
|
30
|
-
// defaults, so the SDK cannot mistake an untouched banner for a withdrawal.
|
|
31
|
-
// ---------------------------------------------------------------------------
|
|
32
|
-
|
|
33
|
-
type Consents = Record<string, boolean>;
|
|
34
|
-
type ConsentListener = (payload: { consents: Consents }) => void;
|
|
35
|
-
|
|
36
|
-
declare global {
|
|
37
|
-
interface Window {
|
|
38
|
-
c15t?: {
|
|
39
|
-
consents?: Consents;
|
|
40
|
-
onConsentChange?: (cb: ConsentListener) => void;
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const consentListeners: ConsentListener[] = [];
|
|
46
|
-
|
|
47
|
-
function publishAciConsents(consents: Consents): void {
|
|
48
|
-
const bridge = (window.c15t ??= {});
|
|
49
|
-
bridge.consents = consents;
|
|
50
|
-
bridge.onConsentChange ??= (cb: ConsentListener) => {
|
|
51
|
-
consentListeners.push(cb);
|
|
52
|
-
};
|
|
53
|
-
for (const listener of [...consentListeners]) {
|
|
54
|
-
listener({ consents });
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function AciConsentBridge() {
|
|
59
|
-
const { consents, consentInfo } = useConsentManager();
|
|
60
|
-
useEffect(() => {
|
|
61
|
-
if (!consentInfo || !consents) return;
|
|
62
|
-
publishAciConsents(consents as Consents);
|
|
63
|
-
}, [consents, consentInfo]);
|
|
64
|
-
return null;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// ---------------------------------------------------------------------------
|
|
68
|
-
// Consent manager
|
|
69
|
-
// ---------------------------------------------------------------------------
|
|
70
|
-
|
|
71
|
-
function getConsentOptions(): ConsentManagerProviderProps['options'] {
|
|
72
|
-
const baseOptions = {
|
|
73
|
-
consentCategories: [...CONSENT_CATEGORIES],
|
|
74
|
-
legalLinks: {
|
|
75
|
-
privacyPolicy: {
|
|
76
|
-
href: '/privacy/',
|
|
77
|
-
target: '_self' as const,
|
|
78
|
-
label: 'Privacy policy',
|
|
79
|
-
},
|
|
80
|
-
},
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
if (C15T_BACKEND_URL) {
|
|
84
|
-
return {
|
|
85
|
-
...baseOptions,
|
|
86
|
-
mode: 'hosted',
|
|
87
|
-
backendURL: C15T_BACKEND_URL,
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return {
|
|
92
|
-
...baseOptions,
|
|
93
|
-
mode: 'offline',
|
|
94
|
-
offlinePolicy: {
|
|
95
|
-
policyPacks: [
|
|
96
|
-
{
|
|
97
|
-
id: 'default-opt-in',
|
|
98
|
-
match: { isDefault: true },
|
|
99
|
-
consent: {
|
|
100
|
-
model: 'opt-in',
|
|
101
|
-
categories: [...CONSENT_CATEGORIES],
|
|
102
|
-
},
|
|
103
|
-
ui: { mode: 'banner' },
|
|
104
|
-
},
|
|
105
|
-
],
|
|
106
|
-
},
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
export function ConsentManager({ children }: { children: ReactNode }) {
|
|
111
|
-
const options = useMemo(() => getConsentOptions(), []);
|
|
112
|
-
|
|
113
|
-
return (
|
|
114
|
-
<ConsentManagerProvider options={options}>
|
|
115
|
-
{children}
|
|
116
|
-
<AciConsentBridge />
|
|
117
|
-
<ConsentBanner
|
|
118
|
-
title="Cookie preferences"
|
|
119
|
-
description="We use cookies to keep the site working, measure performance, and support marketing."
|
|
120
|
-
acceptButtonText="Accept all"
|
|
121
|
-
rejectButtonText="Reject all"
|
|
122
|
-
customizeButtonText="Customize"
|
|
123
|
-
legalLinks={['privacyPolicy']}
|
|
124
|
-
layout={[['reject', 'accept'], 'customize']}
|
|
125
|
-
primaryButton="accept"
|
|
126
|
-
scrollLock={false}
|
|
127
|
-
hideBranding
|
|
128
|
-
/>
|
|
129
|
-
<ConsentDialog legalLinks={['privacyPolicy']} scrollLock trapFocus hideBranding />
|
|
130
|
-
</ConsentManagerProvider>
|
|
131
|
-
);
|
|
132
|
-
}
|