@116zoo/plugin-rgaa 0.0.0-stage → 0.1.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 +63 -2
- package/dist/catalog.d.ts +21 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/catalog.js +101 -0
- package/dist/catalog.js.map +1 -0
- package/dist/components/AccessibilityReview/index.d.ts +3 -0
- package/dist/components/AccessibilityReview/index.d.ts.map +1 -0
- package/dist/components/AccessibilityReview/index.js +8 -0
- package/dist/components/AccessibilityReview/index.js.map +1 -0
- package/dist/content.d.ts +42 -0
- package/dist/content.d.ts.map +1 -0
- package/dist/content.js +71 -0
- package/dist/content.js.map +1 -0
- package/dist/exports/client.d.ts +2 -0
- package/dist/exports/client.d.ts.map +1 -0
- package/dist/exports/client.js +3 -0
- package/dist/exports/client.js.map +1 -0
- package/dist/exports/types.d.ts +2 -0
- package/dist/exports/types.d.ts.map +1 -0
- package/dist/exports/types.js +3 -0
- package/dist/exports/types.js.map +1 -0
- package/dist/fields.d.ts +3 -0
- package/dist/fields.d.ts.map +1 -0
- package/dist/fields.js +45 -0
- package/dist/fields.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +186 -0
- package/dist/index.js.map +1 -0
- package/dist/nim.d.ts +14 -0
- package/dist/nim.d.ts.map +1 -0
- package/dist/nim.js +62 -0
- package/dist/nim.js.map +1 -0
- package/dist/report.d.ts +33 -0
- package/dist/report.d.ts.map +1 -0
- package/dist/report.js +43 -0
- package/dist/report.js.map +1 -0
- package/dist/runtime.d.ts +19 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +28 -0
- package/dist/runtime.js.map +1 -0
- package/dist/types.d.ts +33 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +59 -4
package/README.md
CHANGED
|
@@ -1,3 +1,64 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Payload RGAA plugin
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`@116zoo/plugin-rgaa` prepares Payload editorial content for RGAA 4.1.2 review. It is an accessibility-audit aid, not a declaration of RGAA conformance.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { rgaaPlugin } from '@116zoo/plugin-rgaa'
|
|
9
|
+
|
|
10
|
+
export default buildConfig({
|
|
11
|
+
plugins: [
|
|
12
|
+
rgaaPlugin({
|
|
13
|
+
// Omit collections to target every non-auth collection.
|
|
14
|
+
excludeCollections: ['audit-logs'],
|
|
15
|
+
tabbedUI: true,
|
|
16
|
+
ai: {
|
|
17
|
+
apiKey: process.env.NIM_API_KEY,
|
|
18
|
+
baseURL: process.env.NIM_BASE_URL,
|
|
19
|
+
model: 'nvidia/nemotron-3.5-lightning-30b-a3b',
|
|
20
|
+
},
|
|
21
|
+
}),
|
|
22
|
+
],
|
|
23
|
+
})
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The NIM configuration is optional. Do not expose its key through `NEXT_PUBLIC_` variables.
|
|
27
|
+
|
|
28
|
+
## Payload 3.93 compatibility
|
|
29
|
+
|
|
30
|
+
The published package declares `payload` and `@payloadcms/ui` peers of `^3.93.0`. Its plugin entry point supports Payload 3.93's plugin-option shape as well as newer Payload releases. Before this release, the packed package was installed into a clean consumer using `payload@3.93.0`, `@payloadcms/ui@3.93.0` and `@payloadcms/db-sqlite@3.93.0`; its configuration check verified that the accessibility tab is added to a normal collection and omitted from an auth collection.
|
|
31
|
+
|
|
32
|
+
## What the plugin adds
|
|
33
|
+
|
|
34
|
+
Selected collections receive an `accessibility` group with a BCP 47 language tag, a review status and editorial notes. Authentication collections are excluded by default. Existing fields and tabs are preserved.
|
|
35
|
+
|
|
36
|
+
If `@payloadcms/plugin-seo` is present, the content audit can read `meta.title` as a title input. It does not alter SEO fields.
|
|
37
|
+
|
|
38
|
+
## Render semantic attributes
|
|
39
|
+
|
|
40
|
+
Payload cannot add correct HTML semantics to a frontend it does not render. Use the explicit helpers in the frontend:
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
import { getRGAAImageAttributes, getRGAALanguageAttributes } from '@116zoo/plugin-rgaa'
|
|
44
|
+
|
|
45
|
+
<html {...getRGAALanguageAttributes({ language: page.accessibility?.language })}>
|
|
46
|
+
<img {...getRGAAImageAttributes({ alt: media.alt, isDecorative: media.isDecorative })} />
|
|
47
|
+
</html>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The helpers only return safe attributes. They never generate an ARIA role, label or description from uncertain editorial context.
|
|
51
|
+
|
|
52
|
+
## Audit endpoints
|
|
53
|
+
|
|
54
|
+
All endpoints require Payload admin access:
|
|
55
|
+
|
|
56
|
+
- `POST /api/plugin-rgaa/audit-content` accepts either a normalised input or `{ document }` and returns the 106-criterion report.
|
|
57
|
+
- `POST /api/plugin-rgaa/audit-rendered-pages` accepts `{ baseURL, pages }` and uses Eqo to audit rendered URLs.
|
|
58
|
+
- `POST /api/plugin-rgaa/suggestions` accepts `{ context }` and returns validated NIM suggestions only when `ai` is configured.
|
|
59
|
+
|
|
60
|
+
Suggestions are never written automatically. An editor must review and explicitly save any change.
|
|
61
|
+
|
|
62
|
+
## Limits
|
|
63
|
+
|
|
64
|
+
The plugin identifies deterministic field/content failures and delegates rendered-page checks to Eqo. It cannot establish legal RGAA conformity: media quality, visual context, keyboard journeys, assistive-technology output and other human criteria still require a qualified audit.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type RGAAAutomationLevel = 'deterministic' | 'human-review' | 'rendered-page';
|
|
2
|
+
export type RGAACriterion = {
|
|
3
|
+
automationLevel: RGAAAutomationLevel;
|
|
4
|
+
id: string;
|
|
5
|
+
theme: number;
|
|
6
|
+
};
|
|
7
|
+
export type RGAAReferenceCriterion = {
|
|
8
|
+
automationLevel: 'full' | 'manual' | 'partial';
|
|
9
|
+
id: string;
|
|
10
|
+
tests: Array<{
|
|
11
|
+
automated: boolean;
|
|
12
|
+
id: string;
|
|
13
|
+
}>;
|
|
14
|
+
theme: number;
|
|
15
|
+
wcag: string[];
|
|
16
|
+
};
|
|
17
|
+
/** The RGAA 4.1.2 criterion identifiers. Their official test procedure remains the source of truth. */
|
|
18
|
+
export declare const rgaaCriteria: readonly RGAACriterion[];
|
|
19
|
+
/** Loads the complete RGAA 4.1.2 test metadata from the Eqo reference engine. */
|
|
20
|
+
export declare const loadRGAAReferenceCatalog: () => Promise<readonly RGAAReferenceCriterion[]>;
|
|
21
|
+
//# sourceMappingURL=catalog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,mBAAmB,GAAG,eAAe,GAAG,cAAc,GAAG,eAAe,CAAA;AAEpF,MAAM,MAAM,aAAa,GAAG;IAC1B,eAAe,EAAE,mBAAmB,CAAA;IACpC,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED,MAAM,MAAM,sBAAsB,GAAG;IACnC,eAAe,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAA;IAC9C,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,KAAK,CAAC;QAAE,SAAS,EAAE,OAAO,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAChD,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,EAAE,CAAA;CACf,CAAA;AA+FD,uGAAuG;AACvG,eAAO,MAAM,YAAY,EAAE,SAAS,aAAa,EAQ9C,CAAA;AAMH,iFAAiF;AACjF,eAAO,MAAM,wBAAwB,QAAa,OAAO,CAAC,SAAS,sBAAsB,EAAE,CAQ1F,CAAA"}
|
package/dist/catalog.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
const criterionIDs = '1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8,1.9,2.1,2.2,3.1,3.2,3.3,4.1,4.2,4.3,4.4,4.5,4.6,4.7,4.8,4.9,4.10,4.11,4.12,4.13,5.1,5.2,5.3,5.4,5.5,5.6,5.7,5.8,6.1,6.2,7.1,7.2,7.3,7.4,7.5,8.1,8.2,8.3,8.4,8.5,8.6,8.7,8.8,8.9,8.10,9.1,9.2,9.3,9.4,10.1,10.2,10.3,10.4,10.5,10.6,10.7,10.8,10.9,10.10,10.11,10.12,10.13,10.14,11.1,11.2,11.3,11.4,11.5,11.6,11.7,11.8,11.9,11.10,11.11,11.12,11.13,12.1,12.2,12.3,12.4,12.5,12.6,12.7,12.8,12.9,12.10,12.11,13.1,13.2,13.3,13.4,13.5,13.6,13.7,13.8,13.9,13.10,13.11,13.12';
|
|
2
|
+
const deterministicCriterionIDs = new Set([
|
|
3
|
+
'1.1',
|
|
4
|
+
'1.2',
|
|
5
|
+
'2.1',
|
|
6
|
+
'3.2',
|
|
7
|
+
'3.3',
|
|
8
|
+
'5.1',
|
|
9
|
+
'5.2',
|
|
10
|
+
'6.1',
|
|
11
|
+
'8.1',
|
|
12
|
+
'8.2',
|
|
13
|
+
'8.4',
|
|
14
|
+
'8.5',
|
|
15
|
+
'8.7',
|
|
16
|
+
'9.1',
|
|
17
|
+
'9.2',
|
|
18
|
+
'9.3',
|
|
19
|
+
'10.1',
|
|
20
|
+
'10.2',
|
|
21
|
+
'10.3',
|
|
22
|
+
'10.5',
|
|
23
|
+
'10.6',
|
|
24
|
+
'10.7',
|
|
25
|
+
'10.8',
|
|
26
|
+
'10.9',
|
|
27
|
+
'10.10',
|
|
28
|
+
'10.11',
|
|
29
|
+
'10.12',
|
|
30
|
+
'11.1',
|
|
31
|
+
'11.2',
|
|
32
|
+
'11.3',
|
|
33
|
+
'11.4',
|
|
34
|
+
'11.5',
|
|
35
|
+
'11.9'
|
|
36
|
+
]);
|
|
37
|
+
const renderedPageCriterionIDs = new Set([
|
|
38
|
+
'2.2',
|
|
39
|
+
'3.2',
|
|
40
|
+
'3.3',
|
|
41
|
+
'4.3',
|
|
42
|
+
'4.7',
|
|
43
|
+
'5.4',
|
|
44
|
+
'5.6',
|
|
45
|
+
'6.2',
|
|
46
|
+
'7.1',
|
|
47
|
+
'7.3',
|
|
48
|
+
'7.4',
|
|
49
|
+
'8.9',
|
|
50
|
+
'8.10',
|
|
51
|
+
'10.4',
|
|
52
|
+
'10.13',
|
|
53
|
+
'10.14',
|
|
54
|
+
'11.6',
|
|
55
|
+
'11.7',
|
|
56
|
+
'11.8',
|
|
57
|
+
'11.10',
|
|
58
|
+
'11.11',
|
|
59
|
+
'11.12',
|
|
60
|
+
'11.13',
|
|
61
|
+
'12.1',
|
|
62
|
+
'12.2',
|
|
63
|
+
'12.3',
|
|
64
|
+
'12.4',
|
|
65
|
+
'12.5',
|
|
66
|
+
'12.6',
|
|
67
|
+
'12.7',
|
|
68
|
+
'12.8',
|
|
69
|
+
'12.9',
|
|
70
|
+
'12.10',
|
|
71
|
+
'12.11',
|
|
72
|
+
'13.1',
|
|
73
|
+
'13.2',
|
|
74
|
+
'13.3',
|
|
75
|
+
'13.4',
|
|
76
|
+
'13.5',
|
|
77
|
+
'13.6',
|
|
78
|
+
'13.7',
|
|
79
|
+
'13.8',
|
|
80
|
+
'13.9',
|
|
81
|
+
'13.10',
|
|
82
|
+
'13.11',
|
|
83
|
+
'13.12'
|
|
84
|
+
]);
|
|
85
|
+
/** The RGAA 4.1.2 criterion identifiers. Their official test procedure remains the source of truth. */ export const rgaaCriteria = criterionIDs.split(',').map((id)=>({
|
|
86
|
+
automationLevel: deterministicCriterionIDs.has(id) ? 'deterministic' : renderedPageCriterionIDs.has(id) ? 'rendered-page' : 'human-review',
|
|
87
|
+
id,
|
|
88
|
+
theme: Number(id.split('.')[0])
|
|
89
|
+
}));
|
|
90
|
+
if (rgaaCriteria.length !== 106 || new Set(rgaaCriteria.map(({ id })=>id)).size !== 106) {
|
|
91
|
+
throw new Error('The RGAA 4.1.2 catalogue must contain 106 unique criteria.');
|
|
92
|
+
}
|
|
93
|
+
/** Loads the complete RGAA 4.1.2 test metadata from the Eqo reference engine. */ export const loadRGAAReferenceCatalog = async ()=>{
|
|
94
|
+
const eqo = await import('@kodalabs-io/eqo');
|
|
95
|
+
if (eqo.TOTAL_CRITERIA !== 106 || eqo.ALL_CRITERIA.length !== 106) {
|
|
96
|
+
throw new Error('The Eqo reference catalogue does not contain 106 RGAA 4.1.2 criteria.');
|
|
97
|
+
}
|
|
98
|
+
return eqo.ALL_CRITERIA;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
//# sourceMappingURL=catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/catalog.ts"],"sourcesContent":["export type RGAAAutomationLevel = 'deterministic' | 'human-review' | 'rendered-page'\n\nexport type RGAACriterion = {\n automationLevel: RGAAAutomationLevel\n id: string\n theme: number\n}\n\nexport type RGAAReferenceCriterion = {\n automationLevel: 'full' | 'manual' | 'partial'\n id: string\n tests: Array<{ automated: boolean; id: string }>\n theme: number\n wcag: string[]\n}\n\ntype EqoCatalogModule = {\n ALL_CRITERIA: RGAAReferenceCriterion[]\n TOTAL_CRITERIA: number\n}\n\nconst criterionIDs =\n '1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8,1.9,2.1,2.2,3.1,3.2,3.3,4.1,4.2,4.3,4.4,4.5,4.6,4.7,4.8,4.9,4.10,4.11,4.12,4.13,5.1,5.2,5.3,5.4,5.5,5.6,5.7,5.8,6.1,6.2,7.1,7.2,7.3,7.4,7.5,8.1,8.2,8.3,8.4,8.5,8.6,8.7,8.8,8.9,8.10,9.1,9.2,9.3,9.4,10.1,10.2,10.3,10.4,10.5,10.6,10.7,10.8,10.9,10.10,10.11,10.12,10.13,10.14,11.1,11.2,11.3,11.4,11.5,11.6,11.7,11.8,11.9,11.10,11.11,11.12,11.13,12.1,12.2,12.3,12.4,12.5,12.6,12.7,12.8,12.9,12.10,12.11,13.1,13.2,13.3,13.4,13.5,13.6,13.7,13.8,13.9,13.10,13.11,13.12'\n\nconst deterministicCriterionIDs = new Set([\n '1.1',\n '1.2',\n '2.1',\n '3.2',\n '3.3',\n '5.1',\n '5.2',\n '6.1',\n '8.1',\n '8.2',\n '8.4',\n '8.5',\n '8.7',\n '9.1',\n '9.2',\n '9.3',\n '10.1',\n '10.2',\n '10.3',\n '10.5',\n '10.6',\n '10.7',\n '10.8',\n '10.9',\n '10.10',\n '10.11',\n '10.12',\n '11.1',\n '11.2',\n '11.3',\n '11.4',\n '11.5',\n '11.9',\n])\n\nconst renderedPageCriterionIDs = new Set([\n '2.2',\n '3.2',\n '3.3',\n '4.3',\n '4.7',\n '5.4',\n '5.6',\n '6.2',\n '7.1',\n '7.3',\n '7.4',\n '8.9',\n '8.10',\n '10.4',\n '10.13',\n '10.14',\n '11.6',\n '11.7',\n '11.8',\n '11.10',\n '11.11',\n '11.12',\n '11.13',\n '12.1',\n '12.2',\n '12.3',\n '12.4',\n '12.5',\n '12.6',\n '12.7',\n '12.8',\n '12.9',\n '12.10',\n '12.11',\n '13.1',\n '13.2',\n '13.3',\n '13.4',\n '13.5',\n '13.6',\n '13.7',\n '13.8',\n '13.9',\n '13.10',\n '13.11',\n '13.12',\n])\n\n/** The RGAA 4.1.2 criterion identifiers. Their official test procedure remains the source of truth. */\nexport const rgaaCriteria: readonly RGAACriterion[] = criterionIDs.split(',').map((id) => ({\n automationLevel: deterministicCriterionIDs.has(id)\n ? 'deterministic'\n : renderedPageCriterionIDs.has(id)\n ? 'rendered-page'\n : 'human-review',\n id,\n theme: Number(id.split('.')[0]),\n}))\n\nif (rgaaCriteria.length !== 106 || new Set(rgaaCriteria.map(({ id }) => id)).size !== 106) {\n throw new Error('The RGAA 4.1.2 catalogue must contain 106 unique criteria.')\n}\n\n/** Loads the complete RGAA 4.1.2 test metadata from the Eqo reference engine. */\nexport const loadRGAAReferenceCatalog = async (): Promise<readonly RGAAReferenceCriterion[]> => {\n const eqo = (await import('@kodalabs-io/eqo')) as EqoCatalogModule\n\n if (eqo.TOTAL_CRITERIA !== 106 || eqo.ALL_CRITERIA.length !== 106) {\n throw new Error('The Eqo reference catalogue does not contain 106 RGAA 4.1.2 criteria.')\n }\n\n return eqo.ALL_CRITERIA\n}\n"],"names":["criterionIDs","deterministicCriterionIDs","Set","renderedPageCriterionIDs","rgaaCriteria","split","map","id","automationLevel","has","theme","Number","length","size","Error","loadRGAAReferenceCatalog","eqo","TOTAL_CRITERIA","ALL_CRITERIA"],"mappings":"AAqBA,MAAMA,eACJ;AAEF,MAAMC,4BAA4B,IAAIC,IAAI;IACxC;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;CACD;AAED,MAAMC,2BAA2B,IAAID,IAAI;IACvC;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;CACD;AAED,qGAAqG,GACrG,OAAO,MAAME,eAAyCJ,aAAaK,KAAK,CAAC,KAAKC,GAAG,CAAC,CAACC,KAAQ,CAAA;QACzFC,iBAAiBP,0BAA0BQ,GAAG,CAACF,MAC3C,kBACAJ,yBAAyBM,GAAG,CAACF,MAC3B,kBACA;QACNA;QACAG,OAAOC,OAAOJ,GAAGF,KAAK,CAAC,IAAI,CAAC,EAAE;IAChC,CAAA,GAAG;AAEH,IAAID,aAAaQ,MAAM,KAAK,OAAO,IAAIV,IAAIE,aAAaE,GAAG,CAAC,CAAC,EAAEC,EAAE,EAAE,GAAKA,KAAKM,IAAI,KAAK,KAAK;IACzF,MAAM,IAAIC,MAAM;AAClB;AAEA,+EAA+E,GAC/E,OAAO,MAAMC,2BAA2B;IACtC,MAAMC,MAAO,MAAM,MAAM,CAAC;IAE1B,IAAIA,IAAIC,cAAc,KAAK,OAAOD,IAAIE,YAAY,CAACN,MAAM,KAAK,KAAK;QACjE,MAAM,IAAIE,MAAM;IAClB;IAEA,OAAOE,IAAIE,YAAY;AACzB,EAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/AccessibilityReview/index.tsx"],"names":[],"mappings":"AAEA,kGAAkG;AAClG,eAAO,MAAM,mBAAmB,mCAa/B,CAAA"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
/** Editorial guidance uses native HTML; saving a suggestion always remains an explicit action. */ export const AccessibilityReview = ()=>/*#__PURE__*/ React.createElement("section", {
|
|
3
|
+
"aria-labelledby": "rgaa-review-heading"
|
|
4
|
+
}, /*#__PURE__*/ React.createElement("h2", {
|
|
5
|
+
id: "rgaa-review-heading"
|
|
6
|
+
}, "Revue humaine RGAA"), /*#__PURE__*/ React.createElement("p", null, "Les contrôles automatisés ne suffisent pas à déclarer une page conforme. Vérifiez les alternatives, les médias, le parcours clavier, les contrastes et la restitution avec les technologies d’assistance avant de choisir « Revue humaine terminée »."), /*#__PURE__*/ React.createElement("p", null, "Les suggestions IA ne sont jamais enregistrées automatiquement : examinez-les, modifiez-les si nécessaire, puis enregistrez explicitement le document."));
|
|
7
|
+
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/AccessibilityReview/index.tsx"],"sourcesContent":["'use client'\n\n/** Editorial guidance uses native HTML; saving a suggestion always remains an explicit action. */\nexport const AccessibilityReview = () => (\n <section aria-labelledby=\"rgaa-review-heading\">\n <h2 id=\"rgaa-review-heading\">Revue humaine RGAA</h2>\n <p>\n Les contrôles automatisés ne suffisent pas à déclarer une page conforme. Vérifiez les\n alternatives, les médias, le parcours clavier, les contrastes et la restitution avec les\n technologies d’assistance avant de choisir « Revue humaine terminée ».\n </p>\n <p>\n Les suggestions IA ne sont jamais enregistrées automatiquement : examinez-les, modifiez-les si\n nécessaire, puis enregistrez explicitement le document.\n </p>\n </section>\n)\n"],"names":["AccessibilityReview","section","aria-labelledby","h2","id","p"],"mappings":"AAAA;AAEA,gGAAgG,GAChG,OAAO,MAAMA,sBAAsB,kBACjC,oBAACC;QAAQC,mBAAgB;qBACvB,oBAACC;QAAGC,IAAG;OAAsB,qCAC7B,oBAACC,WAAE,wQAKH,oBAACA,WAAE,2JAKN"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { RGAAFinding } from './report.js';
|
|
2
|
+
export type AccessibleImage = {
|
|
3
|
+
alt?: string | null;
|
|
4
|
+
isDecorative?: boolean;
|
|
5
|
+
};
|
|
6
|
+
export type AccessibleLink = {
|
|
7
|
+
text?: string | null;
|
|
8
|
+
};
|
|
9
|
+
export type RGAADocumentInput = {
|
|
10
|
+
images?: AccessibleImage[];
|
|
11
|
+
language?: string | null;
|
|
12
|
+
links?: AccessibleLink[];
|
|
13
|
+
title?: string | null;
|
|
14
|
+
};
|
|
15
|
+
type DocumentRecord = Record<string, unknown>;
|
|
16
|
+
/**
|
|
17
|
+
* Performs only checks that can be established from supplied editorial data.
|
|
18
|
+
* Contextual quality stays a human review rather than a generated pass.
|
|
19
|
+
*/
|
|
20
|
+
export declare const auditRGAAContent: ({ input }: {
|
|
21
|
+
input: RGAADocumentInput;
|
|
22
|
+
}) => RGAAFinding[];
|
|
23
|
+
/**
|
|
24
|
+
* Reads conventional Payload and plugin-seo fields as audit input without
|
|
25
|
+
* mutating either schema. Projects with custom field names can call
|
|
26
|
+
* `auditRGAAContent` directly instead.
|
|
27
|
+
*/
|
|
28
|
+
export declare const getRGAADocumentInput: ({ document, }: {
|
|
29
|
+
document: DocumentRecord;
|
|
30
|
+
}) => RGAADocumentInput;
|
|
31
|
+
/** Safe rendering attributes. Callers retain control of the element and never receive speculative ARIA. */
|
|
32
|
+
export declare const getRGAALanguageAttributes: ({ language, }: {
|
|
33
|
+
language?: string | null;
|
|
34
|
+
}) => {
|
|
35
|
+
lang: string;
|
|
36
|
+
} | undefined;
|
|
37
|
+
/** A decorative image only receives the standard empty alternative; no ARIA is added. */
|
|
38
|
+
export declare const getRGAAImageAttributes: ({ alt, isDecorative, }: AccessibleImage) => {
|
|
39
|
+
alt: string;
|
|
40
|
+
} | undefined;
|
|
41
|
+
export {};
|
|
42
|
+
//# sourceMappingURL=content.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../src/content.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAE9C,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACnB,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACrB,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,CAAC,EAAE,eAAe,EAAE,CAAA;IAC1B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,KAAK,CAAC,EAAE,cAAc,EAAE,CAAA;IACxB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACtB,CAAA;AAED,KAAK,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAI7C;;;GAGG;AACH,eAAO,MAAM,gBAAgB,cAAe;IAAE,KAAK,EAAE,iBAAiB,CAAA;CAAE,KAAG,WAAW,EA2CrF,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,kBAE9B;IACD,QAAQ,EAAE,cAAc,CAAA;CACzB,KAAG,iBAQH,CAAA;AAED,2GAA2G;AAC3G,eAAO,MAAM,yBAAyB,kBAEnC;IACD,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACzB,KAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,SAMtB,CAAA;AAED,yFAAyF;AACzF,eAAO,MAAM,sBAAsB,2BAGhC,eAAe,KAAG;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,SAMtC,CAAA"}
|
package/dist/content.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
const languageTagPattern = /^[a-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$/;
|
|
2
|
+
/**
|
|
3
|
+
* Performs only checks that can be established from supplied editorial data.
|
|
4
|
+
* Contextual quality stays a human review rather than a generated pass.
|
|
5
|
+
*/ export const auditRGAAContent = ({ input })=>{
|
|
6
|
+
const findings = [];
|
|
7
|
+
const language = input.language?.trim();
|
|
8
|
+
findings.push({
|
|
9
|
+
criterionID: '8.3',
|
|
10
|
+
evidence: languageTagPattern.test(language ?? '') ? `The configured language tag ${language} has a valid BCP 47 shape.` : 'A valid document language tag is missing.',
|
|
11
|
+
status: languageTagPattern.test(language ?? '') ? 'passed' : 'failed'
|
|
12
|
+
});
|
|
13
|
+
const title = input.title?.trim();
|
|
14
|
+
findings.push({
|
|
15
|
+
criterionID: '8.6',
|
|
16
|
+
evidence: title ? 'The document has a non-empty title.' : 'A non-empty document title is required.',
|
|
17
|
+
status: title ? 'passed' : 'failed'
|
|
18
|
+
});
|
|
19
|
+
for (const image of input.images ?? []){
|
|
20
|
+
const hasAlternative = Boolean(image.isDecorative || image.alt?.trim());
|
|
21
|
+
if (!hasAlternative) {
|
|
22
|
+
findings.push({
|
|
23
|
+
criterionID: '1.1',
|
|
24
|
+
evidence: 'An informative image has no text alternative.',
|
|
25
|
+
status: 'failed'
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
for (const link of input.links ?? []){
|
|
30
|
+
if (!link.text?.trim()) {
|
|
31
|
+
findings.push({
|
|
32
|
+
criterionID: '6.1',
|
|
33
|
+
evidence: 'A link has no accessible text in its editorial data.',
|
|
34
|
+
status: 'failed'
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return findings;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Reads conventional Payload and plugin-seo fields as audit input without
|
|
42
|
+
* mutating either schema. Projects with custom field names can call
|
|
43
|
+
* `auditRGAAContent` directly instead.
|
|
44
|
+
*/ export const getRGAADocumentInput = ({ document })=>{
|
|
45
|
+
const accessibility = isRecord(document.accessibility) ? document.accessibility : {};
|
|
46
|
+
const meta = isRecord(document.meta) ? document.meta : {};
|
|
47
|
+
return {
|
|
48
|
+
language: getString(accessibility.language),
|
|
49
|
+
title: getString(meta.title) ?? getString(document.title)
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
/** Safe rendering attributes. Callers retain control of the element and never receive speculative ARIA. */ export const getRGAALanguageAttributes = ({ language })=>{
|
|
53
|
+
const trimmedLanguage = language?.trim();
|
|
54
|
+
return trimmedLanguage && languageTagPattern.test(trimmedLanguage) ? {
|
|
55
|
+
lang: trimmedLanguage
|
|
56
|
+
} : undefined;
|
|
57
|
+
};
|
|
58
|
+
/** A decorative image only receives the standard empty alternative; no ARIA is added. */ export const getRGAAImageAttributes = ({ alt, isDecorative })=>{
|
|
59
|
+
if (isDecorative) {
|
|
60
|
+
return {
|
|
61
|
+
alt: ''
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
return alt?.trim() ? {
|
|
65
|
+
alt: alt.trim()
|
|
66
|
+
} : undefined;
|
|
67
|
+
};
|
|
68
|
+
const getString = (value)=>typeof value === 'string' ? value : undefined;
|
|
69
|
+
const isRecord = (value)=>Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
70
|
+
|
|
71
|
+
//# sourceMappingURL=content.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/content.ts"],"sourcesContent":["import type { RGAAFinding } from './report.js'\n\nexport type AccessibleImage = {\n alt?: string | null\n isDecorative?: boolean\n}\n\nexport type AccessibleLink = {\n text?: string | null\n}\n\nexport type RGAADocumentInput = {\n images?: AccessibleImage[]\n language?: string | null\n links?: AccessibleLink[]\n title?: string | null\n}\n\ntype DocumentRecord = Record<string, unknown>\n\nconst languageTagPattern = /^[a-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$/\n\n/**\n * Performs only checks that can be established from supplied editorial data.\n * Contextual quality stays a human review rather than a generated pass.\n */\nexport const auditRGAAContent = ({ input }: { input: RGAADocumentInput }): RGAAFinding[] => {\n const findings: RGAAFinding[] = []\n const language = input.language?.trim()\n\n findings.push({\n criterionID: '8.3',\n evidence: languageTagPattern.test(language ?? '')\n ? `The configured language tag ${language} has a valid BCP 47 shape.`\n : 'A valid document language tag is missing.',\n status: languageTagPattern.test(language ?? '') ? 'passed' : 'failed',\n })\n\n const title = input.title?.trim()\n findings.push({\n criterionID: '8.6',\n evidence: title\n ? 'The document has a non-empty title.'\n : 'A non-empty document title is required.',\n status: title ? 'passed' : 'failed',\n })\n\n for (const image of input.images ?? []) {\n const hasAlternative = Boolean(image.isDecorative || image.alt?.trim())\n if (!hasAlternative) {\n findings.push({\n criterionID: '1.1',\n evidence: 'An informative image has no text alternative.',\n status: 'failed',\n })\n }\n }\n\n for (const link of input.links ?? []) {\n if (!link.text?.trim()) {\n findings.push({\n criterionID: '6.1',\n evidence: 'A link has no accessible text in its editorial data.',\n status: 'failed',\n })\n }\n }\n\n return findings\n}\n\n/**\n * Reads conventional Payload and plugin-seo fields as audit input without\n * mutating either schema. Projects with custom field names can call\n * `auditRGAAContent` directly instead.\n */\nexport const getRGAADocumentInput = ({\n document,\n}: {\n document: DocumentRecord\n}): RGAADocumentInput => {\n const accessibility = isRecord(document.accessibility) ? document.accessibility : {}\n const meta = isRecord(document.meta) ? document.meta : {}\n\n return {\n language: getString(accessibility.language),\n title: getString(meta.title) ?? getString(document.title),\n }\n}\n\n/** Safe rendering attributes. Callers retain control of the element and never receive speculative ARIA. */\nexport const getRGAALanguageAttributes = ({\n language,\n}: {\n language?: string | null\n}): { lang: string } | undefined => {\n const trimmedLanguage = language?.trim()\n\n return trimmedLanguage && languageTagPattern.test(trimmedLanguage)\n ? { lang: trimmedLanguage }\n : undefined\n}\n\n/** A decorative image only receives the standard empty alternative; no ARIA is added. */\nexport const getRGAAImageAttributes = ({\n alt,\n isDecorative,\n}: AccessibleImage): { alt: string } | undefined => {\n if (isDecorative) {\n return { alt: '' }\n }\n\n return alt?.trim() ? { alt: alt.trim() } : undefined\n}\n\nconst getString = (value: unknown): string | undefined =>\n typeof value === 'string' ? value : undefined\n\nconst isRecord = (value: unknown): value is DocumentRecord =>\n Boolean(value) && typeof value === 'object' && !Array.isArray(value)\n"],"names":["languageTagPattern","auditRGAAContent","input","findings","language","trim","push","criterionID","evidence","test","status","title","image","images","hasAlternative","Boolean","isDecorative","alt","link","links","text","getRGAADocumentInput","document","accessibility","isRecord","meta","getString","getRGAALanguageAttributes","trimmedLanguage","lang","undefined","getRGAAImageAttributes","value","Array","isArray"],"mappings":"AAoBA,MAAMA,qBAAqB;AAE3B;;;CAGC,GACD,OAAO,MAAMC,mBAAmB,CAAC,EAAEC,KAAK,EAAgC;IACtE,MAAMC,WAA0B,EAAE;IAClC,MAAMC,WAAWF,MAAME,QAAQ,EAAEC;IAEjCF,SAASG,IAAI,CAAC;QACZC,aAAa;QACbC,UAAUR,mBAAmBS,IAAI,CAACL,YAAY,MAC1C,CAAC,4BAA4B,EAAEA,SAAS,0BAA0B,CAAC,GACnE;QACJM,QAAQV,mBAAmBS,IAAI,CAACL,YAAY,MAAM,WAAW;IAC/D;IAEA,MAAMO,QAAQT,MAAMS,KAAK,EAAEN;IAC3BF,SAASG,IAAI,CAAC;QACZC,aAAa;QACbC,UAAUG,QACN,wCACA;QACJD,QAAQC,QAAQ,WAAW;IAC7B;IAEA,KAAK,MAAMC,SAASV,MAAMW,MAAM,IAAI,EAAE,CAAE;QACtC,MAAMC,iBAAiBC,QAAQH,MAAMI,YAAY,IAAIJ,MAAMK,GAAG,EAAEZ;QAChE,IAAI,CAACS,gBAAgB;YACnBX,SAASG,IAAI,CAAC;gBACZC,aAAa;gBACbC,UAAU;gBACVE,QAAQ;YACV;QACF;IACF;IAEA,KAAK,MAAMQ,QAAQhB,MAAMiB,KAAK,IAAI,EAAE,CAAE;QACpC,IAAI,CAACD,KAAKE,IAAI,EAAEf,QAAQ;YACtBF,SAASG,IAAI,CAAC;gBACZC,aAAa;gBACbC,UAAU;gBACVE,QAAQ;YACV;QACF;IACF;IAEA,OAAOP;AACT,EAAC;AAED;;;;CAIC,GACD,OAAO,MAAMkB,uBAAuB,CAAC,EACnCC,QAAQ,EAGT;IACC,MAAMC,gBAAgBC,SAASF,SAASC,aAAa,IAAID,SAASC,aAAa,GAAG,CAAC;IACnF,MAAME,OAAOD,SAASF,SAASG,IAAI,IAAIH,SAASG,IAAI,GAAG,CAAC;IAExD,OAAO;QACLrB,UAAUsB,UAAUH,cAAcnB,QAAQ;QAC1CO,OAAOe,UAAUD,KAAKd,KAAK,KAAKe,UAAUJ,SAASX,KAAK;IAC1D;AACF,EAAC;AAED,yGAAyG,GACzG,OAAO,MAAMgB,4BAA4B,CAAC,EACxCvB,QAAQ,EAGT;IACC,MAAMwB,kBAAkBxB,UAAUC;IAElC,OAAOuB,mBAAmB5B,mBAAmBS,IAAI,CAACmB,mBAC9C;QAAEC,MAAMD;IAAgB,IACxBE;AACN,EAAC;AAED,uFAAuF,GACvF,OAAO,MAAMC,yBAAyB,CAAC,EACrCd,GAAG,EACHD,YAAY,EACI;IAChB,IAAIA,cAAc;QAChB,OAAO;YAAEC,KAAK;QAAG;IACnB;IAEA,OAAOA,KAAKZ,SAAS;QAAEY,KAAKA,IAAIZ,IAAI;IAAG,IAAIyB;AAC7C,EAAC;AAED,MAAMJ,YAAY,CAACM,QACjB,OAAOA,UAAU,WAAWA,QAAQF;AAEtC,MAAMN,WAAW,CAACQ,QAChBjB,QAAQiB,UAAU,OAAOA,UAAU,YAAY,CAACC,MAAMC,OAAO,CAACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/exports/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,4CAA4C,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/exports/client.ts"],"sourcesContent":["export { AccessibilityReview } from '../components/AccessibilityReview/index.js'\n"],"names":["AccessibilityReview"],"mappings":"AAAA,SAASA,mBAAmB,QAAQ,6CAA4C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/exports/types.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/exports/types.ts"],"sourcesContent":["export type { RGAAAIProvider, RGAAPluginConfig, RGAASuggestion } from '../types.js'\n"],"names":[],"mappings":"AAAA,WAAmF"}
|
package/dist/fields.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fields.d.ts","sourceRoot":"","sources":["../src/fields.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAEpC,eAAO,MAAM,mBAAmB,QAAO,KAAK,EAgC3C,CAAA"}
|
package/dist/fields.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export const accessibilityFields = ()=>[
|
|
2
|
+
{
|
|
3
|
+
name: 'language',
|
|
4
|
+
type: 'text',
|
|
5
|
+
admin: {
|
|
6
|
+
components: {
|
|
7
|
+
afterInput: [
|
|
8
|
+
'@116zoo/plugin-rgaa/client#AccessibilityReview'
|
|
9
|
+
]
|
|
10
|
+
},
|
|
11
|
+
description: 'BCP 47 language tag exposed on the rendered document, for example fr or fr-FR.'
|
|
12
|
+
},
|
|
13
|
+
label: 'Langue du contenu'
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
name: 'reviewStatus',
|
|
17
|
+
type: 'select',
|
|
18
|
+
defaultValue: 'not-reviewed',
|
|
19
|
+
label: 'Revue RGAA',
|
|
20
|
+
options: [
|
|
21
|
+
{
|
|
22
|
+
label: 'Non revue',
|
|
23
|
+
value: 'not-reviewed'
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
label: 'À revoir par un humain',
|
|
27
|
+
value: 'needs-human-review'
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
label: 'Revue humaine terminée',
|
|
31
|
+
value: 'human-reviewed'
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: 'reviewNotes',
|
|
37
|
+
type: 'textarea',
|
|
38
|
+
admin: {
|
|
39
|
+
description: 'Décisions éditoriales et vérifications non automatisables. Ce champ ne constitue pas une déclaration de conformité.'
|
|
40
|
+
},
|
|
41
|
+
label: 'Notes de revue RGAA'
|
|
42
|
+
}
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
//# sourceMappingURL=fields.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/fields.ts"],"sourcesContent":["import type { Field } from 'payload'\n\nexport const accessibilityFields = (): Field[] => [\n {\n name: 'language',\n type: 'text',\n admin: {\n components: {\n afterInput: ['@116zoo/plugin-rgaa/client#AccessibilityReview'],\n },\n description: 'BCP 47 language tag exposed on the rendered document, for example fr or fr-FR.',\n },\n label: 'Langue du contenu',\n },\n {\n name: 'reviewStatus',\n type: 'select',\n defaultValue: 'not-reviewed',\n label: 'Revue RGAA',\n options: [\n { label: 'Non revue', value: 'not-reviewed' },\n { label: 'À revoir par un humain', value: 'needs-human-review' },\n { label: 'Revue humaine terminée', value: 'human-reviewed' },\n ],\n },\n {\n name: 'reviewNotes',\n type: 'textarea',\n admin: {\n description:\n 'Décisions éditoriales et vérifications non automatisables. Ce champ ne constitue pas une déclaration de conformité.',\n },\n label: 'Notes de revue RGAA',\n },\n]\n"],"names":["accessibilityFields","name","type","admin","components","afterInput","description","label","defaultValue","options","value"],"mappings":"AAEA,OAAO,MAAMA,sBAAsB,IAAe;QAChD;YACEC,MAAM;YACNC,MAAM;YACNC,OAAO;gBACLC,YAAY;oBACVC,YAAY;wBAAC;qBAAiD;gBAChE;gBACAC,aAAa;YACf;YACAC,OAAO;QACT;QACA;YACEN,MAAM;YACNC,MAAM;YACNM,cAAc;YACdD,OAAO;YACPE,SAAS;gBACP;oBAAEF,OAAO;oBAAaG,OAAO;gBAAe;gBAC5C;oBAAEH,OAAO;oBAA0BG,OAAO;gBAAqB;gBAC/D;oBAAEH,OAAO;oBAA0BG,OAAO;gBAAiB;aAC5D;QACH;QACA;YACET,MAAM;YACNC,MAAM;YACNC,OAAO;gBACLG,aACE;YACJ;YACAC,OAAO;QACT;KACD,CAAA"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { RGAAPluginConfig } from './types.js';
|
|
2
|
+
export { loadRGAAReferenceCatalog, rgaaCriteria } from './catalog.js';
|
|
3
|
+
export type { RGAAReferenceCriterion } from './catalog.js';
|
|
4
|
+
export { auditRGAAContent, getRGAAImageAttributes, getRGAADocumentInput, getRGAALanguageAttributes, } from './content.js';
|
|
5
|
+
export type { AccessibleImage, AccessibleLink, RGAADocumentInput } from './content.js';
|
|
6
|
+
export { generateNIMSuggestions, parseRGAASuggestions } from './nim.js';
|
|
7
|
+
export { buildRGAAReport } from './report.js';
|
|
8
|
+
export { auditRenderedPages } from './runtime.js';
|
|
9
|
+
export type { RGAAAuditPage, RenderedPageAuditOptions, RenderedPageAuditResult } from './runtime.js';
|
|
10
|
+
export type { RGAAFinding, RGAAReport } from './report.js';
|
|
11
|
+
export type { RGAAAIProvider, RGAAPluginConfig, RGAASuggestion } from './types.js';
|
|
12
|
+
/**
|
|
13
|
+
* Adds auditable RGAA editorial metadata. It deliberately does not claim that
|
|
14
|
+
* a document or site is compliant: rendered UI and human-only criteria need a
|
|
15
|
+
* review outside the content schema.
|
|
16
|
+
*/
|
|
17
|
+
export declare const rgaaPlugin: (options: RGAAPluginConfig) => import("payload").Plugin;
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAElD,OAAO,EAAE,wBAAwB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AACrE,YAAY,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAA;AAC1D,OAAO,EACL,gBAAgB,EAChB,sBAAsB,EACtB,oBAAoB,EACpB,yBAAyB,GAC1B,MAAM,cAAc,CAAA;AACrB,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AACtF,OAAO,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAA;AACvE,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AACjD,YAAY,EAAE,aAAa,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAA;AACpG,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAC1D,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAElF;;;;GAIG;AACH,eAAO,MAAM,UAAU,yDA+IrB,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { canAccessAdmin, definePlugin } from 'payload';
|
|
2
|
+
import { accessibilityFields } from './fields.js';
|
|
3
|
+
import { auditRGAAContent, getRGAADocumentInput } from './content.js';
|
|
4
|
+
import { generateNIMSuggestions } from './nim.js';
|
|
5
|
+
import { buildRGAAReport } from './report.js';
|
|
6
|
+
import { auditRenderedPages } from './runtime.js';
|
|
7
|
+
export { loadRGAAReferenceCatalog, rgaaCriteria } from './catalog.js';
|
|
8
|
+
export { auditRGAAContent, getRGAAImageAttributes, getRGAADocumentInput, getRGAALanguageAttributes } from './content.js';
|
|
9
|
+
export { generateNIMSuggestions, parseRGAASuggestions } from './nim.js';
|
|
10
|
+
export { buildRGAAReport } from './report.js';
|
|
11
|
+
export { auditRenderedPages } from './runtime.js';
|
|
12
|
+
/**
|
|
13
|
+
* Adds auditable RGAA editorial metadata. It deliberately does not claim that
|
|
14
|
+
* a document or site is compliant: rendered UI and human-only criteria need a
|
|
15
|
+
* review outside the content schema.
|
|
16
|
+
*/ export const rgaaPlugin = definePlugin({
|
|
17
|
+
slug: '@116zoo/plugin-rgaa',
|
|
18
|
+
plugin: (pluginArgs)=>{
|
|
19
|
+
const { config } = pluginArgs;
|
|
20
|
+
// Payload 3.93 spreads plugin options alongside config/plugins, whereas
|
|
21
|
+
// later Payload versions expose them through `options`. Accept both
|
|
22
|
+
// shapes so the published package remains a real 3.93-compatible plugin.
|
|
23
|
+
const options = getRGAAPluginOptions({
|
|
24
|
+
pluginArgs
|
|
25
|
+
});
|
|
26
|
+
const selectedCollections = new Set(options?.collections ?? []);
|
|
27
|
+
const excludedCollections = new Set(options?.excludeCollections ?? []);
|
|
28
|
+
const isIncluded = ({ collection })=>{
|
|
29
|
+
if (collection.auth || excludedCollections.has(collection.slug)) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
return selectedCollections.size === 0 || selectedCollections.has(collection.slug);
|
|
33
|
+
};
|
|
34
|
+
const rgaaFields = [
|
|
35
|
+
{
|
|
36
|
+
name: 'accessibility',
|
|
37
|
+
type: 'group',
|
|
38
|
+
fields: typeof options?.fields === 'function' ? options.fields({
|
|
39
|
+
defaultFields: accessibilityFields()
|
|
40
|
+
}) : accessibilityFields(),
|
|
41
|
+
label: 'Accessibilité (RGAA)'
|
|
42
|
+
}
|
|
43
|
+
];
|
|
44
|
+
return {
|
|
45
|
+
...config,
|
|
46
|
+
collections: config.collections?.map((collection)=>{
|
|
47
|
+
const hasAccessibilityGroup = collection.fields.some((field)=>'name' in field && field.name === 'accessibility');
|
|
48
|
+
if (!isIncluded({
|
|
49
|
+
collection
|
|
50
|
+
}) || hasAccessibilityGroup) {
|
|
51
|
+
return collection;
|
|
52
|
+
}
|
|
53
|
+
if (options?.tabbedUI) {
|
|
54
|
+
const tabs = [
|
|
55
|
+
{
|
|
56
|
+
type: 'tabs',
|
|
57
|
+
tabs: [
|
|
58
|
+
...collection.fields[0]?.type === 'tabs' ? collection.fields[0].tabs : [
|
|
59
|
+
{
|
|
60
|
+
fields: collection.fields,
|
|
61
|
+
label: 'Contenu'
|
|
62
|
+
}
|
|
63
|
+
],
|
|
64
|
+
{
|
|
65
|
+
fields: rgaaFields,
|
|
66
|
+
label: 'Accessibilité'
|
|
67
|
+
}
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
];
|
|
71
|
+
return {
|
|
72
|
+
...collection,
|
|
73
|
+
fields: [
|
|
74
|
+
...tabs,
|
|
75
|
+
...collection.fields[0]?.type === 'tabs' ? collection.fields.slice(1) : []
|
|
76
|
+
]
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
...collection,
|
|
81
|
+
fields: [
|
|
82
|
+
...collection.fields,
|
|
83
|
+
...rgaaFields
|
|
84
|
+
]
|
|
85
|
+
};
|
|
86
|
+
}),
|
|
87
|
+
endpoints: [
|
|
88
|
+
...config.endpoints ?? [],
|
|
89
|
+
{
|
|
90
|
+
handler: async (req)=>{
|
|
91
|
+
await authorizeRGAA({
|
|
92
|
+
req
|
|
93
|
+
});
|
|
94
|
+
const body = await req.json?.();
|
|
95
|
+
const document = body && typeof body === 'object' && 'document' in body && body.document && typeof body.document === 'object' ? body.document : undefined;
|
|
96
|
+
const collectionSlug = body && typeof body === 'object' && 'collectionSlug' in body ? body.collectionSlug : undefined;
|
|
97
|
+
const adapter = typeof collectionSlug === 'string' ? options?.adapters?.[collectionSlug] : undefined;
|
|
98
|
+
const input = document ? adapter?.getAuditInput?.({
|
|
99
|
+
document
|
|
100
|
+
}) ?? getRGAADocumentInput({
|
|
101
|
+
document
|
|
102
|
+
}) : body ?? {};
|
|
103
|
+
const report = buildRGAAReport({
|
|
104
|
+
findings: auditRGAAContent({
|
|
105
|
+
input: input ?? {}
|
|
106
|
+
})
|
|
107
|
+
});
|
|
108
|
+
return Response.json(report);
|
|
109
|
+
},
|
|
110
|
+
method: 'post',
|
|
111
|
+
path: '/plugin-rgaa/audit-content'
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
handler: async (req)=>{
|
|
115
|
+
await authorizeRGAA({
|
|
116
|
+
req
|
|
117
|
+
});
|
|
118
|
+
if (!options?.ai) {
|
|
119
|
+
return Response.json({
|
|
120
|
+
error: 'NIM suggestions are not configured.'
|
|
121
|
+
}, {
|
|
122
|
+
status: 403
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
const body = await req.json?.();
|
|
126
|
+
const context = body && typeof body === 'object' && 'context' in body ? body.context : undefined;
|
|
127
|
+
if (typeof context !== 'string') {
|
|
128
|
+
return Response.json({
|
|
129
|
+
error: 'A textual context is required.'
|
|
130
|
+
}, {
|
|
131
|
+
status: 400
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
const suggestions = await generateNIMSuggestions({
|
|
135
|
+
context,
|
|
136
|
+
provider: options.ai
|
|
137
|
+
});
|
|
138
|
+
return Response.json({
|
|
139
|
+
suggestions
|
|
140
|
+
});
|
|
141
|
+
},
|
|
142
|
+
method: 'post',
|
|
143
|
+
path: '/plugin-rgaa/suggestions'
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
handler: async (req)=>{
|
|
147
|
+
await authorizeRGAA({
|
|
148
|
+
req
|
|
149
|
+
});
|
|
150
|
+
const body = await req.json?.();
|
|
151
|
+
const baseURL = body && typeof body === 'object' && 'baseURL' in body ? body.baseURL : undefined;
|
|
152
|
+
const pages = body && typeof body === 'object' && 'pages' in body ? body.pages : undefined;
|
|
153
|
+
if (typeof baseURL !== 'string' || !Array.isArray(pages)) {
|
|
154
|
+
return Response.json({
|
|
155
|
+
error: 'baseURL and pages are required.'
|
|
156
|
+
}, {
|
|
157
|
+
status: 400
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
const result = await auditRenderedPages({
|
|
161
|
+
baseURL,
|
|
162
|
+
pages
|
|
163
|
+
});
|
|
164
|
+
return Response.json(result);
|
|
165
|
+
},
|
|
166
|
+
method: 'post',
|
|
167
|
+
path: '/plugin-rgaa/audit-rendered-pages'
|
|
168
|
+
}
|
|
169
|
+
]
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
const getRGAAPluginOptions = ({ pluginArgs })=>{
|
|
174
|
+
if (pluginArgs.options) {
|
|
175
|
+
return pluginArgs.options;
|
|
176
|
+
}
|
|
177
|
+
const { config: _config, plugins: _plugins, options: _options, ...legacyOptions } = pluginArgs;
|
|
178
|
+
return legacyOptions;
|
|
179
|
+
};
|
|
180
|
+
const authorizeRGAA = async ({ req })=>{
|
|
181
|
+
await canAccessAdmin({
|
|
182
|
+
req
|
|
183
|
+
});
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { CollectionConfig, Field, PayloadRequest, TabsField } from 'payload'\n\nimport { canAccessAdmin, definePlugin } from 'payload'\n\nimport { accessibilityFields } from './fields.js'\nimport { auditRGAAContent, getRGAADocumentInput } from './content.js'\nimport { generateNIMSuggestions } from './nim.js'\nimport { buildRGAAReport } from './report.js'\nimport { auditRenderedPages } from './runtime.js'\nimport type { RGAAPluginConfig } from './types.js'\n\nexport { loadRGAAReferenceCatalog, rgaaCriteria } from './catalog.js'\nexport type { RGAAReferenceCriterion } from './catalog.js'\nexport {\n auditRGAAContent,\n getRGAAImageAttributes,\n getRGAADocumentInput,\n getRGAALanguageAttributes,\n} from './content.js'\nexport type { AccessibleImage, AccessibleLink, RGAADocumentInput } from './content.js'\nexport { generateNIMSuggestions, parseRGAASuggestions } from './nim.js'\nexport { buildRGAAReport } from './report.js'\nexport { auditRenderedPages } from './runtime.js'\nexport type { RGAAAuditPage, RenderedPageAuditOptions, RenderedPageAuditResult } from './runtime.js'\nexport type { RGAAFinding, RGAAReport } from './report.js'\nexport type { RGAAAIProvider, RGAAPluginConfig, RGAASuggestion } from './types.js'\n\n/**\n * Adds auditable RGAA editorial metadata. It deliberately does not claim that\n * a document or site is compliant: rendered UI and human-only criteria need a\n * review outside the content schema.\n */\nexport const rgaaPlugin = definePlugin<RGAAPluginConfig>({\n slug: '@116zoo/plugin-rgaa',\n plugin: (pluginArgs) => {\n const { config } = pluginArgs\n // Payload 3.93 spreads plugin options alongside config/plugins, whereas\n // later Payload versions expose them through `options`. Accept both\n // shapes so the published package remains a real 3.93-compatible plugin.\n const options = getRGAAPluginOptions({ pluginArgs })\n const selectedCollections = new Set(options?.collections ?? [])\n const excludedCollections = new Set(options?.excludeCollections ?? [])\n\n const isIncluded = ({ collection }: { collection: CollectionConfig }): boolean => {\n if (collection.auth || excludedCollections.has(collection.slug)) {\n return false\n }\n\n return selectedCollections.size === 0 || selectedCollections.has(collection.slug)\n }\n\n const rgaaFields: Field[] = [\n {\n name: 'accessibility',\n type: 'group',\n fields:\n typeof options?.fields === 'function'\n ? options.fields({ defaultFields: accessibilityFields() })\n : accessibilityFields(),\n label: 'Accessibilité (RGAA)',\n },\n ]\n\n return {\n ...config,\n collections: config.collections?.map((collection) => {\n const hasAccessibilityGroup = collection.fields.some(\n (field) => 'name' in field && field.name === 'accessibility',\n )\n\n if (!isIncluded({ collection }) || hasAccessibilityGroup) {\n return collection\n }\n\n if (options?.tabbedUI) {\n const tabs: TabsField[] = [\n {\n type: 'tabs',\n tabs: [\n ...(collection.fields[0]?.type === 'tabs'\n ? collection.fields[0].tabs\n : [{ fields: collection.fields, label: 'Contenu' }]),\n { fields: rgaaFields, label: 'Accessibilité' },\n ],\n },\n ]\n\n return {\n ...collection,\n fields: [\n ...tabs,\n ...(collection.fields[0]?.type === 'tabs' ? collection.fields.slice(1) : []),\n ],\n }\n }\n\n return { ...collection, fields: [...collection.fields, ...rgaaFields] }\n }),\n endpoints: [\n ...(config.endpoints ?? []),\n {\n handler: async (req) => {\n await authorizeRGAA({ req })\n const body = await req.json?.()\n const document =\n body &&\n typeof body === 'object' &&\n 'document' in body &&\n body.document &&\n typeof body.document === 'object'\n ? (body.document as Record<string, unknown>)\n : undefined\n const collectionSlug =\n body && typeof body === 'object' && 'collectionSlug' in body\n ? body.collectionSlug\n : undefined\n const adapter =\n typeof collectionSlug === 'string' ? options?.adapters?.[collectionSlug] : undefined\n const input = document\n ? (adapter?.getAuditInput?.({ document }) ?? getRGAADocumentInput({ document }))\n : (body ?? {})\n const report = buildRGAAReport({ findings: auditRGAAContent({ input: input ?? {} }) })\n\n return Response.json(report)\n },\n method: 'post',\n path: '/plugin-rgaa/audit-content',\n },\n {\n handler: async (req) => {\n await authorizeRGAA({ req })\n if (!options?.ai) {\n return Response.json(\n { error: 'NIM suggestions are not configured.' },\n { status: 403 },\n )\n }\n\n const body = await req.json?.()\n const context =\n body && typeof body === 'object' && 'context' in body ? body.context : undefined\n if (typeof context !== 'string') {\n return Response.json({ error: 'A textual context is required.' }, { status: 400 })\n }\n\n const suggestions = await generateNIMSuggestions({ context, provider: options.ai })\n\n return Response.json({ suggestions })\n },\n method: 'post',\n path: '/plugin-rgaa/suggestions',\n },\n {\n handler: async (req) => {\n await authorizeRGAA({ req })\n const body = await req.json?.()\n const baseURL =\n body && typeof body === 'object' && 'baseURL' in body ? body.baseURL : undefined\n const pages =\n body && typeof body === 'object' && 'pages' in body ? body.pages : undefined\n\n if (typeof baseURL !== 'string' || !Array.isArray(pages)) {\n return Response.json({ error: 'baseURL and pages are required.' }, { status: 400 })\n }\n\n const result = await auditRenderedPages({ baseURL, pages })\n\n return Response.json(result)\n },\n method: 'post',\n path: '/plugin-rgaa/audit-rendered-pages',\n },\n ],\n }\n },\n})\n\nconst getRGAAPluginOptions = ({\n pluginArgs,\n}: {\n pluginArgs: { config: unknown; options?: RGAAPluginConfig; plugins: unknown } & RGAAPluginConfig\n}): RGAAPluginConfig => {\n if (pluginArgs.options) {\n return pluginArgs.options\n }\n\n const { config: _config, plugins: _plugins, options: _options, ...legacyOptions } = pluginArgs\n\n return legacyOptions\n}\n\nconst authorizeRGAA = async ({ req }: { req: PayloadRequest }): Promise<void> => {\n await canAccessAdmin({ req })\n}\n"],"names":["canAccessAdmin","definePlugin","accessibilityFields","auditRGAAContent","getRGAADocumentInput","generateNIMSuggestions","buildRGAAReport","auditRenderedPages","loadRGAAReferenceCatalog","rgaaCriteria","getRGAAImageAttributes","getRGAALanguageAttributes","parseRGAASuggestions","rgaaPlugin","slug","plugin","pluginArgs","config","options","getRGAAPluginOptions","selectedCollections","Set","collections","excludedCollections","excludeCollections","isIncluded","collection","auth","has","size","rgaaFields","name","type","fields","defaultFields","label","map","hasAccessibilityGroup","some","field","tabbedUI","tabs","slice","endpoints","handler","req","authorizeRGAA","body","json","document","undefined","collectionSlug","adapter","adapters","input","getAuditInput","report","findings","Response","method","path","ai","error","status","context","suggestions","provider","baseURL","pages","Array","isArray","result","_config","plugins","_plugins","_options","legacyOptions"],"mappings":"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"}
|
package/dist/nim.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { RGAAAIProvider, RGAASuggestion } from './types.js';
|
|
2
|
+
/** Validates untrusted model output before it can appear in an editor workflow. */
|
|
3
|
+
export declare const parseRGAASuggestions: ({ content }: {
|
|
4
|
+
content: string;
|
|
5
|
+
}) => RGAASuggestion[];
|
|
6
|
+
/**
|
|
7
|
+
* NIM is intentionally suggestion-only. The caller must expose accept/edit/reject
|
|
8
|
+
* controls and must not apply the returned values without a human action.
|
|
9
|
+
*/
|
|
10
|
+
export declare const generateNIMSuggestions: ({ context, provider, }: {
|
|
11
|
+
context: string;
|
|
12
|
+
provider: RGAAAIProvider;
|
|
13
|
+
}) => Promise<RGAASuggestion[]>;
|
|
14
|
+
//# sourceMappingURL=nim.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nim.d.ts","sourceRoot":"","sources":["../src/nim.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AA2BhE,mFAAmF;AACnF,eAAO,MAAM,oBAAoB,gBAAiB;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,KAAG,cAAc,EAarF,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,sBAAsB,2BAGhC;IACD,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,cAAc,CAAA;CACzB,KAAG,OAAO,CAAC,cAAc,EAAE,CAmC3B,CAAA"}
|
package/dist/nim.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
const defaultNIMBaseURL = 'https://integrate.api.nvidia.com/v1';
|
|
2
|
+
const defaultNIMModel = 'nvidia/nemotron-3.5-lightning-30b-a3b';
|
|
3
|
+
const isSuggestion = (value)=>{
|
|
4
|
+
if (!value || typeof value !== 'object') {
|
|
5
|
+
return false;
|
|
6
|
+
}
|
|
7
|
+
const suggestion = value;
|
|
8
|
+
return typeof suggestion.confidence === 'number' && suggestion.confidence >= 0 && suggestion.confidence <= 1 && Array.isArray(suggestion.criterionIDs) && suggestion.criterionIDs.every((id)=>typeof id === 'string') && typeof suggestion.evidence === 'string' && typeof suggestion.proposedValue === 'string' && typeof suggestion.target === 'string';
|
|
9
|
+
};
|
|
10
|
+
/** Validates untrusted model output before it can appear in an editor workflow. */ export const parseRGAASuggestions = ({ content })=>{
|
|
11
|
+
const parsed = JSON.parse(content);
|
|
12
|
+
const suggestions = Array.isArray(parsed) ? parsed : parsed && typeof parsed === 'object' && 'suggestions' in parsed ? parsed.suggestions : undefined;
|
|
13
|
+
if (!Array.isArray(suggestions) || !suggestions.every(isSuggestion)) {
|
|
14
|
+
throw new Error('The AI response does not match the RGAA suggestion contract.');
|
|
15
|
+
}
|
|
16
|
+
return suggestions;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* NIM is intentionally suggestion-only. The caller must expose accept/edit/reject
|
|
20
|
+
* controls and must not apply the returned values without a human action.
|
|
21
|
+
*/ export const generateNIMSuggestions = async ({ context, provider })=>{
|
|
22
|
+
if (!provider.apiKey) {
|
|
23
|
+
throw new Error('An explicit NIM API key is required before editorial content can be sent.');
|
|
24
|
+
}
|
|
25
|
+
const response = await fetch(`${provider.baseURL ?? defaultNIMBaseURL}/chat/completions`, {
|
|
26
|
+
body: JSON.stringify({
|
|
27
|
+
messages: [
|
|
28
|
+
{
|
|
29
|
+
content: 'You are an RGAA editorial assistant. Return only a JSON object with a suggestions array. Never claim compliance. Each item has target, proposedValue, evidence, confidence (0-1), and criterionIDs.',
|
|
30
|
+
role: 'system'
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
content: context,
|
|
34
|
+
role: 'user'
|
|
35
|
+
}
|
|
36
|
+
],
|
|
37
|
+
model: provider.model ?? defaultNIMModel,
|
|
38
|
+
response_format: {
|
|
39
|
+
type: 'json_object'
|
|
40
|
+
},
|
|
41
|
+
temperature: 0.1
|
|
42
|
+
}),
|
|
43
|
+
headers: {
|
|
44
|
+
Authorization: `Bearer ${provider.apiKey}`,
|
|
45
|
+
'Content-Type': 'application/json'
|
|
46
|
+
},
|
|
47
|
+
method: 'POST'
|
|
48
|
+
});
|
|
49
|
+
if (!response.ok) {
|
|
50
|
+
throw new Error(`NIM suggestion request failed with HTTP ${response.status}.`);
|
|
51
|
+
}
|
|
52
|
+
const payload = await response.json();
|
|
53
|
+
const content = payload.choices?.[0]?.message?.content;
|
|
54
|
+
if (!content) {
|
|
55
|
+
throw new Error('NIM returned no suggestion content.');
|
|
56
|
+
}
|
|
57
|
+
return parseRGAASuggestions({
|
|
58
|
+
content
|
|
59
|
+
});
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
//# sourceMappingURL=nim.js.map
|
package/dist/nim.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/nim.ts"],"sourcesContent":["import type { RGAAAIProvider, RGAASuggestion } from './types.js'\n\nconst defaultNIMBaseURL = 'https://integrate.api.nvidia.com/v1'\nconst defaultNIMModel = 'nvidia/nemotron-3.5-lightning-30b-a3b'\n\ntype ChatCompletionResponse = {\n choices?: Array<{ message?: { content?: string | null } }>\n}\n\nconst isSuggestion = (value: unknown): value is RGAASuggestion => {\n if (!value || typeof value !== 'object') {\n return false\n }\n\n const suggestion = value as Partial<RGAASuggestion>\n return (\n typeof suggestion.confidence === 'number' &&\n suggestion.confidence >= 0 &&\n suggestion.confidence <= 1 &&\n Array.isArray(suggestion.criterionIDs) &&\n suggestion.criterionIDs.every((id) => typeof id === 'string') &&\n typeof suggestion.evidence === 'string' &&\n typeof suggestion.proposedValue === 'string' &&\n typeof suggestion.target === 'string'\n )\n}\n\n/** Validates untrusted model output before it can appear in an editor workflow. */\nexport const parseRGAASuggestions = ({ content }: { content: string }): RGAASuggestion[] => {\n const parsed: unknown = JSON.parse(content)\n const suggestions = Array.isArray(parsed)\n ? parsed\n : parsed && typeof parsed === 'object' && 'suggestions' in parsed\n ? (parsed as { suggestions?: unknown }).suggestions\n : undefined\n\n if (!Array.isArray(suggestions) || !suggestions.every(isSuggestion)) {\n throw new Error('The AI response does not match the RGAA suggestion contract.')\n }\n\n return suggestions\n}\n\n/**\n * NIM is intentionally suggestion-only. The caller must expose accept/edit/reject\n * controls and must not apply the returned values without a human action.\n */\nexport const generateNIMSuggestions = async ({\n context,\n provider,\n}: {\n context: string\n provider: RGAAAIProvider\n}): Promise<RGAASuggestion[]> => {\n if (!provider.apiKey) {\n throw new Error('An explicit NIM API key is required before editorial content can be sent.')\n }\n\n const response = await fetch(`${provider.baseURL ?? defaultNIMBaseURL}/chat/completions`, {\n body: JSON.stringify({\n messages: [\n {\n content:\n 'You are an RGAA editorial assistant. Return only a JSON object with a suggestions array. Never claim compliance. Each item has target, proposedValue, evidence, confidence (0-1), and criterionIDs.',\n role: 'system',\n },\n { content: context, role: 'user' },\n ],\n model: provider.model ?? defaultNIMModel,\n response_format: { type: 'json_object' },\n temperature: 0.1,\n }),\n headers: { Authorization: `Bearer ${provider.apiKey}`, 'Content-Type': 'application/json' },\n method: 'POST',\n })\n\n if (!response.ok) {\n throw new Error(`NIM suggestion request failed with HTTP ${response.status}.`)\n }\n\n const payload = (await response.json()) as ChatCompletionResponse\n const content = payload.choices?.[0]?.message?.content\n\n if (!content) {\n throw new Error('NIM returned no suggestion content.')\n }\n\n return parseRGAASuggestions({ content })\n}\n"],"names":["defaultNIMBaseURL","defaultNIMModel","isSuggestion","value","suggestion","confidence","Array","isArray","criterionIDs","every","id","evidence","proposedValue","target","parseRGAASuggestions","content","parsed","JSON","parse","suggestions","undefined","Error","generateNIMSuggestions","context","provider","apiKey","response","fetch","baseURL","body","stringify","messages","role","model","response_format","type","temperature","headers","Authorization","method","ok","status","payload","json","choices","message"],"mappings":"AAEA,MAAMA,oBAAoB;AAC1B,MAAMC,kBAAkB;AAMxB,MAAMC,eAAe,CAACC;IACpB,IAAI,CAACA,SAAS,OAAOA,UAAU,UAAU;QACvC,OAAO;IACT;IAEA,MAAMC,aAAaD;IACnB,OACE,OAAOC,WAAWC,UAAU,KAAK,YACjCD,WAAWC,UAAU,IAAI,KACzBD,WAAWC,UAAU,IAAI,KACzBC,MAAMC,OAAO,CAACH,WAAWI,YAAY,KACrCJ,WAAWI,YAAY,CAACC,KAAK,CAAC,CAACC,KAAO,OAAOA,OAAO,aACpD,OAAON,WAAWO,QAAQ,KAAK,YAC/B,OAAOP,WAAWQ,aAAa,KAAK,YACpC,OAAOR,WAAWS,MAAM,KAAK;AAEjC;AAEA,iFAAiF,GACjF,OAAO,MAAMC,uBAAuB,CAAC,EAAEC,OAAO,EAAuB;IACnE,MAAMC,SAAkBC,KAAKC,KAAK,CAACH;IACnC,MAAMI,cAAcb,MAAMC,OAAO,CAACS,UAC9BA,SACAA,UAAU,OAAOA,WAAW,YAAY,iBAAiBA,SACvD,AAACA,OAAqCG,WAAW,GACjDC;IAEN,IAAI,CAACd,MAAMC,OAAO,CAACY,gBAAgB,CAACA,YAAYV,KAAK,CAACP,eAAe;QACnE,MAAM,IAAImB,MAAM;IAClB;IAEA,OAAOF;AACT,EAAC;AAED;;;CAGC,GACD,OAAO,MAAMG,yBAAyB,OAAO,EAC3CC,OAAO,EACPC,QAAQ,EAIT;IACC,IAAI,CAACA,SAASC,MAAM,EAAE;QACpB,MAAM,IAAIJ,MAAM;IAClB;IAEA,MAAMK,WAAW,MAAMC,MAAM,GAAGH,SAASI,OAAO,IAAI5B,kBAAkB,iBAAiB,CAAC,EAAE;QACxF6B,MAAMZ,KAAKa,SAAS,CAAC;YACnBC,UAAU;gBACR;oBACEhB,SACE;oBACFiB,MAAM;gBACR;gBACA;oBAAEjB,SAASQ;oBAASS,MAAM;gBAAO;aAClC;YACDC,OAAOT,SAASS,KAAK,IAAIhC;YACzBiC,iBAAiB;gBAAEC,MAAM;YAAc;YACvCC,aAAa;QACf;QACAC,SAAS;YAAEC,eAAe,CAAC,OAAO,EAAEd,SAASC,MAAM,EAAE;YAAE,gBAAgB;QAAmB;QAC1Fc,QAAQ;IACV;IAEA,IAAI,CAACb,SAASc,EAAE,EAAE;QAChB,MAAM,IAAInB,MAAM,CAAC,wCAAwC,EAAEK,SAASe,MAAM,CAAC,CAAC,CAAC;IAC/E;IAEA,MAAMC,UAAW,MAAMhB,SAASiB,IAAI;IACpC,MAAM5B,UAAU2B,QAAQE,OAAO,EAAE,CAAC,EAAE,EAAEC,SAAS9B;IAE/C,IAAI,CAACA,SAAS;QACZ,MAAM,IAAIM,MAAM;IAClB;IAEA,OAAOP,qBAAqB;QAAEC;IAAQ;AACxC,EAAC"}
|
package/dist/report.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export type RGAAFinding = {
|
|
2
|
+
criterionID: string;
|
|
3
|
+
evidence: string;
|
|
4
|
+
source?: {
|
|
5
|
+
collection?: string;
|
|
6
|
+
documentID?: number | string;
|
|
7
|
+
url?: string;
|
|
8
|
+
};
|
|
9
|
+
status: 'failed' | 'passed' | 'suggested';
|
|
10
|
+
};
|
|
11
|
+
export type RGAACriterionResult = RGAAFinding & {
|
|
12
|
+
automationLevel: 'deterministic' | 'human-review' | 'rendered-page';
|
|
13
|
+
};
|
|
14
|
+
export type RGAAReport = {
|
|
15
|
+
criteria: RGAACriterionResult[];
|
|
16
|
+
generatedAt: string;
|
|
17
|
+
notice: 'Automated checks and suggestions are not an RGAA conformance declaration.';
|
|
18
|
+
summary: {
|
|
19
|
+
failed: number;
|
|
20
|
+
needsHumanReview: number;
|
|
21
|
+
passed: number;
|
|
22
|
+
suggested: number;
|
|
23
|
+
total: 106;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Returns every RGAA criterion. Missing checks remain suggestions for a human
|
|
28
|
+
* review instead of being silently counted as compliant.
|
|
29
|
+
*/
|
|
30
|
+
export declare const buildRGAAReport: ({ findings }: {
|
|
31
|
+
findings: RGAAFinding[];
|
|
32
|
+
}) => RGAAReport;
|
|
33
|
+
//# sourceMappingURL=report.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,WAAW,GAAG;IACxB,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC5E,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,WAAW,CAAA;CAC1C,CAAA;AAED,MAAM,MAAM,mBAAmB,GAAG,WAAW,GAAG;IAC9C,eAAe,EAAE,eAAe,GAAG,cAAc,GAAG,eAAe,CAAA;CACpE,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,EAAE,mBAAmB,EAAE,CAAA;IAC/B,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,2EAA2E,CAAA;IACnF,OAAO,EAAE;QACP,MAAM,EAAE,MAAM,CAAA;QACd,gBAAgB,EAAE,MAAM,CAAA;QACxB,MAAM,EAAE,MAAM,CAAA;QACd,SAAS,EAAE,MAAM,CAAA;QACjB,KAAK,EAAE,GAAG,CAAA;KACX,CAAA;CACF,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,iBAAkB;IAAE,QAAQ,EAAE,WAAW,EAAE,CAAA;CAAE,KAAG,UAgC3E,CAAA"}
|
package/dist/report.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { rgaaCriteria } from './catalog.js';
|
|
2
|
+
/**
|
|
3
|
+
* Returns every RGAA criterion. Missing checks remain suggestions for a human
|
|
4
|
+
* review instead of being silently counted as compliant.
|
|
5
|
+
*/ export const buildRGAAReport = ({ findings })=>{
|
|
6
|
+
const findingsByCriterion = new Map(findings.map((finding)=>[
|
|
7
|
+
finding.criterionID,
|
|
8
|
+
finding
|
|
9
|
+
]));
|
|
10
|
+
const criteria = rgaaCriteria.map((criterion)=>{
|
|
11
|
+
const finding = findingsByCriterion.get(criterion.id);
|
|
12
|
+
return {
|
|
13
|
+
automationLevel: criterion.automationLevel,
|
|
14
|
+
criterionID: criterion.id,
|
|
15
|
+
evidence: finding?.evidence ?? 'A human review is required before this criterion can be evaluated.',
|
|
16
|
+
...finding?.source ? {
|
|
17
|
+
source: finding.source
|
|
18
|
+
} : {},
|
|
19
|
+
status: finding?.status ?? 'suggested'
|
|
20
|
+
};
|
|
21
|
+
});
|
|
22
|
+
const summary = criteria.reduce((counts, { status })=>({
|
|
23
|
+
...counts,
|
|
24
|
+
[status]: counts[status] + 1
|
|
25
|
+
}), {
|
|
26
|
+
failed: 0,
|
|
27
|
+
needsHumanReview: 0,
|
|
28
|
+
passed: 0,
|
|
29
|
+
suggested: 0
|
|
30
|
+
});
|
|
31
|
+
return {
|
|
32
|
+
criteria,
|
|
33
|
+
generatedAt: new Date().toISOString(),
|
|
34
|
+
notice: 'Automated checks and suggestions are not an RGAA conformance declaration.',
|
|
35
|
+
summary: {
|
|
36
|
+
...summary,
|
|
37
|
+
needsHumanReview: criteria.filter(({ automationLevel, status })=>automationLevel === 'human-review' && status === 'suggested').length,
|
|
38
|
+
total: 106
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
//# sourceMappingURL=report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/report.ts"],"sourcesContent":["import { rgaaCriteria } from './catalog.js'\n\nexport type RGAAFinding = {\n criterionID: string\n evidence: string\n source?: { collection?: string; documentID?: number | string; url?: string }\n status: 'failed' | 'passed' | 'suggested'\n}\n\nexport type RGAACriterionResult = RGAAFinding & {\n automationLevel: 'deterministic' | 'human-review' | 'rendered-page'\n}\n\nexport type RGAAReport = {\n criteria: RGAACriterionResult[]\n generatedAt: string\n notice: 'Automated checks and suggestions are not an RGAA conformance declaration.'\n summary: {\n failed: number\n needsHumanReview: number\n passed: number\n suggested: number\n total: 106\n }\n}\n\n/**\n * Returns every RGAA criterion. Missing checks remain suggestions for a human\n * review instead of being silently counted as compliant.\n */\nexport const buildRGAAReport = ({ findings }: { findings: RGAAFinding[] }): RGAAReport => {\n const findingsByCriterion = new Map(findings.map((finding) => [finding.criterionID, finding]))\n const criteria = rgaaCriteria.map((criterion) => {\n const finding = findingsByCriterion.get(criterion.id)\n\n return {\n automationLevel: criterion.automationLevel,\n criterionID: criterion.id,\n evidence:\n finding?.evidence ?? 'A human review is required before this criterion can be evaluated.',\n ...(finding?.source ? { source: finding.source } : {}),\n status: finding?.status ?? 'suggested',\n }\n })\n const summary = criteria.reduce(\n (counts, { status }) => ({ ...counts, [status]: counts[status] + 1 }),\n { failed: 0, needsHumanReview: 0, passed: 0, suggested: 0 } as RGAAReport['summary'],\n )\n\n return {\n criteria,\n generatedAt: new Date().toISOString(),\n notice: 'Automated checks and suggestions are not an RGAA conformance declaration.',\n summary: {\n ...summary,\n needsHumanReview: criteria.filter(\n ({ automationLevel, status }) =>\n automationLevel === 'human-review' && status === 'suggested',\n ).length,\n total: 106,\n },\n }\n}\n"],"names":["rgaaCriteria","buildRGAAReport","findings","findingsByCriterion","Map","map","finding","criterionID","criteria","criterion","get","id","automationLevel","evidence","source","status","summary","reduce","counts","failed","needsHumanReview","passed","suggested","generatedAt","Date","toISOString","notice","filter","length","total"],"mappings":"AAAA,SAASA,YAAY,QAAQ,eAAc;AA0B3C;;;CAGC,GACD,OAAO,MAAMC,kBAAkB,CAAC,EAAEC,QAAQ,EAA+B;IACvE,MAAMC,sBAAsB,IAAIC,IAAIF,SAASG,GAAG,CAAC,CAACC,UAAY;YAACA,QAAQC,WAAW;YAAED;SAAQ;IAC5F,MAAME,WAAWR,aAAaK,GAAG,CAAC,CAACI;QACjC,MAAMH,UAAUH,oBAAoBO,GAAG,CAACD,UAAUE,EAAE;QAEpD,OAAO;YACLC,iBAAiBH,UAAUG,eAAe;YAC1CL,aAAaE,UAAUE,EAAE;YACzBE,UACEP,SAASO,YAAY;YACvB,GAAIP,SAASQ,SAAS;gBAAEA,QAAQR,QAAQQ,MAAM;YAAC,IAAI,CAAC,CAAC;YACrDC,QAAQT,SAASS,UAAU;QAC7B;IACF;IACA,MAAMC,UAAUR,SAASS,MAAM,CAC7B,CAACC,QAAQ,EAAEH,MAAM,EAAE,GAAM,CAAA;YAAE,GAAGG,MAAM;YAAE,CAACH,OAAO,EAAEG,MAAM,CAACH,OAAO,GAAG;QAAE,CAAA,GACnE;QAAEI,QAAQ;QAAGC,kBAAkB;QAAGC,QAAQ;QAAGC,WAAW;IAAE;IAG5D,OAAO;QACLd;QACAe,aAAa,IAAIC,OAAOC,WAAW;QACnCC,QAAQ;QACRV,SAAS;YACP,GAAGA,OAAO;YACVI,kBAAkBZ,SAASmB,MAAM,CAC/B,CAAC,EAAEf,eAAe,EAAEG,MAAM,EAAE,GAC1BH,oBAAoB,kBAAkBG,WAAW,aACnDa,MAAM;YACRC,OAAO;QACT;IACF;AACF,EAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type RGAAAuditPage = {
|
|
2
|
+
name?: string;
|
|
3
|
+
path: string;
|
|
4
|
+
};
|
|
5
|
+
export type RenderedPageAuditOptions = {
|
|
6
|
+
baseURL: string;
|
|
7
|
+
pages: RGAAAuditPage[];
|
|
8
|
+
projectName?: string;
|
|
9
|
+
};
|
|
10
|
+
export type RenderedPageAuditResult = {
|
|
11
|
+
report: unknown;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Audits public or preview URLs with Eqo's browser runtime. It intentionally
|
|
15
|
+
* returns the source report unchanged so that failures and human-review states
|
|
16
|
+
* remain visible to the caller.
|
|
17
|
+
*/
|
|
18
|
+
export declare const auditRenderedPages: ({ baseURL, pages, projectName, }: RenderedPageAuditOptions) => Promise<RenderedPageAuditResult>;
|
|
19
|
+
//# sourceMappingURL=runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAA;AAE3D,MAAM,MAAM,wBAAwB,GAAG;IACrC,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,aAAa,EAAE,CAAA;IACtB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,CAAA;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC,MAAM,EAAE,OAAO,CAAA;CAChB,CAAA;AAeD;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,qCAI5B,wBAAwB,KAAG,OAAO,CAAC,uBAAuB,CAuB5D,CAAA"}
|
package/dist/runtime.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audits public or preview URLs with Eqo's browser runtime. It intentionally
|
|
3
|
+
* returns the source report unchanged so that failures and human-review states
|
|
4
|
+
* remain visible to the caller.
|
|
5
|
+
*/ export const auditRenderedPages = async ({ baseURL, pages, projectName })=>{
|
|
6
|
+
let eqo;
|
|
7
|
+
try {
|
|
8
|
+
eqo = await import('@kodalabs-io/eqo');
|
|
9
|
+
} catch {
|
|
10
|
+
throw new Error('Rendered-page auditing requires the optional @kodalabs-io/eqo runtime and its Playwright peers.');
|
|
11
|
+
}
|
|
12
|
+
const report = await eqo.analyze({
|
|
13
|
+
baseUrl: baseURL,
|
|
14
|
+
locale: 'fr-FR',
|
|
15
|
+
output: [],
|
|
16
|
+
pages,
|
|
17
|
+
...projectName ? {
|
|
18
|
+
projectName
|
|
19
|
+
} : {}
|
|
20
|
+
}, {
|
|
21
|
+
runtimeOnly: true
|
|
22
|
+
});
|
|
23
|
+
return {
|
|
24
|
+
report
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/runtime.ts"],"sourcesContent":["export type RGAAAuditPage = { name?: string; path: string }\n\nexport type RenderedPageAuditOptions = {\n baseURL: string\n pages: RGAAAuditPage[]\n projectName?: string\n}\n\nexport type RenderedPageAuditResult = {\n report: unknown\n}\n\ntype EqoModule = {\n analyze: (\n config: {\n baseUrl: string\n locale: 'fr-FR'\n output: []\n pages: RGAAAuditPage[]\n projectName?: string\n },\n options: { runtimeOnly: true },\n ) => Promise<unknown>\n}\n\n/**\n * Audits public or preview URLs with Eqo's browser runtime. It intentionally\n * returns the source report unchanged so that failures and human-review states\n * remain visible to the caller.\n */\nexport const auditRenderedPages = async ({\n baseURL,\n pages,\n projectName,\n}: RenderedPageAuditOptions): Promise<RenderedPageAuditResult> => {\n let eqo: EqoModule\n\n try {\n eqo = (await import('@kodalabs-io/eqo')) as EqoModule\n } catch {\n throw new Error(\n 'Rendered-page auditing requires the optional @kodalabs-io/eqo runtime and its Playwright peers.',\n )\n }\n\n const report = await eqo.analyze(\n {\n baseUrl: baseURL,\n locale: 'fr-FR',\n output: [],\n pages,\n ...(projectName ? { projectName } : {}),\n },\n { runtimeOnly: true },\n )\n\n return { report }\n}\n"],"names":["auditRenderedPages","baseURL","pages","projectName","eqo","Error","report","analyze","baseUrl","locale","output","runtimeOnly"],"mappings":"AAyBA;;;;CAIC,GACD,OAAO,MAAMA,qBAAqB,OAAO,EACvCC,OAAO,EACPC,KAAK,EACLC,WAAW,EACc;IACzB,IAAIC;IAEJ,IAAI;QACFA,MAAO,MAAM,MAAM,CAAC;IACtB,EAAE,OAAM;QACN,MAAM,IAAIC,MACR;IAEJ;IAEA,MAAMC,SAAS,MAAMF,IAAIG,OAAO,CAC9B;QACEC,SAASP;QACTQ,QAAQ;QACRC,QAAQ,EAAE;QACVR;QACA,GAAIC,cAAc;YAAEA;QAAY,IAAI,CAAC,CAAC;IACxC,GACA;QAAEQ,aAAa;IAAK;IAGtB,OAAO;QAAEL;IAAO;AAClB,EAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { RGAADocumentInput } from './content.js';
|
|
2
|
+
import type { CollectionSlug, Field } from 'payload';
|
|
3
|
+
export type RGAAAIProvider = {
|
|
4
|
+
apiKey?: string;
|
|
5
|
+
baseURL?: string;
|
|
6
|
+
model?: string;
|
|
7
|
+
};
|
|
8
|
+
export type RGAASuggestion = {
|
|
9
|
+
confidence: number;
|
|
10
|
+
criterionIDs: string[];
|
|
11
|
+
evidence: string;
|
|
12
|
+
proposedValue: string;
|
|
13
|
+
target: string;
|
|
14
|
+
};
|
|
15
|
+
export type RGAAPluginConfig = {
|
|
16
|
+
/** Per-collection mapping for editorial schemas that do not use conventional field names. */
|
|
17
|
+
adapters?: Partial<Record<CollectionSlug, {
|
|
18
|
+
getAuditInput?: (args: {
|
|
19
|
+
document: Record<string, unknown>;
|
|
20
|
+
}) => RGAADocumentInput;
|
|
21
|
+
}>>;
|
|
22
|
+
/** Collections to enrich. Omit to target every non-auth collection. */
|
|
23
|
+
collections?: ({} | CollectionSlug)[];
|
|
24
|
+
/** Never transmit editorial data unless an administrator explicitly opts in. */
|
|
25
|
+
ai?: false | RGAAAIProvider;
|
|
26
|
+
/** Exclude technical collections from automatic enrichment. */
|
|
27
|
+
excludeCollections?: ({} | CollectionSlug)[];
|
|
28
|
+
fields?: (args: {
|
|
29
|
+
defaultFields: Field[];
|
|
30
|
+
}) => Field[];
|
|
31
|
+
tabbedUI?: boolean;
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAErD,OAAO,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAEpD,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,EAAE,MAAM,CAAA;IACrB,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,6FAA6F;IAC7F,QAAQ,CAAC,EAAE,OAAO,CAChB,MAAM,CACJ,cAAc,EACd;QACE,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE;YAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;SAAE,KAAK,iBAAiB,CAAA;KACnF,CACF,CACF,CAAA;IACD,uEAAuE;IACvE,WAAW,CAAC,EAAE,CAAC,EAAE,GAAG,cAAc,CAAC,EAAE,CAAA;IACrC,gFAAgF;IAChF,EAAE,CAAC,EAAE,KAAK,GAAG,cAAc,CAAA;IAC3B,+DAA+D;IAC/D,kBAAkB,CAAC,EAAE,CAAC,EAAE,GAAG,cAAc,CAAC,EAAE,CAAA;IAC5C,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,aAAa,EAAE,KAAK,EAAE,CAAA;KAAE,KAAK,KAAK,EAAE,CAAA;IACtD,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type { RGAADocumentInput } from './content.js'\n\nimport type { CollectionSlug, Field } from 'payload'\n\nexport type RGAAAIProvider = {\n apiKey?: string\n baseURL?: string\n model?: string\n}\n\nexport type RGAASuggestion = {\n confidence: number\n criterionIDs: string[]\n evidence: string\n proposedValue: string\n target: string\n}\n\nexport type RGAAPluginConfig = {\n /** Per-collection mapping for editorial schemas that do not use conventional field names. */\n adapters?: Partial<\n Record<\n CollectionSlug,\n {\n getAuditInput?: (args: { document: Record<string, unknown> }) => RGAADocumentInput\n }\n >\n >\n /** Collections to enrich. Omit to target every non-auth collection. */\n collections?: ({} | CollectionSlug)[]\n /** Never transmit editorial data unless an administrator explicitly opts in. */\n ai?: false | RGAAAIProvider\n /** Exclude technical collections from automatic enrichment. */\n excludeCollections?: ({} | CollectionSlug)[]\n fields?: (args: { defaultFields: Field[] }) => Field[]\n tabbedUI?: boolean\n}\n"],"names":[],"mappings":"AAkBA,WAkBC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,61 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@116zoo/plugin-rgaa",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "RGAA review and deterministic accessibility metadata for Payload",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"LICENSE.md",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"main": "./dist/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"import": "./dist/index.js",
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"default": "./dist/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./types": {
|
|
22
|
+
"import": "./dist/exports/types.js",
|
|
23
|
+
"types": "./dist/exports/types.d.ts",
|
|
24
|
+
"default": "./dist/exports/types.js"
|
|
25
|
+
},
|
|
26
|
+
"./client": {
|
|
27
|
+
"import": "./dist/exports/client.js",
|
|
28
|
+
"types": "./dist/exports/client.d.ts",
|
|
29
|
+
"default": "./dist/exports/client.js"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "pnpm copyfiles && pnpm build:types && pnpm build:swc",
|
|
34
|
+
"build:swc": "swc ./src -d ./dist --config-file .swcrc --strip-leading-paths",
|
|
35
|
+
"build:types": "tsc --emitDeclarationOnly --outDir dist",
|
|
36
|
+
"clean": "rimraf -g {dist,*.tsbuildinfo}",
|
|
37
|
+
"copyfiles": "copyfiles -u 1 -e \"**/*.spec.*\" \"src/**/*.{json}\" dist/"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@axe-core/playwright": "4.11.0",
|
|
41
|
+
"@kodalabs-io/eqo": "1.0.0"
|
|
42
|
+
,"playwright": "1.63.0"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@payloadcms/ui": "workspace:*",
|
|
46
|
+
"@types/react": "19.3.0",
|
|
47
|
+
"@types/react-dom": "19.3.0",
|
|
48
|
+
"@swc/cli": "0.6.0",
|
|
49
|
+
"copyfiles": "catalog:",
|
|
50
|
+
"rimraf": "3.0.2",
|
|
51
|
+
"payload": "workspace:*",
|
|
52
|
+
"typescript": "catalog:",
|
|
53
|
+
"vitest": "5.0.1"
|
|
54
|
+
},
|
|
55
|
+
"peerDependencies": {
|
|
56
|
+
"@payloadcms/ui": "^3.93.0",
|
|
57
|
+
"payload": "^3.93.0",
|
|
58
|
+
"react": "^19.3.1",
|
|
59
|
+
"react-dom": "^19.3.1"
|
|
60
|
+
}
|
|
61
|
+
}
|