@tinycloud/node-sdk 3.8.1-beta.2 → 3.9.0-beta.4

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.
@@ -1,4 +1,5 @@
1
1
  import { IssuedCredentialEnvelope, VerifiedCredential, CredentialFlowDescriptor, StoredCredentialRecord, CredentialRequirement } from '@tinycloud/sdk-core';
2
+ import { VerifiedHeldEmailCredential } from '@tinycloud/sdk-core/held-credentials';
2
3
 
3
4
  declare const EMAIL_PROOF_CREDENTIAL_TYPE: {
4
5
  readonly id: "opencredentials.email/v1";
@@ -6,7 +7,7 @@ declare const EMAIL_PROOF_CREDENTIAL_TYPE: {
6
7
  };
7
8
  /** A pending request is never trusted beyond this window, measured from creation. */
8
9
  declare const EMAIL_PROOF_PENDING_MAX_MS: number;
9
- type EmailProofProfileId = "tinycloud.email-proof/v1";
10
+ type EmailProofProfileId = "tinycloud.email-proof/v1" | "tinycloud.email-held/v1";
10
11
  declare const DEFAULT_EMAIL_PROOF_PROFILE: EmailProofProfileId;
11
12
  /** Which part of the two-step flow failed. */
12
13
  type EmailProofStep = "request" | "code" | "credential" | "session";
@@ -29,10 +30,11 @@ type EmailProofStep = "request" | "code" | "credential" | "session";
29
30
  * | CREDENTIAL_INVALID | false | issued credential failed local verification |
30
31
  * | SESSION_EXPIRED | false | pending window or server expiry has passed |
31
32
  * | SESSION_INVALID | false | pending does not match holder, descriptor, or requirement |
33
+ * | CLIENT_CLOCK_SKEW | false | device clock more than 5 min behind the witness; no mail sent; fix the clock and start again |
32
34
  * | CANCELED | false | caller aborted; pending is deleted |
33
35
  * | FAILED | false | unclassified failure; pending is deleted |
34
36
  */
35
- type EmailProofErrorCode = "ADDRESS_INVALID" | "HOLDER_INVALID" | "CODE_INVALID" | "RATE_LIMITED" | "ISSUER_UNAVAILABLE" | "NETWORK" | "PROFILE_UNAVAILABLE" | "CODE_REJECTED" | "CODE_ATTEMPTS_EXHAUSTED" | "SIGNATURE_REJECTED" | "CREDENTIAL_INVALID" | "SESSION_EXPIRED" | "SESSION_INVALID" | "CANCELED" | "FAILED";
37
+ type EmailProofErrorCode = "ADDRESS_INVALID" | "HOLDER_INVALID" | "CODE_INVALID" | "RATE_LIMITED" | "ISSUER_UNAVAILABLE" | "NETWORK" | "PROFILE_UNAVAILABLE" | "CODE_REJECTED" | "CODE_ATTEMPTS_EXHAUSTED" | "SIGNATURE_REJECTED" | "CREDENTIAL_INVALID" | "SESSION_EXPIRED" | "SESSION_INVALID" | "CLIENT_CLOCK_SKEW" | "CANCELED" | "FAILED";
36
38
  /** Stable, redaction-safe error. The message never includes the code, verifier, or key material. */
37
39
  declare class EmailProofError extends Error {
38
40
  readonly name = "EmailProofError";
@@ -44,10 +46,11 @@ declare class EmailProofError extends Error {
44
46
  }
45
47
  type HolderAlgorithm = "EdDSA" | "EIP191";
46
48
  /**
47
- * Holder key adapter. `sign` MUST return a raw signature over exactly the bytes it
48
- * is given: the signer does no hashing, prefixing, or domain separation. `kid` names
49
- * the key the witness verifies against. `completeEmailProof` rejects with
49
+ * Holder key adapter. `kid` names the key the witness verifies against. `completeEmailProof` rejects with
50
50
  * SESSION_INVALID unless `did === pending.holderDid`.
51
+ * `sign` MUST return a raw signature over exactly the bytes it is given. For `EdDSA` the signer applies no
52
+ * prefix. For `EIP191` the adapter performs `personal_sign` over those bytes, and the wallet applies the
53
+ * `\x19Ethereum Signed Message:\n<len>` prefix. The prefix is applied in that one place and nowhere else.
51
54
  */
52
55
  interface HolderSigner {
53
56
  readonly did: string;
@@ -62,6 +65,14 @@ interface HolderSigner {
62
65
  declare function createEd25519HolderSigner(did: string, sign: (bytes: Uint8Array) => Promise<Uint8Array>): HolderSigner;
63
66
  /** Options shared by the public steps. Issuer keys are never caller-supplied. */
64
67
  interface EmailProofOptions {
68
+ /**
69
+ * Per-call opt-in for the held profile `tinycloud.email-held/v1`. Only the literal `true` counts, it enables the held
70
+ * profile for this call alone (never stored in a pending, never read from the environment), and it is ignored for any other
71
+ * profile. Without it a held request is refused PROFILE_UNAVAILABLE before any network call. Nothing else can be supplied with
72
+ * it: the origin, issuer key and descriptor digest are compiled pins. The default 60 s step signal spans the wallet prompt in
73
+ * `completeEmailProof` for an account holder: pass a `signal` bounded by the request `expiresAt` if the user may take longer.
74
+ */
75
+ readonly allowHeldProfile?: true;
65
76
  readonly fetch?: typeof fetch;
66
77
  readonly signal?: AbortSignal;
67
78
  readonly now?: () => Date;
@@ -89,6 +100,8 @@ interface EmailProofPending {
89
100
  readonly openerOrigin: string;
90
101
  readonly createdAt: string;
91
102
  readonly expiresAt: string;
103
+ /** Held only: `expiresAt` of the create response (the witness's own deadline). The signed binding must carry it. */
104
+ readonly serverExpiresAt?: string;
92
105
  }
93
106
  /** Holds pending requests keyed by requestId. Implementations must never return an expired request from `findLive`. */
94
107
  interface EmailProofPendingStore {
@@ -103,13 +116,18 @@ interface EmailProofPendingStore {
103
116
  declare function createMemoryEmailProofPendingStore(): EmailProofPendingStore;
104
117
  interface EmailProofResult {
105
118
  readonly envelope: IssuedCredentialEnvelope;
106
- readonly verified: VerifiedCredential;
119
+ /** The ticket verifier's result, or for the held profile (`envelope.profile.id`) the held verifier's. */
120
+ readonly verified: VerifiedCredential | VerifiedHeldEmailCredential;
107
121
  readonly credentialId: string;
108
122
  readonly issuedAt: string;
109
123
  readonly expiresAt: string;
110
124
  /** The descriptor the verifier checked against. Stored alongside the credential for offline re-verification. */
111
125
  readonly descriptor: CredentialFlowDescriptor;
112
126
  }
127
+ /** True for a ticket (did:key) result, whose `verified` is the ticket verifier's output. The held profile's result carries the held verifier's. */
128
+ declare function isTicketEmailProofResult(result: EmailProofResult): result is EmailProofResult & {
129
+ readonly verified: VerifiedCredential;
130
+ };
113
131
  interface EmailProofAcquireInput extends EmailProofRequestInput {
114
132
  /** Supplies the 8-digit code. Omit to only request one; the pending request is returned for a later call. */
115
133
  readonly getCode?: (context: {
@@ -173,4 +191,4 @@ type StoredEmailProofInput = {
173
191
  */
174
192
  declare function verifyStoredEmailProof(input: StoredEmailProofInput): Promise<VerifiedCredential>;
175
193
 
176
- export { DEFAULT_EMAIL_PROOF_PROFILE as D, EMAIL_PROOF_CREDENTIAL_TYPE as E, type HolderAlgorithm as H, type StoredEmailProofInput as S, EMAIL_PROOF_PENDING_MAX_MS as a, type EmailProofAcquireInput as b, type EmailProofAcquisition as c, EmailProofError as d, type EmailProofErrorCode as e, type EmailProofOptions as f, type EmailProofPending as g, type EmailProofPendingStore as h, type EmailProofProfileId as i, type EmailProofRequestInput as j, type EmailProofResult as k, type EmailProofStep as l, type HolderSigner as m, type StoredEmailProofRecord as n, acquireEmailProof as o, completeEmailProof as p, createEd25519HolderSigner as q, createMemoryEmailProofPendingStore as r, emailProofRequirement as s, requestEmailProofCode as t, verifyStoredEmailProof as v };
194
+ export { DEFAULT_EMAIL_PROOF_PROFILE as D, type EmailProofPendingStore as E, type HolderAlgorithm as H, type StoredEmailProofInput as S, type EmailProofPending as a, EMAIL_PROOF_CREDENTIAL_TYPE as b, EMAIL_PROOF_PENDING_MAX_MS as c, type EmailProofAcquireInput as d, type EmailProofAcquisition as e, EmailProofError as f, type EmailProofErrorCode as g, type EmailProofOptions as h, type EmailProofProfileId as i, type EmailProofRequestInput as j, type EmailProofResult as k, type EmailProofStep as l, type HolderSigner as m, type StoredEmailProofRecord as n, acquireEmailProof as o, completeEmailProof as p, createEd25519HolderSigner as q, createMemoryEmailProofPendingStore as r, emailProofRequirement as s, isTicketEmailProofResult as t, requestEmailProofCode as u, verifyStoredEmailProof as v };
@@ -1,4 +1,5 @@
1
1
  import { IssuedCredentialEnvelope, VerifiedCredential, CredentialFlowDescriptor, StoredCredentialRecord, CredentialRequirement } from '@tinycloud/sdk-core';
2
+ import { VerifiedHeldEmailCredential } from '@tinycloud/sdk-core/held-credentials';
2
3
 
3
4
  declare const EMAIL_PROOF_CREDENTIAL_TYPE: {
4
5
  readonly id: "opencredentials.email/v1";
@@ -6,7 +7,7 @@ declare const EMAIL_PROOF_CREDENTIAL_TYPE: {
6
7
  };
7
8
  /** A pending request is never trusted beyond this window, measured from creation. */
8
9
  declare const EMAIL_PROOF_PENDING_MAX_MS: number;
9
- type EmailProofProfileId = "tinycloud.email-proof/v1";
10
+ type EmailProofProfileId = "tinycloud.email-proof/v1" | "tinycloud.email-held/v1";
10
11
  declare const DEFAULT_EMAIL_PROOF_PROFILE: EmailProofProfileId;
11
12
  /** Which part of the two-step flow failed. */
12
13
  type EmailProofStep = "request" | "code" | "credential" | "session";
@@ -29,10 +30,11 @@ type EmailProofStep = "request" | "code" | "credential" | "session";
29
30
  * | CREDENTIAL_INVALID | false | issued credential failed local verification |
30
31
  * | SESSION_EXPIRED | false | pending window or server expiry has passed |
31
32
  * | SESSION_INVALID | false | pending does not match holder, descriptor, or requirement |
33
+ * | CLIENT_CLOCK_SKEW | false | device clock more than 5 min behind the witness; no mail sent; fix the clock and start again |
32
34
  * | CANCELED | false | caller aborted; pending is deleted |
33
35
  * | FAILED | false | unclassified failure; pending is deleted |
34
36
  */
35
- type EmailProofErrorCode = "ADDRESS_INVALID" | "HOLDER_INVALID" | "CODE_INVALID" | "RATE_LIMITED" | "ISSUER_UNAVAILABLE" | "NETWORK" | "PROFILE_UNAVAILABLE" | "CODE_REJECTED" | "CODE_ATTEMPTS_EXHAUSTED" | "SIGNATURE_REJECTED" | "CREDENTIAL_INVALID" | "SESSION_EXPIRED" | "SESSION_INVALID" | "CANCELED" | "FAILED";
37
+ type EmailProofErrorCode = "ADDRESS_INVALID" | "HOLDER_INVALID" | "CODE_INVALID" | "RATE_LIMITED" | "ISSUER_UNAVAILABLE" | "NETWORK" | "PROFILE_UNAVAILABLE" | "CODE_REJECTED" | "CODE_ATTEMPTS_EXHAUSTED" | "SIGNATURE_REJECTED" | "CREDENTIAL_INVALID" | "SESSION_EXPIRED" | "SESSION_INVALID" | "CLIENT_CLOCK_SKEW" | "CANCELED" | "FAILED";
36
38
  /** Stable, redaction-safe error. The message never includes the code, verifier, or key material. */
37
39
  declare class EmailProofError extends Error {
38
40
  readonly name = "EmailProofError";
@@ -44,10 +46,11 @@ declare class EmailProofError extends Error {
44
46
  }
45
47
  type HolderAlgorithm = "EdDSA" | "EIP191";
46
48
  /**
47
- * Holder key adapter. `sign` MUST return a raw signature over exactly the bytes it
48
- * is given: the signer does no hashing, prefixing, or domain separation. `kid` names
49
- * the key the witness verifies against. `completeEmailProof` rejects with
49
+ * Holder key adapter. `kid` names the key the witness verifies against. `completeEmailProof` rejects with
50
50
  * SESSION_INVALID unless `did === pending.holderDid`.
51
+ * `sign` MUST return a raw signature over exactly the bytes it is given. For `EdDSA` the signer applies no
52
+ * prefix. For `EIP191` the adapter performs `personal_sign` over those bytes, and the wallet applies the
53
+ * `\x19Ethereum Signed Message:\n<len>` prefix. The prefix is applied in that one place and nowhere else.
51
54
  */
52
55
  interface HolderSigner {
53
56
  readonly did: string;
@@ -62,6 +65,14 @@ interface HolderSigner {
62
65
  declare function createEd25519HolderSigner(did: string, sign: (bytes: Uint8Array) => Promise<Uint8Array>): HolderSigner;
63
66
  /** Options shared by the public steps. Issuer keys are never caller-supplied. */
64
67
  interface EmailProofOptions {
68
+ /**
69
+ * Per-call opt-in for the held profile `tinycloud.email-held/v1`. Only the literal `true` counts, it enables the held
70
+ * profile for this call alone (never stored in a pending, never read from the environment), and it is ignored for any other
71
+ * profile. Without it a held request is refused PROFILE_UNAVAILABLE before any network call. Nothing else can be supplied with
72
+ * it: the origin, issuer key and descriptor digest are compiled pins. The default 60 s step signal spans the wallet prompt in
73
+ * `completeEmailProof` for an account holder: pass a `signal` bounded by the request `expiresAt` if the user may take longer.
74
+ */
75
+ readonly allowHeldProfile?: true;
65
76
  readonly fetch?: typeof fetch;
66
77
  readonly signal?: AbortSignal;
67
78
  readonly now?: () => Date;
@@ -89,6 +100,8 @@ interface EmailProofPending {
89
100
  readonly openerOrigin: string;
90
101
  readonly createdAt: string;
91
102
  readonly expiresAt: string;
103
+ /** Held only: `expiresAt` of the create response (the witness's own deadline). The signed binding must carry it. */
104
+ readonly serverExpiresAt?: string;
92
105
  }
93
106
  /** Holds pending requests keyed by requestId. Implementations must never return an expired request from `findLive`. */
94
107
  interface EmailProofPendingStore {
@@ -103,13 +116,18 @@ interface EmailProofPendingStore {
103
116
  declare function createMemoryEmailProofPendingStore(): EmailProofPendingStore;
104
117
  interface EmailProofResult {
105
118
  readonly envelope: IssuedCredentialEnvelope;
106
- readonly verified: VerifiedCredential;
119
+ /** The ticket verifier's result, or for the held profile (`envelope.profile.id`) the held verifier's. */
120
+ readonly verified: VerifiedCredential | VerifiedHeldEmailCredential;
107
121
  readonly credentialId: string;
108
122
  readonly issuedAt: string;
109
123
  readonly expiresAt: string;
110
124
  /** The descriptor the verifier checked against. Stored alongside the credential for offline re-verification. */
111
125
  readonly descriptor: CredentialFlowDescriptor;
112
126
  }
127
+ /** True for a ticket (did:key) result, whose `verified` is the ticket verifier's output. The held profile's result carries the held verifier's. */
128
+ declare function isTicketEmailProofResult(result: EmailProofResult): result is EmailProofResult & {
129
+ readonly verified: VerifiedCredential;
130
+ };
113
131
  interface EmailProofAcquireInput extends EmailProofRequestInput {
114
132
  /** Supplies the 8-digit code. Omit to only request one; the pending request is returned for a later call. */
115
133
  readonly getCode?: (context: {
@@ -173,4 +191,4 @@ type StoredEmailProofInput = {
173
191
  */
174
192
  declare function verifyStoredEmailProof(input: StoredEmailProofInput): Promise<VerifiedCredential>;
175
193
 
176
- export { DEFAULT_EMAIL_PROOF_PROFILE as D, EMAIL_PROOF_CREDENTIAL_TYPE as E, type HolderAlgorithm as H, type StoredEmailProofInput as S, EMAIL_PROOF_PENDING_MAX_MS as a, type EmailProofAcquireInput as b, type EmailProofAcquisition as c, EmailProofError as d, type EmailProofErrorCode as e, type EmailProofOptions as f, type EmailProofPending as g, type EmailProofPendingStore as h, type EmailProofProfileId as i, type EmailProofRequestInput as j, type EmailProofResult as k, type EmailProofStep as l, type HolderSigner as m, type StoredEmailProofRecord as n, acquireEmailProof as o, completeEmailProof as p, createEd25519HolderSigner as q, createMemoryEmailProofPendingStore as r, emailProofRequirement as s, requestEmailProofCode as t, verifyStoredEmailProof as v };
194
+ export { DEFAULT_EMAIL_PROOF_PROFILE as D, type EmailProofPendingStore as E, type HolderAlgorithm as H, type StoredEmailProofInput as S, type EmailProofPending as a, EMAIL_PROOF_CREDENTIAL_TYPE as b, EMAIL_PROOF_PENDING_MAX_MS as c, type EmailProofAcquireInput as d, type EmailProofAcquisition as e, EmailProofError as f, type EmailProofErrorCode as g, type EmailProofOptions as h, type EmailProofProfileId as i, type EmailProofRequestInput as j, type EmailProofResult as k, type EmailProofStep as l, type HolderSigner as m, type StoredEmailProofRecord as n, acquireEmailProof as o, completeEmailProof as p, createEd25519HolderSigner as q, createMemoryEmailProofPendingStore as r, emailProofRequirement as s, isTicketEmailProofResult as t, requestEmailProofCode as u, verifyStoredEmailProof as v };