antifraud-sdk-core-ts 0.1.1 → 0.1.2
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/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.1.2 - 2026-10-18
|
|
6
|
+
|
|
7
|
+
- Replace binary qualification-issuer lookup with explicit
|
|
8
|
+
`participant-resolved`, `identity-resolved` and `not-resolved` outcomes.
|
|
9
|
+
- Record employer evidence for a known non-participating issuer as
|
|
10
|
+
`awaiting-issuer-onboarding` without fabricating a tenant or queueing a
|
|
11
|
+
confirmation request.
|
|
12
|
+
- Reuse the canonical CIDv1(raw, SHA3-384) validator and synthetic attachment
|
|
13
|
+
fixture from `antifraud-data-utils-ts@0.1.3` instead of duplicating the
|
|
14
|
+
multibase and multihash implementation.
|
|
15
|
+
|
|
5
16
|
## 0.1.1 - 2026-10-17
|
|
6
17
|
|
|
7
18
|
- Add runtime-neutral authoritative credential issuance orchestration using
|
package/README.md
CHANGED
|
@@ -4,7 +4,8 @@ Runtime-neutral orchestration contracts for identity verification, subject and r
|
|
|
4
4
|
|
|
5
5
|
## Status
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Published public implementation foundation. Registry publication proves the
|
|
8
|
+
package artifact only; no deployment or production readiness is claimed.
|
|
8
9
|
|
|
9
10
|
## Responsibility
|
|
10
11
|
|
|
@@ -65,9 +66,13 @@ jurisdiction. If no source credential exists, the employer may sign its own
|
|
|
65
66
|
attestation but must not be represented as the awarding organization's issuer.
|
|
66
67
|
|
|
67
68
|
The implemented qualification-evidence controller records the employer's proof
|
|
68
|
-
through a trusted port
|
|
69
|
-
jurisdiction
|
|
70
|
-
confirmation
|
|
69
|
+
through a trusted port and resolves the claimed issuer by legal identifier and
|
|
70
|
+
jurisdiction with three explicit outcomes. A participating issuer has a known
|
|
71
|
+
tenant and confirmation service, so the controller anchors opaque continuity
|
|
72
|
+
and queues a tenant-to-tenant confirmation request. A known legal identity
|
|
73
|
+
without a participating tenant is recorded as `awaiting-issuer-onboarding`
|
|
74
|
+
without sending a message or inventing tenant authority. An unresolved identity
|
|
75
|
+
fails before evidence recording. See [Qualification evidence confirmation prototype](docs/QUALIFICATION_EVIDENCE_CONFIRMATION.md)
|
|
71
76
|
for attachment, issuer notification, ledger recovery and credential-rendering
|
|
72
77
|
boundaries.
|
|
73
78
|
|
|
@@ -7,6 +7,15 @@ export type ResolvedQualificationIssuer = QualificationIssuerQuery & Readonly<{
|
|
|
7
7
|
issuerOrganizationReference: string;
|
|
8
8
|
confirmationServiceReference: string;
|
|
9
9
|
}>;
|
|
10
|
+
export type QualificationIssuerResolution = Readonly<{
|
|
11
|
+
kind: 'participant-resolved';
|
|
12
|
+
issuer: ResolvedQualificationIssuer;
|
|
13
|
+
}> | Readonly<{
|
|
14
|
+
kind: 'identity-resolved';
|
|
15
|
+
issuerOrganizationReference: string;
|
|
16
|
+
}> | Readonly<{
|
|
17
|
+
kind: 'not-resolved';
|
|
18
|
+
}>;
|
|
10
19
|
export type QualificationEvidenceRequest = Readonly<{
|
|
11
20
|
trustedContext: Readonly<{
|
|
12
21
|
controllerAuthorizationReference: string;
|
|
@@ -40,7 +49,7 @@ export type QualificationConfirmationRequestMessage = Readonly<{
|
|
|
40
49
|
}>;
|
|
41
50
|
export type QualificationEvidenceControllerPorts = Readonly<{
|
|
42
51
|
issuerDirectory: Readonly<{
|
|
43
|
-
resolve(query: QualificationIssuerQuery): Promise<
|
|
52
|
+
resolve(query: QualificationIssuerQuery): Promise<QualificationIssuerResolution>;
|
|
44
53
|
}>;
|
|
45
54
|
evidenceRecorder: Readonly<{
|
|
46
55
|
recordEmployerAttestation(request: QualificationEvidenceRequest): Promise<Readonly<{
|
|
@@ -57,9 +66,13 @@ export type QualificationEvidenceControllerPorts = Readonly<{
|
|
|
57
66
|
anchorReference: string;
|
|
58
67
|
evidenceReference: string;
|
|
59
68
|
contentHash: string;
|
|
69
|
+
issuerOrganizationReference: string;
|
|
70
|
+
}> & (Readonly<{
|
|
60
71
|
issuerTenantReference: string;
|
|
61
72
|
lifecycleStatus: 'awaiting-issuer-confirmation';
|
|
62
|
-
}>
|
|
73
|
+
}> | Readonly<{
|
|
74
|
+
lifecycleStatus: 'awaiting-issuer-onboarding';
|
|
75
|
+
}>)): Promise<void>;
|
|
63
76
|
}>;
|
|
64
77
|
outbox: Readonly<{
|
|
65
78
|
queue(message: QualificationConfirmationRequestMessage): Promise<Readonly<{
|
|
@@ -71,6 +84,12 @@ export type QualificationEvidenceControllerPorts = Readonly<{
|
|
|
71
84
|
export declare function createQualificationEvidenceController(ports: QualificationEvidenceControllerPorts): {
|
|
72
85
|
submit(request: QualificationEvidenceRequest): Promise<Readonly<{
|
|
73
86
|
phase: "issuer-not-resolved";
|
|
87
|
+
}> | Readonly<{
|
|
88
|
+
phase: "awaiting-issuer-onboarding";
|
|
89
|
+
evidenceReference: string;
|
|
90
|
+
employerProofReference: string;
|
|
91
|
+
ledgerAnchorReference: string;
|
|
92
|
+
issuerOrganizationReference: string;
|
|
74
93
|
}> | Readonly<{
|
|
75
94
|
phase: "issuer-confirmation-queued";
|
|
76
95
|
evidenceReference: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qualification-evidence-controller.d.ts","sourceRoot":"","sources":["../src/qualification-evidence-controller.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"qualification-evidence-controller.d.ts","sourceRoot":"","sources":["../src/qualification-evidence-controller.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,42 +1,9 @@
|
|
|
1
1
|
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
|
+
import { assertSha3_384EvidenceContentId } from 'antifraud-data-utils-ts';
|
|
2
3
|
function requireReference(value, path) {
|
|
3
4
|
if (value.trim().length === 0)
|
|
4
5
|
throw new TypeError(`${path} must not be empty`);
|
|
5
6
|
}
|
|
6
|
-
const BASE58BTC_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
|
|
7
|
-
function decodeBase58btc(value) {
|
|
8
|
-
let decoded = 0n;
|
|
9
|
-
for (const character of value) {
|
|
10
|
-
const index = BASE58BTC_ALPHABET.indexOf(character);
|
|
11
|
-
if (index < 0)
|
|
12
|
-
throw new TypeError('Invalid base58btc character');
|
|
13
|
-
decoded = decoded * 58n + BigInt(index);
|
|
14
|
-
}
|
|
15
|
-
const bytes = [];
|
|
16
|
-
while (decoded > 0n) {
|
|
17
|
-
bytes.unshift(Number(decoded & 0xffn));
|
|
18
|
-
decoded >>= 8n;
|
|
19
|
-
}
|
|
20
|
-
for (const character of value) {
|
|
21
|
-
if (character !== '1')
|
|
22
|
-
break;
|
|
23
|
-
bytes.unshift(0);
|
|
24
|
-
}
|
|
25
|
-
return Uint8Array.from(bytes);
|
|
26
|
-
}
|
|
27
|
-
function assertRawSha3_384CidV1(contentId) {
|
|
28
|
-
if (!/^z[1-9A-HJ-NP-Za-km-z]+$/u.test(contentId)) {
|
|
29
|
-
throw new TypeError('evidence.contentId must be a base58btc multibase CID');
|
|
30
|
-
}
|
|
31
|
-
const bytes = decodeBase58btc(contentId.slice(1));
|
|
32
|
-
if (bytes.length !== 52
|
|
33
|
-
|| bytes[0] !== 0x01
|
|
34
|
-
|| bytes[1] !== 0x55
|
|
35
|
-
|| bytes[2] !== 0x15
|
|
36
|
-
|| bytes[3] !== 0x30) {
|
|
37
|
-
throw new TypeError('evidence.contentId must be CIDv1 raw with a SHA3-384 multihash');
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
7
|
function validateRequest(request) {
|
|
41
8
|
requireReference(request.trustedContext.controllerAuthorizationReference, 'controllerAuthorizationReference');
|
|
42
9
|
requireReference(request.trustedContext.employerTenantReference, 'employerTenantReference');
|
|
@@ -47,22 +14,40 @@ function validateRequest(request) {
|
|
|
47
14
|
requireReference(request.claimedIssuer.legalIdentifier, 'claimedIssuer.legalIdentifier');
|
|
48
15
|
requireReference(request.claimedIssuer.jurisdiction, 'claimedIssuer.jurisdiction');
|
|
49
16
|
requireReference(request.evidence.reference, 'evidence.reference');
|
|
50
|
-
|
|
17
|
+
assertSha3_384EvidenceContentId(request.evidence.contentId);
|
|
51
18
|
}
|
|
52
19
|
export function createQualificationEvidenceController(ports) {
|
|
53
20
|
return {
|
|
54
21
|
async submit(request) {
|
|
55
22
|
validateRequest(request);
|
|
56
|
-
const
|
|
57
|
-
if (
|
|
23
|
+
const resolution = await ports.issuerDirectory.resolve(request.claimedIssuer);
|
|
24
|
+
if (resolution.kind === 'not-resolved') {
|
|
58
25
|
return Object.freeze({ phase: 'issuer-not-resolved' });
|
|
59
26
|
}
|
|
60
27
|
const recorded = await ports.evidenceRecorder.recordEmployerAttestation(request);
|
|
28
|
+
if (resolution.kind === 'identity-resolved') {
|
|
29
|
+
await ports.ledger.recordAnchor({
|
|
30
|
+
anchorReference: recorded.anchor.anchorReference,
|
|
31
|
+
evidenceReference: recorded.evidenceReference,
|
|
32
|
+
contentHash: recorded.anchor.contentHash,
|
|
33
|
+
issuerOrganizationReference: resolution.issuerOrganizationReference,
|
|
34
|
+
lifecycleStatus: 'awaiting-issuer-onboarding',
|
|
35
|
+
});
|
|
36
|
+
return Object.freeze({
|
|
37
|
+
phase: 'awaiting-issuer-onboarding',
|
|
38
|
+
evidenceReference: recorded.evidenceReference,
|
|
39
|
+
employerProofReference: recorded.employerProofReference,
|
|
40
|
+
ledgerAnchorReference: recorded.anchor.anchorReference,
|
|
41
|
+
issuerOrganizationReference: resolution.issuerOrganizationReference,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
const issuer = resolution.issuer;
|
|
61
45
|
await ports.ledger.recordAnchor({
|
|
62
46
|
anchorReference: recorded.anchor.anchorReference,
|
|
63
47
|
evidenceReference: recorded.evidenceReference,
|
|
64
48
|
contentHash: recorded.anchor.contentHash,
|
|
65
49
|
issuerTenantReference: issuer.issuerTenantReference,
|
|
50
|
+
issuerOrganizationReference: issuer.issuerOrganizationReference,
|
|
66
51
|
lifecycleStatus: 'awaiting-issuer-confirmation',
|
|
67
52
|
});
|
|
68
53
|
const message = Object.freeze({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "antifraud-sdk-core-ts",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Runtime-neutral orchestration for identity verification and provider-issued credentials",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -34,6 +34,6 @@
|
|
|
34
34
|
"typescript": "^5.9.3"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"antifraud-data-utils-ts": "0.1.
|
|
37
|
+
"antifraud-data-utils-ts": "0.1.3"
|
|
38
38
|
}
|
|
39
39
|
}
|