mailschema 0.2.1 → 0.3.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,165 @@
1
+ // The regular expressions a contract's schemas may use: the subset that ECMA-262 (with the
2
+ // u flag) and other engines read alike, so every implementation enforces the same contract.
3
+ const SYNTAX_CHARACTERS = '^$\\.*+?()[]{}|/';
4
+ const CONTROL_ESCAPES = { t: 0x09, n: 0x0a, f: 0x0c, r: 0x0d };
5
+ const QUANTIFIERS = '*+?{';
6
+ /**
7
+ * Why a pattern is outside the portable subset, or undefined. The subset is printable ASCII
8
+ * text, with any other code point written as \uXXXX. It has literal characters and escaped
9
+ * syntax characters; \t, \n, \f, \r and \d, the ASCII digits; non-empty classes of literal or
10
+ * escaped members and ranges, with a literal hyphen only first or last; (?: groups;
11
+ * alternation; ^ and $; and one *, +, ?, {n}, {n,} or {n,m} after an atom. Other class
12
+ * escapes and the dot match different characters in different engines, and brackets, && or a
13
+ * stray brace inside a class, or a quantifier on a quantifier, are read differently or refused
14
+ * by one of them. ^ and $ anchor the whole value, as in ECMA-262; an engine whose anchors also
15
+ * match at line breaks must read them so.
16
+ */
17
+ export function unportablePattern(pattern) {
18
+ if (!/^[\x20-\x7e]*$/.test(pattern))
19
+ return 'a character outside printable ASCII';
20
+ let at = 0;
21
+ // One escaped code point, the digit class outside a class, or a problem.
22
+ const escape = (inClass) => {
23
+ const next = pattern[at + 1];
24
+ if (next === undefined)
25
+ return 'a trailing backslash';
26
+ if (next === 'u') {
27
+ const digits = pattern.slice(at + 2, at + 6);
28
+ if (!/^[0-9a-fA-F]{4}$/.test(digits))
29
+ return 'a malformed \\u escape';
30
+ const code = parseInt(digits, 16);
31
+ if (code >= 0xd800 && code <= 0xdfff)
32
+ return 'a surrogate \\u escape';
33
+ at += 6;
34
+ return code;
35
+ }
36
+ at += 2;
37
+ if (next === 'd' && !inClass)
38
+ return -1;
39
+ if (Object.hasOwn(CONTROL_ESCAPES, next))
40
+ return CONTROL_ESCAPES[next];
41
+ if (SYNTAX_CHARACTERS.includes(next) || (inClass && next === '-'))
42
+ return next.charCodeAt(0);
43
+ return `the escape \\${next}`;
44
+ };
45
+ const characterClass = () => {
46
+ at += pattern[at + 1] === '^' ? 2 : 1;
47
+ // Each member's code point, or null for an unescaped hyphen.
48
+ const members = [];
49
+ while (pattern[at] !== ']') {
50
+ const char = pattern[at];
51
+ if (char === undefined)
52
+ return 'an unclosed character class';
53
+ if (char === '[')
54
+ return 'a bracket inside a class';
55
+ if (char === '&' && pattern[at + 1] === '&')
56
+ return '&& inside a class';
57
+ if (char === '\\') {
58
+ const code = escape(true);
59
+ if (typeof code === 'string')
60
+ return code;
61
+ members.push(code);
62
+ }
63
+ else {
64
+ members.push(char === '-' ? null : char.charCodeAt(0));
65
+ at += 1;
66
+ }
67
+ }
68
+ at += 1;
69
+ if (!members.length)
70
+ return 'an empty character class';
71
+ for (let index = 0; index < members.length; index += 1) {
72
+ const low = members[index];
73
+ if (low === null) {
74
+ if (index !== 0 && index !== members.length - 1)
75
+ return 'an ambiguous hyphen in a class';
76
+ continue;
77
+ }
78
+ if (members[index + 1] !== null || index + 2 >= members.length)
79
+ continue;
80
+ const high = members[index + 2];
81
+ if (high === null)
82
+ return 'an ambiguous hyphen in a class';
83
+ if (high < low)
84
+ return 'a class range out of order';
85
+ index += 2;
86
+ if (members[index + 1] === null && index + 1 !== members.length - 1)
87
+ return 'an ambiguous hyphen in a class';
88
+ }
89
+ };
90
+ const quantifier = () => {
91
+ if (pattern[at] === '{') {
92
+ const bounds = /^\{([0-9]{1,4})(?:(,)([0-9]{1,4})?)?\}/.exec(pattern.slice(at));
93
+ if (!bounds)
94
+ return 'a malformed {n,m} quantifier';
95
+ if (bounds[3] !== undefined && Number(bounds[3]) < Number(bounds[1]))
96
+ return 'a {n,m} quantifier with m below n';
97
+ at += bounds[0].length;
98
+ }
99
+ else
100
+ at += 1;
101
+ const next = pattern[at];
102
+ if (next !== undefined && QUANTIFIERS.includes(next))
103
+ return 'a quantifier on a quantifier';
104
+ };
105
+ const disjunction = (depth) => {
106
+ let quantifiable = false;
107
+ while (at < pattern.length) {
108
+ const char = pattern[at];
109
+ if (char === '|') {
110
+ at += 1;
111
+ quantifiable = false;
112
+ }
113
+ else if (char === ')') {
114
+ if (depth === 0)
115
+ return 'an unmatched )';
116
+ return;
117
+ }
118
+ else if (char === '^' || char === '$') {
119
+ at += 1;
120
+ quantifiable = false;
121
+ }
122
+ else if (QUANTIFIERS.includes(char)) {
123
+ if (!quantifiable)
124
+ return char === '{' ? 'an unescaped {' : 'a quantifier with nothing to repeat';
125
+ const problem = quantifier();
126
+ if (problem)
127
+ return problem;
128
+ quantifiable = false;
129
+ }
130
+ else if (char === '(') {
131
+ if (!pattern.startsWith('(?:', at))
132
+ return 'a group other than (?:';
133
+ at += 3;
134
+ const problem = disjunction(depth + 1);
135
+ if (problem)
136
+ return problem;
137
+ if (pattern[at] !== ')')
138
+ return 'an unclosed group';
139
+ at += 1;
140
+ quantifiable = true;
141
+ }
142
+ else if (char === '[') {
143
+ const problem = characterClass();
144
+ if (problem)
145
+ return problem;
146
+ quantifiable = true;
147
+ }
148
+ else if (char === '\\') {
149
+ const code = escape(false);
150
+ if (typeof code === 'string')
151
+ return code;
152
+ quantifiable = true;
153
+ }
154
+ else if (char === '.')
155
+ return 'an unescaped dot';
156
+ else if (char === ']' || char === '}')
157
+ return `an unescaped ${char}`;
158
+ else {
159
+ at += 1;
160
+ quantifiable = true;
161
+ }
162
+ }
163
+ };
164
+ return disjunction(0);
165
+ }
@@ -0,0 +1,2 @@
1
+ /** The lowercase hexadecimal SHA-256 of the bytes, or of the text's UTF-8 encoding. */
2
+ export declare function sha256(input: string | Uint8Array): string;
@@ -0,0 +1,59 @@
1
+ // SHA-256 (FIPS 180-4) over bytes, so the core needs no platform crypto and runs the same
2
+ // in Node, browsers and workers.
3
+ const K = Uint32Array.from([
4
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
5
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
6
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
7
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
8
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
9
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
10
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
11
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
12
+ ]);
13
+ const rotate = (value, bits) => (value >>> bits) | (value << (32 - bits));
14
+ /** The lowercase hexadecimal SHA-256 of the bytes, or of the text's UTF-8 encoding. */
15
+ export function sha256(input) {
16
+ const bytes = typeof input === 'string' ? new TextEncoder().encode(input) : input;
17
+ // The message, a 1 bit, zeros, and its length in bits as a 64-bit big-endian integer.
18
+ const padded = new Uint8Array(Math.ceil((bytes.length + 9) / 64) * 64);
19
+ padded.set(bytes);
20
+ padded[bytes.length] = 0x80;
21
+ const view = new DataView(padded.buffer);
22
+ view.setUint32(padded.length - 8, Math.floor(bytes.length / 0x20000000));
23
+ view.setUint32(padded.length - 4, (bytes.length * 8) >>> 0);
24
+ const hash = Uint32Array.from([
25
+ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
26
+ ]);
27
+ const w = new Uint32Array(64);
28
+ for (let block = 0; block < padded.length; block += 64) {
29
+ for (let t = 0; t < 16; t += 1)
30
+ w[t] = view.getUint32(block + t * 4);
31
+ for (let t = 16; t < 64; t += 1) {
32
+ const s0 = rotate(w[t - 15], 7) ^ rotate(w[t - 15], 18) ^ (w[t - 15] >>> 3);
33
+ const s1 = rotate(w[t - 2], 17) ^ rotate(w[t - 2], 19) ^ (w[t - 2] >>> 10);
34
+ w[t] = w[t - 16] + s0 + w[t - 7] + s1;
35
+ }
36
+ let [a, b, c, d, e, f, g, h] = hash;
37
+ for (let t = 0; t < 64; t += 1) {
38
+ const t1 = h + (rotate(e, 6) ^ rotate(e, 11) ^ rotate(e, 25)) + ((e & f) ^ (~e & g)) + K[t] + w[t];
39
+ const t2 = (rotate(a, 2) ^ rotate(a, 13) ^ rotate(a, 22)) + ((a & b) ^ (a & c) ^ (b & c));
40
+ h = g;
41
+ g = f;
42
+ f = e;
43
+ e = (d + t1) >>> 0;
44
+ d = c;
45
+ c = b;
46
+ b = a;
47
+ a = (t1 + t2) >>> 0;
48
+ }
49
+ hash[0] += a;
50
+ hash[1] += b;
51
+ hash[2] += c;
52
+ hash[3] += d;
53
+ hash[4] += e;
54
+ hash[5] += f;
55
+ hash[6] += g;
56
+ hash[7] += h;
57
+ }
58
+ return Array.from(hash, (word) => word.toString(16).padStart(8, '0')).join('');
59
+ }
@@ -0,0 +1,210 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://mailschema.org/artifacts/map-0.3/schemas/core.schema.json",
4
+ "title": "MAP 0.3 description shape; semantic checks in Core are additionally required",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": [
8
+ "@context",
9
+ "@type",
10
+ "@id",
11
+ "profile",
12
+ "type",
13
+ "issuedAt",
14
+ "expiresAt",
15
+ "inLanguage",
16
+ "service",
17
+ "recipient",
18
+ "subject",
19
+ "terms",
20
+ "details",
21
+ "operations",
22
+ "human"
23
+ ],
24
+ "properties": {
25
+ "@context": {
26
+ "const": "https://mailschema.org/contexts/map-0.3.jsonld"
27
+ },
28
+ "@type": {
29
+ "const": "MailAction"
30
+ },
31
+ "@id": {
32
+ "type": "string",
33
+ "minLength": 1,
34
+ "format": "uri",
35
+ "maxLength": 2048
36
+ },
37
+ "profile": {
38
+ "const": "https://mailschema.org/profiles/map/0.3"
39
+ },
40
+ "type": {
41
+ "type": "object",
42
+ "additionalProperties": false,
43
+ "required": [
44
+ "id",
45
+ "version",
46
+ "contractDigest"
47
+ ],
48
+ "properties": {
49
+ "id": {
50
+ "type": "string",
51
+ "minLength": 1,
52
+ "format": "uri",
53
+ "pattern": "^https://",
54
+ "maxLength": 2048
55
+ },
56
+ "version": {
57
+ "type": "string",
58
+ "minLength": 1,
59
+ "maxLength": 64
60
+ },
61
+ "contractDigest": {
62
+ "type": "string",
63
+ "minLength": 1,
64
+ "pattern": "^sha-256:[0-9a-f]{64}$"
65
+ }
66
+ }
67
+ },
68
+ "issuedAt": {
69
+ "type": "string",
70
+ "minLength": 1,
71
+ "format": "date-time",
72
+ "pattern": "^\\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])T([01]\\d|2[0-3]):[0-5]\\d:[0-5]\\dZ$"
73
+ },
74
+ "expiresAt": {
75
+ "type": "string",
76
+ "minLength": 1,
77
+ "format": "date-time",
78
+ "pattern": "^\\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])T([01]\\d|2[0-3]):[0-5]\\d:[0-5]\\dZ$"
79
+ },
80
+ "inLanguage": {
81
+ "type": "string",
82
+ "minLength": 1,
83
+ "maxLength": 255
84
+ },
85
+ "service": {
86
+ "type": "object",
87
+ "additionalProperties": false,
88
+ "required": [
89
+ "id"
90
+ ],
91
+ "properties": {
92
+ "id": {
93
+ "type": "string",
94
+ "minLength": 1,
95
+ "format": "uri",
96
+ "pattern": "^https://(?![0-9.]+(:[0-9]+)?$)[A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*(:[0-9]{1,5})?$",
97
+ "maxLength": 2048
98
+ },
99
+ "tenant": {
100
+ "type": "string",
101
+ "minLength": 1,
102
+ "format": "uri",
103
+ "maxLength": 2048
104
+ }
105
+ }
106
+ },
107
+ "recipient": {
108
+ "type": "string",
109
+ "minLength": 1,
110
+ "maxLength": 320
111
+ },
112
+ "subject": {
113
+ "type": "object",
114
+ "additionalProperties": false,
115
+ "required": [
116
+ "id",
117
+ "title"
118
+ ],
119
+ "properties": {
120
+ "id": {
121
+ "type": "string",
122
+ "minLength": 1,
123
+ "format": "uri",
124
+ "maxLength": 2048
125
+ },
126
+ "title": {
127
+ "type": "string",
128
+ "minLength": 1,
129
+ "maxLength": 2048
130
+ }
131
+ }
132
+ },
133
+ "terms": {
134
+ "type": "object",
135
+ "additionalProperties": false,
136
+ "required": [
137
+ "id",
138
+ "version"
139
+ ],
140
+ "properties": {
141
+ "id": {
142
+ "type": "string",
143
+ "minLength": 1,
144
+ "format": "uri",
145
+ "maxLength": 2048
146
+ },
147
+ "version": {
148
+ "type": "string",
149
+ "minLength": 1,
150
+ "pattern": "^[ -~]+$",
151
+ "maxLength": 1024
152
+ }
153
+ }
154
+ },
155
+ "details": {
156
+ "type": "object"
157
+ },
158
+ "operations": {
159
+ "type": "array",
160
+ "items": {
161
+ "type": "object",
162
+ "additionalProperties": false,
163
+ "required": [
164
+ "id"
165
+ ],
166
+ "properties": {
167
+ "id": {
168
+ "type": "string",
169
+ "minLength": 1,
170
+ "pattern": "^[a-z][a-z0-9-]{0,63}$"
171
+ },
172
+ "capability": {
173
+ "type": "object",
174
+ "additionalProperties": false,
175
+ "required": [
176
+ "url"
177
+ ],
178
+ "properties": {
179
+ "url": {
180
+ "type": "string",
181
+ "minLength": 1,
182
+ "format": "uri",
183
+ "pattern": "^https://[^/?#@]+([/?][^#]*)?$",
184
+ "maxLength": 4096
185
+ }
186
+ }
187
+ }
188
+ }
189
+ },
190
+ "minItems": 1,
191
+ "maxItems": 32
192
+ },
193
+ "human": {
194
+ "type": "object",
195
+ "additionalProperties": false,
196
+ "required": [
197
+ "url"
198
+ ],
199
+ "properties": {
200
+ "url": {
201
+ "type": "string",
202
+ "minLength": 1,
203
+ "format": "uri",
204
+ "pattern": "^https://[^/?#@]+([/?][^#]*)?$",
205
+ "maxLength": 4096
206
+ }
207
+ }
208
+ }
209
+ }
210
+ }
@@ -0,0 +1,173 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://mailschema.org/artifacts/map-0.3/schemas/implementation.schema.json",
4
+ "title": "MAP implementation record",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": [
8
+ "service",
9
+ "maintainer",
10
+ "type",
11
+ "operations",
12
+ "binding",
13
+ "status",
14
+ "documentation",
15
+ "evidence"
16
+ ],
17
+ "dependentRequired": {
18
+ "artifact": ["format"],
19
+ "format": ["artifact"]
20
+ },
21
+ "properties": {
22
+ "service": {
23
+ "type": "string",
24
+ "minLength": 1,
25
+ "format": "uri",
26
+ "pattern": "^https://"
27
+ },
28
+ "maintainer": {
29
+ "type": "object",
30
+ "additionalProperties": false,
31
+ "required": [
32
+ "name",
33
+ "url"
34
+ ],
35
+ "properties": {
36
+ "name": {
37
+ "type": "string",
38
+ "minLength": 1
39
+ },
40
+ "url": {
41
+ "type": "string",
42
+ "minLength": 1,
43
+ "format": "uri",
44
+ "pattern": "^https://"
45
+ }
46
+ }
47
+ },
48
+ "type": {
49
+ "type": "object",
50
+ "additionalProperties": false,
51
+ "required": [
52
+ "id",
53
+ "version",
54
+ "contractDigest"
55
+ ],
56
+ "properties": {
57
+ "id": {
58
+ "type": "string",
59
+ "minLength": 1,
60
+ "format": "uri",
61
+ "pattern": "^https://"
62
+ },
63
+ "version": {
64
+ "type": "string",
65
+ "minLength": 1
66
+ },
67
+ "contractDigest": {
68
+ "type": "string",
69
+ "pattern": "^sha-256:[0-9a-f]{64}$"
70
+ }
71
+ }
72
+ },
73
+ "operations": {
74
+ "type": "array",
75
+ "minItems": 1,
76
+ "uniqueItems": true,
77
+ "items": {
78
+ "type": "string",
79
+ "minLength": 1
80
+ }
81
+ },
82
+ "binding": {
83
+ "type": "string",
84
+ "format": "uri",
85
+ "pattern": "^https://",
86
+ "description": "Identifier of the binding specification or documented service binding. It is not a request destination. Clients must explicitly support it."
87
+ },
88
+ "artifact": {
89
+ "type": "object",
90
+ "additionalProperties": false,
91
+ "required": [
92
+ "url",
93
+ "digest",
94
+ "digestMode"
95
+ ],
96
+ "properties": {
97
+ "url": {
98
+ "type": "string",
99
+ "minLength": 1,
100
+ "format": "uri",
101
+ "pattern": "^https://"
102
+ },
103
+ "digest": {
104
+ "type": "string",
105
+ "pattern": "^sha-256:[0-9a-f]{64}$"
106
+ },
107
+ "digestMode": {
108
+ "enum": [
109
+ "canonical-json",
110
+ "bytes"
111
+ ],
112
+ "description": "canonical-json hashes the RFC 8785 representation; bytes hashes the exact downloaded artifact. Both use SHA-256."
113
+ }
114
+ }
115
+ },
116
+ "format": {
117
+ "type": "string",
118
+ "minLength": 1
119
+ },
120
+ "status": {
121
+ "enum": [
122
+ "Draft",
123
+ "Experimental",
124
+ "Stable",
125
+ "Deprecated",
126
+ "Superseded"
127
+ ]
128
+ },
129
+ "documentation": {
130
+ "type": "string",
131
+ "minLength": 1,
132
+ "format": "uri",
133
+ "pattern": "^https://"
134
+ },
135
+ "evidence": {
136
+ "type": "array",
137
+ "minItems": 1,
138
+ "items": {
139
+ "type": "object",
140
+ "additionalProperties": false,
141
+ "required": [
142
+ "kind",
143
+ "url",
144
+ "summary"
145
+ ],
146
+ "properties": {
147
+ "kind": {
148
+ "enum": [
149
+ "declaration",
150
+ "test-report"
151
+ ]
152
+ },
153
+ "url": {
154
+ "type": "string",
155
+ "minLength": 1,
156
+ "format": "uri",
157
+ "pattern": "^https://"
158
+ },
159
+ "summary": {
160
+ "type": "string",
161
+ "minLength": 1
162
+ }
163
+ }
164
+ }
165
+ },
166
+ "successor": {
167
+ "type": "string",
168
+ "minLength": 1,
169
+ "format": "uri",
170
+ "pattern": "^https://"
171
+ }
172
+ }
173
+ }
package/dist/index.d.ts CHANGED
@@ -1,9 +1,5 @@
1
- export { contributionErrors, assertContribution, assertTypeRecord, referenceErrors, } from './validation.js';
2
- export type { CatalogView } from './validation.js';
3
- export { typeStages } from './model.js';
4
- export type { Party, TypeDefinition, TypeRecord, Contribution, Implementation } from './model.js';
5
- export { MAP_PROFILE, getMapSchema, getMapContext, getContractFormatSchema, getFormsSchema, } from './map.js';
6
- /** Return an independent copy of the contribution JSON Schema (Draft 2020-12). */
7
- export declare function getContributionSchema(): Record<string, unknown>;
8
- /** Return the schema for an expanded Registry record, including attribution and history. */
9
- export declare function getRecordSchema(): Record<string, unknown>;
1
+ /**
2
+ * Mail Action Protocol 0.3 processing: parse and check descriptions, type contracts and
3
+ * implementation records, and compute the RFC 8785 digests that identify contracts.
4
+ */
5
+ export * from './core/index.js';
package/dist/index.js CHANGED
@@ -1,13 +1,5 @@
1
- /** The MAP 0.2 core artifacts and validation tools for MailSchema Registry contributions. */
2
- import schema from './contribution.schema.json' with { type: 'json' };
3
- export { contributionErrors, assertContribution, assertTypeRecord, referenceErrors, } from './validation.js';
4
- export { typeStages } from './model.js';
5
- export { MAP_PROFILE, getMapSchema, getMapContext, getContractFormatSchema, getFormsSchema, } from './map.js';
6
- /** Return an independent copy of the contribution JSON Schema (Draft 2020-12). */
7
- export function getContributionSchema() {
8
- return structuredClone(schema);
9
- }
10
- /** Return the schema for an expanded Registry record, including attribution and history. */
11
- export function getRecordSchema() {
12
- return { $schema: schema.$schema, $defs: structuredClone(schema.$defs), $ref: '#/$defs/record' };
13
- }
1
+ /**
2
+ * Mail Action Protocol 0.3 processing: parse and check descriptions, type contracts and
3
+ * implementation records, and compute the RFC 8785 digests that identify contracts.
4
+ */
5
+ export * from './core/index.js';
@@ -0,0 +1,27 @@
1
+ {
2
+ "id": "https://mailschema.org/profiles/map/0.3",
3
+ "name": "Mail Action Protocol 0.3",
4
+ "status": "working-draft",
5
+ "description": "An action description carried in Structured Email. A trusted service binding maps each decision to the service's existing operations, and the service enforces permission and exact terms. Types are defined by digest-bound contracts.",
6
+ "context": "https://mailschema.org/contexts/map-0.3.jsonld",
7
+ "schema": "https://mailschema.org/artifacts/map-0.3/schemas/core.schema.json",
8
+ "contractFormat": "https://mailschema.org/artifacts/map-0.3/schemas/contract.schema.json",
9
+ "specification": "https://mailschema.org/specification/core",
10
+ "artifacts": {
11
+ "context": {
12
+ "url": "https://mailschema.org/contexts/map-0.3.jsonld",
13
+ "sha256": "a51490d1fe8af695c14ea508aad88fd0429d18564791b6b52f3ab07d5c51aab3"
14
+ },
15
+ "schema": {
16
+ "url": "https://mailschema.org/artifacts/map-0.3/schemas/core.schema.json",
17
+ "sha256": "0ad09a6955a47e7a2c1c1eec0747a3e0b15c08a79860e90ce4e65da11983aeb3"
18
+ },
19
+ "contractFormat": {
20
+ "url": "https://mailschema.org/artifacts/map-0.3/schemas/contract.schema.json",
21
+ "sha256": "86bf057529c4fd2c7f0a880825774afeed31e9f7ba1d99760858a585fe28d18d"
22
+ },
23
+ "conformance": {
24
+ "url": "https://github.com/mailschema/mailschema/blob/main/conformance/map-0.3/README.md"
25
+ }
26
+ }
27
+ }