mailschema 0.2.2 → 0.3.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 +27 -119
- package/bin/mailschema.js +42 -53
- package/dist/context.jsonld +50 -0
- package/dist/contract.schema.json +206 -0
- package/dist/core/artifacts.d.ts +11 -36
- package/dist/core/artifacts.js +21 -69
- package/dist/core/bundled.d.ts +4 -4
- package/dist/core/bundled.js +7 -7
- package/dist/core/contract.d.ts +59 -56
- package/dist/core/contract.js +224 -298
- package/dist/core/description.d.ts +45 -0
- package/dist/core/description.js +47 -0
- package/dist/core/implementation.d.ts +32 -0
- package/dist/core/implementation.js +25 -0
- package/dist/core/index.d.ts +7 -6
- package/dist/core/index.js +9 -9
- package/dist/core/json.d.ts +23 -0
- package/dist/core/{document.js → json.js} +61 -51
- package/dist/core/patterns.d.ts +12 -0
- package/dist/core/patterns.js +165 -0
- package/dist/core/sha256.d.ts +2 -0
- package/dist/core/sha256.js +59 -0
- package/dist/core.schema.json +210 -0
- package/dist/implementation.schema.json +173 -0
- package/dist/index.d.ts +4 -9
- package/dist/index.js +2 -14
- package/dist/profile.json +27 -0
- package/package.json +9 -10
- package/dist/contribution.schema.json +0 -874
- package/dist/core/binding.d.ts +0 -24
- package/dist/core/binding.js +0 -50
- package/dist/core/document.d.ts +0 -24
- package/dist/core/documents.d.ts +0 -68
- package/dist/core/documents.js +0 -145
- package/dist/core/limits.d.ts +0 -19
- package/dist/core/limits.js +0 -55
- package/dist/core/pointer.d.ts +0 -12
- package/dist/core/pointer.js +0 -48
- package/dist/core/schemas.d.ts +0 -21
- package/dist/core/schemas.js +0 -125
- package/dist/core/types.d.ts +0 -127
- package/dist/core/types.js +0 -2
- package/dist/forms-0.1.schema.json +0 -329
- package/dist/map-0.2.jsonld +0 -91
- package/dist/map-0.2.schema.json +0 -1033
- package/dist/map.d.ts +0 -8
- package/dist/map.js +0 -18
- package/dist/model.d.ts +0 -95
- package/dist/model.js +0 -5
- package/dist/type-contract-0.2.schema.json +0 -179
- package/dist/validation.d.ts +0 -15
- package/dist/validation.js +0 -64
package/dist/map.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/** A fresh copy of the MAP 0.2 core schema, as the profile record binds it by SHA-256. */
|
|
2
|
-
export declare function getMapSchema(): Record<string, unknown>;
|
|
3
|
-
/** A fresh copy of the MAP 0.2 JSON-LD context. */
|
|
4
|
-
export declare function getMapContext(): Record<string, unknown>;
|
|
5
|
-
/** A fresh copy of the type contract format every MAP 0.2 contract follows. */
|
|
6
|
-
export declare function getContractFormatSchema(): Record<string, unknown>;
|
|
7
|
-
/** A fresh copy of the form fields block contracts pin. */
|
|
8
|
-
export declare function getFormsSchema(): Record<string, unknown>;
|
package/dist/map.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from 'node:fs';
|
|
2
|
-
const artifact = (name) => JSON.parse(readFileSync(new URL(`./${name}`, import.meta.url), 'utf8'));
|
|
3
|
-
/** A fresh copy of the MAP 0.2 core schema, as the profile record binds it by SHA-256. */
|
|
4
|
-
export function getMapSchema() {
|
|
5
|
-
return artifact('map-0.2.schema.json');
|
|
6
|
-
}
|
|
7
|
-
/** A fresh copy of the MAP 0.2 JSON-LD context. */
|
|
8
|
-
export function getMapContext() {
|
|
9
|
-
return artifact('map-0.2.jsonld');
|
|
10
|
-
}
|
|
11
|
-
/** A fresh copy of the type contract format every MAP 0.2 contract follows. */
|
|
12
|
-
export function getContractFormatSchema() {
|
|
13
|
-
return artifact('type-contract-0.2.schema.json');
|
|
14
|
-
}
|
|
15
|
-
/** A fresh copy of the form fields block contracts pin. */
|
|
16
|
-
export function getFormsSchema() {
|
|
17
|
-
return artifact('forms-0.1.schema.json');
|
|
18
|
-
}
|
package/dist/model.d.ts
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
export declare const typeStages: readonly [{
|
|
2
|
-
readonly status: "Draft";
|
|
3
|
-
readonly singular: "draft";
|
|
4
|
-
readonly plural: "drafts";
|
|
5
|
-
}, {
|
|
6
|
-
readonly status: "Proposal";
|
|
7
|
-
readonly singular: "proposal";
|
|
8
|
-
readonly plural: "proposals";
|
|
9
|
-
}, {
|
|
10
|
-
readonly status: "Reuse assessment";
|
|
11
|
-
readonly singular: "reuse assessment";
|
|
12
|
-
readonly plural: "reuse assessments";
|
|
13
|
-
}];
|
|
14
|
-
export interface Party {
|
|
15
|
-
name: string;
|
|
16
|
-
url?: string;
|
|
17
|
-
}
|
|
18
|
-
export interface TypeDefinition {
|
|
19
|
-
slug: string;
|
|
20
|
-
name: string;
|
|
21
|
-
summary: string;
|
|
22
|
-
category: string;
|
|
23
|
-
status: (typeof typeStages)[number]['status'];
|
|
24
|
-
version: string | null;
|
|
25
|
-
profile: string;
|
|
26
|
-
overview: string;
|
|
27
|
-
target: string;
|
|
28
|
-
operations: {
|
|
29
|
-
id: string;
|
|
30
|
-
name: string;
|
|
31
|
-
description: string;
|
|
32
|
-
}[];
|
|
33
|
-
inputs: string;
|
|
34
|
-
results: string;
|
|
35
|
-
permissions: string;
|
|
36
|
-
humanRoute: string;
|
|
37
|
-
example: {
|
|
38
|
-
title: string;
|
|
39
|
-
steps: string[];
|
|
40
|
-
exception: string;
|
|
41
|
-
};
|
|
42
|
-
references: {
|
|
43
|
-
title: string;
|
|
44
|
-
href: string;
|
|
45
|
-
description: string;
|
|
46
|
-
}[];
|
|
47
|
-
openQuestions: string[];
|
|
48
|
-
maintainers: Party[];
|
|
49
|
-
definition?: {
|
|
50
|
-
label: string;
|
|
51
|
-
href: string;
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
export interface TypeRecord extends TypeDefinition {
|
|
55
|
-
origin: string;
|
|
56
|
-
contributors: Party[];
|
|
57
|
-
history: {
|
|
58
|
-
label: string;
|
|
59
|
-
description: string;
|
|
60
|
-
contributionId?: string;
|
|
61
|
-
}[];
|
|
62
|
-
}
|
|
63
|
-
interface Submission {
|
|
64
|
-
format: 'mailschema-contribution/1';
|
|
65
|
-
id: string;
|
|
66
|
-
contributor: Party;
|
|
67
|
-
source?: string;
|
|
68
|
-
summary: string;
|
|
69
|
-
}
|
|
70
|
-
export type Contribution = Submission & ({
|
|
71
|
-
kind: 'new-type';
|
|
72
|
-
record: TypeDefinition;
|
|
73
|
-
} | {
|
|
74
|
-
kind: 'amendment';
|
|
75
|
-
baseDigest: string;
|
|
76
|
-
record: TypeDefinition;
|
|
77
|
-
} | {
|
|
78
|
-
kind: 'implementation';
|
|
79
|
-
type: string;
|
|
80
|
-
typeVersion: string;
|
|
81
|
-
typeDigest: string;
|
|
82
|
-
profile: string;
|
|
83
|
-
product: Party;
|
|
84
|
-
operations: string[];
|
|
85
|
-
evidence: {
|
|
86
|
-
kind: 'declaration' | 'test-report';
|
|
87
|
-
url?: string;
|
|
88
|
-
reproduction?: string;
|
|
89
|
-
results?: string;
|
|
90
|
-
};
|
|
91
|
-
});
|
|
92
|
-
export type Implementation = Extract<Contribution, {
|
|
93
|
-
kind: 'implementation';
|
|
94
|
-
}>;
|
|
95
|
-
export {};
|
package/dist/model.js
DELETED
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "https://mailschema.org/schemas/type-contract-0.2.schema.json",
|
|
4
|
-
"title": "MailSchema type contract for MAP 0.2",
|
|
5
|
-
"description": "A versioned interaction contract: the details, inputs, results, authority, repeatability and consequences of each operation, with every schema it depends on pinned by digest.",
|
|
6
|
-
"type": "object",
|
|
7
|
-
"additionalProperties": false,
|
|
8
|
-
"properties": {
|
|
9
|
-
"kind": {
|
|
10
|
-
"const": "MapTypeContract"
|
|
11
|
-
},
|
|
12
|
-
"id": {
|
|
13
|
-
"type": "string",
|
|
14
|
-
"pattern": "^https://mailschema\\.org/types/[a-z][a-z0-9]*(?:-[a-z0-9]+)*$",
|
|
15
|
-
"maxLength": 2048
|
|
16
|
-
},
|
|
17
|
-
"version": {
|
|
18
|
-
"type": "string",
|
|
19
|
-
"pattern": "^[0-9]+\\.[0-9]+(?:\\.[0-9]+)?(?:-[a-zA-Z0-9.-]+)?$",
|
|
20
|
-
"maxLength": 80
|
|
21
|
-
},
|
|
22
|
-
"profile": {
|
|
23
|
-
"const": "https://mailschema.org/profiles/map/0.2"
|
|
24
|
-
},
|
|
25
|
-
"target": {
|
|
26
|
-
"$ref": "#/$defs/prose"
|
|
27
|
-
},
|
|
28
|
-
"dependencies": {
|
|
29
|
-
"type": "array",
|
|
30
|
-
"minItems": 1,
|
|
31
|
-
"maxItems": 20,
|
|
32
|
-
"items": {
|
|
33
|
-
"$ref": "#/$defs/schemaReference"
|
|
34
|
-
}
|
|
35
|
-
},
|
|
36
|
-
"detailsSchema": {
|
|
37
|
-
"type": "object"
|
|
38
|
-
},
|
|
39
|
-
"requestSchema": {
|
|
40
|
-
"$ref": "#/$defs/schemaReference"
|
|
41
|
-
},
|
|
42
|
-
"operations": {
|
|
43
|
-
"type": "array",
|
|
44
|
-
"minItems": 1,
|
|
45
|
-
"maxItems": 100,
|
|
46
|
-
"items": {
|
|
47
|
-
"type": "object",
|
|
48
|
-
"additionalProperties": false,
|
|
49
|
-
"properties": {
|
|
50
|
-
"id": {
|
|
51
|
-
"$ref": "#/$defs/token"
|
|
52
|
-
},
|
|
53
|
-
"effect": {
|
|
54
|
-
"$ref": "#/$defs/prose"
|
|
55
|
-
},
|
|
56
|
-
"authority": {
|
|
57
|
-
"type": "array",
|
|
58
|
-
"items": {
|
|
59
|
-
"enum": ["credential", "possession"]
|
|
60
|
-
},
|
|
61
|
-
"minItems": 1,
|
|
62
|
-
"maxItems": 2,
|
|
63
|
-
"uniqueItems": true
|
|
64
|
-
},
|
|
65
|
-
"consequences": {
|
|
66
|
-
"type": "array",
|
|
67
|
-
"items": {
|
|
68
|
-
"enum": [
|
|
69
|
-
"refusal",
|
|
70
|
-
"protection",
|
|
71
|
-
"record",
|
|
72
|
-
"disclosure",
|
|
73
|
-
"commitment",
|
|
74
|
-
"authorization",
|
|
75
|
-
"assertion"
|
|
76
|
-
]
|
|
77
|
-
},
|
|
78
|
-
"minItems": 1,
|
|
79
|
-
"maxItems": 7,
|
|
80
|
-
"uniqueItems": true
|
|
81
|
-
},
|
|
82
|
-
"repeatable": {
|
|
83
|
-
"type": "boolean"
|
|
84
|
-
},
|
|
85
|
-
"fieldBindings": {
|
|
86
|
-
"type": "array",
|
|
87
|
-
"minItems": 1,
|
|
88
|
-
"maxItems": 10,
|
|
89
|
-
"items": {
|
|
90
|
-
"type": "object",
|
|
91
|
-
"additionalProperties": false,
|
|
92
|
-
"properties": {
|
|
93
|
-
"input": {
|
|
94
|
-
"$ref": "#/$defs/pointer"
|
|
95
|
-
},
|
|
96
|
-
"fields": {
|
|
97
|
-
"$ref": "#/$defs/pointer"
|
|
98
|
-
}
|
|
99
|
-
},
|
|
100
|
-
"required": ["input", "fields"]
|
|
101
|
-
}
|
|
102
|
-
},
|
|
103
|
-
"results": {
|
|
104
|
-
"type": "array",
|
|
105
|
-
"minItems": 1,
|
|
106
|
-
"maxItems": 5,
|
|
107
|
-
"items": {
|
|
108
|
-
"type": "object",
|
|
109
|
-
"additionalProperties": false,
|
|
110
|
-
"properties": {
|
|
111
|
-
"state": {
|
|
112
|
-
"enum": ["accepted", "completed", "failed", "pending", "approval-required"]
|
|
113
|
-
},
|
|
114
|
-
"reasons": {
|
|
115
|
-
"type": "array",
|
|
116
|
-
"items": {
|
|
117
|
-
"$ref": "#/$defs/token"
|
|
118
|
-
},
|
|
119
|
-
"minItems": 1,
|
|
120
|
-
"maxItems": 20,
|
|
121
|
-
"uniqueItems": true
|
|
122
|
-
},
|
|
123
|
-
"outputSchema": {
|
|
124
|
-
"type": "object"
|
|
125
|
-
}
|
|
126
|
-
},
|
|
127
|
-
"required": ["state", "outputSchema"]
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
},
|
|
131
|
-
"required": ["id", "effect", "authority", "consequences", "results"]
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
},
|
|
135
|
-
"required": [
|
|
136
|
-
"kind",
|
|
137
|
-
"id",
|
|
138
|
-
"version",
|
|
139
|
-
"profile",
|
|
140
|
-
"target",
|
|
141
|
-
"dependencies",
|
|
142
|
-
"requestSchema",
|
|
143
|
-
"operations"
|
|
144
|
-
],
|
|
145
|
-
"$defs": {
|
|
146
|
-
"prose": {
|
|
147
|
-
"type": "string",
|
|
148
|
-
"minLength": 1,
|
|
149
|
-
"maxLength": 12000,
|
|
150
|
-
"pattern": "[^\\t\\n\\u000b\\f\\r \\u00a0\\u1680\\u2000-\\u200a\\u2028\\u2029\\u202f\\u205f\\u3000\\ufeff]"
|
|
151
|
-
},
|
|
152
|
-
"token": {
|
|
153
|
-
"type": "string",
|
|
154
|
-
"pattern": "^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$",
|
|
155
|
-
"maxLength": 100
|
|
156
|
-
},
|
|
157
|
-
"pointer": {
|
|
158
|
-
"type": "string",
|
|
159
|
-
"pattern": "^(?:/(?:[^~/]|~[01])*)+$",
|
|
160
|
-
"maxLength": 1000
|
|
161
|
-
},
|
|
162
|
-
"schemaReference": {
|
|
163
|
-
"type": "object",
|
|
164
|
-
"additionalProperties": false,
|
|
165
|
-
"properties": {
|
|
166
|
-
"url": {
|
|
167
|
-
"type": "string",
|
|
168
|
-
"pattern": "^https://mailschema\\.org/schemas/[a-z0-9.-]+\\.json$",
|
|
169
|
-
"maxLength": 2048
|
|
170
|
-
},
|
|
171
|
-
"canonicalDigest": {
|
|
172
|
-
"type": "string",
|
|
173
|
-
"pattern": "^sha-256:[a-f0-9]{64}$"
|
|
174
|
-
}
|
|
175
|
-
},
|
|
176
|
-
"required": ["url", "canonicalDigest"]
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
package/dist/validation.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { Contribution, TypeRecord } from './model.ts';
|
|
2
|
-
export declare function contributionErrors(value: unknown): string[];
|
|
3
|
-
export declare function assertContribution(value: unknown): asserts value is Contribution;
|
|
4
|
-
export declare function assertTypeRecord(value: unknown): asserts value is TypeRecord;
|
|
5
|
-
export interface CatalogView {
|
|
6
|
-
types: {
|
|
7
|
-
record: TypeRecord;
|
|
8
|
-
digest: string;
|
|
9
|
-
}[];
|
|
10
|
-
snapshots: {
|
|
11
|
-
record: TypeRecord;
|
|
12
|
-
digest: string;
|
|
13
|
-
}[];
|
|
14
|
-
}
|
|
15
|
-
export declare function referenceErrors(input: Contribution, catalog: CatalogView): string[];
|
package/dist/validation.js
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import Ajv2020 from 'ajv/dist/2020.js';
|
|
2
|
-
import addFormats from 'ajv-formats';
|
|
3
|
-
import schema from './contribution.schema.json' with { type: 'json' };
|
|
4
|
-
const ajv = new Ajv2020({ allErrors: true, strict: true, strictRequired: false });
|
|
5
|
-
addFormats(ajv);
|
|
6
|
-
const contribution = ajv.compile(schema);
|
|
7
|
-
const variants = new Map(schema.oneOf.map((variant) => [
|
|
8
|
-
variant.properties.kind.const,
|
|
9
|
-
ajv.compile({ $schema: schema.$schema, $defs: schema.$defs, ...variant }),
|
|
10
|
-
]));
|
|
11
|
-
const record = ajv.compile({
|
|
12
|
-
$schema: schema.$schema,
|
|
13
|
-
$defs: schema.$defs,
|
|
14
|
-
$ref: '#/$defs/record',
|
|
15
|
-
});
|
|
16
|
-
export function contributionErrors(value) {
|
|
17
|
-
const kind = value && typeof value === 'object' && 'kind' in value ? value.kind : undefined;
|
|
18
|
-
const validate = typeof kind === 'string' ? variants.get(kind) || contribution : contribution;
|
|
19
|
-
if (validate(value))
|
|
20
|
-
return [];
|
|
21
|
-
return (validate.errors || []).map((error) => `${error.instancePath || '/'} ${error.message}${error.keyword === 'required' ? `: ${error.params.missingProperty}` : ''}`);
|
|
22
|
-
}
|
|
23
|
-
export function assertContribution(value) {
|
|
24
|
-
const errors = contributionErrors(value);
|
|
25
|
-
if (errors.length)
|
|
26
|
-
throw new Error(`Invalid contribution:\n${errors.join('\n')}`);
|
|
27
|
-
}
|
|
28
|
-
export function assertTypeRecord(value) {
|
|
29
|
-
if (!record(value))
|
|
30
|
-
throw new Error(`Invalid type record: ${ajv.errorsText(record.errors, { separator: '\n' })}`);
|
|
31
|
-
}
|
|
32
|
-
export function referenceErrors(input, catalog) {
|
|
33
|
-
const errors = [];
|
|
34
|
-
if (input.kind === 'implementation') {
|
|
35
|
-
const target = catalog.snapshots.find((item) => item.digest === input.typeDigest)?.record;
|
|
36
|
-
if (!target || target.slug !== input.type || target.version !== input.typeVersion)
|
|
37
|
-
return [
|
|
38
|
-
'Unknown type version or record digest. Download the current record from the Registry.',
|
|
39
|
-
];
|
|
40
|
-
if (target.profile !== input.profile)
|
|
41
|
-
errors.push('Execution profile does not match the targeted record.');
|
|
42
|
-
const operations = new Set(target.operations.map((operation) => operation.id));
|
|
43
|
-
if (new Set(input.operations).size !== input.operations.length ||
|
|
44
|
-
input.operations.some((operation) => !operations.has(operation)))
|
|
45
|
-
errors.push('Unknown or duplicate operation in the implementation declaration.');
|
|
46
|
-
}
|
|
47
|
-
else {
|
|
48
|
-
const existing = catalog.types.find((item) => item.record.slug === input.record.slug);
|
|
49
|
-
if (input.kind === 'new-type' && existing)
|
|
50
|
-
errors.push('This type already exists. Submit an amendment instead.');
|
|
51
|
-
if (input.kind === 'amendment' && (!existing || existing.digest !== input.baseDigest))
|
|
52
|
-
errors.push('Stale or unknown amendment base. Download the current record and reconcile your changes.');
|
|
53
|
-
if (catalog.types.some((item) => item.record.slug !== input.record.slug &&
|
|
54
|
-
item.record.name.toLocaleLowerCase() === input.record.name.toLocaleLowerCase()))
|
|
55
|
-
errors.push('Another type already uses this name.');
|
|
56
|
-
const operationIds = input.record.operations.map((operation) => operation.id);
|
|
57
|
-
const operationNames = input.record.operations.map((operation) => operation.name.toLocaleLowerCase());
|
|
58
|
-
if (new Set(operationIds).size !== operationIds.length)
|
|
59
|
-
errors.push('Operation identifiers must be unique within a type.');
|
|
60
|
-
if (new Set(operationNames).size !== operationNames.length)
|
|
61
|
-
errors.push('Operation names must be unique within a type.');
|
|
62
|
-
}
|
|
63
|
-
return errors;
|
|
64
|
-
}
|