@ahtmljs/schema 0.1.0

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.
@@ -0,0 +1,179 @@
1
+ /**
2
+ * Zero-dependency structural validator for AHTML snapshots.
3
+ *
4
+ * Returns a list of human-readable issues. Empty array = valid.
5
+ * For full JSON Schema validation, run schema.json through any standard
6
+ * JSON Schema validator (ajv, etc.). This validator is intentionally lean
7
+ * so the @ahtmljs/schema package has zero runtime dependencies.
8
+ */
9
+ const ENTITY_TYPES = new Set([
10
+ 'product',
11
+ 'document',
12
+ 'task',
13
+ 'profile',
14
+ 'dataset',
15
+ 'conversation',
16
+ ]);
17
+ const PAGE_TYPES = new Set([
18
+ 'home',
19
+ 'product_detail',
20
+ 'product_list',
21
+ 'article',
22
+ 'document',
23
+ 'profile',
24
+ 'task_list',
25
+ 'task_detail',
26
+ 'dataset',
27
+ 'conversation',
28
+ 'checkout',
29
+ 'search_results',
30
+ 'category',
31
+ 'other',
32
+ ]);
33
+ export function validate(snap) {
34
+ const issues = [];
35
+ if (typeof snap !== 'object' || snap === null) {
36
+ issues.push({ path: '', message: 'snapshot must be an object', severity: 'error' });
37
+ return issues;
38
+ }
39
+ const s = snap;
40
+ if (s.ahtml !== '0.1') {
41
+ issues.push({
42
+ path: 'ahtml',
43
+ message: `unsupported version "${String(s.ahtml)}" (expected "0.1")`,
44
+ severity: 'error',
45
+ });
46
+ }
47
+ if (typeof s.url !== 'string' || !s.url) {
48
+ issues.push({ path: 'url', message: 'url is required', severity: 'error' });
49
+ }
50
+ if (typeof s.fetched_at !== 'string' || !isIso8601(s.fetched_at)) {
51
+ issues.push({
52
+ path: 'fetched_at',
53
+ message: 'fetched_at must be an ISO 8601 timestamp',
54
+ severity: 'error',
55
+ });
56
+ }
57
+ if (typeof s.page_type !== 'string' || !PAGE_TYPES.has(s.page_type)) {
58
+ issues.push({
59
+ path: 'page_type',
60
+ message: `unknown page_type "${String(s.page_type)}"`,
61
+ severity: 'error',
62
+ });
63
+ }
64
+ if (!Array.isArray(s.entities)) {
65
+ issues.push({ path: 'entities', message: 'entities must be an array', severity: 'error' });
66
+ }
67
+ else {
68
+ const seen = new Set();
69
+ s.entities.forEach((e, i) => {
70
+ const p = `entities[${i}]`;
71
+ issues.push(...validateEntity(e, p));
72
+ if (e?.id) {
73
+ if (seen.has(e.id)) {
74
+ issues.push({ path: p + '.id', message: `duplicate entity id "${e.id}"`, severity: 'error' });
75
+ }
76
+ seen.add(e.id);
77
+ }
78
+ });
79
+ }
80
+ if (!Array.isArray(s.actions)) {
81
+ issues.push({ path: 'actions', message: 'actions must be an array', severity: 'error' });
82
+ }
83
+ else {
84
+ const seen = new Set();
85
+ s.actions.forEach((a, i) => {
86
+ const p = `actions[${i}]`;
87
+ issues.push(...validateAction(a, p));
88
+ if (a?.id) {
89
+ if (seen.has(a.id)) {
90
+ issues.push({ path: p + '.id', message: `duplicate action id "${a.id}"`, severity: 'error' });
91
+ }
92
+ seen.add(a.id);
93
+ }
94
+ });
95
+ }
96
+ if (s.ttl !== undefined && (typeof s.ttl !== 'number' || s.ttl < 0)) {
97
+ issues.push({ path: 'ttl', message: 'ttl must be a non-negative number', severity: 'error' });
98
+ }
99
+ return issues;
100
+ }
101
+ function validateEntity(e, path) {
102
+ const issues = [];
103
+ if (typeof e !== 'object' || e === null) {
104
+ issues.push({ path, message: 'entity must be an object', severity: 'error' });
105
+ return issues;
106
+ }
107
+ const ent = e;
108
+ if (!ent.id || typeof ent.id !== 'string') {
109
+ issues.push({ path: path + '.id', message: 'entity.id is required', severity: 'error' });
110
+ }
111
+ else if (!/^[a-z_]+:[A-Za-z0-9_\-.]+$/.test(ent.id)) {
112
+ issues.push({
113
+ path: path + '.id',
114
+ message: `entity id "${ent.id}" should match "type:slug" (e.g. "product:mbp-14")`,
115
+ severity: 'warning',
116
+ });
117
+ }
118
+ if (!ent.type || !ENTITY_TYPES.has(ent.type)) {
119
+ issues.push({
120
+ path: path + '.type',
121
+ message: `unknown entity type "${String(ent.type)}"`,
122
+ severity: 'error',
123
+ });
124
+ }
125
+ else if (ent.id && !ent.id.startsWith(ent.type + ':')) {
126
+ issues.push({
127
+ path: path + '.id',
128
+ message: `id prefix should match type ("${ent.type}:..."), got "${ent.id}"`,
129
+ severity: 'warning',
130
+ });
131
+ }
132
+ if (ent.type === 'product') {
133
+ if (!ent.name) {
134
+ issues.push({ path: path + '.name', message: 'product.name is required', severity: 'error' });
135
+ }
136
+ if (ent.price) {
137
+ if (typeof ent.price.amount !== 'number') {
138
+ issues.push({ path: path + '.price.amount', message: 'price.amount must be a number', severity: 'error' });
139
+ }
140
+ if (typeof ent.price.currency !== 'string') {
141
+ issues.push({ path: path + '.price.currency', message: 'price.currency must be a string (ISO 4217)', severity: 'error' });
142
+ }
143
+ }
144
+ }
145
+ return issues;
146
+ }
147
+ function validateAction(a, path) {
148
+ const issues = [];
149
+ if (typeof a !== 'object' || a === null) {
150
+ issues.push({ path, message: 'action must be an object', severity: 'error' });
151
+ return issues;
152
+ }
153
+ const act = a;
154
+ if (!act.id || typeof act.id !== 'string') {
155
+ issues.push({ path: path + '.id', message: 'action.id is required', severity: 'error' });
156
+ }
157
+ if (act.cost && !['free', 'purchase', 'subscription', 'rate_limited', 'compute'].includes(act.cost.category)) {
158
+ issues.push({
159
+ path: path + '.cost.category',
160
+ message: `unknown cost category "${act.cost.category}"`,
161
+ severity: 'error',
162
+ });
163
+ }
164
+ if (act.confirmation && !['none', 'recommended', 'required'].includes(act.confirmation)) {
165
+ issues.push({
166
+ path: path + '.confirmation',
167
+ message: `confirmation must be none|recommended|required`,
168
+ severity: 'error',
169
+ });
170
+ }
171
+ return issues;
172
+ }
173
+ function isIso8601(s) {
174
+ return /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})$/.test(s);
175
+ }
176
+ export function isValid(snap) {
177
+ return validate(snap).every((i) => i.severity !== 'error');
178
+ }
179
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "@ahtmljs/schema",
3
+ "version": "0.1.0",
4
+ "description": "AHTML semantic snapshot schema — types, validator, builder, and dual-format serializers (JSON + token-optimal compact text).",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ },
13
+ "./schema.json": "./src/schema.json"
14
+ },
15
+ "files": ["dist", "src/schema.json"],
16
+ "publishConfig": { "access": "public" },
17
+ "scripts": {
18
+ "build": "tsc -p tsconfig.json",
19
+ "dev": "tsc -p tsconfig.json --watch"
20
+ },
21
+ "keywords": ["ahtml", "agent", "semantic-web", "ai", "llm", "crawler", "mcp"],
22
+ "license": "MIT"
23
+ }
@@ -0,0 +1,222 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://ahtml.dev/schema/v0.1/snapshot.json",
4
+ "title": "AHTML Snapshot",
5
+ "description": "Canonical agent-facing representation of a web page.",
6
+ "type": "object",
7
+ "required": ["ahtml", "url", "fetched_at", "page_type", "entities", "actions"],
8
+ "properties": {
9
+ "ahtml": { "const": "0.1" },
10
+ "url": { "type": "string", "format": "uri" },
11
+ "fetched_at": { "type": "string", "format": "date-time" },
12
+ "ttl": { "type": "integer", "minimum": 0 },
13
+ "etag": { "type": "string" },
14
+ "page_type": {
15
+ "type": "string",
16
+ "enum": ["home", "product_detail", "product_list", "article", "document", "profile", "task_list", "task_detail", "dataset", "conversation", "checkout", "search_results", "category", "other"]
17
+ },
18
+ "policy": { "$ref": "#/$defs/Policy" },
19
+ "provenance": { "$ref": "#/$defs/Provenance" },
20
+ "entities": { "type": "array", "items": { "$ref": "#/$defs/Entity" } },
21
+ "actions": { "type": "array", "items": { "$ref": "#/$defs/Action" } },
22
+ "links": { "$ref": "#/$defs/Links" },
23
+ "schemas": { "type": "object", "additionalProperties": true },
24
+ "meta": { "type": "object", "additionalProperties": true }
25
+ },
26
+ "$defs": {
27
+ "Money": {
28
+ "type": "object",
29
+ "required": ["amount", "currency"],
30
+ "properties": {
31
+ "amount": { "type": "number" },
32
+ "currency": { "type": "string", "minLength": 3, "maxLength": 3 }
33
+ }
34
+ },
35
+ "Stock": {
36
+ "type": "object",
37
+ "required": ["status"],
38
+ "properties": {
39
+ "status": { "enum": ["in_stock", "low_stock", "out_of_stock", "preorder", "discontinued"] },
40
+ "quantity": { "type": "integer", "minimum": 0 }
41
+ }
42
+ },
43
+ "Entity": {
44
+ "type": "object",
45
+ "required": ["id", "type"],
46
+ "properties": {
47
+ "id": { "type": "string", "pattern": "^[a-z_]+:[A-Za-z0-9_\\-.]+$" },
48
+ "type": { "enum": ["product", "document", "task", "profile", "dataset", "conversation"] },
49
+ "freshness": { "enum": ["live", "near_realtime", "daily", "static"] },
50
+ "updated_at": { "type": "string", "format": "date-time" }
51
+ },
52
+ "additionalProperties": true,
53
+ "oneOf": [
54
+ { "$ref": "#/$defs/Product" },
55
+ { "$ref": "#/$defs/Document" },
56
+ { "$ref": "#/$defs/Task" },
57
+ { "$ref": "#/$defs/Profile" },
58
+ { "$ref": "#/$defs/Dataset" },
59
+ { "$ref": "#/$defs/Conversation" }
60
+ ]
61
+ },
62
+ "Product": {
63
+ "type": "object",
64
+ "required": ["id", "type", "name"],
65
+ "properties": {
66
+ "type": { "const": "product" },
67
+ "name": { "type": "string" },
68
+ "brand": { "type": "string" },
69
+ "description": { "type": "string" },
70
+ "price": { "$ref": "#/$defs/Money" },
71
+ "list_price": { "$ref": "#/$defs/Money" },
72
+ "stock": { "$ref": "#/$defs/Stock" },
73
+ "sku": { "type": "string" },
74
+ "rating": {
75
+ "type": "object",
76
+ "properties": {
77
+ "average": { "type": "number", "minimum": 0, "maximum": 5 },
78
+ "count": { "type": "integer", "minimum": 0 }
79
+ }
80
+ }
81
+ }
82
+ },
83
+ "Document": {
84
+ "type": "object",
85
+ "required": ["id", "type", "title"],
86
+ "properties": {
87
+ "type": { "const": "document" },
88
+ "title": { "type": "string" },
89
+ "author": { "oneOf": [{ "type": "string" }, { "type": "array", "items": { "type": "string" } }] },
90
+ "published_at": { "type": "string", "format": "date-time" },
91
+ "summary": { "type": "string" },
92
+ "content": { "type": "string" },
93
+ "word_count": { "type": "integer", "minimum": 0 },
94
+ "language": { "type": "string" }
95
+ }
96
+ },
97
+ "Task": {
98
+ "type": "object",
99
+ "required": ["id", "type", "title", "state"],
100
+ "properties": {
101
+ "type": { "const": "task" },
102
+ "title": { "type": "string" },
103
+ "state": { "enum": ["open", "in_progress", "blocked", "done", "cancelled"] },
104
+ "priority": { "enum": ["low", "medium", "high", "urgent"] },
105
+ "assignee": { "type": "string" },
106
+ "due_at": { "type": "string", "format": "date-time" }
107
+ }
108
+ },
109
+ "Profile": {
110
+ "type": "object",
111
+ "required": ["id", "type", "name", "kind"],
112
+ "properties": {
113
+ "type": { "const": "profile" },
114
+ "name": { "type": "string" },
115
+ "kind": { "enum": ["person", "organization", "bot"] }
116
+ }
117
+ },
118
+ "Dataset": {
119
+ "type": "object",
120
+ "required": ["id", "type", "name", "columns", "rows"],
121
+ "properties": {
122
+ "type": { "const": "dataset" },
123
+ "name": { "type": "string" },
124
+ "columns": { "type": "array" },
125
+ "rows": { "type": "array" }
126
+ }
127
+ },
128
+ "Conversation": {
129
+ "type": "object",
130
+ "required": ["id", "type", "participants", "messages"],
131
+ "properties": {
132
+ "type": { "const": "conversation" },
133
+ "participants": { "type": "array", "items": { "type": "string" } },
134
+ "messages": { "type": "array" }
135
+ }
136
+ },
137
+ "Action": {
138
+ "type": "object",
139
+ "required": ["id"],
140
+ "properties": {
141
+ "id": { "type": "string" },
142
+ "label": { "type": "string" },
143
+ "target": { "oneOf": [{ "type": "string" }, { "type": "array", "items": { "type": "string" } }] },
144
+ "auth": {
145
+ "oneOf": [
146
+ { "enum": ["none", "optional", "required"] },
147
+ {
148
+ "type": "object",
149
+ "required": ["scheme"],
150
+ "properties": {
151
+ "scheme": { "type": "string" },
152
+ "scopes": { "type": "array", "items": { "type": "string" } }
153
+ }
154
+ }
155
+ ]
156
+ },
157
+ "cost": {
158
+ "type": "object",
159
+ "required": ["category"],
160
+ "properties": {
161
+ "amount": { "type": "number" },
162
+ "currency": { "type": "string" },
163
+ "category": { "enum": ["free", "purchase", "subscription", "rate_limited", "compute"] }
164
+ }
165
+ },
166
+ "reversible": {
167
+ "type": "object",
168
+ "required": ["reversible"],
169
+ "properties": {
170
+ "reversible": { "type": "boolean" },
171
+ "window": { "type": "string" },
172
+ "policy": { "type": "string" }
173
+ }
174
+ },
175
+ "side_effects": { "type": "array", "items": { "type": "string" } },
176
+ "confirmation": { "enum": ["none", "recommended", "required"] },
177
+ "category": { "enum": ["read", "search", "navigate", "create", "update", "delete", "transact", "send", "auth"] }
178
+ }
179
+ },
180
+ "Policy": {
181
+ "type": "object",
182
+ "required": ["agents_welcome"],
183
+ "properties": {
184
+ "agents_welcome": { "type": "boolean" },
185
+ "license": { "type": "string" },
186
+ "rate_limit": { "type": "string" },
187
+ "actions_require": { "type": "string" },
188
+ "contact": { "type": "string" },
189
+ "republish": { "enum": ["allowed", "denied", "attribution_only"] }
190
+ }
191
+ },
192
+ "Provenance": {
193
+ "type": "object",
194
+ "properties": {
195
+ "issuer": { "type": "string" },
196
+ "signed": { "type": "boolean" },
197
+ "signature": { "type": "string" },
198
+ "signature_alg": { "type": "string" }
199
+ }
200
+ },
201
+ "Links": {
202
+ "type": "object",
203
+ "properties": {
204
+ "self": { "type": "string" },
205
+ "canonical": { "type": "string" },
206
+ "parent": { "type": "string" },
207
+ "related": { "type": "array", "items": { "type": "string" } },
208
+ "next": { "$ref": "#/$defs/PaginationLink" },
209
+ "prev": { "$ref": "#/$defs/PaginationLink" }
210
+ }
211
+ },
212
+ "PaginationLink": {
213
+ "type": "object",
214
+ "properties": {
215
+ "cursor": { "type": "string" },
216
+ "url": { "type": "string" },
217
+ "expected": { "type": "integer" },
218
+ "total": { "type": "integer" }
219
+ }
220
+ }
221
+ }
222
+ }