@tinycloud/web-sdk 3.8.1-beta.2 → 3.9.0-beta.3
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/dist/credentials/account-holder.d.ts +12 -0
- package/dist/credentials/held-source.d.ts +52 -0
- package/dist/credentials/held-store.d.ts +138 -0
- package/dist/credentials-subpath.d.ts +5 -0
- package/dist/credentials.cjs +1 -2
- package/dist/credentials.mjs +1 -2
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +3 -3
- package/dist/credentials.cjs.LICENSE.txt +0 -21
- package/dist/credentials.mjs.LICENSE.txt +0 -21
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type HolderSigner } from "@tinycloud/node-sdk/credentials";
|
|
2
|
+
/** Kid fragment for an account (EIP-191) holder key, as the witness expects it. */
|
|
3
|
+
export declare const ACCOUNT_KID_FRAGMENT = "blockchainAccountId";
|
|
4
|
+
/**
|
|
5
|
+
* Account (EIP-191) holder. The caller supplies `sign`, which must be the wallet's `personal_sign` over the
|
|
6
|
+
* exact bytes it is given. That is the one place the EIP-191 prefix is applied. This module adds no prefix.
|
|
7
|
+
* It verifies the returned 65-byte signature by recovering the signer over the same message, and refuses
|
|
8
|
+
* unless the recovered address equals the account. `did` must be did:pkh:eip155:1, canonicalised to EIP-55.
|
|
9
|
+
* Bytes outside the account-binding domain are refused before `sign` is called.
|
|
10
|
+
*/
|
|
11
|
+
export declare function createAccountHolderSigner(did: string, sign: (bytes: Uint8Array) => Promise<Uint8Array>): HolderSigner;
|
|
12
|
+
//# sourceMappingURL=account-holder.d.ts.map
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { type IKVService } from "@tinycloud/sdk-core";
|
|
2
|
+
import { type EmailProofAcquireInput, type EmailProofAcquisition, type EmailProofOptions, type EmailProofPendingStore, type HolderSigner } from "@tinycloud/node-sdk/credentials";
|
|
3
|
+
import { type HeldIssuerPolicy } from "./held-store";
|
|
4
|
+
export type HeldSourceErrorCode = "held-store-listing-limit";
|
|
5
|
+
/** Typed, non-retryable refusal. Its message carries no credential or email text. */
|
|
6
|
+
export declare class HeldSourceError extends Error {
|
|
7
|
+
readonly code: HeldSourceErrorCode;
|
|
8
|
+
readonly retryable = false;
|
|
9
|
+
constructor(code: HeldSourceErrorCode, message: string);
|
|
10
|
+
}
|
|
11
|
+
export interface HeldAcquireInput extends HeldIssuerPolicy {
|
|
12
|
+
readonly kv: IKVService;
|
|
13
|
+
/** Email address to prove. Matched case-insensitively against stored records. */
|
|
14
|
+
readonly address: string;
|
|
15
|
+
/** Account holder. Its did must be did:pkh:eip155; its signer is supplied by the caller. */
|
|
16
|
+
readonly holder: HolderSigner;
|
|
17
|
+
/** Session principal, when one exists. Must be the same account as `holder`. */
|
|
18
|
+
readonly sessionDid?: string;
|
|
19
|
+
/** Caller-supplied code source. Not hard-wired here. */
|
|
20
|
+
readonly getCode: NonNullable<EmailProofAcquireInput["getCode"]>;
|
|
21
|
+
readonly pendingStore?: EmailProofPendingStore;
|
|
22
|
+
readonly fetch?: EmailProofOptions["fetch"];
|
|
23
|
+
readonly signal?: EmailProofOptions["signal"];
|
|
24
|
+
readonly now?: () => Date;
|
|
25
|
+
}
|
|
26
|
+
export interface HeldCredentialResult {
|
|
27
|
+
/** The verified SD-JWT, as stored. */
|
|
28
|
+
readonly credential: string;
|
|
29
|
+
/** Canonical account owner: did:pkh:eip155:<chain>:<EIP-55 address>. */
|
|
30
|
+
readonly holderDid: string;
|
|
31
|
+
readonly expiresAt: Date;
|
|
32
|
+
}
|
|
33
|
+
/** Acquisition step. Production passes `acquireEmailProof`; tests inject a fake to reach the success branch. */
|
|
34
|
+
export type HeldAcquireStep = (input: EmailProofAcquireInput) => Promise<EmailProofAcquisition>;
|
|
35
|
+
/**
|
|
36
|
+
* Returns a verified, stored held credential for the account and email.
|
|
37
|
+
* Order: owner canonicalisation, session match, reuse lookup, acquisition, store-on-issue.
|
|
38
|
+
* Stored records are returned without network. A store failure after verification is VERIFIED_NOT_SAVED.
|
|
39
|
+
*/
|
|
40
|
+
export declare function acquireHeldCredential(input: HeldAcquireInput): Promise<HeldCredentialResult>;
|
|
41
|
+
/**
|
|
42
|
+
* `acquireHeldCredential` with the acquisition step injected. Production calls `acquireHeldCredential`.
|
|
43
|
+
* This seam exists so the issued branch can be exercised while the held profile pin stays disabled.
|
|
44
|
+
*/
|
|
45
|
+
export declare function acquireHeldCredentialWith(input: HeldAcquireInput, acquire: HeldAcquireStep): Promise<HeldCredentialResult>;
|
|
46
|
+
/**
|
|
47
|
+
* Scopes a shared pending store to one held owner. The did:key email flow uses the same store, so a held
|
|
48
|
+
* acquisition must never resume, prompt for, or delete a pending request of another profile or holder.
|
|
49
|
+
* Pending requests are matched by profile and by holder principal, never by string equality.
|
|
50
|
+
*/
|
|
51
|
+
export declare function scopeHeldPendingStore(store: EmailProofPendingStore | undefined, holderDid: string, now: () => Date): EmailProofPendingStore | undefined;
|
|
52
|
+
//# sourceMappingURL=held-source.d.ts.map
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { CredentialError, type IKVService } from "@tinycloud/sdk-core";
|
|
2
|
+
import { type HeldEmailCredentialOptions, type VerifiedHeldEmailCredential } from "@tinycloud/sdk-core/held-credentials";
|
|
3
|
+
/** A held record whose verified expiry is within this many milliseconds is not offered; the caller re-acquires. */
|
|
4
|
+
export declare const HELD_REUSE_MARGIN_MS = 600000;
|
|
5
|
+
/** Issuer policy for the S3.1 verifier. The owner and the clock are supplied per call. */
|
|
6
|
+
export type HeldIssuerPolicy = Omit<HeldEmailCredentialOptions, "owner" | "now">;
|
|
7
|
+
/**
|
|
8
|
+
* Stored shape. Only `credential` is trusted: every read re-verifies it, and no other stored field
|
|
9
|
+
* (email, expiry, subject) is read.
|
|
10
|
+
*/
|
|
11
|
+
export interface HeldCredentialRecord {
|
|
12
|
+
readonly type: "TinyCloudHeldCredential";
|
|
13
|
+
readonly version: 1;
|
|
14
|
+
readonly ownerDid: string;
|
|
15
|
+
readonly recordId: string;
|
|
16
|
+
readonly credentialDigest: string;
|
|
17
|
+
readonly credential: string;
|
|
18
|
+
readonly storedAt: string;
|
|
19
|
+
}
|
|
20
|
+
export interface HeldStorageReceipt {
|
|
21
|
+
readonly type: "TinyCloudHeldStorageReceipt";
|
|
22
|
+
readonly version: 1;
|
|
23
|
+
readonly ownerDid: string;
|
|
24
|
+
readonly recordId: string;
|
|
25
|
+
readonly recordDigest: string;
|
|
26
|
+
readonly storedAt: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A stored record that re-verified under the caller's policy, with the verifier's output.
|
|
30
|
+
* `record` is the raw stored value: only `verified` and the summary fields below are authoritative.
|
|
31
|
+
* `recordId`, `email`, `issuedAt`, `expiresAt` and `issuer` are a summary for display. They come from the
|
|
32
|
+
* re-verified credential and from the record key, never from any stored field other than `credential`.
|
|
33
|
+
*/
|
|
34
|
+
export interface HeldMatch {
|
|
35
|
+
readonly record: HeldCredentialRecord;
|
|
36
|
+
readonly verified: VerifiedHeldEmailCredential;
|
|
37
|
+
/** The record key's id: the digest the store derives from the credential and the owner. */
|
|
38
|
+
readonly recordId: string;
|
|
39
|
+
/** The disclosed email as the credential carries it. */
|
|
40
|
+
readonly email: string;
|
|
41
|
+
/** The signed `iat`. */
|
|
42
|
+
readonly issuedAt: Date;
|
|
43
|
+
/** The signed `exp`. */
|
|
44
|
+
readonly expiresAt: Date;
|
|
45
|
+
/** The issuer DID that signed the credential. */
|
|
46
|
+
readonly issuer: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Canonical account owner: `did:pkh:eip155:1:<EIP-55 address>`.
|
|
50
|
+
* Anything that is not a did:pkh (for example a did:key holder) is refused, and so is any chain other than 1.
|
|
51
|
+
*/
|
|
52
|
+
export declare function heldAccountOwner(ownerDid: unknown): string;
|
|
53
|
+
/** Key prefix for one owner. Keyed by the lowercase address, so case variants of one owner share it. */
|
|
54
|
+
export declare function heldPrefix(ownerDid: string): string;
|
|
55
|
+
export declare function heldRecordKey(ownerDid: string, recordId: string): string;
|
|
56
|
+
export declare function createHeldStorageReceipt(record: HeldCredentialRecord): Promise<HeldStorageReceipt>;
|
|
57
|
+
/** Owner and holder compares use principal equality, never string equality. */
|
|
58
|
+
export declare function verifyHeldStorageReceipt(record: HeldCredentialRecord, receipt: HeldStorageReceipt, ownerDid: string): Promise<boolean>;
|
|
59
|
+
export interface StoreHeldCredentialInput extends HeldIssuerPolicy {
|
|
60
|
+
readonly kv: IKVService;
|
|
61
|
+
readonly ownerDid: unknown;
|
|
62
|
+
readonly sdJwt: unknown;
|
|
63
|
+
readonly now?: Date;
|
|
64
|
+
}
|
|
65
|
+
export interface StoreHeldCredentialResult {
|
|
66
|
+
readonly record: HeldCredentialRecord;
|
|
67
|
+
readonly receipt: HeldStorageReceipt;
|
|
68
|
+
readonly verified: VerifiedHeldEmailCredential;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Store-on-issue. Verifies the SD-JWT itself, writes one record under the owner's prefix, and reads
|
|
72
|
+
* it back. Refuses before any write unless the credential verifies, belongs to the owner, and stays
|
|
73
|
+
* outside the reuse margin. `verified` is the verifier's output for the stored credential.
|
|
74
|
+
*/
|
|
75
|
+
export declare function storeHeldCredential(input: StoreHeldCredentialInput): Promise<StoreHeldCredentialResult>;
|
|
76
|
+
/** Listing refused beyond the page limit. Keeps the VERIFICATION_FAILED wire code; recovery callers test for this subclass. */
|
|
77
|
+
export declare class HeldListingLimitError extends CredentialError {
|
|
78
|
+
}
|
|
79
|
+
export interface FindHeldCredentialInput extends HeldIssuerPolicy {
|
|
80
|
+
readonly kv: IKVService;
|
|
81
|
+
readonly ownerDid: unknown;
|
|
82
|
+
readonly email: string;
|
|
83
|
+
readonly now?: Date;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Owner-scoped read. Lists only `v1/held/<registryKey>/`, so `v1/records/` is never considered.
|
|
87
|
+
* Returns the verified record with the latest expiry that still clears the reuse margin, or undefined.
|
|
88
|
+
*/
|
|
89
|
+
export declare function findHeldCredential(input: FindHeldCredentialInput): Promise<HeldMatch | undefined>;
|
|
90
|
+
export type ListHeldEmailCredentialsInput = Omit<FindHeldCredentialInput, "email"> & {
|
|
91
|
+
/** Accepted so a `FindHeldCredentialInput` can be passed as is. Ignored: the listing is never filtered by email. */
|
|
92
|
+
readonly email?: string;
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* Lists the account's own VALID held email credentials. Owner-only: it reads `v1/held/<registryKey>/` for the
|
|
96
|
+
* canonical `ownerDid` and nothing else, and refuses any owner that is not an Ethereum mainnet did:pkh.
|
|
97
|
+
*
|
|
98
|
+
* Returns every valid record, not one per email: no email filter and no "latest" pick. Expired records and
|
|
99
|
+
* records the verifier refuses (status other than none, issuer retired or not accepted, bad signature) are
|
|
100
|
+
* EXCLUDED. Validity is what `findHeldCredential` applies: re-verification plus the reuse margin. A record is
|
|
101
|
+
* listed only if it is valid for more than 10 more minutes, meaning its expiry is more than `HELD_REUSE_MARGIN_MS`
|
|
102
|
+
* after `now`. A record with exactly 10 minutes left is excluded, as in `findHeldCredential`, so the screen never
|
|
103
|
+
* offers a record that `findHeldCredential` or a presentation would refuse.
|
|
104
|
+
*
|
|
105
|
+
* Order: newest `issuedAt` first; equal `issuedAt` by ascending `recordId`. Returns `[]` when there are none.
|
|
106
|
+
*
|
|
107
|
+
* Throws if the store cannot be read; skips records that fail verification. A record that is corrupt,
|
|
108
|
+
* malformed or fails verification is skipped silently, never reported and never thrown. A store failure is
|
|
109
|
+
* not a bad record, so the screen can tell "none" from "unreachable": a `kv.get` or `kv.list` that throws
|
|
110
|
+
* propagates, and one that resolves not-ok is an `OFFLINE` CredentialError (a key that is gone by the time it
|
|
111
|
+
* is read, `KV_NOT_FOUND`, is skipped). A refused owner, or a listing that is truncated or beyond the page
|
|
112
|
+
* limit, also throws. `findHeldCredential` is looser: it reads a failed `kv.list` as "not found".
|
|
113
|
+
* Every returned summary field comes from the re-verified credential, never from other stored fields.
|
|
114
|
+
* `record` is the raw stored value; only the `verified` fields and the summary above are authoritative.
|
|
115
|
+
*/
|
|
116
|
+
export declare function listHeldEmailCredentials(input: ListHeldEmailCredentialsInput): Promise<readonly HeldMatch[]>;
|
|
117
|
+
/**
|
|
118
|
+
* Deletes the named record key only. The recordId is validated first, so a caller-supplied value cannot
|
|
119
|
+
* address another key. Copies outside this store remain valid until their own expiry.
|
|
120
|
+
*/
|
|
121
|
+
export declare function deleteHeldCredential(input: {
|
|
122
|
+
readonly kv: IKVService;
|
|
123
|
+
readonly ownerDid: unknown;
|
|
124
|
+
readonly recordId: string;
|
|
125
|
+
}): Promise<boolean>;
|
|
126
|
+
export interface PruneHeldCredentialsInput extends HeldIssuerPolicy {
|
|
127
|
+
readonly kv: IKVService;
|
|
128
|
+
readonly ownerDid: unknown;
|
|
129
|
+
readonly now?: Date;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Refresh housekeeping for one owner. Deletes records whose signature verifies but whose expiry has
|
|
133
|
+
* passed, and for each email keeps only the verified record with the newest expiry. Unverifiable records
|
|
134
|
+
* are left in place: prune cannot tell a forgery from a policy mismatch, so it never deletes on that basis.
|
|
135
|
+
* Returns the keys actually removed.
|
|
136
|
+
*/
|
|
137
|
+
export declare function pruneHeldCredentials(input: PruneHeldCredentialsInput): Promise<readonly string[]>;
|
|
138
|
+
//# sourceMappingURL=held-store.d.ts.map
|
|
@@ -3,4 +3,9 @@ export { interpretCredentialFlow } from "@tinycloud/node-sdk/credentials";
|
|
|
3
3
|
export type { CredentialAcquisitionTransport, CredentialRequestState, CredentialSigningAdapter, PrimitiveStepHandler, PrimitiveStepResult, } from "@tinycloud/node-sdk/credentials";
|
|
4
4
|
export { acquireEmailProof, completeEmailProof, createEd25519HolderSigner, createMemoryEmailProofPendingStore, EmailProofError, requestEmailProofCode, verifyStoredEmailProof, } from "@tinycloud/node-sdk/credentials";
|
|
5
5
|
export type { EmailProofAcquireInput, EmailProofAcquisition, EmailProofErrorCode, EmailProofOptions, EmailProofPending, EmailProofPendingStore, EmailProofProfileId, EmailProofRequestInput, EmailProofResult, EmailProofStep, HolderAlgorithm, HolderSigner, StoredEmailProofInput, StoredEmailProofRecord, } from "@tinycloud/node-sdk/credentials";
|
|
6
|
+
export { createAccountHolderSigner } from "./credentials/account-holder";
|
|
7
|
+
export { findHeldCredential, listHeldEmailCredentials, storeHeldCredential, } from "./credentials/held-store";
|
|
8
|
+
export type { FindHeldCredentialInput, HeldCredentialRecord, HeldIssuerPolicy, HeldMatch, HeldStorageReceipt, ListHeldEmailCredentialsInput, StoreHeldCredentialInput, } from "./credentials/held-store";
|
|
9
|
+
export { acquireHeldCredential } from "./credentials/held-source";
|
|
10
|
+
export type { HeldAcquireInput, HeldCredentialResult } from "./credentials/held-source";
|
|
6
11
|
//# sourceMappingURL=credentials-subpath.d.ts.map
|