@gradial/aci 0.2.0-canary.720 → 0.2.0-canary.726
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/CHANGELOG.md +9 -0
- package/README.md +4 -4
- package/dist/verify/checks/fetch.js +2 -1
- package/dist/verify/checks/resource.js +3 -3
- package/dist/verify/html/refs.d.ts +2 -0
- package/dist/verify/html/refs.js +26 -2
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,15 @@
|
|
|
4
4
|
|
|
5
5
|
### Fixed
|
|
6
6
|
|
|
7
|
+
- Page verification judges a Next.js image optimizer URL
|
|
8
|
+
(`/_next/image?url=…`, what `next/image` renders) by the image it wraps.
|
|
9
|
+
The optimizer is the host's runtime endpoint, not a file in the release,
|
|
10
|
+
so before staging it answered 404 and every Next site using `next/image`
|
|
11
|
+
was refused with `fetch.notFound` although its images load. A root-relative
|
|
12
|
+
source is fetched like any own file (a missing one is still an error, named
|
|
13
|
+
by its own path "via next/image"); a remote source is a third-party URL
|
|
14
|
+
(a warning). Each source is fetched and reported once per page, however
|
|
15
|
+
many srcset widths name it.
|
|
7
16
|
- The staged and live checks fetch the stable collect script
|
|
8
17
|
(`/_aci/aci.js`) at the judged release's own path,
|
|
9
18
|
`/__r/<release>/_aci/aci.js`. The stable URL answers the active
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Agentic Content Infrastructure SDK
|
|
2
2
|
|
|
3
|
-
`@gradial/aci` `0.2.0-canary.
|
|
3
|
+
`@gradial/aci` `0.2.0-canary.726` 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.2.0-canary.
|
|
11
|
+
npm install @gradial/aci@0.2.0-canary.726 zod@^4
|
|
12
12
|
```
|
|
13
13
|
|
|
14
14
|
## Root Import
|
|
@@ -141,13 +141,13 @@ host bundles select and serve immutable release artifacts.
|
|
|
141
141
|
The first RC scaffold path is Next:
|
|
142
142
|
|
|
143
143
|
```bash
|
|
144
|
-
npx @gradial/aci@0.2.0-canary.
|
|
144
|
+
npx @gradial/aci@0.2.0-canary.726 init my-site --template next-starter
|
|
145
145
|
```
|
|
146
146
|
|
|
147
147
|
List available templates:
|
|
148
148
|
|
|
149
149
|
```bash
|
|
150
|
-
npx @gradial/aci@0.2.0-canary.
|
|
150
|
+
npx @gradial/aci@0.2.0-canary.726 init --list
|
|
151
151
|
```
|
|
152
152
|
|
|
153
153
|
## Personalization: The One-Tag Install
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
// references answers 2xx. Each URL is fetched once per unit, and once per run
|
|
4
4
|
// when the caller shares withFetchCache. A failed own URL is an error, a
|
|
5
5
|
// failed third-party URL a warning (resource.ts). Same-origin links to routes
|
|
6
|
-
// are the links check's.
|
|
6
|
+
// are the links check's. A next/image optimizer URL is judged by the image it
|
|
7
|
+
// wraps (html/refs.ts).
|
|
7
8
|
import { isFilePath } from '../paths.js';
|
|
8
9
|
import { fetchAll } from './resource.js';
|
|
9
10
|
const FETCH_CODES = {
|
|
@@ -8,7 +8,7 @@ function judgeFetched(input, ref, outcome, codes) {
|
|
|
8
8
|
if ('status' in outcome && outcome.status >= 200 && outcome.status < 300)
|
|
9
9
|
return null;
|
|
10
10
|
const own = ref.url.origin === input.origin;
|
|
11
|
-
const shown = own ? `${ref.url.pathname}${ref.url.search}` : ref.url.href
|
|
11
|
+
const shown = `"${own ? `${ref.url.pathname}${ref.url.search}` : ref.url.href}"${ref.via ? ` (via ${ref.via})` : ''}`;
|
|
12
12
|
const fix = own
|
|
13
13
|
? 'publish the file it points to, or change the reference to one that exists'
|
|
14
14
|
: 'this third-party URL is outside the release; check it is still live';
|
|
@@ -16,7 +16,7 @@ function judgeFetched(input, ref, outcome, codes) {
|
|
|
16
16
|
return judge(own ? 'error' : 'warning', input, {
|
|
17
17
|
code: codes.failed,
|
|
18
18
|
url: ref.raw,
|
|
19
|
-
message: `the ${ref.source}
|
|
19
|
+
message: `the ${ref.source} ${shown} could not be fetched (${outcome.error}); ${fix}`,
|
|
20
20
|
});
|
|
21
21
|
}
|
|
22
22
|
const notFound = outcome.status === 404 || outcome.status === 410;
|
|
@@ -28,7 +28,7 @@ function judgeFetched(input, ref, outcome, codes) {
|
|
|
28
28
|
return judge(own ? 'error' : 'warning', input, {
|
|
29
29
|
code: notFound ? codes.notFound : codes.failed,
|
|
30
30
|
url: ref.raw,
|
|
31
|
-
message: `the ${ref.source}
|
|
31
|
+
message: `the ${ref.source} ${shown} ${answered}; ${fix}`,
|
|
32
32
|
});
|
|
33
33
|
}
|
|
34
34
|
/** Fetches every target once through the context's cache and keeps the failures. */
|
|
@@ -8,6 +8,8 @@ export interface Ref {
|
|
|
8
8
|
raw: string;
|
|
9
9
|
/** Resolved against the page (or its <base>); null when it does not parse as a URL. */
|
|
10
10
|
url: URL | null;
|
|
11
|
+
/** Set when `url` is the source a wrapper URL in `raw` names, e.g. a next/image optimizer URL. */
|
|
12
|
+
via?: 'next/image';
|
|
11
13
|
}
|
|
12
14
|
/** Every reference in `tags`, resolved against `pageURL`. Fragment-only and non-HTTP references are left out. */
|
|
13
15
|
export declare function collectRefs(tags: readonly Tag[], pageURL: string): Ref[];
|
package/dist/verify/html/refs.js
CHANGED
|
@@ -4,7 +4,13 @@
|
|
|
4
4
|
// rendered HTML, not content fields, so links components generate count too.
|
|
5
5
|
// An inline `style` attribute's `url()` images are resources; a fetched
|
|
6
6
|
// stylesheet's `url()`s are not read (the suite fetches status only).
|
|
7
|
+
// A Next.js image optimizer URL (`/_next/image?url=…`) is the host's runtime
|
|
8
|
+
// endpoint, not a file in the release, so it stands for its wrapped source:
|
|
9
|
+
// the source is the reference, collected once per page however many widths
|
|
10
|
+
// and attributes name it.
|
|
7
11
|
import { srcsetURLs } from './srcset.js';
|
|
12
|
+
/** The Next.js image optimizer's path; its `url` query parameter is the image it serves. */
|
|
13
|
+
const NEXT_IMAGE_PATH = '/_next/image';
|
|
8
14
|
/** link rel values whose href the browser loads for the page itself. Other rels (canonical, alternate, preconnect) are not fetched. */
|
|
9
15
|
const RESOURCE_RELS = new Set(['stylesheet', 'icon', 'apple-touch-icon', 'mask-icon', 'preload', 'modulepreload', 'manifest']);
|
|
10
16
|
/** Resource attributes by tag. */
|
|
@@ -23,14 +29,23 @@ const SKIPPED = /^(?:#|mailto:|tel:|sms:|javascript:|data:|blob:|about:)/i;
|
|
|
23
29
|
export function collectRefs(tags, pageURL) {
|
|
24
30
|
const base = baseURL(tags, pageURL);
|
|
25
31
|
const refs = [];
|
|
32
|
+
const nextImageSources = new Set();
|
|
26
33
|
const add = (kind, source, raw) => {
|
|
27
34
|
const value = raw?.trim();
|
|
28
35
|
if (!value || SKIPPED.test(value))
|
|
29
36
|
return;
|
|
30
37
|
const url = parseURL(value, base);
|
|
31
|
-
if (url && url
|
|
38
|
+
if (url && !isHTTP(url))
|
|
32
39
|
return;
|
|
33
|
-
|
|
40
|
+
const wrapped = url && nextImageSource(url);
|
|
41
|
+
if (!wrapped) {
|
|
42
|
+
refs.push({ kind, source, raw: value, url });
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (nextImageSources.has(wrapped.href))
|
|
46
|
+
return;
|
|
47
|
+
nextImageSources.add(wrapped.href);
|
|
48
|
+
refs.push({ kind, source, raw: value, url: wrapped, via: 'next/image' });
|
|
34
49
|
};
|
|
35
50
|
for (const tag of tags) {
|
|
36
51
|
if (NAVIGATION_TAGS.has(tag.name))
|
|
@@ -62,6 +77,15 @@ function cssURLs(css) {
|
|
|
62
77
|
}
|
|
63
78
|
return urls;
|
|
64
79
|
}
|
|
80
|
+
/** The image a next/image optimizer URL serves, resolved against it; null for any other URL, or a source that is not HTTP. */
|
|
81
|
+
function nextImageSource(url) {
|
|
82
|
+
const param = url.pathname === NEXT_IMAGE_PATH ? url.searchParams.get('url') : null;
|
|
83
|
+
const wrapped = param ? parseURL(param, url.href) : null;
|
|
84
|
+
return wrapped && isHTTP(wrapped) ? wrapped : null;
|
|
85
|
+
}
|
|
86
|
+
function isHTTP(url) {
|
|
87
|
+
return url.protocol === 'http:' || url.protocol === 'https:';
|
|
88
|
+
}
|
|
65
89
|
function isResourceLink(tag) {
|
|
66
90
|
const rels = (tag.attrs.get('rel') ?? '').toLowerCase().split(/\s+/);
|
|
67
91
|
return rels.some((rel) => RESOURCE_RELS.has(rel));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gradial/aci",
|
|
3
|
-
"version": "0.2.0-canary.
|
|
3
|
+
"version": "0.2.0-canary.726",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/gradial/bare-metal-go.git",
|
|
@@ -179,11 +179,11 @@
|
|
|
179
179
|
"astro": "^6.4.8"
|
|
180
180
|
},
|
|
181
181
|
"optionalDependencies": {
|
|
182
|
-
"@gradial/aci-cli-darwin-arm64": "0.2.0-canary.
|
|
183
|
-
"@gradial/aci-cli-darwin-x64": "0.2.0-canary.
|
|
184
|
-
"@gradial/aci-cli-linux-arm64": "0.2.0-canary.
|
|
185
|
-
"@gradial/aci-cli-linux-x64": "0.2.0-canary.
|
|
186
|
-
"@gradial/aci-cli-win32-arm64": "0.2.0-canary.
|
|
187
|
-
"@gradial/aci-cli-win32-x64": "0.2.0-canary.
|
|
182
|
+
"@gradial/aci-cli-darwin-arm64": "0.2.0-canary.726",
|
|
183
|
+
"@gradial/aci-cli-darwin-x64": "0.2.0-canary.726",
|
|
184
|
+
"@gradial/aci-cli-linux-arm64": "0.2.0-canary.726",
|
|
185
|
+
"@gradial/aci-cli-linux-x64": "0.2.0-canary.726",
|
|
186
|
+
"@gradial/aci-cli-win32-arm64": "0.2.0-canary.726",
|
|
187
|
+
"@gradial/aci-cli-win32-x64": "0.2.0-canary.726"
|
|
188
188
|
}
|
|
189
189
|
}
|