@bsv/dpp-profiles 0.3.0-beta.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/LICENSE +58 -0
- package/README.md +64 -0
- package/dist/applicability.d.ts +96 -0
- package/dist/applicability.d.ts.map +1 -0
- package/dist/applicability.js +181 -0
- package/dist/applicability.js.map +1 -0
- package/dist/combinations.d.ts +30 -0
- package/dist/combinations.d.ts.map +1 -0
- package/dist/combinations.js +103 -0
- package/dist/combinations.js.map +1 -0
- package/dist/evidence-shapes.d.ts +198 -0
- package/dist/evidence-shapes.d.ts.map +1 -0
- package/dist/evidence-shapes.js +123 -0
- package/dist/evidence-shapes.js.map +1 -0
- package/dist/gs1-epc-binary.d.ts +81 -0
- package/dist/gs1-epc-binary.d.ts.map +1 -0
- package/dist/gs1-epc-binary.js +252 -0
- package/dist/gs1-epc-binary.js.map +1 -0
- package/dist/gs1-resolution.d.ts +392 -0
- package/dist/gs1-resolution.d.ts.map +1 -0
- package/dist/gs1-resolution.js +696 -0
- package/dist/gs1-resolution.js.map +1 -0
- package/dist/identifiers.d.ts +57 -0
- package/dist/identifiers.d.ts.map +1 -0
- package/dist/identifiers.js +117 -0
- package/dist/identifiers.js.map +1 -0
- package/dist/index.d.ts +235 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +124 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest-v2.d.ts +87 -0
- package/dist/manifest-v2.d.ts.map +1 -0
- package/dist/manifest-v2.js +31 -0
- package/dist/manifest-v2.js.map +1 -0
- package/dist/mapping.d.ts +84 -0
- package/dist/mapping.d.ts.map +1 -0
- package/dist/mapping.js +88 -0
- package/dist/mapping.js.map +1 -0
- package/dist/projections.d.ts +233 -0
- package/dist/projections.d.ts.map +1 -0
- package/dist/projections.js +466 -0
- package/dist/projections.js.map +1 -0
- package/frozen.json +42 -0
- package/generated/consumer/battery-v2.json +2248 -0
- package/generated/consumer/battery-v3.json +4354 -0
- package/generated/consumer/general-v1.json +9 -0
- package/generated/consumer/general-v2.json +714 -0
- package/generated/consumer/textile-v1.json +101 -0
- package/generated/consumer/textile-v2.json +1033 -0
- package/generated/consumer/textile-v3.json +2011 -0
- package/generated/index.json +86 -0
- package/generated/mapping/battery@2.md +116 -0
- package/generated/mapping/battery@3.md +130 -0
- package/generated/mapping/general@2.md +50 -0
- package/generated/mapping/textile@2.md +61 -0
- package/generated/mapping/textile@3.md +73 -0
- package/generated/payload-schema/battery@2.public.schema.json +609 -0
- package/generated/payload-schema/battery@2.restricted.schema.json +377 -0
- package/generated/payload-schema/battery@3.public.schema.json +1364 -0
- package/generated/payload-schema/battery@3.restricted.schema.json +1097 -0
- package/generated/payload-schema/general@1.public.schema.json +37 -0
- package/generated/payload-schema/general@1.restricted.schema.json +9 -0
- package/generated/payload-schema/general@2.public.schema.json +352 -0
- package/generated/payload-schema/general@2.restricted.schema.json +52 -0
- package/generated/payload-schema/textile@1.public.schema.json +82 -0
- package/generated/payload-schema/textile@1.restricted.schema.json +22 -0
- package/generated/payload-schema/textile@2.public.schema.json +464 -0
- package/generated/payload-schema/textile@2.restricted.schema.json +78 -0
- package/generated/payload-schema/textile@3.public.schema.json +1299 -0
- package/generated/payload-schema/textile@3.restricted.schema.json +78 -0
- package/manifests/battery@2.json +4047 -0
- package/manifests/battery@3.json +6164 -0
- package/manifests/exchange/untp-0.7.0-jose@1.json +191 -0
- package/manifests/exchange/vc-di-ecdsa-rdfc-2019@1.json +74 -0
- package/manifests/exchange/vsc-draft-compat@0.1.0.json +64 -0
- package/manifests/general@1.json +148 -0
- package/manifests/general@2.json +1266 -0
- package/manifests/interoperability/epcis-json@1.json +69 -0
- package/manifests/interoperability/epcis-vsc@1.json +64 -0
- package/manifests/interoperability/gs1-digital-link@1.json +71 -0
- package/manifests/operator/federated-operators@1.json +54 -0
- package/manifests/operator/single-operator@1.json +52 -0
- package/manifests/textile@1.json +383 -0
- package/manifests/textile@2.json +1682 -0
- package/manifests/textile@3.json +2763 -0
- package/package.json +59 -0
- package/schemas/exchange-profile.schema.json +134 -0
- package/schemas/gs1/NOTICE.md +11 -0
- package/schemas/gs1/resolver-description-file-schema-1.2.0.json +124 -0
- package/schemas/gs1/resolver-linkset-context-1.2.1.jsonld +39 -0
- package/schemas/gs1/resolver-linkset-schema-1.2.1.json +96 -0
- package/schemas/interoperability-profile.schema.json +347 -0
- package/schemas/operator-profile.schema.json +108 -0
- package/schemas/product-identity.schema.json +45 -0
- package/schemas/profile-manifest-v2.schema.json +1087 -0
- package/schemas/profile-manifest.schema.json +291 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
Open BSV License Version 6 – granted by BSV Association, Alpenstrasse 15, 6300
|
|
2
|
+
Zug, Switzerland (CHE-427.008.338) ("Licensor"), to you as a user (henceforth
|
|
3
|
+
"You", "User" or "Licensee").
|
|
4
|
+
|
|
5
|
+
For the purposes of this license, the definitions below have the following
|
|
6
|
+
meanings:
|
|
7
|
+
|
|
8
|
+
"Bitcoin Protocol" means the protocol implementation, cryptographic rules,
|
|
9
|
+
network protocols, and consensus mechanisms in the Bitcoin White Paper as
|
|
10
|
+
described here https://protocol.bsvblockchain.org.
|
|
11
|
+
|
|
12
|
+
"Bitcoin White Paper" means the paper entitled 'Bitcoin: A Peer-to-Peer
|
|
13
|
+
Electronic Cash System' published by 'Satoshi Nakamoto' in October 2008.
|
|
14
|
+
|
|
15
|
+
"BSV Blockchain" means:
|
|
16
|
+
|
|
17
|
+
(a) the Bitcoin blockchain containing block height #556767 with the hash
|
|
18
|
+
"000000000000000001d956714215d96ffc00e0afda4cd0a96c96f8d802b1662b" and
|
|
19
|
+
that contains the longest honest persistent chain of blocks which has been
|
|
20
|
+
produced in a manner which is consistent with the rules set forth in the
|
|
21
|
+
Network Access Rules; and
|
|
22
|
+
(b) the test blockchains that contain the longest honest persistent chains of
|
|
23
|
+
blocks which has been produced in a manner which is consistent with the
|
|
24
|
+
rules set forth in the Network Access Rules.
|
|
25
|
+
|
|
26
|
+
"Network Access Rules" or "Rules" means the set of rules regulating the
|
|
27
|
+
relationship between BSV Association and the nodes on BSV based on the Bitcoin
|
|
28
|
+
Protocol rules and those set out in the Bitcoin White Paper, and available here
|
|
29
|
+
https://bsvblockchain.org/network-access-rules.
|
|
30
|
+
|
|
31
|
+
"Software" means the software the subject of this license, including any/all
|
|
32
|
+
intellectual property rights therein and associated documentation files.
|
|
33
|
+
|
|
34
|
+
BSV Association grants permission, free of charge and on a non-exclusive basis
|
|
35
|
+
to any person obtaining a copy of the Software to deal in the Software, including
|
|
36
|
+
without limitation the rights to use, copy, modify, merge, publish, distribute,
|
|
37
|
+
sublicense, and/or sell copies of the Software, and to permit persons to whom the
|
|
38
|
+
Software is furnished to do so, subject to and conditioned upon the following
|
|
39
|
+
conditions:
|
|
40
|
+
|
|
41
|
+
1 - The text "© BSV Association", and this license shall be included in all
|
|
42
|
+
copies or substantial portions of the Software.
|
|
43
|
+
|
|
44
|
+
2 - The Software, and any software that is derived from the Software or parts
|
|
45
|
+
thereof, may only be used exclusively on the BSV Blockchain.
|
|
46
|
+
|
|
47
|
+
For the avoidance of doubt, this license is granted subject to and conditioned
|
|
48
|
+
upon your compliance with these terms only and is limited to uses on the BSV
|
|
49
|
+
Blockchain. Any exercise of rights not compliant with these terms including
|
|
50
|
+
use not for the BSV Blockchain is deemed outside the scope of the license.
|
|
51
|
+
|
|
52
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
53
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES REGARDING ENTITLEMENT,
|
|
54
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
|
|
55
|
+
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS THEREOF BE LIABLE FOR ANY CLAIM,
|
|
56
|
+
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
57
|
+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
58
|
+
DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# @bsv/dpp-profiles
|
|
2
|
+
|
|
3
|
+
**Experimental prerelease:** For implementation and interoperability testing. APIs may change significantly before a stable release. Pin exact package versions and retain your lockfile. This package is not declared production-ready. Package versions are separate from the specification, wire-format and frozen profile versions they implement.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
This is a pre-1.0 candidate. After publication, install the selected version from npm:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npm install --save-exact @bsv/dpp-profiles@0.3.0-beta.1
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The runtime requires Node >=22 and ECMAScript modules. The JSON data exports can be read in other runtimes. No repository checkout or package build is needed after installation.
|
|
14
|
+
|
|
15
|
+
The canonical industry data profiles of the DPP standard, as `spec/profiles.md` defines them: immutable manifests, the artefacts generated from them, the digests they are frozen at, and the GS1 identifier helpers a writer uses to mint an identifier it can stand behind. Data first: the manifests, schemas and generated documents are plain files any language reads, and the one runtime dependency of the code beside them is the RFC 8785 canonicaliser (`canonicalize`) the projection digest uses. The code reads its data files through the Node file system, so the root entry point is a Node module; a browser or another language reads the data files directly through the `./manifests/*`, `./schemas/*`, `./generated/*` and `./frozen.json` entry points.
|
|
16
|
+
|
|
17
|
+
## What is in it
|
|
18
|
+
|
|
19
|
+
| Path | What it is |
|
|
20
|
+
|---|---|
|
|
21
|
+
| `manifests/<id>@<version>.json` | The canonical definition of one profile: every field with its pointer, semantic URI, value type, unit or code list, resolved constraints, cardinality, granularity, provenance, access tier, obligation, legal basis and applicability; the stamps, event mappings, access tiers, sources and identity model. Immutable once published. |
|
|
22
|
+
| `schemas/profile-manifest.schema.json` | The JSON Schema (2020-12) every manifest validates against. |
|
|
23
|
+
| `schemas/product-identity.schema.json` | The model, batch and item identity document a passport may relate. |
|
|
24
|
+
| `generated/payload-schema/<profile>.public.schema.json` | The JSON Schema for the public payload carried on chain, generated from the manifest. |
|
|
25
|
+
| `generated/payload-schema/<profile>.restricted.schema.json` | The same for the off-chain restricted tiers. |
|
|
26
|
+
| `generated/consumer/<id>-v<version>.json` | The legacy consumer document the registry serves and the application publishes, generated from the manifest. |
|
|
27
|
+
| `generated/mapping/<profile>.md` | The row-level field mapping inventory of each current profile, generated from the manifest; `needs review` where no generator can decide. |
|
|
28
|
+
| `generated/index.json` | Every file with its digest. |
|
|
29
|
+
| `frozen.json` | The digests every published manifest and generated file is held to. |
|
|
30
|
+
| `src/identifiers.ts` | GS1 check digit, GTIN-14 spelling, the demonstration prefix 952 and the Digital Link path parser and builder. |
|
|
31
|
+
| `src/combinations.ts` | `checkSelection`: supported combinations of baseline, industry, exchange and operator profiles pass, and contradictory selections are refused by name (a write under a superseded version, a claim on a proposed profile, a single operator with peers, a federation of one). |
|
|
32
|
+
| `src/mapping.ts` | `mapNativeOperation`: the conditional lifecycle mapping of `spec/rules.md` §2, one of four outcomes with a loss list on every outcome that is not lossless. |
|
|
33
|
+
| `src/gs1-resolution.ts`, `src/gs1-epc-binary.ts` | The `gs1-digital-link@1` discovery profile (`spec/gs1-discovery.md`): the full grammar for primary key 01 with its qualifiers and data attributes, key-tuple equivalence across hosts, EPC-binary decompression for SGTIN-96 and SGTIN-198, resolution records, the linkset hierarchy and selection, and the resolver description file; `schemas/gs1/` carries the pinned GS1 resolver schemas. |
|
|
34
|
+
| `manifests/interoperability/*.json`, `schemas/interoperability-profile.schema.json` | The interoperability profiles: discovery (`gs1-digital-link@1`), source exchange (`epcis-json@1`) and mapping (`epcis-vsc@1`), each recording its standards, pinned artefacts, formats, limits and what it cannot map. |
|
|
35
|
+
| `src/evidence-shapes.ts`, `src/applicability.ts`, `src/projections.ts` | The shared evidence, measurement, certification, document and language shapes of `contracts/profile-evidence.schema.json`, the declarative applicability evaluator of manifest version 2 (`schemas/profile-manifest-v2.schema.json`) whose `unresolved` outcome is never a pass, and `projectPassport`, the pure deterministic `passport-projection@1` of `spec/passport-projections.md` over versioned model, batch and item sources, digested under RFC 8785. |
|
|
36
|
+
|
|
37
|
+
Five profiles are published: `battery@2`, `textile@2` and `general@2` (current) and `textile@1` and `general@1` (superseded, and served for as long as any state declares them). They were inventoried from the application's attribute registries in full, including the fields captured over life or derived rather than at registration, and frozen. `battery@3` and `textile@3` are draft successors under manifest version 2: opt-in by explicit version, carrying a requirement status per field and a migration outcome per field, and leaving every byte of the two current versions unchanged until a reviewed cutover.
|
|
38
|
+
|
|
39
|
+
## Working on it
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
npm run build # tsc, then the generator: regenerates generated/ and refuses drift from frozen.json
|
|
43
|
+
npm run generate # the generator alone
|
|
44
|
+
npm run refreeze # writes the current digests into the manifests and frozen.json; review that diff
|
|
45
|
+
npm test # schema validity, uniqueness, freezing, deterministic generation, payload validation, identifiers, lifecycle mapping
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
A frozen profile changes only by publishing a new version. A corrected mandatory field, a changed meaning or an incompatible validation rule is a new version; a state decodes under the version it declares and is never reinterpreted under a newer one. `--refreeze` exists for a reviewed change to the generator's output for an existing version, and the diff it produces is the review.
|
|
49
|
+
|
|
50
|
+
## Using it
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import { readManifest, fieldsFor, missingRequired, parseGs1DigitalLink, parseGs1DigitalLinkUri, decompressGs1DigitalLink, projectPassport } from '@bsv/dpp-profiles'
|
|
54
|
+
|
|
55
|
+
const battery = readManifest('battery@2')
|
|
56
|
+
const { applies, needsReview } = fieldsFor(battery, 'ev')
|
|
57
|
+
const gaps = missingRequired(battery, payload, 'ev') // gaps.missing blocks; gaps.needsReview is shown, never assumed
|
|
58
|
+
const link = parseGs1DigitalLink(passportId) // link.checkDigitValid, link.demonstration, never allocation authority
|
|
59
|
+
const request = parseGs1DigitalLinkUri(uri) // key 01 with 22, 10 and 21, data attributes, linkType; never an exception
|
|
60
|
+
const plain = decompressGs1DigitalLink(compressed) // eh and ex forms carrying SGTIN-96 or SGTIN-198; other schemes refused by name
|
|
61
|
+
const { projection } = projectPassport(input) // one digest for one set of pinned sources, policy, cutoff and disclosure
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
A consumer validates a public payload against the generated schema with a validator that asserts formats and refuses an unknown dialect, and reads `needs-review` as a list to show a person, never as satisfied and never as universally required. Syntax and a correct check digit never prove that GS1 allocated a number to the brand a record describes.
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The declarative applicability evaluator (`spec/profiles.md` §3,
|
|
3
|
+
* `spec/passport-projections.md` §6). A rule is data, never an expression:
|
|
4
|
+
* category membership, jurisdiction, an effective interval, a numeric
|
|
5
|
+
* threshold on a payload value, `all` and `any` over those, `needs-review`
|
|
6
|
+
* for what only a person can decide, and `unresolved` for what the primary
|
|
7
|
+
* source could not establish. Three outcomes and never a fourth: a field
|
|
8
|
+
* applies, does not apply, or is unresolved. Unresolved is not satisfied and
|
|
9
|
+
* is not a failure either; it is shown, and it never becomes a pass.
|
|
10
|
+
*/
|
|
11
|
+
import type { ApplicabilityRule, ProfileManifest } from './index.js';
|
|
12
|
+
import { type AnyProfileField, type AnyProfileManifest, type ApplicabilityRuleV2 } from './manifest-v2.js';
|
|
13
|
+
export type ApplicabilityOutcome = 'applies' | 'not-applicable' | 'unresolved';
|
|
14
|
+
export interface ApplicabilityContext {
|
|
15
|
+
/** The product category, as the manifest's `applicability.categoryKey` payload value names it. */
|
|
16
|
+
category?: string;
|
|
17
|
+
/** The jurisdiction the passport is evaluated for, for example `EU`. */
|
|
18
|
+
jurisdiction?: string;
|
|
19
|
+
/** The date or instant the evaluation is made at, for `effective` rules. */
|
|
20
|
+
asOf?: string;
|
|
21
|
+
/** Payload values a `threshold` rule may read, as numbers or as `{ value, unit }`. */
|
|
22
|
+
values?: Record<string, unknown>;
|
|
23
|
+
/**
|
|
24
|
+
* The field keys the record declares inapplicable under `inapplicableFields`
|
|
25
|
+
* (`spec/profiles.md` §3): a declaration by the declaring party, with a
|
|
26
|
+
* reason, that a conditional data point does not apply to this record. It
|
|
27
|
+
* turns an unresolved field into not-applicable with the reason `declared`;
|
|
28
|
+
* it never makes a required, enacted, unconditionally applicable field
|
|
29
|
+
* optional, because a declaration is not a value.
|
|
30
|
+
*/
|
|
31
|
+
declaredNotApplicable?: string[];
|
|
32
|
+
}
|
|
33
|
+
export interface ApplicabilityResult {
|
|
34
|
+
outcome: ApplicabilityOutcome;
|
|
35
|
+
reasons: string[];
|
|
36
|
+
}
|
|
37
|
+
export declare function evaluateApplicability(rule: ApplicabilityRule | ApplicabilityRuleV2, ctx?: ApplicabilityContext): ApplicabilityResult;
|
|
38
|
+
/** The key under which a record declares fields inapplicable, and the shape of each declaration. */
|
|
39
|
+
export declare const INAPPLICABLE_FIELDS_KEY = "inapplicableFields";
|
|
40
|
+
export interface InapplicabilityDeclaration {
|
|
41
|
+
field: string;
|
|
42
|
+
reason: string;
|
|
43
|
+
declaredBy?: string;
|
|
44
|
+
}
|
|
45
|
+
/** The declarations a payload carries under `inapplicableFields`, as field keys; malformed entries are ignored, never read as a declaration. */
|
|
46
|
+
export declare function declaredInapplicable(payload: Record<string, unknown> | undefined): string[];
|
|
47
|
+
/**
|
|
48
|
+
* A field's applicability under a context: a declaration under
|
|
49
|
+
* `inapplicableFields` answers not-applicable with the reason `declared`
|
|
50
|
+
* only where the rule would otherwise be unresolved or conditional, so a
|
|
51
|
+
* declaration cannot switch off a field that applies unconditionally; the
|
|
52
|
+
* rule answers otherwise.
|
|
53
|
+
*/
|
|
54
|
+
export declare function evaluateFieldApplicability(field: Pick<AnyProfileField, 'key' | 'applicability'>, ctx?: ApplicabilityContext): ApplicabilityResult;
|
|
55
|
+
export interface FieldsForResult<F extends AnyProfileField> {
|
|
56
|
+
applies: F[];
|
|
57
|
+
notApplicable: F[];
|
|
58
|
+
unresolved: Array<{
|
|
59
|
+
field: F;
|
|
60
|
+
reasons: string[];
|
|
61
|
+
}>;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* The fields of a version 1 or version 2 manifest under a context: what
|
|
65
|
+
* applies, what does not, and what is unresolved with its reasons. The
|
|
66
|
+
* version 1 `fieldsFor` remains the reader for version 1 manifests with a
|
|
67
|
+
* bare category; this one takes the whole context.
|
|
68
|
+
*/
|
|
69
|
+
export declare function fieldsForV2<M extends AnyProfileManifest>(manifest: M, ctx?: ApplicabilityContext): FieldsForResult<M['fields'][number]>;
|
|
70
|
+
export interface MissingRequiredV2Result<F extends AnyProfileField> {
|
|
71
|
+
/** Required, applicable, captured at registration, and absent: this blocks. */
|
|
72
|
+
missing: F[];
|
|
73
|
+
/** Required and absent, but whether it applies is unresolved: shown, never blocking, never satisfied. */
|
|
74
|
+
unresolved: Array<{
|
|
75
|
+
field: F;
|
|
76
|
+
reasons: string[];
|
|
77
|
+
}>;
|
|
78
|
+
/** Required in the profile's own terms but whose requirement status defers it: anticipated, not to be displayed, or under review. Never counted as missing. */
|
|
79
|
+
deferred: Array<{
|
|
80
|
+
field: F;
|
|
81
|
+
status: string;
|
|
82
|
+
}>;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Which required fields a payload lacks under a context, on three separate
|
|
86
|
+
* lists. A field whose applicability is unresolved is never missing and never
|
|
87
|
+
* satisfied; a field whose requirement status is anticipated, not to be
|
|
88
|
+
* displayed or under review is deferred and never blocks, so an adopter can
|
|
89
|
+
* keep incomplete draft data without a false failure or a false pass. A
|
|
90
|
+
* field the payload declares inapplicable under `inapplicableFields` is
|
|
91
|
+
* not-applicable where it would otherwise be unresolved.
|
|
92
|
+
*/
|
|
93
|
+
export declare function missingRequiredV2<M extends AnyProfileManifest>(manifest: M, payload: Record<string, unknown>, ctx?: ApplicabilityContext): MissingRequiredV2Result<M['fields'][number]>;
|
|
94
|
+
/** The category value a payload names for a manifest, read at the manifest's declared category key. */
|
|
95
|
+
export declare function categoryOf(manifest: Pick<ProfileManifest, 'applicability'>, payload: Record<string, unknown> | undefined): string | undefined;
|
|
96
|
+
//# sourceMappingURL=applicability.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"applicability.d.ts","sourceRoot":"","sources":["../src/applicability.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAgB,MAAM,YAAY,CAAA;AAClF,OAAO,EAAa,KAAK,eAAe,EAAE,KAAK,kBAAkB,EAAE,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AAErH,MAAM,MAAM,oBAAoB,GAAG,SAAS,GAAG,gBAAgB,GAAG,YAAY,CAAA;AAE9E,MAAM,WAAW,oBAAoB;IACnC,kGAAkG;IAClG,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,wEAAwE;IACxE,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,sFAAsF;IACtF,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAChC;;;;;;;OAOG;IACH,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAA;CACjC;AAED,MAAM,WAAW,mBAAmB;IAAG,OAAO,EAAE,oBAAoB,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE;AAwBzF,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,iBAAiB,GAAG,mBAAmB,EAAE,GAAG,GAAE,oBAAyB,GAAG,mBAAmB,CAqDxI;AAED,oGAAoG;AACpG,eAAO,MAAM,uBAAuB,uBAAuB,CAAA;AAC3D,MAAM,WAAW,0BAA0B;IAAG,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE;AAElG,gJAAgJ;AAChJ,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,MAAM,EAAE,CAI3F;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,IAAI,CAAC,eAAe,EAAE,KAAK,GAAG,eAAe,CAAC,EAAE,GAAG,GAAE,oBAAyB,GAAG,mBAAmB,CAIrJ;AAED,MAAM,WAAW,eAAe,CAAC,CAAC,SAAS,eAAe;IACxD,OAAO,EAAE,CAAC,EAAE,CAAA;IACZ,aAAa,EAAE,CAAC,EAAE,CAAA;IAClB,UAAU,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,CAAC,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAA;CACnD;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,kBAAkB,EAAE,QAAQ,EAAE,CAAC,EAAE,GAAG,GAAE,oBAAyB,GAAG,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAU3I;AAWD,MAAM,WAAW,uBAAuB,CAAC,CAAC,SAAS,eAAe;IAChE,+EAA+E;IAC/E,OAAO,EAAE,CAAC,EAAE,CAAA;IACZ,yGAAyG;IACzG,UAAU,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,CAAC,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAA;IAClD,+JAA+J;IAC/J,QAAQ,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,CAAC,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAC9C;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,kBAAkB,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,GAAE,oBAAyB,GAAG,uBAAuB,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAiB3L;AAED,uGAAuG;AACvG,wBAAgB,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC,eAAe,EAAE,eAAe,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAK7I"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { isFieldV2 } from './manifest-v2.js';
|
|
2
|
+
const applies = (reasons = []) => ({ outcome: 'applies', reasons });
|
|
3
|
+
const notApplicable = (reason) => ({ outcome: 'not-applicable', reasons: [reason] });
|
|
4
|
+
const unresolved = (reason) => ({ outcome: 'unresolved', reasons: [reason] });
|
|
5
|
+
/** The calendar day of a date or instant, as `YYYY-MM-DD`, for a lexicographic comparison that needs no clock. */
|
|
6
|
+
function dayOf(value) {
|
|
7
|
+
const day = value.slice(0, 10);
|
|
8
|
+
return /^\d{4}-\d{2}-\d{2}$/.test(day) ? day : /^\d{4}-\d{2}$/.test(value) ? `${value}-01` : /^\d{4}$/.test(value) ? `${value}-01-01` : undefined;
|
|
9
|
+
}
|
|
10
|
+
function thresholdValue(raw, unit) {
|
|
11
|
+
if (raw == null)
|
|
12
|
+
return { reason: 'not supplied' };
|
|
13
|
+
if (typeof raw === 'number')
|
|
14
|
+
return Number.isFinite(raw) ? { value: raw } : { reason: 'not a finite number' };
|
|
15
|
+
if (typeof raw === 'object' && !Array.isArray(raw)) {
|
|
16
|
+
const record = raw;
|
|
17
|
+
if (typeof record.value !== 'number' || !Number.isFinite(record.value))
|
|
18
|
+
return { reason: 'carries no finite numeric value' };
|
|
19
|
+
if (unit != null && record.unit !== unit)
|
|
20
|
+
return { reason: `is in ${String(record.unit)}, not the rule's ${unit}` };
|
|
21
|
+
return { value: record.value };
|
|
22
|
+
}
|
|
23
|
+
return { reason: 'is not numeric' };
|
|
24
|
+
}
|
|
25
|
+
export function evaluateApplicability(rule, ctx = {}) {
|
|
26
|
+
switch (rule.rule) {
|
|
27
|
+
case 'always':
|
|
28
|
+
return applies();
|
|
29
|
+
case 'category-in': {
|
|
30
|
+
const categories = rule.categories ?? [];
|
|
31
|
+
if (ctx.category == null)
|
|
32
|
+
return applies(['no category supplied; a category-in rule is read as applying, as fieldsFor reads it']);
|
|
33
|
+
return categories.includes(ctx.category) ? applies() : notApplicable(`category ${ctx.category} is not one of ${categories.join(', ')}`);
|
|
34
|
+
}
|
|
35
|
+
case 'needs-review': {
|
|
36
|
+
const categories = rule.categories;
|
|
37
|
+
if (categories != null && ctx.category != null && !categories.includes(ctx.category))
|
|
38
|
+
return notApplicable(`category ${ctx.category} is outside the categories the review concerns`);
|
|
39
|
+
return unresolved(`needs review: ${rule.condition ?? 'the condition is not stated'}`);
|
|
40
|
+
}
|
|
41
|
+
case 'all': {
|
|
42
|
+
const results = rule.rules.map((r) => evaluateApplicability(r, ctx));
|
|
43
|
+
const no = results.filter((r) => r.outcome === 'not-applicable');
|
|
44
|
+
if (no.length > 0)
|
|
45
|
+
return { outcome: 'not-applicable', reasons: no.flatMap((r) => r.reasons) };
|
|
46
|
+
const open = results.filter((r) => r.outcome === 'unresolved');
|
|
47
|
+
if (open.length > 0)
|
|
48
|
+
return { outcome: 'unresolved', reasons: open.flatMap((r) => r.reasons) };
|
|
49
|
+
return applies(results.flatMap((r) => r.reasons));
|
|
50
|
+
}
|
|
51
|
+
case 'any': {
|
|
52
|
+
const results = rule.rules.map((r) => evaluateApplicability(r, ctx));
|
|
53
|
+
const yes = results.find((r) => r.outcome === 'applies');
|
|
54
|
+
if (yes != null)
|
|
55
|
+
return applies(yes.reasons);
|
|
56
|
+
const open = results.filter((r) => r.outcome === 'unresolved');
|
|
57
|
+
if (open.length > 0)
|
|
58
|
+
return { outcome: 'unresolved', reasons: open.flatMap((r) => r.reasons) };
|
|
59
|
+
return { outcome: 'not-applicable', reasons: results.flatMap((r) => r.reasons) };
|
|
60
|
+
}
|
|
61
|
+
case 'jurisdiction-in':
|
|
62
|
+
if (ctx.jurisdiction == null)
|
|
63
|
+
return unresolved('no jurisdiction supplied');
|
|
64
|
+
return rule.jurisdictions.includes(ctx.jurisdiction) ? applies() : notApplicable(`jurisdiction ${ctx.jurisdiction} is not one of ${rule.jurisdictions.join(', ')}`);
|
|
65
|
+
case 'effective': {
|
|
66
|
+
if (ctx.asOf == null)
|
|
67
|
+
return unresolved('no evaluation date supplied for an effective-date rule');
|
|
68
|
+
const day = dayOf(ctx.asOf);
|
|
69
|
+
if (day == null)
|
|
70
|
+
return unresolved(`the evaluation date ${ctx.asOf} is not a date`);
|
|
71
|
+
if (rule.from != null && day < rule.from)
|
|
72
|
+
return notApplicable(`not effective until ${rule.from}`);
|
|
73
|
+
if (rule.until != null && day > rule.until)
|
|
74
|
+
return notApplicable(`no longer effective after ${rule.until}`);
|
|
75
|
+
return applies();
|
|
76
|
+
}
|
|
77
|
+
case 'threshold': {
|
|
78
|
+
const read = thresholdValue(ctx.values?.[rule.field], rule.unit);
|
|
79
|
+
if ('reason' in read)
|
|
80
|
+
return unresolved(`${rule.field} ${read.reason}, so the threshold cannot be decided`);
|
|
81
|
+
const v = read.value;
|
|
82
|
+
const holds = rule.operator === 'gt' ? v > rule.value : rule.operator === 'gte' ? v >= rule.value : rule.operator === 'lt' ? v < rule.value : rule.operator === 'lte' ? v <= rule.value : v === rule.value;
|
|
83
|
+
return holds ? applies() : notApplicable(`${rule.field} ${v}${rule.unit == null ? '' : ` ${rule.unit}`} is not ${rule.operator} ${rule.value}`);
|
|
84
|
+
}
|
|
85
|
+
case 'unresolved':
|
|
86
|
+
return unresolved(`${rule.reason}${rule.source == null ? '' : ` (${rule.source})`}`);
|
|
87
|
+
default:
|
|
88
|
+
return unresolved(`rule ${String(rule.rule)} is not one this evaluator implements`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/** The key under which a record declares fields inapplicable, and the shape of each declaration. */
|
|
92
|
+
export const INAPPLICABLE_FIELDS_KEY = 'inapplicableFields';
|
|
93
|
+
/** The declarations a payload carries under `inapplicableFields`, as field keys; malformed entries are ignored, never read as a declaration. */
|
|
94
|
+
export function declaredInapplicable(payload) {
|
|
95
|
+
const raw = payload?.[INAPPLICABLE_FIELDS_KEY];
|
|
96
|
+
if (!Array.isArray(raw))
|
|
97
|
+
return [];
|
|
98
|
+
return raw.filter((d) => d != null && typeof d === 'object' && typeof d.field === 'string' && typeof d.reason === 'string' && d.reason.trim() !== '').map((d) => d.field);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* A field's applicability under a context: a declaration under
|
|
102
|
+
* `inapplicableFields` answers not-applicable with the reason `declared`
|
|
103
|
+
* only where the rule would otherwise be unresolved or conditional, so a
|
|
104
|
+
* declaration cannot switch off a field that applies unconditionally; the
|
|
105
|
+
* rule answers otherwise.
|
|
106
|
+
*/
|
|
107
|
+
export function evaluateFieldApplicability(field, ctx = {}) {
|
|
108
|
+
const result = evaluateApplicability(field.applicability, ctx);
|
|
109
|
+
if (result.outcome !== 'unresolved' || !(ctx.declaredNotApplicable ?? []).includes(field.key))
|
|
110
|
+
return result;
|
|
111
|
+
return { outcome: 'not-applicable', reasons: ['declared: the record declares the field inapplicable under inapplicableFields'] };
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* The fields of a version 1 or version 2 manifest under a context: what
|
|
115
|
+
* applies, what does not, and what is unresolved with its reasons. The
|
|
116
|
+
* version 1 `fieldsFor` remains the reader for version 1 manifests with a
|
|
117
|
+
* bare category; this one takes the whole context.
|
|
118
|
+
*/
|
|
119
|
+
export function fieldsForV2(manifest, ctx = {}) {
|
|
120
|
+
const result = { applies: [], notApplicable: [], unresolved: [] };
|
|
121
|
+
for (const field of manifest.fields) {
|
|
122
|
+
const r = evaluateFieldApplicability(field, ctx);
|
|
123
|
+
if (r.outcome === 'applies')
|
|
124
|
+
result.applies.push(field);
|
|
125
|
+
else if (r.outcome === 'not-applicable')
|
|
126
|
+
result.notApplicable.push(field);
|
|
127
|
+
else
|
|
128
|
+
result.unresolved.push({ field, reasons: r.reasons });
|
|
129
|
+
}
|
|
130
|
+
return result;
|
|
131
|
+
}
|
|
132
|
+
const CAPTURED_AT_REGISTRATION = ['form', 'brand', 'platform'];
|
|
133
|
+
function present(payload, key) {
|
|
134
|
+
const value = payload[key];
|
|
135
|
+
if (value === undefined || value === null || value === '')
|
|
136
|
+
return false;
|
|
137
|
+
if (Array.isArray(value) && value.length === 0)
|
|
138
|
+
return false;
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Which required fields a payload lacks under a context, on three separate
|
|
143
|
+
* lists. A field whose applicability is unresolved is never missing and never
|
|
144
|
+
* satisfied; a field whose requirement status is anticipated, not to be
|
|
145
|
+
* displayed or under review is deferred and never blocks, so an adopter can
|
|
146
|
+
* keep incomplete draft data without a false failure or a false pass. A
|
|
147
|
+
* field the payload declares inapplicable under `inapplicableFields` is
|
|
148
|
+
* not-applicable where it would otherwise be unresolved.
|
|
149
|
+
*/
|
|
150
|
+
export function missingRequiredV2(manifest, payload, ctx = {}) {
|
|
151
|
+
const result = { missing: [], unresolved: [], deferred: [] };
|
|
152
|
+
// The payload's own declarations, unless the caller supplied the list.
|
|
153
|
+
const effective = ctx.declaredNotApplicable == null ? { ...ctx, declaredNotApplicable: declaredInapplicable(payload) } : ctx;
|
|
154
|
+
for (const field of manifest.fields) {
|
|
155
|
+
if (field.obligation !== 'required' || present(payload, field.key))
|
|
156
|
+
continue;
|
|
157
|
+
if (isFieldV2(field) && ['anticipated', 'not-to-be-displayed', 'needs-review'].includes(field.requirement.status)) {
|
|
158
|
+
result.deferred.push({ field, status: field.requirement.status });
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
const r = evaluateFieldApplicability(field, effective);
|
|
162
|
+
if (r.outcome === 'not-applicable')
|
|
163
|
+
continue;
|
|
164
|
+
if (r.outcome === 'unresolved') {
|
|
165
|
+
result.unresolved.push({ field, reasons: r.reasons });
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
if (CAPTURED_AT_REGISTRATION.includes(field.provenance.capture))
|
|
169
|
+
result.missing.push(field);
|
|
170
|
+
}
|
|
171
|
+
return result;
|
|
172
|
+
}
|
|
173
|
+
/** The category value a payload names for a manifest, read at the manifest's declared category key. */
|
|
174
|
+
export function categoryOf(manifest, payload) {
|
|
175
|
+
const key = manifest.applicability.categoryKey;
|
|
176
|
+
if (key == null || payload == null)
|
|
177
|
+
return undefined;
|
|
178
|
+
const value = payload[key];
|
|
179
|
+
return typeof value === 'string' ? value : undefined;
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=applicability.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"applicability.js","sourceRoot":"","sources":["../src/applicability.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export declare const BASELINE_ID = "native-baseline@1";
|
|
2
|
+
/** The second recommended baseline: record version 2 with the managed-custody profile (conformance/baseline-native-2.json). */
|
|
3
|
+
export declare const BASELINE_ID_2 = "native-baseline@2";
|
|
4
|
+
export declare const BASELINE_IDS: readonly ["native-baseline@1", "native-baseline@2"];
|
|
5
|
+
export type SelectionPurpose = 'read' | 'write' | 'claim';
|
|
6
|
+
export interface DeploymentDeclaration {
|
|
7
|
+
operators?: number;
|
|
8
|
+
discovery?: 'none' | 'ship-slap' | 'static-peers';
|
|
9
|
+
gasp?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface ProfileSelection {
|
|
12
|
+
baseline: string;
|
|
13
|
+
industry?: string;
|
|
14
|
+
exchange?: string[];
|
|
15
|
+
operator?: string;
|
|
16
|
+
deployment?: DeploymentDeclaration;
|
|
17
|
+
/** read: verify what exists; write: issue new states or claims; claim: state conformance to the selected profiles. */
|
|
18
|
+
purpose: SelectionPurpose;
|
|
19
|
+
}
|
|
20
|
+
export type SelectionConflictCode = 'baseline-unknown' | 'industry-unknown' | 'industry-superseded' | 'industry-draft' | 'exchange-unknown' | 'exchange-duplicate' | 'exchange-proposed' | 'exchange-artefacts-unpinned' | 'operator-unknown' | 'operator-proposed' | 'operator-single-with-federation-options' | 'operator-federation-needs-two' | 'operator-federation-without-discovery';
|
|
21
|
+
export interface SelectionResult {
|
|
22
|
+
ok: boolean;
|
|
23
|
+
conflicts: Array<{
|
|
24
|
+
code: SelectionConflictCode;
|
|
25
|
+
detail: string;
|
|
26
|
+
}>;
|
|
27
|
+
notes: string[];
|
|
28
|
+
}
|
|
29
|
+
export declare function checkSelection(selection: ProfileSelection): SelectionResult;
|
|
30
|
+
//# sourceMappingURL=combinations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"combinations.d.ts","sourceRoot":"","sources":["../src/combinations.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,WAAW,sBAAsB,CAAA;AAC9C,+HAA+H;AAC/H,eAAO,MAAM,aAAa,sBAAsB,CAAA;AAChD,eAAO,MAAM,YAAY,qDAAwC,CAAA;AAEjE,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAA;AAEzD,MAAM,WAAW,qBAAqB;IACpC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,cAAc,CAAA;IACjD,IAAI,CAAC,EAAE,OAAO,CAAA;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,qBAAqB,CAAA;IAClC,sHAAsH;IACtH,OAAO,EAAE,gBAAgB,CAAA;CAC1B;AAED,MAAM,MAAM,qBAAqB,GAC7B,kBAAkB,GAClB,kBAAkB,GAClB,qBAAqB,GACrB,gBAAgB,GAChB,kBAAkB,GAClB,oBAAoB,GACpB,mBAAmB,GACnB,6BAA6B,GAC7B,kBAAkB,GAClB,mBAAmB,GACnB,yCAAyC,GACzC,+BAA+B,GAC/B,uCAAuC,CAAA;AAE3C,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,OAAO,CAAA;IACX,SAAS,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,qBAAqB,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACjE,KAAK,EAAE,MAAM,EAAE,CAAA;CAChB;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,gBAAgB,GAAG,eAAe,CAoE3E"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Profile combinations (`spec/conformance.md` §4, `spec/profiles.md`): an
|
|
3
|
+
* industry profile says what a passport carries, an exchange profile how a
|
|
4
|
+
* credential travels beside it, an operator profile how an index is run. They
|
|
5
|
+
* are selected together, and some selections contradict themselves: a new
|
|
6
|
+
* state under a superseded version, a conformance claim on a proposed profile
|
|
7
|
+
* whose artefacts were never pinned, a single operator declaring peers, a
|
|
8
|
+
* federation of one. `checkSelection` names every contradiction rather than
|
|
9
|
+
* choosing for the caller, and passes with notes when the selection is only
|
|
10
|
+
* unusual.
|
|
11
|
+
*/
|
|
12
|
+
import { EXCHANGE_PROFILE_IDS, OPERATOR_PROFILE_IDS, PROFILE_IDS, readExchangeProfile, readOperatorProfile } from './index.js';
|
|
13
|
+
import { isManifestV2, readManifestAny } from './manifest-v2.js';
|
|
14
|
+
export const BASELINE_ID = 'native-baseline@1';
|
|
15
|
+
/** The second recommended baseline: record version 2 with the managed-custody profile (conformance/baseline-native-2.json). */
|
|
16
|
+
export const BASELINE_ID_2 = 'native-baseline@2';
|
|
17
|
+
export const BASELINE_IDS = [BASELINE_ID, BASELINE_ID_2];
|
|
18
|
+
export function checkSelection(selection) {
|
|
19
|
+
const conflicts = [];
|
|
20
|
+
const notes = [];
|
|
21
|
+
const conflict = (code, detail) => { conflicts.push({ code, detail }); };
|
|
22
|
+
if (!BASELINE_IDS.includes(selection.baseline))
|
|
23
|
+
conflict('baseline-unknown', `${selection.baseline} is not a baseline this catalogue knows; the baselines are ${BASELINE_IDS.join(' and ')}`);
|
|
24
|
+
if (selection.industry != null) {
|
|
25
|
+
if (!PROFILE_IDS.includes(selection.industry)) {
|
|
26
|
+
conflict('industry-unknown', `${selection.industry} is not an industry profile in this catalogue`);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
const manifest = readManifestAny(selection.industry);
|
|
30
|
+
if (manifest.status === 'superseded') {
|
|
31
|
+
if (selection.purpose === 'read')
|
|
32
|
+
notes.push(`${manifest.profile} is superseded by ${manifest.supersededBy}; states that declare it decode under it and are never reinterpreted`);
|
|
33
|
+
else
|
|
34
|
+
conflict('industry-superseded', `${manifest.profile} is superseded by ${manifest.supersededBy}; a new state or claim is issued under the current version`);
|
|
35
|
+
}
|
|
36
|
+
else if (manifest.status === 'draft') {
|
|
37
|
+
// A draft successor is opt-in: a deployment may read and write under
|
|
38
|
+
// it by explicit version, and is told so; a conformance claim rests on
|
|
39
|
+
// the current version until the reviewed cutover marks it superseded.
|
|
40
|
+
const of = isManifestV2(manifest) && manifest.succession != null ? manifest.succession.of : 'the current version';
|
|
41
|
+
if (selection.purpose === 'claim')
|
|
42
|
+
conflict('industry-draft', `${manifest.profile} is a draft successor to ${of}; a conformance claim rests on the current version`);
|
|
43
|
+
else
|
|
44
|
+
notes.push(`${manifest.profile} is a draft: opt-in successor to ${of}, not yet the current version; a conformance claim rests on the current version`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const seen = new Set();
|
|
49
|
+
for (const id of selection.exchange ?? []) {
|
|
50
|
+
if (seen.has(id)) {
|
|
51
|
+
conflict('exchange-duplicate', `${id} is selected twice`);
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
seen.add(id);
|
|
55
|
+
if (!EXCHANGE_PROFILE_IDS.includes(id)) {
|
|
56
|
+
conflict('exchange-unknown', `${id} is not an exchange profile in this catalogue`);
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
const profile = readExchangeProfile(id);
|
|
60
|
+
const unpinned = (profile.artefacts ?? []).filter((a) => a.retrieval === 'not-retrieved').map((a) => a.id);
|
|
61
|
+
if (selection.purpose === 'claim') {
|
|
62
|
+
if (profile.status !== 'current') {
|
|
63
|
+
conflict('exchange-proposed', `${id} is ${profile.status}; no conformance claim rests on a profile that is not current`);
|
|
64
|
+
if (unpinned.length > 0)
|
|
65
|
+
conflict('exchange-artefacts-unpinned', `${id} has artefacts not retrieved and pinned: ${unpinned.join(', ')}`);
|
|
66
|
+
}
|
|
67
|
+
else if (unpinned.length > 0) {
|
|
68
|
+
// A current profile with an upstream artefact nobody could retrieve
|
|
69
|
+
// (the ledger's unassessed rows) supports the implemented-subset claim
|
|
70
|
+
// and never the full one; the ledger's claim gate is where that split
|
|
71
|
+
// is enforced, and the note points at it.
|
|
72
|
+
notes.push(`${id}: the claim covers the implemented subset; artefacts not retrieved (${unpinned.join(', ')}) keep the full-conformance claim blocked in the ledger`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
else if (profile.status !== 'current' || unpinned.length > 0) {
|
|
76
|
+
notes.push(`${id} is ${profile.status}${unpinned.length > 0 ? ` with unpinned artefacts (${unpinned.join(', ')})` : ''}; usable for a pilot, not for a claim`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (selection.operator != null) {
|
|
80
|
+
if (!OPERATOR_PROFILE_IDS.includes(selection.operator)) {
|
|
81
|
+
conflict('operator-unknown', `${selection.operator} is not an operator profile in this catalogue`);
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
const profile = readOperatorProfile(selection.operator);
|
|
85
|
+
const d = selection.deployment ?? {};
|
|
86
|
+
if (selection.operator === 'single-operator@1') {
|
|
87
|
+
if ((d.operators ?? 1) > 1 || d.gasp === true || (d.discovery != null && d.discovery !== 'none')) {
|
|
88
|
+
conflict('operator-single-with-federation-options', 'single-operator@1 declares one administration with discovery and synchronisation off; peers, GASP or advertisement belong to federated-operators@1');
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
if ((d.operators ?? 1) < 2)
|
|
93
|
+
conflict('operator-federation-needs-two', 'federated-operators@1 needs at least two independently administered operators; one operator is single-operator@1');
|
|
94
|
+
if (d.discovery == null || d.discovery === 'none')
|
|
95
|
+
conflict('operator-federation-without-discovery', 'federated-operators@1 needs SHIP and SLAP or a declared static-peer profile so operators find each other; discovery none is single-operator@1');
|
|
96
|
+
if (selection.purpose === 'claim' && profile.status !== 'current')
|
|
97
|
+
conflict('operator-proposed', `${selection.operator} is ${profile.status}; the independently administered exercise has not been run, so no claim rests on it`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return { ok: conflicts.length === 0, conflicts, notes };
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=combinations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"combinations.js","sourceRoot":"","sources":["../src/combinations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,WAAW,EAAE,mBAAmB,EAAE,mBAAmB,EAAkD,MAAM,YAAY,CAAA;AAC9K,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAEhE,MAAM,CAAC,MAAM,WAAW,GAAG,mBAAmB,CAAA;AAC9C,+HAA+H;AAC/H,MAAM,CAAC,MAAM,aAAa,GAAG,mBAAmB,CAAA;AAChD,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,WAAW,EAAE,aAAa,CAAU,CAAA;AAyCjE,MAAM,UAAU,cAAc,CAAC,SAA2B;IACxD,MAAM,SAAS,GAAiC,EAAE,CAAA;IAClD,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,MAAM,QAAQ,GAAG,CAAC,IAA2B,EAAE,MAAc,EAAQ,EAAE,GAAG,SAAS,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAA,CAAC,CAAC,CAAA;IAE5G,IAAI,CAAE,YAAkC,CAAC,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC;QAAE,QAAQ,CAAC,kBAAkB,EAAE,GAAG,SAAS,CAAC,QAAQ,8DAA8D,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;IAEpN,IAAI,SAAS,CAAC,QAAQ,IAAI,IAAI,EAAE,CAAC;QAC/B,IAAI,CAAE,WAAiC,CAAC,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC;YACrE,QAAQ,CAAC,kBAAkB,EAAE,GAAG,SAAS,CAAC,QAAQ,+CAA+C,CAAC,CAAA;QACpG,CAAC;aAAM,CAAC;YACN,MAAM,QAAQ,GAAG,eAAe,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAA;YACpD,IAAI,QAAQ,CAAC,MAAM,KAAK,YAAY,EAAE,CAAC;gBACrC,IAAI,SAAS,CAAC,OAAO,KAAK,MAAM;oBAAE,KAAK,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,OAAO,qBAAqB,QAAQ,CAAC,YAAY,sEAAsE,CAAC,CAAA;;oBAC5K,QAAQ,CAAC,qBAAqB,EAAE,GAAG,QAAQ,CAAC,OAAO,qBAAqB,QAAQ,CAAC,YAAY,4DAA4D,CAAC,CAAA;YACjK,CAAC;iBAAM,IAAI,QAAQ,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;gBACvC,qEAAqE;gBACrE,uEAAuE;gBACvE,sEAAsE;gBACtE,MAAM,EAAE,GAAG,YAAY,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,qBAAqB,CAAA;gBACjH,IAAI,SAAS,CAAC,OAAO,KAAK,OAAO;oBAAE,QAAQ,CAAC,gBAAgB,EAAE,GAAG,QAAQ,CAAC,OAAO,4BAA4B,EAAE,oDAAoD,CAAC,CAAA;;oBAC/J,KAAK,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,OAAO,oCAAoC,EAAE,iFAAiF,CAAC,CAAA;YAC7J,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;IAC9B,KAAK,MAAM,EAAE,IAAI,SAAS,CAAC,QAAQ,IAAI,EAAE,EAAE,CAAC;QAC1C,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YAAC,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE,oBAAoB,CAAC,CAAC;YAAC,SAAQ;QAAC,CAAC;QACzF,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACZ,IAAI,CAAE,oBAA0C,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;YAAC,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE,+CAA+C,CAAC,CAAC;YAAC,SAAQ;QAAC,CAAC;QAC/J,MAAM,OAAO,GAAG,mBAAmB,CAAC,EAAuB,CAA8E,CAAA;QACzI,MAAM,QAAQ,GAAG,CAAC,OAAO,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,eAAe,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;QAC1G,IAAI,SAAS,CAAC,OAAO,KAAK,OAAO,EAAE,CAAC;YAClC,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBACjC,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE,OAAO,OAAO,CAAC,MAAM,+DAA+D,CAAC,CAAA;gBACxH,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;oBAAE,QAAQ,CAAC,6BAA6B,EAAE,GAAG,EAAE,4CAA4C,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YAC1I,CAAC;iBAAM,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC/B,oEAAoE;gBACpE,uEAAuE;gBACvE,sEAAsE;gBACtE,0CAA0C;gBAC1C,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,uEAAuE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,yDAAyD,CAAC,CAAA;YACtK,CAAC;QACH,CAAC;aAAM,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC/D,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,OAAO,CAAC,MAAM,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,6BAA6B,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,uCAAuC,CAAC,CAAA;QAChK,CAAC;IACH,CAAC;IAED,IAAI,SAAS,CAAC,QAAQ,IAAI,IAAI,EAAE,CAAC;QAC/B,IAAI,CAAE,oBAA0C,CAAC,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC9E,QAAQ,CAAC,kBAAkB,EAAE,GAAG,SAAS,CAAC,QAAQ,+CAA+C,CAAC,CAAA;QACpG,CAAC;aAAM,CAAC;YACN,MAAM,OAAO,GAAG,mBAAmB,CAAC,SAAS,CAAC,QAA6B,CAAuF,CAAA;YAClK,MAAM,CAAC,GAAG,SAAS,CAAC,UAAU,IAAI,EAAE,CAAA;YACpC,IAAI,SAAS,CAAC,QAAQ,KAAK,mBAAmB,EAAE,CAAC;gBAC/C,IAAI,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,IAAI,IAAI,IAAI,CAAC,CAAC,SAAS,KAAK,MAAM,CAAC,EAAE,CAAC;oBACjG,QAAQ,CAAC,yCAAyC,EAAE,oJAAoJ,CAAC,CAAA;gBAC3M,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,GAAG,CAAC;oBAAE,QAAQ,CAAC,+BAA+B,EAAE,kHAAkH,CAAC,CAAA;gBACzL,IAAI,CAAC,CAAC,SAAS,IAAI,IAAI,IAAI,CAAC,CAAC,SAAS,KAAK,MAAM;oBAAE,QAAQ,CAAC,uCAAuC,EAAE,+IAA+I,CAAC,CAAA;gBACrP,IAAI,SAAS,CAAC,OAAO,KAAK,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,SAAS;oBAAE,QAAQ,CAAC,mBAAmB,EAAE,GAAG,SAAS,CAAC,QAAQ,OAAO,OAAO,CAAC,MAAM,qFAAqF,CAAC,CAAA;YACnO,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,EAAE,EAAE,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAA;AACzD,CAAC"}
|