twin3-sdk 0.2.14-pre-alpha → 0.2.15-pre-alpha
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 +6 -5
- package/index.d.ts +73 -2
- package/js/index.js +10 -0
- package/js/index.mjs +10 -0
- package/js/internal/comm.js +362 -2
- package/js/memory-guard.js +173 -0
- package/js/shield.d.ts +4 -0
- package/js/shield.js +5 -0
- package/js/shield.mjs +4 -0
- package/js/trust/didweb.js +262 -0
- package/js/trust.d.ts +6 -0
- package/js/trust.js +7 -0
- package/js/trust.mjs +6 -0
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -66,7 +66,8 @@ L1 also exposes a candidate discovery evidence API for xAgent ID and xHuman ID.
|
|
|
66
66
|
|
|
67
67
|
Python and Node support [explicit Matrix comparison profiles](docs/matrix-runtime-profiles.md),
|
|
68
68
|
including weighted/masked cosine and structured coverage results. Node constructor
|
|
69
|
-
coercions still differ
|
|
69
|
+
coercions still differ. Node TaskInbox admits owner-policy receipts with
|
|
70
|
+
applyPayment and injected-verifier receipts with applyX402Payment. Evidence
|
|
70
71
|
trail is experimental until an actual consumer supplies durable integration evidence.
|
|
71
72
|
|
|
72
73
|
`(experimental)` marks a capability whose row in [`tests/capability-inventory.json`](tests/capability-inventory.json) is not yet `available`: it is importable today and its surface may still change. Everything unmarked is `available`. A name written `Class.method` is a method, not a module export. Every name in this table is checked against a real public export by [`tests/test_readme_capability_claims.py`](tests/test_readme_capability_claims.py).
|
|
@@ -115,22 +116,22 @@ pip install -e /path/to/twin3-sdk
|
|
|
115
116
|
* Any protocol or algorithm improvement in `twin3-sdk` is reflected in both applications in **0 milliseconds**.
|
|
116
117
|
|
|
117
118
|
#### 2. Production Distribution
|
|
118
|
-
`v0.2.
|
|
119
|
+
`v0.2.15-pre-alpha` is the current release candidate: `0.2.15-pre-alpha` for npm and `0.2.15a0` for PyPI. Publication is pending. Consumers must pin the exact released version and lock its registry integrity; never use a mutable range for a cryptographic protocol dependency. This release stays pre-alpha. Marketplace or sales copy may offer it for evaluation; it is not a stable release, and the npm dist-tag is `next`, not `latest`.
|
|
119
120
|
|
|
120
121
|
`package.json` `engines` sets Node.js to `>=18` and does not set an npm engine. Any npm that can install a tarball can consume the package. Packing this repository was checked with npm 10 or newer; the stricter npm version in the release runbook applies only to Trusted Publishing.
|
|
121
122
|
|
|
122
123
|
After publication, install the exact released version from the registry:
|
|
123
124
|
|
|
124
125
|
```bash
|
|
125
|
-
npm install twin3-sdk@0.2.
|
|
126
|
-
pip install twin3-sdk==0.2.
|
|
126
|
+
npm install twin3-sdk@0.2.15-pre-alpha
|
|
127
|
+
pip install twin3-sdk==0.2.15a0
|
|
127
128
|
```
|
|
128
129
|
|
|
129
130
|
For local evaluation, you can also use the packed npm tarball. Do not install from a git URL or a version range:
|
|
130
131
|
|
|
131
132
|
```bash
|
|
132
133
|
npm pack --ignore-scripts
|
|
133
|
-
npm install ./twin3-sdk-0.2.
|
|
134
|
+
npm install ./twin3-sdk-0.2.15-pre-alpha.tgz
|
|
134
135
|
```
|
|
135
136
|
|
|
136
137
|
---
|
package/index.d.ts
CHANGED
|
@@ -848,6 +848,12 @@ export interface KyaBinding {
|
|
|
848
848
|
receipt: string;
|
|
849
849
|
}
|
|
850
850
|
|
|
851
|
+
export declare class DidResolutionError extends Error { readonly code: string; }
|
|
852
|
+
export declare function didWebForHost(host: string): string;
|
|
853
|
+
export declare function didWebUrl(did: string): string;
|
|
854
|
+
export declare function resolveDidWeb(did: string, fetch: (method: string, url: string, headers: Record<string, string>, body: null) => [number, string | Uint8Array | null], maxBytes?: number): { did: string; url: string; method_id: string; key_id: string; public_key: string; };
|
|
855
|
+
export declare function multibaseEd25519(raw: Uint8Array, multicodec?: boolean): string;
|
|
856
|
+
export declare const AuthorityAnchor: { readonly SUPPORTED_KINDS: readonly string[]; isValidKind(kind: string): boolean; };
|
|
851
857
|
export declare function createKyaChallenge(params: {
|
|
852
858
|
owner: string;
|
|
853
859
|
identity: KyaIdentity;
|
|
@@ -1032,6 +1038,54 @@ export declare function verifyEnvelopeSignature(envelope: Envelope, publicKey: C
|
|
|
1032
1038
|
|
|
1033
1039
|
export declare function scanText(text: string, options?: { source?: string; now?: number }): ShieldVerdict;
|
|
1034
1040
|
|
|
1041
|
+
export declare const MEMORY_SCHEMA: string;
|
|
1042
|
+
export declare const REVOCATION_SCHEMA: string;
|
|
1043
|
+
|
|
1044
|
+
export declare class MemoryRejected extends Error {
|
|
1045
|
+
readonly code: string;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
export interface MemoryShieldStamp {
|
|
1049
|
+
verdict: string;
|
|
1050
|
+
reason_codes: string[];
|
|
1051
|
+
receipt: unknown;
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
export interface MemoryEntry {
|
|
1055
|
+
schema: string;
|
|
1056
|
+
id: string;
|
|
1057
|
+
text: string;
|
|
1058
|
+
origin: string;
|
|
1059
|
+
kind: "data" | "instruction";
|
|
1060
|
+
treat_as: "data" | "instruction";
|
|
1061
|
+
actor: string;
|
|
1062
|
+
source: string;
|
|
1063
|
+
source_epoch: number;
|
|
1064
|
+
at: number;
|
|
1065
|
+
shield: MemoryShieldStamp | null;
|
|
1066
|
+
flagged: boolean;
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
export interface MemoryRevocation {
|
|
1070
|
+
schema: string;
|
|
1071
|
+
source: string;
|
|
1072
|
+
epoch: number;
|
|
1073
|
+
actor: string;
|
|
1074
|
+
reason: string;
|
|
1075
|
+
at: number;
|
|
1076
|
+
removed: number;
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
export declare class MemoryGuard {
|
|
1080
|
+
constructor(store: { entries?: MemoryEntry[]; revocations?: Record<string, MemoryRevocation>; purges?: unknown[] }, ensemble?: unknown, intel?: unknown);
|
|
1081
|
+
revokedEpoch(source: string): number | null;
|
|
1082
|
+
purgeSource(source: string, actor: string, reason: string, now?: number, epoch?: number): MemoryRevocation;
|
|
1083
|
+
write(text: string, origin: string, actor: string, kind?: "data" | "instruction", source?: string, sourceEpoch?: number, now?: number): MemoryEntry;
|
|
1084
|
+
recall(kinds?: Array<"data" | "instruction">, origins?: string[] | null, includeFlagged?: boolean): MemoryEntry[];
|
|
1085
|
+
instructions(): MemoryEntry[];
|
|
1086
|
+
purgeOrigin(origin: string, actor: string, reason: string): number;
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1035
1089
|
export declare const TASK_EXPORT_SCHEMA: string;
|
|
1036
1090
|
|
|
1037
1091
|
export declare function taskTrustLine(task: Record<string, unknown>, row: Record<string, unknown> | null): string;
|
|
@@ -1552,8 +1606,8 @@ export interface TaskInboxOptions {
|
|
|
1552
1606
|
ensemble?: null | undefined;
|
|
1553
1607
|
intel?: null | undefined;
|
|
1554
1608
|
requirePlanDiff?: true;
|
|
1555
|
-
replayStore?:
|
|
1556
|
-
replay_store?:
|
|
1609
|
+
replayStore?: { consume(key: string, expiresAt: number, now?: number): boolean | Promise<boolean> } | null;
|
|
1610
|
+
replay_store?: { consume(key: string, expiresAt: number, now?: number): boolean | Promise<boolean> } | null;
|
|
1557
1611
|
}
|
|
1558
1612
|
|
|
1559
1613
|
export declare class IntakeRejected extends Error {
|
|
@@ -1614,6 +1668,10 @@ export declare class TaskInbox {
|
|
|
1614
1668
|
}): TaskInboxTask;
|
|
1615
1669
|
clearReview(taskId: string, actor: string, reason: string, now?: number): TaskInboxTask;
|
|
1616
1670
|
clearReview(input: { taskId: string; actor: string; reason: string; now?: number }): TaskInboxTask;
|
|
1671
|
+
getPolicy(): Record<string, any> | null;
|
|
1672
|
+
setPolicy(policy: Record<string, any>): Record<string, any>;
|
|
1673
|
+
quoteFor(identity: { kind: string; value: string }, now?: number): Record<string, any> | null;
|
|
1674
|
+
applyPayment(identity: { kind: string; value: string }, receipt: Record<string, any>, ownerPublicKey: CryptoKeyInput, quoteBody?: Record<string, any> | null, actor?: string, now?: number): Promise<Record<string, any>>;
|
|
1617
1675
|
recordPlanDiff(taskId: string, before: any[], after: any[], actor: string,
|
|
1618
1676
|
authorized?: string[], now?: number): Record<string, any>;
|
|
1619
1677
|
recordPlanDiff(input: {
|
|
@@ -1624,6 +1682,19 @@ export declare class TaskInbox {
|
|
|
1624
1682
|
authorized?: string[];
|
|
1625
1683
|
now?: number;
|
|
1626
1684
|
}): Record<string, any>;
|
|
1685
|
+
getPolicy(): Record<string, any> | null;
|
|
1686
|
+
setPolicy(policy: Record<string, any>): Record<string, any>;
|
|
1687
|
+
applyX402Payment(
|
|
1688
|
+
identity: { kind: string; value: string },
|
|
1689
|
+
demand: Record<string, any>,
|
|
1690
|
+
receipt: Record<string, any>,
|
|
1691
|
+
publicKey: CryptoKeyInput,
|
|
1692
|
+
chainVerifier: { verifyPayment?: (demand: Record<string, any>, receipt: Record<string, any>) => Promise<Record<string, any>> | Record<string, any>; verify_payment?: (demand: Record<string, any>, receipt: Record<string, any>) => Promise<Record<string, any>> | Record<string, any> } | ((demand: Record<string, any>, receipt: Record<string, any>) => Promise<Record<string, any>> | Record<string, any>),
|
|
1693
|
+
replayStore?: { reserve: Function; commit: Function; release: Function } | null,
|
|
1694
|
+
minimumConfirmations?: number,
|
|
1695
|
+
actor?: string,
|
|
1696
|
+
now?: number,
|
|
1697
|
+
): Promise<Record<string, any>>;
|
|
1627
1698
|
expireStale(now?: number): string[];
|
|
1628
1699
|
verifyAuditChain(taskId: string): boolean;
|
|
1629
1700
|
}
|
package/js/index.js
CHANGED
|
@@ -86,6 +86,12 @@ module.exports = {
|
|
|
86
86
|
X402_FETCH_BOUNDS: discovery.X402_FETCH_BOUNDS,
|
|
87
87
|
keyId: trust.keyId,
|
|
88
88
|
createKyaChallenge: trust.createKyaChallenge,
|
|
89
|
+
AuthorityAnchor: trust.AuthorityAnchor,
|
|
90
|
+
DidResolutionError: trust.DidResolutionError,
|
|
91
|
+
didWebForHost: trust.didWebForHost,
|
|
92
|
+
didWebUrl: trust.didWebUrl,
|
|
93
|
+
resolveDidWeb: trust.resolveDidWeb,
|
|
94
|
+
multibaseEd25519: trust.multibaseEd25519,
|
|
89
95
|
verifyKyaChallenge: trust.verifyKyaChallenge,
|
|
90
96
|
completeKyaChallenge: trust.completeKyaChallenge,
|
|
91
97
|
verifyKyaBinding: trust.verifyKyaBinding,
|
|
@@ -154,6 +160,10 @@ module.exports = {
|
|
|
154
160
|
exportTask: comm.exportTask,
|
|
155
161
|
taskTrustLine: comm.taskTrustLine,
|
|
156
162
|
scanText: shield.scanText,
|
|
163
|
+
MEMORY_SCHEMA: shield.MEMORY_SCHEMA,
|
|
164
|
+
REVOCATION_SCHEMA: shield.REVOCATION_SCHEMA,
|
|
165
|
+
MemoryGuard: shield.MemoryGuard,
|
|
166
|
+
MemoryRejected: shield.MemoryRejected,
|
|
157
167
|
PLANDIFF_SCHEMA: shield.PLANDIFF_SCHEMA,
|
|
158
168
|
PLANDIFF_AUTHORITIES: shield.PLANDIFF_AUTHORITIES,
|
|
159
169
|
PLANDIFF_CONSEQUENTIAL: shield.PLANDIFF_CONSEQUENTIAL,
|
package/js/index.mjs
CHANGED
|
@@ -15,6 +15,7 @@ export const AGENT_CARD_SCHEMA = api.AGENT_CARD_SCHEMA;
|
|
|
15
15
|
export const AI_EXPOSURE_SCHEMA = api.AI_EXPOSURE_SCHEMA;
|
|
16
16
|
export const APPEAL_SCHEMA = api.APPEAL_SCHEMA;
|
|
17
17
|
export const AUTHORITY_AMBIGUOUS = api.AUTHORITY_AMBIGUOUS;
|
|
18
|
+
export const AuthorityAnchor = api.AuthorityAnchor;
|
|
18
19
|
export const AuthorizationLeaseError = api.AuthorizationLeaseError;
|
|
19
20
|
export const BUNDLE_MAX_AGE_SECONDS = api.BUNDLE_MAX_AGE_SECONDS;
|
|
20
21
|
export const CARD_CANONICALIZATION = api.CARD_CANONICALIZATION;
|
|
@@ -43,6 +44,7 @@ export const DISCLOSURE_STATES = api.DISCLOSURE_STATES;
|
|
|
43
44
|
export const DISCOVERY_SUMMARY_SCHEMA = api.DISCOVERY_SUMMARY_SCHEMA;
|
|
44
45
|
export const DISCOVERY_VIEW_SCHEMA = api.DISCOVERY_VIEW_SCHEMA;
|
|
45
46
|
export const DenseVector256 = api.DenseVector256;
|
|
47
|
+
export const DidResolutionError = api.DidResolutionError;
|
|
46
48
|
export const DisclosureError = api.DisclosureError;
|
|
47
49
|
export const DiscoveryEvidenceError = api.DiscoveryEvidenceError;
|
|
48
50
|
export const ENTERPRISE_MATRIX_SCHEMA = api.ENTERPRISE_MATRIX_SCHEMA;
|
|
@@ -63,6 +65,9 @@ export const InMemoryNonceStore = api.InMemoryNonceStore;
|
|
|
63
65
|
export const InMemorySignCountStore = api.InMemorySignCountStore;
|
|
64
66
|
export const IntakeRejected = api.IntakeRejected;
|
|
65
67
|
export const MAX_FEDERATED_PENALTY_PER_PEER = api.MAX_FEDERATED_PENALTY_PER_PEER;
|
|
68
|
+
export const MEMORY_SCHEMA = api.MEMORY_SCHEMA;
|
|
69
|
+
export const MemoryGuard = api.MemoryGuard;
|
|
70
|
+
export const MemoryRejected = api.MemoryRejected;
|
|
66
71
|
export const NONCE_RETENTION = api.NONCE_RETENTION;
|
|
67
72
|
export const PLANDIFF_AUTHORITIES = api.PLANDIFF_AUTHORITIES;
|
|
68
73
|
export const PLANDIFF_AUTHORIZED_BY_KIND = api.PLANDIFF_AUTHORIZED_BY_KIND;
|
|
@@ -79,6 +84,7 @@ export const REPLAY_FINAL_EXPIRY = api.REPLAY_FINAL_EXPIRY;
|
|
|
79
84
|
export const REPLAY_RESERVATION_SECONDS = api.REPLAY_RESERVATION_SECONDS;
|
|
80
85
|
export const REPUTATION_BUNDLE_SCHEMA = api.REPUTATION_BUNDLE_SCHEMA;
|
|
81
86
|
export const REPUTATION_HALF_LIFE_SECONDS = api.REPUTATION_HALF_LIFE_SECONDS;
|
|
87
|
+
export const REVOCATION_SCHEMA = api.REVOCATION_SCHEMA;
|
|
82
88
|
export const SETTLEMENT_RECEIPT_SCHEMA = api.SETTLEMENT_RECEIPT_SCHEMA;
|
|
83
89
|
export const SOVEREIGN_CARD_SCHEMA = api.SOVEREIGN_CARD_SCHEMA;
|
|
84
90
|
export const STALE_AFTER = api.STALE_AFTER;
|
|
@@ -153,6 +159,8 @@ export const descriptorBody = api.descriptorBody;
|
|
|
153
159
|
export const descriptorBytes = api.descriptorBytes;
|
|
154
160
|
export const descriptorDigest = api.descriptorDigest;
|
|
155
161
|
export const descriptorEtag = api.descriptorEtag;
|
|
162
|
+
export const didWebForHost = api.didWebForHost;
|
|
163
|
+
export const didWebUrl = api.didWebUrl;
|
|
156
164
|
export const diffPlans = api.diffPlans;
|
|
157
165
|
export const disclose = api.disclose;
|
|
158
166
|
export const disclosureStateOf = api.disclosureStateOf;
|
|
@@ -188,6 +196,7 @@ export const maxTierFor = api.maxTierFor;
|
|
|
188
196
|
export const mayClaim = api.mayClaim;
|
|
189
197
|
export const mayDeny = api.mayDeny;
|
|
190
198
|
export const migrateCardToEmit = api.migrateCardToEmit;
|
|
199
|
+
export const multibaseEd25519 = api.multibaseEd25519;
|
|
191
200
|
export const normalizeAction = api.normalizeAction;
|
|
192
201
|
export const normalizeAiExposure = api.normalizeAiExposure;
|
|
193
202
|
export const normalizeCounterpartyStore = api.normalizeCounterpartyStore;
|
|
@@ -207,6 +216,7 @@ export const receiptForRecord = api.receiptForRecord;
|
|
|
207
216
|
export const recordExecutionOutcome = api.recordExecutionOutcome;
|
|
208
217
|
export const resolveAppeal = api.resolveAppeal;
|
|
209
218
|
export const resolveDeclarationEndpoints = api.resolveDeclarationEndpoints;
|
|
219
|
+
export const resolveDidWeb = api.resolveDidWeb;
|
|
210
220
|
export const resolveDocumentPath = api.resolveDocumentPath;
|
|
211
221
|
export const scanText = api.scanText;
|
|
212
222
|
export const signA2AAgentCard = api.signA2AAgentCard;
|
package/js/internal/comm.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
const core = require("./core.js");
|
|
3
3
|
const shield = require("./shield.js");
|
|
4
4
|
const trust = require("./trust.js");
|
|
5
|
+
const settlement = require("./settlement.js");
|
|
5
6
|
|
|
6
7
|
const commCounterparty = require("../comm/counterparty.js");
|
|
7
8
|
function envelopeBuilderNumber(value, code) {
|
|
@@ -684,7 +685,7 @@ function taskAudit(task, state, actor, reason, at, receipt = null) {
|
|
|
684
685
|
task.history.push(entry);
|
|
685
686
|
task.audit_head = entry.digest;
|
|
686
687
|
}
|
|
687
|
-
const TASK_INBOX_UNSUPPORTED_OPTIONS = Object.freeze(["ensemble", "intel"
|
|
688
|
+
const TASK_INBOX_UNSUPPORTED_OPTIONS = Object.freeze(["ensemble", "intel"]);
|
|
688
689
|
const TASK_INBOX_UNSUPPORTED_OPTION_SET = new Set(TASK_INBOX_UNSUPPORTED_OPTIONS);
|
|
689
690
|
function taskInboxUnsupportedOption(name) {
|
|
690
691
|
const error = new core.ProtocolError("inbox_option_not_supported");
|
|
@@ -715,6 +716,90 @@ function taskInboxCopyOwnEnumerableOptions(target, source) {
|
|
|
715
716
|
}
|
|
716
717
|
}
|
|
717
718
|
}
|
|
719
|
+
function x402Demand(value) {
|
|
720
|
+
const source = core.isPlainObject(value) ? value : {};
|
|
721
|
+
return {
|
|
722
|
+
schema: source.schema || "twin3-settlement-demand-v1",
|
|
723
|
+
demand_id: String(source.demand_id || ""),
|
|
724
|
+
recipient: String(source.recipient || ""),
|
|
725
|
+
amount: source.amount,
|
|
726
|
+
currency: source.currency || "USD",
|
|
727
|
+
network: source.network || "base",
|
|
728
|
+
token_address: source.token_address == null ? null : source.token_address,
|
|
729
|
+
expires_at: source.expires_at,
|
|
730
|
+
memo: source.memo || "",
|
|
731
|
+
};
|
|
732
|
+
}
|
|
733
|
+
function x402Receipt(value) {
|
|
734
|
+
const source = core.isPlainObject(value) ? value : {};
|
|
735
|
+
return {
|
|
736
|
+
schema: source.schema || "twin3-settlement-receipt-v1",
|
|
737
|
+
demand_id: String(source.demand_id || ""),
|
|
738
|
+
tx_hash: String(source.tx_hash || ""),
|
|
739
|
+
payer: String(source.payer || ""),
|
|
740
|
+
amount: source.amount,
|
|
741
|
+
currency: String(source.currency || ""),
|
|
742
|
+
settled_at: source.settled_at,
|
|
743
|
+
recipient: String(source.recipient || ""),
|
|
744
|
+
signature: String(source.signature || ""),
|
|
745
|
+
public_key: source.public_key == null ? null : source.public_key,
|
|
746
|
+
network: source.network || "base",
|
|
747
|
+
};
|
|
748
|
+
}
|
|
749
|
+
function x402JournalDigest(journal) {
|
|
750
|
+
return core.crypto.createHash("sha256")
|
|
751
|
+
.update(core.legacySortedBytes({ binding: journal.binding, context: journal.context, credit: journal.credit }, "payment_journal_unserializable"))
|
|
752
|
+
.digest("hex");
|
|
753
|
+
}
|
|
754
|
+
function x402SameCanonical(left, right) {
|
|
755
|
+
return core.legacySortedBytes(left, "payment_journal_unserializable")
|
|
756
|
+
.equals(core.legacySortedBytes(right, "payment_journal_unserializable"));
|
|
757
|
+
}
|
|
758
|
+
function x402Context(policy, row) {
|
|
759
|
+
const source = row || {};
|
|
760
|
+
return {
|
|
761
|
+
policy,
|
|
762
|
+
kya_binding: source.kya_binding == null ? null : source.kya_binding,
|
|
763
|
+
key_possession_verified: Boolean(source.key_possession_verified),
|
|
764
|
+
bound_key_id: source.bound_key_id == null ? null : source.bound_key_id,
|
|
765
|
+
bound_public_key: source.bound_public_key == null ? null : source.bound_public_key,
|
|
766
|
+
handshake_receipt: source.handshake_receipt == null ? null : source.handshake_receipt,
|
|
767
|
+
bound_wallet: source.bound_wallet == null ? null : source.bound_wallet,
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
function x402BindingError(row) {
|
|
771
|
+
const binding = row && row.kya_binding;
|
|
772
|
+
if (!core.pythonTruthy(row && row.key_possession_verified) || !core.isPlainObject(binding))
|
|
773
|
+
return "payment_current_binding_required";
|
|
774
|
+
if (binding.key_id !== row.bound_key_id || binding.public_key !== row.bound_public_key || binding.receipt !== row.handshake_receipt)
|
|
775
|
+
return "payment_current_binding_mismatch";
|
|
776
|
+
return null;
|
|
777
|
+
}
|
|
778
|
+
function x402ChainAdapter(chainVerifier, demand, receipt) {
|
|
779
|
+
return {
|
|
780
|
+
async verifyPayment() {
|
|
781
|
+
const method = typeof chainVerifier === "function"
|
|
782
|
+
? chainVerifier
|
|
783
|
+
: (chainVerifier && (chainVerifier.verifyPayment || chainVerifier.verify_payment));
|
|
784
|
+
if (typeof method !== "function")
|
|
785
|
+
core.fail("chain_verifier_invalid");
|
|
786
|
+
const evidence = await method.call(chainVerifier, demand, receipt);
|
|
787
|
+
if (!evidence || typeof evidence !== "object")
|
|
788
|
+
return evidence;
|
|
789
|
+
return {
|
|
790
|
+
txHash: evidence.txHash || evidence.tx_hash,
|
|
791
|
+
network: evidence.network,
|
|
792
|
+
payer: evidence.payer,
|
|
793
|
+
recipient: evidence.recipient,
|
|
794
|
+
amount: evidence.amount,
|
|
795
|
+
currency: evidence.currency,
|
|
796
|
+
confirmations: evidence.confirmations,
|
|
797
|
+
finalized: evidence.finalized,
|
|
798
|
+
tokenAddress: evidence.tokenAddress || evidence.token_address,
|
|
799
|
+
};
|
|
800
|
+
},
|
|
801
|
+
};
|
|
802
|
+
}
|
|
718
803
|
class TaskInbox {
|
|
719
804
|
constructor(...args) {
|
|
720
805
|
if (args.length > 4) {
|
|
@@ -770,6 +855,10 @@ class TaskInbox {
|
|
|
770
855
|
if (!Number.isFinite(this._rateWindow))
|
|
771
856
|
throw new core.ProtocolError("rate_window_invalid");
|
|
772
857
|
this._requirePlanDiff = true;
|
|
858
|
+
const replay = options.replay_store !== undefined && options.replay_store !== null
|
|
859
|
+
? options.replay_store
|
|
860
|
+
: (options.replayStore !== undefined && options.replayStore !== null ? options.replayStore : null);
|
|
861
|
+
this._nonceStore = replay;
|
|
773
862
|
}
|
|
774
863
|
_now(override) { return taskNow(this._clock, override); }
|
|
775
864
|
_partition() {
|
|
@@ -803,6 +892,254 @@ class TaskInbox {
|
|
|
803
892
|
part.rate[senderKey].push(at);
|
|
804
893
|
return true;
|
|
805
894
|
}
|
|
895
|
+
getPolicy() {
|
|
896
|
+
const policy = this._partition().policy;
|
|
897
|
+
if (!policy)
|
|
898
|
+
return null;
|
|
899
|
+
return structuredClone(policy);
|
|
900
|
+
}
|
|
901
|
+
setPolicy(policy) {
|
|
902
|
+
const normalized = settlement.normalizePolicy(policy);
|
|
903
|
+
this._partition().policy = normalized;
|
|
904
|
+
return structuredClone(normalized);
|
|
905
|
+
}
|
|
906
|
+
async applyX402Payment(identity, demand, receipt, publicKey, chainVerifier, replayStore = undefined, minimumConfirmations = 1, actor = "x402", now = undefined) {
|
|
907
|
+
const at = this._now(now);
|
|
908
|
+
if (typeof at !== "number" || !Number.isFinite(at))
|
|
909
|
+
core.fail("verification_time_invalid");
|
|
910
|
+
identity = structuredClone(identity);
|
|
911
|
+
this._parties.ensure(identity, { now: at });
|
|
912
|
+
if (this._parties.isFrozen(identity))
|
|
913
|
+
core.fail("counterparty_frozen");
|
|
914
|
+
this._parties.assertAccessReady(identity, { now: at });
|
|
915
|
+
const store = replayStore != null ? replayStore : this._nonceStore;
|
|
916
|
+
if (store == null)
|
|
917
|
+
core.fail("payment_replay_store_required");
|
|
918
|
+
const policy = this.getPolicy();
|
|
919
|
+
if (!policy)
|
|
920
|
+
core.fail("payment_policy_not_configured");
|
|
921
|
+
demand = x402Demand(demand);
|
|
922
|
+
receipt = x402Receipt(receipt);
|
|
923
|
+
const payout = String(policy.payout_address || "").trim();
|
|
924
|
+
if (!payout)
|
|
925
|
+
core.fail("payment_payout_address_required");
|
|
926
|
+
if (demand.recipient.trim().toLowerCase() !== payout.toLowerCase())
|
|
927
|
+
core.fail("payment_demand_recipient_mismatch");
|
|
928
|
+
const price = core.isPlainObject(policy.price) ? policy.price : {};
|
|
929
|
+
if (Number(demand.amount) < Number(price.amount || 0))
|
|
930
|
+
core.fail("payment_demand_amount_insufficient");
|
|
931
|
+
const policyCurrency = String(price.currency || "").trim().toUpperCase();
|
|
932
|
+
if (!policyCurrency || demand.currency.toUpperCase() !== policyCurrency)
|
|
933
|
+
core.fail("payment_demand_currency_mismatch");
|
|
934
|
+
const partyRow = this._parties.get(identity, { now: at }) || {};
|
|
935
|
+
const boundWallet = String(partyRow.bound_wallet || "").trim().toLowerCase();
|
|
936
|
+
const payer = receipt.payer.trim().toLowerCase();
|
|
937
|
+
const senderValue = String(identity.value || "").trim().toLowerCase();
|
|
938
|
+
const senderKey = counterpartyKey(identity).toLowerCase();
|
|
939
|
+
if (boundWallet) {
|
|
940
|
+
if (payer !== boundWallet)
|
|
941
|
+
core.fail("payment_payer_mismatch");
|
|
942
|
+
}
|
|
943
|
+
else if (payer !== senderValue && payer !== senderKey) {
|
|
944
|
+
core.fail("payment_payer_mismatch");
|
|
945
|
+
}
|
|
946
|
+
const part = this._partition();
|
|
947
|
+
if (!core.isPlainObject(part.payment_journal))
|
|
948
|
+
part.payment_journal = {};
|
|
949
|
+
const journalBook = part.payment_journal;
|
|
950
|
+
const txHash = receipt.tx_hash.toLowerCase();
|
|
951
|
+
if (!publicKey)
|
|
952
|
+
core.fail("trusted_receipt_public_key_required");
|
|
953
|
+
let issuerKey;
|
|
954
|
+
try {
|
|
955
|
+
issuerKey = core.exportEd25519PublicKey(publicKey);
|
|
956
|
+
}
|
|
957
|
+
catch (error) {
|
|
958
|
+
core.fail("receipt_signature_invalid", error);
|
|
959
|
+
}
|
|
960
|
+
const binding = {
|
|
961
|
+
owner: this._owner,
|
|
962
|
+
identity_key: counterpartyKey(identity),
|
|
963
|
+
demand,
|
|
964
|
+
receipt,
|
|
965
|
+
issuer_public_key: issuerKey,
|
|
966
|
+
minimum_confirmations: minimumConfirmations,
|
|
967
|
+
};
|
|
968
|
+
const existingKey = Object.prototype.hasOwnProperty.call(journalBook, receipt.tx_hash) ? receipt.tx_hash : txHash;
|
|
969
|
+
if (Object.prototype.hasOwnProperty.call(journalBook, existingKey)) {
|
|
970
|
+
const journal = journalBook[existingKey];
|
|
971
|
+
let valid = false;
|
|
972
|
+
try {
|
|
973
|
+
valid = journal.schema === "twin3-x402-credit-journal-v1"
|
|
974
|
+
&& journal.binding_digest === x402JournalDigest(journal)
|
|
975
|
+
&& (journal.status === "pending_credit" || journal.status === "credited");
|
|
976
|
+
}
|
|
977
|
+
catch {
|
|
978
|
+
valid = false;
|
|
979
|
+
}
|
|
980
|
+
if (!valid)
|
|
981
|
+
core.fail("payment_journal_incomplete");
|
|
982
|
+
if (!x402SameCanonical(journal.binding, binding))
|
|
983
|
+
core.fail("payment_journal_binding_mismatch");
|
|
984
|
+
if (journal.status === "credited")
|
|
985
|
+
core.fail("payment_receipt_replayed");
|
|
986
|
+
return this._creditX402Journal(journal, at);
|
|
987
|
+
}
|
|
988
|
+
const bindingError = x402BindingError(partyRow);
|
|
989
|
+
if (bindingError)
|
|
990
|
+
throw new TierTransitionError(bindingError);
|
|
991
|
+
const splitAt = binding.identity_key.indexOf(":");
|
|
992
|
+
const journal = {
|
|
993
|
+
schema: "twin3-x402-credit-journal-v1",
|
|
994
|
+
binding,
|
|
995
|
+
context: x402Context(policy, partyRow),
|
|
996
|
+
credit: {
|
|
997
|
+
identity: { kind: binding.identity_key.slice(0, splitAt), value: binding.identity_key.slice(splitAt + 1) },
|
|
998
|
+
receipt: {
|
|
999
|
+
payment_id: `x402:${demand.network.toLowerCase()}:${txHash}`,
|
|
1000
|
+
quote_id: demand.demand_id,
|
|
1001
|
+
amount: String(receipt.amount),
|
|
1002
|
+
currency: receipt.currency,
|
|
1003
|
+
reference: receipt.tx_hash,
|
|
1004
|
+
paid_at: receipt.settled_at,
|
|
1005
|
+
},
|
|
1006
|
+
tier_seconds: core.pythonInt(policy.paid_tier_seconds, "paid_tier_seconds_invalid"),
|
|
1007
|
+
actor: String(actor),
|
|
1008
|
+
at,
|
|
1009
|
+
},
|
|
1010
|
+
status: "pending_credit",
|
|
1011
|
+
};
|
|
1012
|
+
journal.binding_digest = x402JournalDigest(journal);
|
|
1013
|
+
await settlement.verifyX402Payment({
|
|
1014
|
+
demandAmount: demand.amount,
|
|
1015
|
+
receiptAmount: receipt.amount,
|
|
1016
|
+
demandRecipient: demand.recipient,
|
|
1017
|
+
receiptRecipient: receipt.recipient,
|
|
1018
|
+
demandCurrency: demand.currency,
|
|
1019
|
+
receiptCurrency: receipt.currency,
|
|
1020
|
+
demandNetwork: demand.network,
|
|
1021
|
+
receiptNetwork: receipt.network,
|
|
1022
|
+
txHash: receipt.tx_hash,
|
|
1023
|
+
payer: receipt.payer,
|
|
1024
|
+
signature: receipt.signature,
|
|
1025
|
+
demandId: demand.demand_id,
|
|
1026
|
+
receiptDemandId: receipt.demand_id,
|
|
1027
|
+
settledAt: receipt.settled_at,
|
|
1028
|
+
trustedPublicKey: issuerKey,
|
|
1029
|
+
demandExpiresAt: demand.expires_at,
|
|
1030
|
+
demandSchema: demand.schema,
|
|
1031
|
+
receiptSchema: receipt.schema,
|
|
1032
|
+
tokenAddress: demand.token_address || undefined,
|
|
1033
|
+
now: at,
|
|
1034
|
+
chainVerifier: x402ChainAdapter(chainVerifier, demand, receipt),
|
|
1035
|
+
replayStore: store,
|
|
1036
|
+
minimumConfirmations,
|
|
1037
|
+
});
|
|
1038
|
+
journalBook[txHash] = journal;
|
|
1039
|
+
return this._creditX402Journal(journal, at);
|
|
1040
|
+
}
|
|
1041
|
+
_creditX402Journal(journal, at) {
|
|
1042
|
+
const credit = journal.credit;
|
|
1043
|
+
const identity = credit.identity;
|
|
1044
|
+
const current = this._parties.get(identity, { now: at }) || {};
|
|
1045
|
+
if (current.frozen)
|
|
1046
|
+
core.fail("counterparty_frozen");
|
|
1047
|
+
this._parties.assertAccessReady(identity, { now: at });
|
|
1048
|
+
if (!x402SameCanonical(journal.context, x402Context(this.getPolicy(), current)))
|
|
1049
|
+
core.fail("payment_recovery_pending");
|
|
1050
|
+
const originalEnd = credit.at + credit.tier_seconds;
|
|
1051
|
+
for (const entry of this._parties.ledger(identity)) {
|
|
1052
|
+
if (entry.kind === "payment" && entry.payment_id === credit.receipt.payment_id) {
|
|
1053
|
+
const drifted = ["quote_id", "amount", "currency", "reference"].some((key) => entry[key] !== credit.receipt[key]);
|
|
1054
|
+
if (drifted || typeof entry.paid_until !== "number" || !Number.isFinite(entry.paid_until) || entry.paid_until > originalEnd)
|
|
1055
|
+
core.fail("payment_recovery_pending");
|
|
1056
|
+
journal.status = "credited";
|
|
1057
|
+
journal.credited_at = entry.at;
|
|
1058
|
+
return current;
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
const remaining = Math.floor(originalEnd - at);
|
|
1062
|
+
if (at < credit.at || remaining <= 0)
|
|
1063
|
+
core.fail("payment_recovery_pending");
|
|
1064
|
+
const row = this._parties.recordPayment(identity, structuredClone(credit.receipt), remaining, credit.actor, { now: at });
|
|
1065
|
+
journal.status = "credited";
|
|
1066
|
+
journal.credited_at = at;
|
|
1067
|
+
return row;
|
|
1068
|
+
}
|
|
1069
|
+
quoteFor(identity, now = undefined) {
|
|
1070
|
+
const at = this._now(now);
|
|
1071
|
+
this._parties.ensure(identity, { now: at });
|
|
1072
|
+
if (this._parties.isFrozen(identity))
|
|
1073
|
+
core.fail("counterparty_frozen");
|
|
1074
|
+
this._parties.assertAccessReady(identity, { now: at });
|
|
1075
|
+
const policy = this._partition().policy;
|
|
1076
|
+
if (!policy)
|
|
1077
|
+
return null;
|
|
1078
|
+
const offer = settlement.quoteForCounterparty(policy, this._parties.get(identity, { now: at }), { now: at });
|
|
1079
|
+
if (offer && core.isPlainObject(offer) && offer.quote_id) {
|
|
1080
|
+
const part = this._partition();
|
|
1081
|
+
if (!core.isPlainObject(part.quotes))
|
|
1082
|
+
part.quotes = {};
|
|
1083
|
+
part.quotes[offer.quote_id] = structuredClone(offer);
|
|
1084
|
+
}
|
|
1085
|
+
return offer;
|
|
1086
|
+
}
|
|
1087
|
+
async applyPayment(identity, receipt, ownerPublicKey, quoteBody = undefined, actor = "billing", now = undefined) {
|
|
1088
|
+
void quoteBody;
|
|
1089
|
+
const at = this._now(now);
|
|
1090
|
+
this._parties.ensure(identity, { now: at });
|
|
1091
|
+
if (this._parties.isFrozen(identity))
|
|
1092
|
+
core.fail("counterparty_is_frozen");
|
|
1093
|
+
this._parties.assertAccessReady(identity, { now: at });
|
|
1094
|
+
const policy = this.getPolicy();
|
|
1095
|
+
const partyRow = this._parties.get(identity, { now: at });
|
|
1096
|
+
if (partyRow && !partyRow.verified)
|
|
1097
|
+
core.fail("unverified_identity_cannot_pay");
|
|
1098
|
+
if (partyRow && core.isPlainObject(receipt)) {
|
|
1099
|
+
for (const entry of Array.isArray(partyRow.ledger) ? partyRow.ledger : []) {
|
|
1100
|
+
if (entry.kind !== "payment")
|
|
1101
|
+
continue;
|
|
1102
|
+
const match = (core.pythonTruthy(receipt.receipt_id) && entry.receipt_id === receipt.receipt_id)
|
|
1103
|
+
|| (core.pythonTruthy(receipt.signature) && core.secureEquals(entry.signature, receipt.signature))
|
|
1104
|
+
|| (core.pythonTruthy(receipt.quote_id) && core.pythonTruthy(receipt.reference)
|
|
1105
|
+
&& entry.quote_id === receipt.quote_id && entry.reference === receipt.reference);
|
|
1106
|
+
if (match)
|
|
1107
|
+
return this._parties.recordPayment(identity, receipt, 0, actor, { now: at });
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
if (!policy)
|
|
1111
|
+
core.fail("payment_policy_not_configured");
|
|
1112
|
+
const quoteId = core.isPlainObject(receipt) ? receipt.quote_id : null;
|
|
1113
|
+
let canonical = null;
|
|
1114
|
+
if (core.pythonTruthy(quoteId)) {
|
|
1115
|
+
const quotes = this._partition().quotes;
|
|
1116
|
+
canonical = core.isPlainObject(quotes) ? quotes[quoteId] : null;
|
|
1117
|
+
if (canonical == null)
|
|
1118
|
+
core.fail("quote_not_found");
|
|
1119
|
+
}
|
|
1120
|
+
const verified = settlement.verifyReceipt({
|
|
1121
|
+
receipt,
|
|
1122
|
+
ownerPublicKey,
|
|
1123
|
+
owner: this._owner,
|
|
1124
|
+
identity,
|
|
1125
|
+
quote: canonical,
|
|
1126
|
+
now: at,
|
|
1127
|
+
});
|
|
1128
|
+
const grantsSeconds = canonical && canonical.grants_seconds != null
|
|
1129
|
+
? core.pythonInt(canonical.grants_seconds, "grants_seconds_invalid")
|
|
1130
|
+
: core.pythonInt(policy.paid_tier_seconds, "paid_tier_seconds_invalid");
|
|
1131
|
+
const receiptId = core.pythonTruthy(verified.receipt_id)
|
|
1132
|
+
? verified.receipt_id
|
|
1133
|
+
: (core.pythonTruthy(verified.quote_id) && core.pythonTruthy(verified.reference)
|
|
1134
|
+
? `${verified.quote_id}:${verified.reference}`
|
|
1135
|
+
: verified.signature);
|
|
1136
|
+
if (this._nonceStore != null && core.pythonTruthy(receiptId)) {
|
|
1137
|
+
const consumed = await this._nonceStore.consume(`offchain:${this._owner}:${receiptId}`, at + grantsSeconds, at);
|
|
1138
|
+
if (!consumed)
|
|
1139
|
+
return this._parties.recordPayment(identity, verified, 0, actor, { now: at });
|
|
1140
|
+
}
|
|
1141
|
+
return this._parties.recordPayment(identity, verified, grantsSeconds, actor, { now: at });
|
|
1142
|
+
}
|
|
806
1143
|
_nonceCheck(part, senderKey, nonce, deadline, at) {
|
|
807
1144
|
const seen = part.nonces;
|
|
808
1145
|
for (const key of Object.keys(seen)) {
|
|
@@ -879,7 +1216,30 @@ class TaskInbox {
|
|
|
879
1216
|
throw new IntakeRejected("sender_unverified_pinned_to_G0");
|
|
880
1217
|
}
|
|
881
1218
|
if ((TASK_TIER_ORDER[tier] ?? 0) < TASK_TIER_ORDER[requestedTier]) {
|
|
882
|
-
|
|
1219
|
+
const policy = part.policy;
|
|
1220
|
+
if (policy && tier === "G0") {
|
|
1221
|
+
let offer;
|
|
1222
|
+
try {
|
|
1223
|
+
offer = settlement.quoteForCounterparty(policy, this._parties.get(sender, { now: at }), { now: at });
|
|
1224
|
+
}
|
|
1225
|
+
catch (error) {
|
|
1226
|
+
throw new IntakeRejected(taskErrorCode(error, "payment_required"), null, null, error);
|
|
1227
|
+
}
|
|
1228
|
+
if (offer && offer.free_allowance) {
|
|
1229
|
+
this._parties.noteFreeAllowanceUse(sender, { now: at });
|
|
1230
|
+
tier = "G1";
|
|
1231
|
+
}
|
|
1232
|
+
else if (offer) {
|
|
1233
|
+
if (core.isPlainObject(offer) && offer.quote_id) {
|
|
1234
|
+
if (!core.isPlainObject(part.quotes))
|
|
1235
|
+
part.quotes = {};
|
|
1236
|
+
part.quotes[offer.quote_id] = structuredClone(offer);
|
|
1237
|
+
}
|
|
1238
|
+
throw new IntakeRejected("payment_required", null, offer);
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
if ((TASK_TIER_ORDER[tier] ?? 0) < TASK_TIER_ORDER[requestedTier])
|
|
1242
|
+
throw new IntakeRejected(`sender_tier_${tier}_below_${requestedTier}`);
|
|
883
1243
|
}
|
|
884
1244
|
let signatureVerified = false;
|
|
885
1245
|
let bound;
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const crypto = require("crypto");
|
|
4
|
+
const shield = require("./internal/shield.js");
|
|
5
|
+
|
|
6
|
+
const MEMORY_SCHEMA = "twin3-shield-memory-entry-v1";
|
|
7
|
+
const REVOCATION_SCHEMA = "twin3-shield-memory-revocation-v1";
|
|
8
|
+
const ORIGINS = new Set(["owner", "system", "counterparty", "tool", "web", "file", "subagent"]);
|
|
9
|
+
const INSTRUCTION_ORIGINS = new Set(["owner", "system"]);
|
|
10
|
+
|
|
11
|
+
class MemoryRejected extends Error {
|
|
12
|
+
constructor(code) {
|
|
13
|
+
super(code);
|
|
14
|
+
this.name = "MemoryRejected";
|
|
15
|
+
this.code = code;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function reject(code) {
|
|
20
|
+
throw new MemoryRejected(code);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function requireStore(store) {
|
|
24
|
+
if (store == null || typeof store !== "object" || Array.isArray(store)) reject("memory_store_required");
|
|
25
|
+
if (!Object.prototype.hasOwnProperty.call(store, "entries")) store.entries = [];
|
|
26
|
+
return store;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function isNonnegativeInteger(value) {
|
|
30
|
+
return typeof value === "number" && Number.isInteger(value) && value >= 0;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function legacySortedJson(value) {
|
|
34
|
+
const ordered = {};
|
|
35
|
+
for (const key of Object.keys(value).sort()) ordered[key] = value[key];
|
|
36
|
+
return Buffer.from(JSON.stringify(ordered));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function clone(value) {
|
|
40
|
+
return structuredClone(value);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
class MemoryGuard {
|
|
44
|
+
constructor(store, ensemble = null, intel = null) {
|
|
45
|
+
if (ensemble != null || intel != null) reject("memory_scanner_unsupported");
|
|
46
|
+
this._store = requireStore(store);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
_revocations() {
|
|
50
|
+
if (!Object.prototype.hasOwnProperty.call(this._store, "revocations") || this._store.revocations == null)
|
|
51
|
+
this._store.revocations = {};
|
|
52
|
+
return this._store.revocations;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
revokedEpoch(source) {
|
|
56
|
+
const entry = this._revocations()[source == null ? "" : String(source)];
|
|
57
|
+
return entry ? entry.epoch : null;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
_isRevoked(source, sourceEpoch) {
|
|
61
|
+
const revoked = this.revokedEpoch(source);
|
|
62
|
+
if (revoked == null) return false;
|
|
63
|
+
const epoch = sourceEpoch == null || sourceEpoch === false ? 0 : sourceEpoch;
|
|
64
|
+
return Number(epoch) <= Number(revoked);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
purgeSource(source, actor, reason, now = undefined, epoch = undefined) {
|
|
68
|
+
const at = now == null ? Math.floor(Date.now() / 1000) : Math.trunc(Number(now));
|
|
69
|
+
source = source == null ? "" : String(source);
|
|
70
|
+
if (!source.trim()) reject("memory_source_required");
|
|
71
|
+
if (epoch !== undefined && !isNonnegativeInteger(epoch)) reject("memory_revocation_epoch_invalid");
|
|
72
|
+
const current = this.revokedEpoch(source);
|
|
73
|
+
if (epoch === undefined) epoch = current == null ? 1 : current + 1;
|
|
74
|
+
if (current != null && epoch <= current) reject("memory_revocation_not_monotonic");
|
|
75
|
+
const revocations = this._revocations();
|
|
76
|
+
revocations[source] = {
|
|
77
|
+
schema: REVOCATION_SCHEMA,
|
|
78
|
+
source,
|
|
79
|
+
epoch,
|
|
80
|
+
actor: actor == null ? "" : String(actor),
|
|
81
|
+
reason: reason == null ? "" : String(reason),
|
|
82
|
+
at,
|
|
83
|
+
};
|
|
84
|
+
const before = this._store.entries.length;
|
|
85
|
+
this._store.entries = this._store.entries.filter(
|
|
86
|
+
(entry) => !(String(entry.source || "") === source && this._isRevoked(source, entry.source_epoch)),
|
|
87
|
+
);
|
|
88
|
+
revocations[source].removed = before - this._store.entries.length;
|
|
89
|
+
return clone(revocations[source]);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
write(text, origin, actor, kind = "data", source = "", sourceEpoch = 0, now = undefined) {
|
|
93
|
+
const at = now == null ? Math.floor(Date.now() / 1000) : Math.trunc(Number(now));
|
|
94
|
+
if (!ORIGINS.has(origin)) reject("memory_origin_unknown");
|
|
95
|
+
if (kind !== "data" && kind !== "instruction") reject("memory_kind_unknown");
|
|
96
|
+
if (kind === "instruction" && !INSTRUCTION_ORIGINS.has(origin)) reject("external_origin_cannot_write_instruction");
|
|
97
|
+
if (typeof text !== "string" || !text.trim()) reject("memory_text_required");
|
|
98
|
+
if (!isNonnegativeInteger(sourceEpoch)) reject("memory_source_epoch_invalid");
|
|
99
|
+
if (this._isRevoked(source, sourceEpoch)) reject("memory_source_revoked");
|
|
100
|
+
let verdict = null;
|
|
101
|
+
if (!INSTRUCTION_ORIGINS.has(origin)) {
|
|
102
|
+
const scanned = shield.scanText(text, { source: `memory:${origin}`, now: at });
|
|
103
|
+
verdict = scanned;
|
|
104
|
+
if (scanned.verdict === "block") reject("memory_blocked:" + scanned.reason_codes.join(","));
|
|
105
|
+
}
|
|
106
|
+
const storedSource = source == null ? "" : String(source);
|
|
107
|
+
const entry = {
|
|
108
|
+
schema: MEMORY_SCHEMA,
|
|
109
|
+
id: "mem_" + crypto.createHash("sha256").update(legacySortedJson({
|
|
110
|
+
t: text,
|
|
111
|
+
o: origin,
|
|
112
|
+
at,
|
|
113
|
+
n: this._store.entries.length,
|
|
114
|
+
})).digest("hex").slice(0, 20),
|
|
115
|
+
text,
|
|
116
|
+
origin,
|
|
117
|
+
kind,
|
|
118
|
+
treat_as: kind === "instruction" ? "instruction" : "data",
|
|
119
|
+
actor: actor == null ? "" : String(actor),
|
|
120
|
+
source: storedSource,
|
|
121
|
+
source_epoch: sourceEpoch,
|
|
122
|
+
at,
|
|
123
|
+
shield: verdict
|
|
124
|
+
? { verdict: verdict.verdict, reason_codes: verdict.reason_codes, receipt: verdict.receipt }
|
|
125
|
+
: null,
|
|
126
|
+
flagged: Boolean(verdict && verdict.verdict === "flag"),
|
|
127
|
+
};
|
|
128
|
+
this._store.entries.push(entry);
|
|
129
|
+
return clone(entry);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
recall(kinds = ["data", "instruction"], origins = null, includeFlagged = false) {
|
|
133
|
+
const allowed = new Set(kinds);
|
|
134
|
+
const originFilter = origins == null ? null : new Set(origins);
|
|
135
|
+
const out = [];
|
|
136
|
+
for (const entry of this._store.entries) {
|
|
137
|
+
if (!allowed.has(entry.kind)) continue;
|
|
138
|
+
if (this._isRevoked(entry.source, entry.source_epoch)) continue;
|
|
139
|
+
if (originFilter && !originFilter.has(entry.origin)) continue;
|
|
140
|
+
if (entry.flagged && !includeFlagged) continue;
|
|
141
|
+
const item = clone(entry);
|
|
142
|
+
if (!INSTRUCTION_ORIGINS.has(item.origin)) item.treat_as = "data";
|
|
143
|
+
out.push(item);
|
|
144
|
+
}
|
|
145
|
+
return out;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
instructions() {
|
|
149
|
+
return this.recall(["instruction"]).filter((entry) => INSTRUCTION_ORIGINS.has(entry.origin));
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
purgeOrigin(origin, actor, reason) {
|
|
153
|
+
const before = this._store.entries.length;
|
|
154
|
+
this._store.entries = this._store.entries.filter((entry) => entry.origin !== origin);
|
|
155
|
+
const removed = before - this._store.entries.length;
|
|
156
|
+
if (!Object.prototype.hasOwnProperty.call(this._store, "purges")) this._store.purges = [];
|
|
157
|
+
this._store.purges.push({
|
|
158
|
+
origin,
|
|
159
|
+
actor: String(actor),
|
|
160
|
+
reason: String(reason),
|
|
161
|
+
removed,
|
|
162
|
+
at: Math.floor(Date.now() / 1000),
|
|
163
|
+
});
|
|
164
|
+
return removed;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
module.exports = {
|
|
169
|
+
MEMORY_SCHEMA,
|
|
170
|
+
REVOCATION_SCHEMA,
|
|
171
|
+
MemoryGuard,
|
|
172
|
+
MemoryRejected,
|
|
173
|
+
};
|
package/js/shield.d.ts
CHANGED
package/js/shield.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const impl = require("./internal/shield.js");
|
|
3
|
+
const memory = require("./memory-guard.js");
|
|
3
4
|
|
|
4
5
|
module.exports = {
|
|
5
6
|
AuthorizationLeaseError: impl.authorizationLeaseApi.AuthorizationLeaseError,
|
|
@@ -16,6 +17,10 @@ module.exports = {
|
|
|
16
17
|
createInMemoryExecutionClaimStore: impl.authorizationLeaseApi.createInMemoryExecutionClaimStore,
|
|
17
18
|
recordExecutionOutcome: impl.authorizationLeaseApi.recordExecutionOutcome,
|
|
18
19
|
scanText: impl.scanText,
|
|
20
|
+
MEMORY_SCHEMA: memory.MEMORY_SCHEMA,
|
|
21
|
+
REVOCATION_SCHEMA: memory.REVOCATION_SCHEMA,
|
|
22
|
+
MemoryGuard: memory.MemoryGuard,
|
|
23
|
+
MemoryRejected: memory.MemoryRejected,
|
|
19
24
|
PLANDIFF_SCHEMA: impl.PLANDIFF_SCHEMA,
|
|
20
25
|
PLANDIFF_AUTHORITIES: impl.AUTHORITIES,
|
|
21
26
|
PLANDIFF_CONSEQUENTIAL: impl.CONSEQUENTIAL,
|
package/js/shield.mjs
CHANGED
|
@@ -13,6 +13,10 @@ export const claimExecution = api.claimExecution;
|
|
|
13
13
|
export const createInMemoryExecutionClaimStore = api.createInMemoryExecutionClaimStore;
|
|
14
14
|
export const recordExecutionOutcome = api.recordExecutionOutcome;
|
|
15
15
|
export const scanText = api.scanText;
|
|
16
|
+
export const MEMORY_SCHEMA = api.MEMORY_SCHEMA;
|
|
17
|
+
export const REVOCATION_SCHEMA = api.REVOCATION_SCHEMA;
|
|
18
|
+
export const MemoryGuard = api.MemoryGuard;
|
|
19
|
+
export const MemoryRejected = api.MemoryRejected;
|
|
16
20
|
export const PLANDIFF_SCHEMA = api.PLANDIFF_SCHEMA;
|
|
17
21
|
export const PLANDIFF_AUTHORITIES = api.PLANDIFF_AUTHORITIES;
|
|
18
22
|
export const PLANDIFF_CONSEQUENTIAL = api.PLANDIFF_CONSEQUENTIAL;
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const core = require("../internal/core.js");
|
|
4
|
+
|
|
5
|
+
const DID_WEB_RE = /^did:web:([A-Za-z0-9.\-]+(?:%3A\d{2,5})?)((?::[A-Za-z0-9._\-%]+)*)$/;
|
|
6
|
+
const NUMERIC_LABEL_RE = /^(?:\d+|0x[0-9a-f]*)$/i;
|
|
7
|
+
const B58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
8
|
+
const ANCHOR_KINDS = new Set(["duns", "lei", "human_id", "passkey"]);
|
|
9
|
+
|
|
10
|
+
class DidResolutionError extends Error {
|
|
11
|
+
constructor(code) {
|
|
12
|
+
super(code);
|
|
13
|
+
this.name = "DidResolutionError";
|
|
14
|
+
this.code = code;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function b58decode(text) {
|
|
19
|
+
let num = 0n;
|
|
20
|
+
for (const char of String(text)) {
|
|
21
|
+
const index = B58_ALPHABET.indexOf(char);
|
|
22
|
+
if (index < 0)
|
|
23
|
+
throw new DidResolutionError("did_key_invalid:invalid_multibase_key");
|
|
24
|
+
num = num * 58n + BigInt(index);
|
|
25
|
+
}
|
|
26
|
+
let hex = num.toString(16);
|
|
27
|
+
if (hex.length % 2)
|
|
28
|
+
hex = "0" + hex;
|
|
29
|
+
const body = num === 0n ? Buffer.alloc(0) : Buffer.from(hex, "hex");
|
|
30
|
+
const pad = text.length - text.replace(/^1+/, "").length;
|
|
31
|
+
return Buffer.concat([Buffer.alloc(pad), body]);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function b58encode(raw) {
|
|
35
|
+
let num = BigInt("0x" + Buffer.from(raw).toString("hex"));
|
|
36
|
+
let out = "";
|
|
37
|
+
while (num > 0n) {
|
|
38
|
+
const rem = num % 58n;
|
|
39
|
+
num /= 58n;
|
|
40
|
+
out = B58_ALPHABET[Number(rem)] + out;
|
|
41
|
+
}
|
|
42
|
+
let pad = 0;
|
|
43
|
+
for (const byte of raw) {
|
|
44
|
+
if (byte !== 0)
|
|
45
|
+
break;
|
|
46
|
+
pad += 1;
|
|
47
|
+
}
|
|
48
|
+
return "1".repeat(pad) + (out || (raw.length ? "" : ""));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function expandIpv6(text) {
|
|
52
|
+
const halves = text.toLowerCase().split("::");
|
|
53
|
+
if (halves.length > 2)
|
|
54
|
+
return null;
|
|
55
|
+
const left = halves[0] ? halves[0].split(":") : [];
|
|
56
|
+
const right = halves.length === 2 ? (halves[1] ? halves[1].split(":") : []) : [];
|
|
57
|
+
if (halves.length === 1 && left.length !== 8)
|
|
58
|
+
return null;
|
|
59
|
+
const missing = 8 - left.length - right.length;
|
|
60
|
+
if (missing < 0)
|
|
61
|
+
return null;
|
|
62
|
+
const parts = [...left, ...Array(missing).fill("0"), ...right];
|
|
63
|
+
if (parts.length !== 8)
|
|
64
|
+
return null;
|
|
65
|
+
const values = [];
|
|
66
|
+
for (const part of parts) {
|
|
67
|
+
if (!/^[0-9a-f]{0,4}$/i.test(part))
|
|
68
|
+
return null;
|
|
69
|
+
values.push(parseInt(part || "0", 16));
|
|
70
|
+
}
|
|
71
|
+
return values;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function forbiddenAddress(text) {
|
|
75
|
+
if (/^\d{1,3}(?:\.\d{1,3}){3}$/.test(text)) {
|
|
76
|
+
const parts = text.split(".").map((part) => Number(part));
|
|
77
|
+
if (parts.some((part) => part > 255))
|
|
78
|
+
return false;
|
|
79
|
+
const [a, b] = parts;
|
|
80
|
+
if (a === 0 || a === 10 || a === 127 || a >= 224)
|
|
81
|
+
return true;
|
|
82
|
+
if (a === 169 && b === 254)
|
|
83
|
+
return true;
|
|
84
|
+
if (a === 172 && b >= 16 && b <= 31)
|
|
85
|
+
return true;
|
|
86
|
+
if (a === 192 && b === 168)
|
|
87
|
+
return true;
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
const hextets = expandIpv6(text);
|
|
91
|
+
if (!hextets)
|
|
92
|
+
return false;
|
|
93
|
+
const first = hextets[0];
|
|
94
|
+
if (hextets.every((part) => part === 0))
|
|
95
|
+
return true;
|
|
96
|
+
if (hextets.slice(0, 7).every((part) => part === 0) && hextets[7] === 1)
|
|
97
|
+
return true;
|
|
98
|
+
if ((first & 0xffc0) === 0xfe80)
|
|
99
|
+
return true;
|
|
100
|
+
if ((first & 0xfe00) === 0xfc00)
|
|
101
|
+
return true;
|
|
102
|
+
if ((first & 0xff00) === 0xff00)
|
|
103
|
+
return true;
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function hostnameOf(host) {
|
|
108
|
+
if (host.startsWith("[")) {
|
|
109
|
+
const end = host.indexOf("]");
|
|
110
|
+
if (end < 1)
|
|
111
|
+
throw new DidResolutionError("did_host_invalid");
|
|
112
|
+
return host.slice(1, end);
|
|
113
|
+
}
|
|
114
|
+
const colon = host.lastIndexOf(":");
|
|
115
|
+
if (colon > 0 && host.indexOf(":") === colon && /^\d+$/.test(host.slice(colon + 1)))
|
|
116
|
+
return host.slice(0, colon);
|
|
117
|
+
return host;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function refuseNonpublicHost(host) {
|
|
121
|
+
let name = String(host || "");
|
|
122
|
+
name = hostnameOf(name);
|
|
123
|
+
const lowered = name.toLowerCase().replace(/\.+$/, "");
|
|
124
|
+
if (lowered === "localhost" || lowered.endsWith(".localhost"))
|
|
125
|
+
throw new DidResolutionError("did_host_forbidden");
|
|
126
|
+
if (forbiddenAddress(lowered))
|
|
127
|
+
throw new DidResolutionError("did_host_forbidden");
|
|
128
|
+
const labels = lowered.split(".");
|
|
129
|
+
if (NUMERIC_LABEL_RE.test(labels[labels.length - 1] || ""))
|
|
130
|
+
throw new DidResolutionError("did_host_forbidden");
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function didWebForHost(host) {
|
|
134
|
+
host = String(host || "").trim().toLowerCase().replace(/\/+$/, "");
|
|
135
|
+
if (!host || host.includes("/") || host.includes(" "))
|
|
136
|
+
throw new DidResolutionError("did_host_invalid");
|
|
137
|
+
refuseNonpublicHost(host);
|
|
138
|
+
return "did:web:" + host;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function didWebUrl(did) {
|
|
142
|
+
const match = DID_WEB_RE.exec(String(did || "").trim());
|
|
143
|
+
if (!match)
|
|
144
|
+
throw new DidResolutionError("did_not_web");
|
|
145
|
+
const host = decodeURIComponent(match[1]).toLowerCase();
|
|
146
|
+
const path = match[2].split(":").filter(Boolean).map((part) => decodeURIComponent(part));
|
|
147
|
+
if (path.some((part) => part === "" || part === "." || part === ".."))
|
|
148
|
+
throw new DidResolutionError("did_path_invalid");
|
|
149
|
+
refuseNonpublicHost(host);
|
|
150
|
+
if (path.length)
|
|
151
|
+
return "https://" + host + "/" + path.map((part) => encodeURIComponent(part)).join("/") + "/did.json";
|
|
152
|
+
return "https://" + host + "/.well-known/did.json";
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function rawEd25519(multibase) {
|
|
156
|
+
const text = String(multibase || "");
|
|
157
|
+
if (!text.startsWith("z"))
|
|
158
|
+
throw new DidResolutionError("did_key_invalid:public_key_format_unknown");
|
|
159
|
+
let raw = b58decode(text.slice(1));
|
|
160
|
+
if (raw.length === 34 && raw[0] === 0xed && raw[1] === 0x01)
|
|
161
|
+
raw = raw.subarray(2);
|
|
162
|
+
if (raw.length !== 32)
|
|
163
|
+
throw new DidResolutionError("did_key_invalid:invalid_ed25519_public_key_length");
|
|
164
|
+
return raw;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function keyFromMethod(method) {
|
|
168
|
+
const kind = String(method.type || "");
|
|
169
|
+
try {
|
|
170
|
+
if (kind === "Ed25519VerificationKey2020" && method.publicKeyMultibase)
|
|
171
|
+
return core.loadEd25519PublicKey("ed25519:" + core.b64url(rawEd25519(method.publicKeyMultibase)));
|
|
172
|
+
if ((kind === "JsonWebKey2020" || kind === "JsonWebKey") && core.isPlainObject(method.publicKeyJwk)) {
|
|
173
|
+
const jwk = method.publicKeyJwk;
|
|
174
|
+
if (jwk.kty === "OKP" && jwk.crv === "Ed25519" && jwk.x) {
|
|
175
|
+
const raw = core.b64urlDecode(String(jwk.x));
|
|
176
|
+
if (raw.length !== 32)
|
|
177
|
+
throw new DidResolutionError("did_jwk_invalid");
|
|
178
|
+
return core.loadEd25519PublicKey("ed25519:" + core.b64url(raw));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
if (error instanceof DidResolutionError)
|
|
184
|
+
throw error;
|
|
185
|
+
throw new DidResolutionError("did_key_invalid:" + (error.code || error.name || "Error"));
|
|
186
|
+
}
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function resolveDidWeb(did, fetch, maxBytes = 64 * 1024) {
|
|
191
|
+
did = String(did || "").trim();
|
|
192
|
+
const url = didWebUrl(did);
|
|
193
|
+
if (typeof fetch !== "function")
|
|
194
|
+
throw new DidResolutionError("did_resolver_not_configured");
|
|
195
|
+
let status;
|
|
196
|
+
let body;
|
|
197
|
+
try {
|
|
198
|
+
[status, body] = fetch("GET", url, { Accept: "application/did+json, application/json" }, null);
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
throw new DidResolutionError("did_fetch_failed:" + (error && error.name ? error.name : "Error"));
|
|
202
|
+
}
|
|
203
|
+
if (status !== 200)
|
|
204
|
+
throw new DidResolutionError("did_http_" + status);
|
|
205
|
+
const encoded = body == null ? null : Buffer.from(typeof body === "string" ? body : body);
|
|
206
|
+
if (encoded == null || encoded.length > maxBytes)
|
|
207
|
+
throw new DidResolutionError("did_document_too_large");
|
|
208
|
+
let doc;
|
|
209
|
+
try {
|
|
210
|
+
doc = JSON.parse(encoded.toString("utf8"));
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
throw new DidResolutionError("did_document_invalid_json");
|
|
214
|
+
}
|
|
215
|
+
if (!core.isPlainObject(doc) || String(doc.id || "") !== did)
|
|
216
|
+
throw new DidResolutionError("did_document_id_mismatch");
|
|
217
|
+
const methods = doc.verificationMethod;
|
|
218
|
+
if (!Array.isArray(methods) || methods.length === 0)
|
|
219
|
+
throw new DidResolutionError("did_no_verification_method");
|
|
220
|
+
for (const method of methods) {
|
|
221
|
+
if (!core.isPlainObject(method))
|
|
222
|
+
continue;
|
|
223
|
+
const controller = String(method.controller || did);
|
|
224
|
+
if (controller !== did)
|
|
225
|
+
continue;
|
|
226
|
+
const key = keyFromMethod(method);
|
|
227
|
+
if (key) {
|
|
228
|
+
return {
|
|
229
|
+
did,
|
|
230
|
+
url,
|
|
231
|
+
method_id: String(method.id || ""),
|
|
232
|
+
key_id: core.keyId(key),
|
|
233
|
+
public_key: core.exportEd25519PublicKey(key),
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
throw new DidResolutionError("did_no_ed25519_key");
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function multibaseEd25519(raw, multicodec = true) {
|
|
241
|
+
const bytes = Buffer.from(raw);
|
|
242
|
+
if (bytes.length !== 32)
|
|
243
|
+
throw new DidResolutionError("invalid_ed25519_public_key_length");
|
|
244
|
+
const prefixed = multicodec ? Buffer.concat([Buffer.from([0xed, 0x01]), bytes]) : bytes;
|
|
245
|
+
return "z" + b58encode(prefixed);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const AuthorityAnchor = Object.freeze({
|
|
249
|
+
SUPPORTED_KINDS: Object.freeze(["duns", "lei", "human_id", "passkey"]),
|
|
250
|
+
isValidKind(kind) {
|
|
251
|
+
return ANCHOR_KINDS.has(String(kind || "").trim().toLowerCase());
|
|
252
|
+
},
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
module.exports = {
|
|
256
|
+
DidResolutionError,
|
|
257
|
+
didWebForHost,
|
|
258
|
+
didWebUrl,
|
|
259
|
+
resolveDidWeb,
|
|
260
|
+
multibaseEd25519,
|
|
261
|
+
AuthorityAnchor,
|
|
262
|
+
};
|
package/js/trust.d.ts
CHANGED
|
@@ -9,6 +9,12 @@ export {
|
|
|
9
9
|
ExternalSignerErrorCode,
|
|
10
10
|
ExternalSignerError,
|
|
11
11
|
createKyaChallengeWithSigner,
|
|
12
|
+
AuthorityAnchor,
|
|
13
|
+
DidResolutionError,
|
|
14
|
+
didWebForHost,
|
|
15
|
+
didWebUrl,
|
|
16
|
+
resolveDidWeb,
|
|
17
|
+
multibaseEd25519,
|
|
12
18
|
signDelegationWithSigner,
|
|
13
19
|
signEnvelopeWithSigner,
|
|
14
20
|
ChallengeStore,
|
package/js/trust.js
CHANGED
|
@@ -3,6 +3,7 @@ const core = require("./internal/core.js");
|
|
|
3
3
|
const impl = require("./internal/trust.js");
|
|
4
4
|
const comm = require("./internal/comm.js");
|
|
5
5
|
const registration = require("./trust/passkey-registration.js");
|
|
6
|
+
const didweb = require("./trust/didweb.js");
|
|
6
7
|
const externalSigner = require("./trust/external-signer.js")({
|
|
7
8
|
canonicalJsonBuffer: core.canonicalJsonBuffer,
|
|
8
9
|
loadEd25519PublicKey: core.loadEd25519PublicKey,
|
|
@@ -23,6 +24,12 @@ module.exports = {
|
|
|
23
24
|
...externalSigner,
|
|
24
25
|
keyId: core.keyId,
|
|
25
26
|
createKyaChallenge: impl.createKyaChallenge,
|
|
27
|
+
AuthorityAnchor: didweb.AuthorityAnchor,
|
|
28
|
+
DidResolutionError: didweb.DidResolutionError,
|
|
29
|
+
didWebForHost: didweb.didWebForHost,
|
|
30
|
+
didWebUrl: didweb.didWebUrl,
|
|
31
|
+
resolveDidWeb: didweb.resolveDidWeb,
|
|
32
|
+
multibaseEd25519: didweb.multibaseEd25519,
|
|
26
33
|
verifyKyaChallenge: impl.verifyKyaChallenge,
|
|
27
34
|
completeKyaChallenge: impl.completeKyaChallenge,
|
|
28
35
|
verifyKyaBinding: impl.verifyKyaBinding,
|
package/js/trust.mjs
CHANGED
|
@@ -7,6 +7,12 @@ export const signDelegationWithSigner = api.signDelegationWithSigner;
|
|
|
7
7
|
export const signEnvelopeWithSigner = api.signEnvelopeWithSigner;
|
|
8
8
|
export const keyId = api.keyId;
|
|
9
9
|
export const createKyaChallenge = api.createKyaChallenge;
|
|
10
|
+
export const AuthorityAnchor = api.AuthorityAnchor;
|
|
11
|
+
export const DidResolutionError = api.DidResolutionError;
|
|
12
|
+
export const didWebForHost = api.didWebForHost;
|
|
13
|
+
export const didWebUrl = api.didWebUrl;
|
|
14
|
+
export const resolveDidWeb = api.resolveDidWeb;
|
|
15
|
+
export const multibaseEd25519 = api.multibaseEd25519;
|
|
10
16
|
export const verifyKyaChallenge = api.verifyKyaChallenge;
|
|
11
17
|
export const completeKyaChallenge = api.completeKyaChallenge;
|
|
12
18
|
export const verifyKyaBinding = api.verifyKyaBinding;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "twin3-sdk",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.15-pre-alpha",
|
|
4
4
|
"description": "Universal Capability Motherboard for Autonomous AI Agents and Self-Sovereign Humans (JS/Node runtime)",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "./js/index.js",
|
|
@@ -104,6 +104,7 @@
|
|
|
104
104
|
"js/matrix.d.ts",
|
|
105
105
|
"js/matrix.js",
|
|
106
106
|
"js/matrix.mjs",
|
|
107
|
+
"js/memory-guard.js",
|
|
107
108
|
"js/settlement.d.ts",
|
|
108
109
|
"js/settlement.js",
|
|
109
110
|
"js/settlement.mjs",
|
|
@@ -112,7 +113,8 @@
|
|
|
112
113
|
"js/shield.mjs",
|
|
113
114
|
"js/trust.d.ts",
|
|
114
115
|
"js/trust.js",
|
|
115
|
-
"js/trust.mjs"
|
|
116
|
+
"js/trust.mjs",
|
|
117
|
+
"js/trust/didweb.js"
|
|
116
118
|
],
|
|
117
119
|
"engines": {
|
|
118
120
|
"node": ">=18"
|