@terminal3/t3n-sdk 1.3.2 → 2.3.0
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 +82 -0
- package/dist/index.d.ts +592 -82
- package/dist/index.esm.js +1 -1
- package/dist/index.js +1 -1
- package/dist/src/client/delegation.d.ts +216 -0
- package/dist/src/client/index.d.ts +1 -0
- package/dist/src/client/t3n-client.d.ts +111 -0
- package/dist/src/index.d.ts +4 -0
- package/dist/src/types/index.d.ts +1 -0
- package/dist/src/types/user.d.ts +194 -0
- package/package.json +4 -1
package/dist/index.d.ts
CHANGED
|
@@ -325,6 +325,281 @@ type AuthInput = EthAuthInput | OidcAuthInput;
|
|
|
325
325
|
declare function createEthAuthInput(address: string): EthAuthInput;
|
|
326
326
|
declare function createOidcAuthInput(credentials: OidcCredentials): OidcAuthInput;
|
|
327
327
|
|
|
328
|
+
/**
|
|
329
|
+
* Error classes for T3n SDK
|
|
330
|
+
*/
|
|
331
|
+
/**
|
|
332
|
+
* Base error class for T3n SDK errors
|
|
333
|
+
*/
|
|
334
|
+
declare class T3nError extends Error {
|
|
335
|
+
readonly code?: string | undefined;
|
|
336
|
+
constructor(message: string, code?: string | undefined);
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Error thrown when session is in invalid state for operation
|
|
340
|
+
*/
|
|
341
|
+
declare class SessionStateError extends T3nError {
|
|
342
|
+
readonly currentState: string;
|
|
343
|
+
constructor(message: string, currentState: string);
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Error thrown during authentication process
|
|
347
|
+
*/
|
|
348
|
+
declare class AuthenticationError extends T3nError {
|
|
349
|
+
readonly authMethod?: string | undefined;
|
|
350
|
+
constructor(message: string, authMethod?: string | undefined);
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Error thrown during handshake process
|
|
354
|
+
*/
|
|
355
|
+
declare class HandshakeError extends T3nError {
|
|
356
|
+
constructor(message: string);
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Error thrown during RPC communication.
|
|
360
|
+
*
|
|
361
|
+
* `message` is the human-readable error (preferring the server's
|
|
362
|
+
* `error.data.detail` when present, with the request id appended in
|
|
363
|
+
* `[<id>]` form so a UI that only surfaces `.message` still gives an
|
|
364
|
+
* operator something to grep). The structured fields below preserve
|
|
365
|
+
* the same info for callers that want to render or log them
|
|
366
|
+
* separately — e.g. a toast that shows `detail` but surfaces
|
|
367
|
+
* `requestId` in a "copy for support" affordance.
|
|
368
|
+
*/
|
|
369
|
+
declare class RpcError extends T3nError {
|
|
370
|
+
readonly rpcMethod?: string | undefined;
|
|
371
|
+
readonly httpStatus?: number | undefined;
|
|
372
|
+
/** Server-attached detail (JSON-RPC `error.data.detail`). User-facing kinds
|
|
373
|
+
* carry the specific reason here; internal kinds omit it. */
|
|
374
|
+
readonly detail?: string | undefined;
|
|
375
|
+
/** Per-request correlation id (JSON-RPC `error.data.request_id`). */
|
|
376
|
+
readonly requestId?: string | undefined;
|
|
377
|
+
constructor(message: string, rpcMethod?: string | undefined, httpStatus?: number | undefined,
|
|
378
|
+
/** Server-attached detail (JSON-RPC `error.data.detail`). User-facing kinds
|
|
379
|
+
* carry the specific reason here; internal kinds omit it. */
|
|
380
|
+
detail?: string | undefined,
|
|
381
|
+
/** Per-request correlation id (JSON-RPC `error.data.request_id`). */
|
|
382
|
+
requestId?: string | undefined);
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Error thrown when WASM operations fail
|
|
386
|
+
*/
|
|
387
|
+
declare class WasmError extends T3nError {
|
|
388
|
+
readonly operation?: string | undefined;
|
|
389
|
+
readonly payload?: unknown | undefined;
|
|
390
|
+
constructor(message: string, operation?: string | undefined, payload?: unknown | undefined);
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Decode WASM error message from comma-separated byte array format
|
|
394
|
+
* WASM errors often come as "83,101,114,100,101..." which represents ASCII bytes
|
|
395
|
+
*
|
|
396
|
+
* @param errorMessage - The error message string that may contain comma-separated bytes
|
|
397
|
+
* @returns Decoded error message if it was encoded, otherwise original message
|
|
398
|
+
*/
|
|
399
|
+
declare function decodeWasmErrorMessage(errorMessage: string): string;
|
|
400
|
+
/**
|
|
401
|
+
* Extract and decode error from WASM ComponentError
|
|
402
|
+
*
|
|
403
|
+
* @param error - The error object from WASM
|
|
404
|
+
* @returns Decoded error message
|
|
405
|
+
*/
|
|
406
|
+
declare function extractWasmError(error: unknown): string;
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* MAT-1374 — wire types for the explicit `otp-request` /
|
|
410
|
+
* `otp-verify` / slim `user-upsert` exports on `tee:user/contracts`
|
|
411
|
+
* (`tee:user@2.0.0`).
|
|
412
|
+
*
|
|
413
|
+
* Pre-2.0.0 the user contract dispatched OTP request and OTP verify
|
|
414
|
+
* implicitly from the input shape of a single `user-upsert` call.
|
|
415
|
+
* 2.0.0 splits that surface into three explicit functions; the
|
|
416
|
+
* shapes here mirror the Rust types in
|
|
417
|
+
* `node/tee_contracts/user/src/otp_types.rs` and
|
|
418
|
+
* `node/tee_contracts/user/src/upsert_types.rs`.
|
|
419
|
+
*
|
|
420
|
+
* Keep the two in sync — bytes flow directly from the contract
|
|
421
|
+
* through the JSON-RPC envelope into the SDK wrappers
|
|
422
|
+
* (`T3nClient.otpRequest`, `T3nClient.otpVerify`,
|
|
423
|
+
* `T3nClient.submitUserInput`).
|
|
424
|
+
*/
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* OTP delivery channel. Matches the `OtpContactChannel` Rust enum
|
|
428
|
+
* with `serde(rename_all = "snake_case")`.
|
|
429
|
+
*/
|
|
430
|
+
type OtpChannel = "email" | "sms";
|
|
431
|
+
/**
|
|
432
|
+
* Discriminated OTP contact target. Mirrors the Rust `OtpRequest` enum
|
|
433
|
+
* (`email_channel` / `sms_channel` on the wire). Exactly one branch is
|
|
434
|
+
* set — no parallel optional email + phone with a separate channel tag.
|
|
435
|
+
*
|
|
436
|
+
* The legacy `keys.generic_api.otp_channel` body shadow was removed
|
|
437
|
+
* in 2.0.0 — the contract rejects calls carrying it with a
|
|
438
|
+
* `legacy_field` error.
|
|
439
|
+
*/
|
|
440
|
+
type OtpRequestInput = {
|
|
441
|
+
emailChannel: {
|
|
442
|
+
emailAddress: string;
|
|
443
|
+
};
|
|
444
|
+
} | {
|
|
445
|
+
smsChannel: {
|
|
446
|
+
phoneNumber: string;
|
|
447
|
+
};
|
|
448
|
+
};
|
|
449
|
+
/**
|
|
450
|
+
* Response returned by `otp-request`. Mirrors `OtpResponse` in
|
|
451
|
+
* `otp_types.rs`.
|
|
452
|
+
*
|
|
453
|
+
* - `contact` echoes the OTP destination so clients that race
|
|
454
|
+
* multiple channels can correlate replies.
|
|
455
|
+
* - `expiresAtSec` is the Unix-second TTL the host minted for the
|
|
456
|
+
* pending OTP. Absent in `skip_otp` test environments.
|
|
457
|
+
* - `status` is `"otp_pending"` on the happy path. `"otp_failed"`
|
|
458
|
+
* only appears on retry without a fresh request — usually you
|
|
459
|
+
* shouldn't see it on `otp-request`.
|
|
460
|
+
* - `txHash` is the host-enriched ledger ref for the OTP-pending
|
|
461
|
+
* write (the contract leaves it `null`; the host injects).
|
|
462
|
+
* - `isNewProfile` is `true` on a fresh DID's first OTP request —
|
|
463
|
+
* read this to detect "did the user just register".
|
|
464
|
+
*/
|
|
465
|
+
interface OtpRequestResult {
|
|
466
|
+
contact: string;
|
|
467
|
+
channel: OtpChannel;
|
|
468
|
+
expiresAtSec?: number;
|
|
469
|
+
status?: string;
|
|
470
|
+
txHash?: string;
|
|
471
|
+
isNewProfile?: boolean;
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* Input to `T3nClient.otpVerify`. `otpCode` is mandatory; `request`
|
|
475
|
+
* repeats the same discriminated contact shape as {@link OtpRequestInput}.
|
|
476
|
+
*/
|
|
477
|
+
interface OtpVerifyInput {
|
|
478
|
+
otpCode: string;
|
|
479
|
+
request: OtpRequestInput;
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* Suggestion surfaced when the bind-target contact already belongs
|
|
483
|
+
* to another DID. The contract refuses to silently steal the
|
|
484
|
+
* authenticator; the caller must resolve the merge (typically via
|
|
485
|
+
* `merge-profiles`) before re-attempting verify.
|
|
486
|
+
*/
|
|
487
|
+
interface OtpMergeSuggestion {
|
|
488
|
+
existingDid: string;
|
|
489
|
+
currentDid: string;
|
|
490
|
+
email?: string;
|
|
491
|
+
phone?: string;
|
|
492
|
+
channel: OtpChannel;
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* Response returned by `otp-verify`. Mirrors
|
|
496
|
+
* `OtpVerifyResponse` in `otp_types.rs`.
|
|
497
|
+
*
|
|
498
|
+
* - `email` is populated on `channel = "email"` success;
|
|
499
|
+
* `phone` on `channel = "sms"` success. Mutually exclusive on
|
|
500
|
+
* the happy path.
|
|
501
|
+
* - `status` carries `"otp_failed"` / `"otp_expired"` on retry; the
|
|
502
|
+
* happy path leaves it `undefined`.
|
|
503
|
+
* - `mergeSuggestion` is set when the contact-to-bind is already
|
|
504
|
+
* owned by another DID. Wire it into your merge UX.
|
|
505
|
+
*/
|
|
506
|
+
interface OtpVerifyResult {
|
|
507
|
+
txHash?: string;
|
|
508
|
+
did: string;
|
|
509
|
+
channel: OtpChannel;
|
|
510
|
+
email?: string;
|
|
511
|
+
phone?: string;
|
|
512
|
+
status?: string;
|
|
513
|
+
mergeSuggestion?: OtpMergeSuggestion;
|
|
514
|
+
isNewProfile?: boolean;
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* Level-1 user-input fields accepted by the slim `user-upsert`.
|
|
518
|
+
* The Rust contract validates these via `validate_profile`; the
|
|
519
|
+
* shape is intentionally open so callers can add provider-specific
|
|
520
|
+
* fields on top of the canonical six.
|
|
521
|
+
*/
|
|
522
|
+
interface UserInputProfile {
|
|
523
|
+
firstName?: string;
|
|
524
|
+
lastName?: string;
|
|
525
|
+
email_address?: string;
|
|
526
|
+
phone_number?: string;
|
|
527
|
+
birthdate?: string;
|
|
528
|
+
nationality?: string;
|
|
529
|
+
[key: string]: unknown;
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* Input to `T3nClient.submitUserInput`. Maps onto the slim
|
|
533
|
+
* `user-upsert` request shape: `{ profile, organisation_did?,
|
|
534
|
+
* attestations?, keys? }`.
|
|
535
|
+
*/
|
|
536
|
+
interface SubmitUserInputArgs {
|
|
537
|
+
profile: UserInputProfile;
|
|
538
|
+
organisationDid?: string;
|
|
539
|
+
attestations?: unknown;
|
|
540
|
+
keys?: Record<string, unknown>;
|
|
541
|
+
/**
|
|
542
|
+
* KYC webhook orphan-attestation flow. When set, the contract
|
|
543
|
+
* skips the email-not-verified gate and only records the
|
|
544
|
+
* attestation if the DID has no profile yet (T3-TS-026 §13).
|
|
545
|
+
* Most callers should leave this `undefined`.
|
|
546
|
+
*/
|
|
547
|
+
requireExistingUser?: boolean;
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Response shape returned by the slim `user-upsert`. Carries the
|
|
551
|
+
* post-merge tx hash plus the L1 merge diagnostics
|
|
552
|
+
* (`refusedFields`, `mergeSuggestion`) the pre-2.0.0 omnibus
|
|
553
|
+
* `UpsertResponse` already surfaced.
|
|
554
|
+
*/
|
|
555
|
+
interface SubmitUserInputResult {
|
|
556
|
+
txHash?: string;
|
|
557
|
+
refusedFields?: string[];
|
|
558
|
+
mergeSuggestion?: OtpMergeSuggestion;
|
|
559
|
+
userFound?: boolean;
|
|
560
|
+
}
|
|
561
|
+
/**
|
|
562
|
+
* Discriminator for {@link UserUpsertError}. Mirrors the
|
|
563
|
+
* `UserUpsertError` Rust enum and its `<code>:<detail>` wire
|
|
564
|
+
* format (see `upsert_types.rs::UserUpsertError::code`). Branch
|
|
565
|
+
* with a `switch` over `kind`.
|
|
566
|
+
*
|
|
567
|
+
* - `EmailNotVerified` — the slim `user-upsert` was called against
|
|
568
|
+
* a DID that has no verified email and no proving authenticator.
|
|
569
|
+
* Run `otpRequest` + `otpVerify` first (or accept an
|
|
570
|
+
* OIDC/Email-authed session).
|
|
571
|
+
* - `LegacyField` — caller passed a pre-2.0.0 dispatch field
|
|
572
|
+
* (`otp_code` to a non-verify export, or
|
|
573
|
+
* `keys.generic_api.otp_channel` anywhere). Migrate the call
|
|
574
|
+
* site to the new explicit functions.
|
|
575
|
+
* - `UserNotFound` — `requireExistingUser` was set but no profile
|
|
576
|
+
* exists for the DID. The attestation is recorded for audit;
|
|
577
|
+
* no profile created.
|
|
578
|
+
*/
|
|
579
|
+
type UserUpsertErrorKind = "EmailNotVerified" | "LegacyField" | "UserNotFound";
|
|
580
|
+
/**
|
|
581
|
+
* Typed wrapper for the `<code>:<detail>` errors the slim
|
|
582
|
+
* `user-upsert` and the OTP entry points emit. `kind` is the
|
|
583
|
+
* structured discriminator the SDK derives from the error code
|
|
584
|
+
* prefix; `code` and `detail` retain the wire components for
|
|
585
|
+
* fall-through logging.
|
|
586
|
+
*
|
|
587
|
+
* Throw site: `T3nClient.submitUserInput` (and friends) when the
|
|
588
|
+
* contract returns a string error matching the
|
|
589
|
+
* `<code>:<detail>` shape.
|
|
590
|
+
*/
|
|
591
|
+
declare class UserUpsertError extends T3nError {
|
|
592
|
+
readonly kind: UserUpsertErrorKind | "Unknown";
|
|
593
|
+
readonly detail: string;
|
|
594
|
+
constructor(code: string, detail: string);
|
|
595
|
+
/**
|
|
596
|
+
* Try to parse a contract error string into a `UserUpsertError`.
|
|
597
|
+
* Returns `null` if `raw` doesn't match the `<code>:<detail>`
|
|
598
|
+
* shape — caller falls back to a generic error.
|
|
599
|
+
*/
|
|
600
|
+
static fromWire(raw: string): UserUpsertError | null;
|
|
601
|
+
}
|
|
602
|
+
|
|
328
603
|
/**
|
|
329
604
|
* Public types export for T3n SDK
|
|
330
605
|
*/
|
|
@@ -515,86 +790,6 @@ interface T3nClientConfig {
|
|
|
515
790
|
handlers?: GuestToHostHandlers;
|
|
516
791
|
}
|
|
517
792
|
|
|
518
|
-
/**
|
|
519
|
-
* Error classes for T3n SDK
|
|
520
|
-
*/
|
|
521
|
-
/**
|
|
522
|
-
* Base error class for T3n SDK errors
|
|
523
|
-
*/
|
|
524
|
-
declare class T3nError extends Error {
|
|
525
|
-
readonly code?: string | undefined;
|
|
526
|
-
constructor(message: string, code?: string | undefined);
|
|
527
|
-
}
|
|
528
|
-
/**
|
|
529
|
-
* Error thrown when session is in invalid state for operation
|
|
530
|
-
*/
|
|
531
|
-
declare class SessionStateError extends T3nError {
|
|
532
|
-
readonly currentState: string;
|
|
533
|
-
constructor(message: string, currentState: string);
|
|
534
|
-
}
|
|
535
|
-
/**
|
|
536
|
-
* Error thrown during authentication process
|
|
537
|
-
*/
|
|
538
|
-
declare class AuthenticationError extends T3nError {
|
|
539
|
-
readonly authMethod?: string | undefined;
|
|
540
|
-
constructor(message: string, authMethod?: string | undefined);
|
|
541
|
-
}
|
|
542
|
-
/**
|
|
543
|
-
* Error thrown during handshake process
|
|
544
|
-
*/
|
|
545
|
-
declare class HandshakeError extends T3nError {
|
|
546
|
-
constructor(message: string);
|
|
547
|
-
}
|
|
548
|
-
/**
|
|
549
|
-
* Error thrown during RPC communication.
|
|
550
|
-
*
|
|
551
|
-
* `message` is the human-readable error (preferring the server's
|
|
552
|
-
* `error.data.detail` when present, with the request id appended in
|
|
553
|
-
* `[<id>]` form so a UI that only surfaces `.message` still gives an
|
|
554
|
-
* operator something to grep). The structured fields below preserve
|
|
555
|
-
* the same info for callers that want to render or log them
|
|
556
|
-
* separately — e.g. a toast that shows `detail` but surfaces
|
|
557
|
-
* `requestId` in a "copy for support" affordance.
|
|
558
|
-
*/
|
|
559
|
-
declare class RpcError extends T3nError {
|
|
560
|
-
readonly rpcMethod?: string | undefined;
|
|
561
|
-
readonly httpStatus?: number | undefined;
|
|
562
|
-
/** Server-attached detail (JSON-RPC `error.data.detail`). User-facing kinds
|
|
563
|
-
* carry the specific reason here; internal kinds omit it. */
|
|
564
|
-
readonly detail?: string | undefined;
|
|
565
|
-
/** Per-request correlation id (JSON-RPC `error.data.request_id`). */
|
|
566
|
-
readonly requestId?: string | undefined;
|
|
567
|
-
constructor(message: string, rpcMethod?: string | undefined, httpStatus?: number | undefined,
|
|
568
|
-
/** Server-attached detail (JSON-RPC `error.data.detail`). User-facing kinds
|
|
569
|
-
* carry the specific reason here; internal kinds omit it. */
|
|
570
|
-
detail?: string | undefined,
|
|
571
|
-
/** Per-request correlation id (JSON-RPC `error.data.request_id`). */
|
|
572
|
-
requestId?: string | undefined);
|
|
573
|
-
}
|
|
574
|
-
/**
|
|
575
|
-
* Error thrown when WASM operations fail
|
|
576
|
-
*/
|
|
577
|
-
declare class WasmError extends T3nError {
|
|
578
|
-
readonly operation?: string | undefined;
|
|
579
|
-
readonly payload?: unknown | undefined;
|
|
580
|
-
constructor(message: string, operation?: string | undefined, payload?: unknown | undefined);
|
|
581
|
-
}
|
|
582
|
-
/**
|
|
583
|
-
* Decode WASM error message from comma-separated byte array format
|
|
584
|
-
* WASM errors often come as "83,101,114,100,101..." which represents ASCII bytes
|
|
585
|
-
*
|
|
586
|
-
* @param errorMessage - The error message string that may contain comma-separated bytes
|
|
587
|
-
* @returns Decoded error message if it was encoded, otherwise original message
|
|
588
|
-
*/
|
|
589
|
-
declare function decodeWasmErrorMessage(errorMessage: string): string;
|
|
590
|
-
/**
|
|
591
|
-
* Extract and decode error from WASM ComponentError
|
|
592
|
-
*
|
|
593
|
-
* @param error - The error object from WASM
|
|
594
|
-
* @returns Decoded error message
|
|
595
|
-
*/
|
|
596
|
-
declare function extractWasmError(error: unknown): string;
|
|
597
|
-
|
|
598
793
|
/**
|
|
599
794
|
* Contract response decoding for {@link T3nClient.execute}.
|
|
600
795
|
*
|
|
@@ -1030,6 +1225,116 @@ declare class T3nClient {
|
|
|
1030
1225
|
* row exists yet), or if the response shape is unexpected.
|
|
1031
1226
|
*/
|
|
1032
1227
|
kycStatus(providerId?: string): Promise<KycStatus>;
|
|
1228
|
+
/**
|
|
1229
|
+
* Dispatch a one-time code to the supplied contact via the host's
|
|
1230
|
+
* OTP provider. Backed by `tee:user/contracts::otp-request`.
|
|
1231
|
+
*
|
|
1232
|
+
* The contract persists the unverified contact in the channel's
|
|
1233
|
+
* pending slot (`pending_email` / `pending_phone`) and returns
|
|
1234
|
+
* `OtpRequestResult` with `status = "otp_pending"` (or `undefined`
|
|
1235
|
+
* when the node is configured with `skip_otp = true`). The next
|
|
1236
|
+
* step is {@link otpVerify} with the code the user typed.
|
|
1237
|
+
*
|
|
1238
|
+
* Behaviour notes:
|
|
1239
|
+
*
|
|
1240
|
+
* - Contact is a discriminated object: `emailChannel` or
|
|
1241
|
+
* `smsChannel` (mirrors Rust `OtpRequest`). The legacy
|
|
1242
|
+
* `keys.generic_api.otp_channel` body shadow is rejected by the
|
|
1243
|
+
* contract.
|
|
1244
|
+
* - SMS channel is gated on a verified email. Calling with
|
|
1245
|
+
* `channel = "sms"` against a DID that hasn't completed an
|
|
1246
|
+
* email roundtrip first throws.
|
|
1247
|
+
* - On a fresh DID's first call, `result.isNewProfile === true`.
|
|
1248
|
+
* Use this signal — not [[otpVerify]]'s response — for "did the
|
|
1249
|
+
* user just register" gating.
|
|
1250
|
+
*
|
|
1251
|
+
* @throws {RpcError} if the node rejects the action; the message
|
|
1252
|
+
* carries the contract-side detail (e.g. sequential-flow guard
|
|
1253
|
+
* when the email is missing).
|
|
1254
|
+
*/
|
|
1255
|
+
otpRequest(input: OtpRequestInput): Promise<OtpRequestResult>;
|
|
1256
|
+
/**
|
|
1257
|
+
* Redeem a one-time code and bind the contact to the
|
|
1258
|
+
* authenticated DID. Backed by
|
|
1259
|
+
* `tee:user/contracts::otp-verify`.
|
|
1260
|
+
*
|
|
1261
|
+
* On success the contract promotes the pending contact back to
|
|
1262
|
+
* the canonical slot, writes the AUTH_MAP / DIDS_MAP /
|
|
1263
|
+
* USER_AUTHS_MAP authenticator entries, stamps
|
|
1264
|
+
* `verified_contacts.{email,phone}`, and mints the ambient
|
|
1265
|
+
* `t3n.personal.contact.1` ownership VC when both contacts are
|
|
1266
|
+
* now verified.
|
|
1267
|
+
*
|
|
1268
|
+
* If the contact is already owned by a different DID the
|
|
1269
|
+
* contract refuses to silently reparent the authenticator and
|
|
1270
|
+
* surfaces a `mergeSuggestion` instead — the caller resolves the
|
|
1271
|
+
* merge (typically via {@link mergeProfiles}) and re-attempts.
|
|
1272
|
+
*
|
|
1273
|
+
* On a wrong / expired code the contract returns the result with
|
|
1274
|
+
* `status = "otp_failed"` or `"otp_expired"` — no exception is
|
|
1275
|
+
* thrown, the error is surfaced as data so the UI can stay on
|
|
1276
|
+
* the verify screen and let the user retry.
|
|
1277
|
+
*
|
|
1278
|
+
* @throws {RpcError} if the node rejects the action outright
|
|
1279
|
+
* (network / decode / bad input shape). Branch on
|
|
1280
|
+
* `result.status` for retryable OTP failures.
|
|
1281
|
+
*/
|
|
1282
|
+
otpVerify(input: OtpVerifyInput): Promise<OtpVerifyResult>;
|
|
1283
|
+
/**
|
|
1284
|
+
* Submit Level-1 user-input fields to the slim
|
|
1285
|
+
* `tee:user/contracts::user-upsert`. The contract merges the
|
|
1286
|
+
* supplied profile fields, validates them, mints
|
|
1287
|
+
* `t3n.user-input.kyc.1` once every Level-1 field is present, and
|
|
1288
|
+
* commits the write.
|
|
1289
|
+
*
|
|
1290
|
+
* **Pre-condition** (MAT-1374): the DID must already have a
|
|
1291
|
+
* verified email — either because {@link otpVerify} bound one or
|
|
1292
|
+
* because the session carries a proving authenticator (OIDC /
|
|
1293
|
+
* Email auth). Calls without proof are rejected with
|
|
1294
|
+
* {@link UserUpsertError} `kind = "EmailNotVerified"`. The
|
|
1295
|
+
* recommended UX is "request OTP -> verify OTP -> submit user
|
|
1296
|
+
* input" (or use {@link runOtpThenUserInput} which chains all
|
|
1297
|
+
* three).
|
|
1298
|
+
*
|
|
1299
|
+
* The KYC webhook orphan-attestation flow stays here: when
|
|
1300
|
+
* `requireExistingUser` is set, the contract identifies the user
|
|
1301
|
+
* by DID (vendorData) instead of email and the gate is bypassed.
|
|
1302
|
+
*
|
|
1303
|
+
* @throws {UserUpsertError} when the contract returns a typed
|
|
1304
|
+
* error (`email_not_verified`, `legacy_field`, `user_not_found`).
|
|
1305
|
+
* Branch on `err.kind`.
|
|
1306
|
+
* @throws {RpcError} for non-typed transport / decode failures.
|
|
1307
|
+
*/
|
|
1308
|
+
submitUserInput(input: SubmitUserInputArgs): Promise<SubmitUserInputResult>;
|
|
1309
|
+
/**
|
|
1310
|
+
* Convenience helper: run the explicit OTP roundtrip and submit
|
|
1311
|
+
* the slim user-upsert in one call.
|
|
1312
|
+
*
|
|
1313
|
+
* The caller supplies a `getOtpCode(contact, channel)` callback
|
|
1314
|
+
* the SDK invokes between request and verify — this is where
|
|
1315
|
+
* a UI prompts the user to type the code that arrived on email
|
|
1316
|
+
* / SMS. Throw from the callback to abort the flow; the helper
|
|
1317
|
+
* does not retry on its own.
|
|
1318
|
+
*
|
|
1319
|
+
* Returns the slim `submitUserInput` result on success. Throws
|
|
1320
|
+
* {@link UserUpsertError} or `RpcError` on the same conditions
|
|
1321
|
+
* as the underlying wrappers.
|
|
1322
|
+
*
|
|
1323
|
+
* Optional, opt-in path — the recommended default is to call
|
|
1324
|
+
* {@link otpRequest}, {@link otpVerify}, and
|
|
1325
|
+
* {@link submitUserInput} explicitly so the application owns the
|
|
1326
|
+
* flow.
|
|
1327
|
+
*/
|
|
1328
|
+
runOtpThenUserInput(args: {
|
|
1329
|
+
channel: OtpChannel;
|
|
1330
|
+
emailAddress?: string;
|
|
1331
|
+
phoneNumber?: string;
|
|
1332
|
+
profile: SubmitUserInputArgs["profile"];
|
|
1333
|
+
organisationDid?: string;
|
|
1334
|
+
attestations?: unknown;
|
|
1335
|
+
keys?: Record<string, unknown>;
|
|
1336
|
+
getOtpCode: (contact: string, channel: OtpChannel) => Promise<string> | string;
|
|
1337
|
+
}): Promise<SubmitUserInputResult>;
|
|
1033
1338
|
/**
|
|
1034
1339
|
* Poll `kyc-status` until a terminal status arrives or the
|
|
1035
1340
|
* configured timeout elapses.
|
|
@@ -1202,6 +1507,211 @@ declare function createRandomHandler(): GuestToHostHandler;
|
|
|
1202
1507
|
*/
|
|
1203
1508
|
declare function createDefaultHandlers(baseUrl: string): GuestToHostHandlers;
|
|
1204
1509
|
|
|
1510
|
+
/**
|
|
1511
|
+
* User-to-Agent Delegation (T3-TS-030).
|
|
1512
|
+
*
|
|
1513
|
+
* TypeScript reference implementation of the delegation credential and
|
|
1514
|
+
* envelope shapes defined in `node/tee_contracts/delegation-types`.
|
|
1515
|
+
*
|
|
1516
|
+
* The wire shape is byte-for-byte identical to the Rust source — pinned
|
|
1517
|
+
* by the KAT fixtures under `tests/kat/`. Specifically:
|
|
1518
|
+
*
|
|
1519
|
+
* - `not_before_secs` / `not_after_secs` / `batch_cap_cents` are
|
|
1520
|
+
* emitted as **JSON strings** (e.g. `"1700086400"`) so JS Number
|
|
1521
|
+
* precision never enters the canonicalisation surface.
|
|
1522
|
+
* - `nonce` (16 B), `vc_id` (16 B), `request_hash` (32 B),
|
|
1523
|
+
* `agent_pubkey` (33 B compressed secp256k1), `user_sig`,
|
|
1524
|
+
* `agent_sig` are emitted as **base64url-no-pad** strings.
|
|
1525
|
+
* - `org_did` / `user_did` are emitted as `did:t3n:<40-hex>` (the
|
|
1526
|
+
* `CompactDid` `Display` form).
|
|
1527
|
+
*
|
|
1528
|
+
* Canonicalisation uses the npm `canonicalize` package (RFC 8785 JCS).
|
|
1529
|
+
* Cryptography uses `@noble/curves` (secp256k1) and `@noble/hashes`
|
|
1530
|
+
* (sha256, keccak_256).
|
|
1531
|
+
*/
|
|
1532
|
+
/** Domain tag carried in `DelegationCredential.v`. */
|
|
1533
|
+
declare const DELEGATION_CREDENTIAL_DOMAIN: "ot3.delegation/1";
|
|
1534
|
+
/** Domain tag prepended to the agent-side pre-image. */
|
|
1535
|
+
declare const DELEGATION_INVOCATION_DOMAIN: "ot3.invocation/1";
|
|
1536
|
+
declare const VC_ID_LEN = 16;
|
|
1537
|
+
declare const NONCE_LEN = 16;
|
|
1538
|
+
declare const REQUEST_HASH_LEN = 32;
|
|
1539
|
+
declare const AGENT_PUBKEY_LEN = 33;
|
|
1540
|
+
declare const ETH_SIG_LEN = 65;
|
|
1541
|
+
/** User-to-agent delegation credential body. */
|
|
1542
|
+
interface DelegationCredential {
|
|
1543
|
+
/** Domain tag, must equal {@link DELEGATION_CREDENTIAL_DOMAIN}. */
|
|
1544
|
+
v: string;
|
|
1545
|
+
/** `did:t3n:<40-hex>` user DID. */
|
|
1546
|
+
user_did: string;
|
|
1547
|
+
/** 33-byte compressed secp256k1 public key the agent uses per call. */
|
|
1548
|
+
agent_pubkey: Uint8Array;
|
|
1549
|
+
/** `did:t3n:<40-hex>` org DID. */
|
|
1550
|
+
org_did: string;
|
|
1551
|
+
/** Contract id, e.g. `"tee:payroll"`. */
|
|
1552
|
+
contract: string;
|
|
1553
|
+
/** Function name, e.g. `"run-payroll"`. */
|
|
1554
|
+
function: string;
|
|
1555
|
+
/** Org-data scopes the contract may read on this user's behalf. */
|
|
1556
|
+
scopes: string[];
|
|
1557
|
+
/** Flat key-value labels checked against the org grant. */
|
|
1558
|
+
metadata: Record<string, string>;
|
|
1559
|
+
/** Inclusive lower bound of the validity window (unix seconds). */
|
|
1560
|
+
not_before_secs: bigint;
|
|
1561
|
+
/** Inclusive upper bound of the validity window (unix seconds). */
|
|
1562
|
+
not_after_secs: bigint;
|
|
1563
|
+
/** Random 16-byte credential id. */
|
|
1564
|
+
vc_id: Uint8Array;
|
|
1565
|
+
}
|
|
1566
|
+
/** Envelope wrapping a contract-specific request body. */
|
|
1567
|
+
interface DelegationEnvelope {
|
|
1568
|
+
/** RFC 8785 JCS bytes of the credential, exactly as signed. */
|
|
1569
|
+
credential_jcs: Uint8Array;
|
|
1570
|
+
/** 65-byte EIP-191 signature over `credential_jcs`. */
|
|
1571
|
+
user_sig: Uint8Array;
|
|
1572
|
+
/** Per-call agent signature over the invocation pre-image. */
|
|
1573
|
+
agent_sig: Uint8Array;
|
|
1574
|
+
/** 16-byte agent-generated per-call nonce. */
|
|
1575
|
+
nonce: Uint8Array;
|
|
1576
|
+
/** SHA-256 of the canonical request body. */
|
|
1577
|
+
request_hash: Uint8Array;
|
|
1578
|
+
}
|
|
1579
|
+
/** Payroll-specific request body wrapped by a delegation envelope. */
|
|
1580
|
+
interface PayrollRunRequest {
|
|
1581
|
+
/** `did:t3n:<40-hex>` org id. */
|
|
1582
|
+
org_id: string;
|
|
1583
|
+
cycle_id: string;
|
|
1584
|
+
pay_period_start: string;
|
|
1585
|
+
pay_period_end: string;
|
|
1586
|
+
/** Total cap on the run's net disbursement, in cents. */
|
|
1587
|
+
batch_cap_cents: bigint;
|
|
1588
|
+
/** `employee_id` → previous-cycle baseline net disbursement, cents (decimal string). */
|
|
1589
|
+
historical_baselines: Record<string, string>;
|
|
1590
|
+
}
|
|
1591
|
+
/** Convenience wrapper paired with the matching delegation envelope. */
|
|
1592
|
+
interface PayrollInvocation {
|
|
1593
|
+
envelope: DelegationEnvelope;
|
|
1594
|
+
request: PayrollRunRequest;
|
|
1595
|
+
}
|
|
1596
|
+
/** Response from `tee:delegation.sign`. */
|
|
1597
|
+
interface SignDelegationResponse {
|
|
1598
|
+
credential_jcs: Uint8Array;
|
|
1599
|
+
user_sig: Uint8Array;
|
|
1600
|
+
}
|
|
1601
|
+
declare function b64uEncode(input: Uint8Array): string;
|
|
1602
|
+
/**
|
|
1603
|
+
* Encode raw bytes to base64url-no-pad (RFC 4648 §5 with padding
|
|
1604
|
+
* dropped). The same encoding T3-TS-030 wire-shape uses for binary
|
|
1605
|
+
* fields (`agent_pubkey`, `vc_id`, `nonce`, `agent_sig`, `user_sig`,
|
|
1606
|
+
* `request_hash`, `credential_jcs`).
|
|
1607
|
+
*
|
|
1608
|
+
* Public API since v2.2: callers building `PayrollInvocation` JSON
|
|
1609
|
+
* for the wire (e.g. the t3n-mcp `runPayroll` handler) need this
|
|
1610
|
+
* encoder to match the contract's deserializer.
|
|
1611
|
+
*/
|
|
1612
|
+
declare function b64uEncodeBytes(input: Uint8Array): string;
|
|
1613
|
+
/**
|
|
1614
|
+
* Decode a base64url-no-pad string. Strict — rejects standard-alphabet
|
|
1615
|
+
* `+` / `/` and any padding `=`.
|
|
1616
|
+
*/
|
|
1617
|
+
declare function b64uDecodeStrict(input: string): Uint8Array;
|
|
1618
|
+
/** @internal — preserved alias for in-tree callers. Prefer
|
|
1619
|
+
* {@link b64uEncodeBytes} / {@link b64uDecodeStrict}. */
|
|
1620
|
+
declare const _b64uEncode: typeof b64uEncode;
|
|
1621
|
+
/** Build a `did:t3n:<40-hex>` from raw 20 bytes. */
|
|
1622
|
+
declare function compactDidFromBytes(bytes: Uint8Array): string;
|
|
1623
|
+
/**
|
|
1624
|
+
* Canonicalise a {@link DelegationCredential} to RFC 8785 JCS bytes.
|
|
1625
|
+
*
|
|
1626
|
+
* Output is byte-identical to the Rust `canonicalise_credential` in
|
|
1627
|
+
* `delegation-types` (pinned by `tests/kat/credential.json`).
|
|
1628
|
+
*/
|
|
1629
|
+
declare function canonicaliseCredential(credential: DelegationCredential): Uint8Array;
|
|
1630
|
+
/** Canonicalise an arbitrary {@link PayrollRunRequest} to JCS bytes. */
|
|
1631
|
+
declare function canonicaliseRequest(request: PayrollRunRequest): Uint8Array;
|
|
1632
|
+
/** SHA-256 of the canonicalised request body. */
|
|
1633
|
+
declare function requestHash(request: PayrollRunRequest): Uint8Array;
|
|
1634
|
+
/**
|
|
1635
|
+
* Build the agent-side pre-image bytes:
|
|
1636
|
+
* `utf8(DELEGATION_INVOCATION_DOMAIN) || vc_id || nonce || request_hash`.
|
|
1637
|
+
*
|
|
1638
|
+
* SHA-256 of these bytes is what the agent's secp256k1 signature is
|
|
1639
|
+
* verified against.
|
|
1640
|
+
*/
|
|
1641
|
+
declare function buildInvocationPreimage(vcId: Uint8Array, nonce: Uint8Array, reqHash: Uint8Array): Uint8Array;
|
|
1642
|
+
/** Options for {@link buildDelegationCredential}. */
|
|
1643
|
+
interface BuildDelegationCredentialOpts {
|
|
1644
|
+
user_did: string;
|
|
1645
|
+
agent_pubkey: Uint8Array;
|
|
1646
|
+
org_did: string;
|
|
1647
|
+
contract: string;
|
|
1648
|
+
function: string;
|
|
1649
|
+
scopes?: string[];
|
|
1650
|
+
metadata?: Record<string, string>;
|
|
1651
|
+
not_before_secs: bigint | number;
|
|
1652
|
+
not_after_secs: bigint | number;
|
|
1653
|
+
vc_id: Uint8Array;
|
|
1654
|
+
}
|
|
1655
|
+
/**
|
|
1656
|
+
* Construct a {@link DelegationCredential} and validate body-level
|
|
1657
|
+
* invariants (domain, lengths, validity window). Throws on the same
|
|
1658
|
+
* conditions the Rust `validate_credential_body` rejects.
|
|
1659
|
+
*/
|
|
1660
|
+
declare function buildDelegationCredential(opts: BuildDelegationCredentialOpts): DelegationCredential;
|
|
1661
|
+
/**
|
|
1662
|
+
* Body-level validation matching `delegation-types::validate_credential_body`,
|
|
1663
|
+
* minus the `now`/`max_validity_secs` checks (which are caller-supplied).
|
|
1664
|
+
* Throws with a message identifying the offending invariant.
|
|
1665
|
+
*/
|
|
1666
|
+
declare function validateCredentialBody(c: DelegationCredential): void;
|
|
1667
|
+
/** Compute the EIP-191 "personal_sign" digest of a message. */
|
|
1668
|
+
declare function eip191Digest(msg: Uint8Array): Uint8Array;
|
|
1669
|
+
/**
|
|
1670
|
+
* EIP-191 sign `jcs` under `secret`, returning a 65-byte signature
|
|
1671
|
+
* (`r || s || v`, with `v` in 27/28 — Ethereum convention) and the
|
|
1672
|
+
* recovered 20-byte ETH address.
|
|
1673
|
+
*/
|
|
1674
|
+
declare function signCredential(jcs: Uint8Array, secret: Uint8Array): {
|
|
1675
|
+
sig: Uint8Array;
|
|
1676
|
+
addr: Uint8Array;
|
|
1677
|
+
};
|
|
1678
|
+
/**
|
|
1679
|
+
* Recover the 20-byte ETH address that signed `msg` under EIP-191.
|
|
1680
|
+
* Mirrors `delegation-types::eth_recover_eip191`.
|
|
1681
|
+
*
|
|
1682
|
+
* **Signature malleability — accepted by design.** This routine does
|
|
1683
|
+
* not enforce low-s. EIP-2 mandates low-s for *transaction* signatures,
|
|
1684
|
+
* but EIP-191 / `personal_sign` has no such requirement, and ethers.js
|
|
1685
|
+
* / MetaMask / web3.js produce both shapes. Two distinct `(r, s)` and
|
|
1686
|
+
* `(r, n − s)` pairs verify under the same recovered address — replay
|
|
1687
|
+
* protection comes from the envelope's `request_hash` + `nonce`, not
|
|
1688
|
+
* from byte-uniqueness of the signature.
|
|
1689
|
+
*/
|
|
1690
|
+
declare function ethRecoverEip191(msg: Uint8Array, sig: Uint8Array): Uint8Array;
|
|
1691
|
+
/**
|
|
1692
|
+
* Sign the agent-side invocation pre-image. The signature is raw
|
|
1693
|
+
* compact ECDSA (64 bytes) over `sha256(preimage)` — what
|
|
1694
|
+
* `delegation-types::verify_agent_sig` accepts as the 64-byte form.
|
|
1695
|
+
*/
|
|
1696
|
+
declare function signAgentInvocation(preimage: Uint8Array, secret: Uint8Array): Uint8Array;
|
|
1697
|
+
/** Options for {@link buildPayrollInvocation}. */
|
|
1698
|
+
interface BuildPayrollInvocationOpts {
|
|
1699
|
+
credentialJcs: Uint8Array;
|
|
1700
|
+
userSig: Uint8Array;
|
|
1701
|
+
/** Credential's `vc_id` — needed for the agent pre-image. */
|
|
1702
|
+
vcId: Uint8Array;
|
|
1703
|
+
nonce: Uint8Array;
|
|
1704
|
+
request: PayrollRunRequest;
|
|
1705
|
+
agentSecret: Uint8Array;
|
|
1706
|
+
}
|
|
1707
|
+
/**
|
|
1708
|
+
* Assemble a complete {@link PayrollInvocation} (envelope + request)
|
|
1709
|
+
* given a user-signed credential and a per-call agent secret. Computes
|
|
1710
|
+
* `request_hash` from the canonical request bytes and produces an
|
|
1711
|
+
* `agent_sig` over `sha256(invocation_preimage)`.
|
|
1712
|
+
*/
|
|
1713
|
+
declare function buildPayrollInvocation(opts: BuildPayrollInvocationOpts): PayrollInvocation;
|
|
1714
|
+
|
|
1205
1715
|
/**
|
|
1206
1716
|
* Cryptographic utilities for T3n SDK
|
|
1207
1717
|
*
|
|
@@ -1423,5 +1933,5 @@ declare function clearKeyCache(): void;
|
|
|
1423
1933
|
*/
|
|
1424
1934
|
declare function loadConfig(baseUrl?: string): SdkConfig;
|
|
1425
1935
|
|
|
1426
|
-
export { AuthMethod, AuthenticationError, ContractResponseError, DEFAULT_KYC_POLL_CADENCE, HandshakeError, HttpTransport, KycStatusTimeoutError, LogLevel, MockTransport, NODE_URLS, RpcError, SessionStateError, SessionStatus, T3nClient, T3nError, TERMINAL_KYC_STATUSES, WasmError, bytesToString, clearKeyCache, createDefaultHandlers, createEthAuthInput, createLogger, createMlKemPublicKeyHandler, createOidcAuthInput, createRandomHandler, decodeWasmErrorMessage, eth_get_address, extractWasmError, fetchDkgAttestation, fetchMlKemPublicKey, generateRandomString, generateUUID, getEnvironment, getEnvironmentName, getGlobalLogLevel, getLogger, getNodeUrl, getScriptVersion, loadConfig, loadWasmComponent, metamask_get_address, metamask_sign, parseContractResponse, redactSecrets, redactSecretsFromJson, setEnvironment, setGlobalLogLevel, setNodeUrl, stringToBytes, validateConfig, verifyDkgAttestation, verifyTdxQuote };
|
|
1427
|
-
export type { AuthInput, ClientAuth, ClientHandshake, ConfigValidationResult, ContractResponseSchema, Did, DkgAttestation, DkgVerifyResult, Environment, EthAuthInput, GuestToHostHandler, GuestToHostHandlers, HandshakeResult, JsonRpcRequest, JsonRpcResponse, KycPollCadence, KycPollOptions, KycStatus, KycStatusKind, Logger, OidcAuthInput, OidcCredentials, PeerQuoteResult, QuoteVerifyResult, SdkConfig, SessionCrypto, SessionId, T3nClientConfig, Transport, WasmComponent, WasmNextResult };
|
|
1936
|
+
export { AGENT_PUBKEY_LEN, AuthMethod, AuthenticationError, ContractResponseError, DEFAULT_KYC_POLL_CADENCE, DELEGATION_CREDENTIAL_DOMAIN, DELEGATION_INVOCATION_DOMAIN, ETH_SIG_LEN, HandshakeError, HttpTransport, KycStatusTimeoutError, LogLevel, MockTransport, NODE_URLS, NONCE_LEN, REQUEST_HASH_LEN, RpcError, SessionStateError, SessionStatus, T3nClient, T3nError, TERMINAL_KYC_STATUSES, UserUpsertError, VC_ID_LEN, WasmError, _b64uEncode, b64uDecodeStrict, b64uEncodeBytes, buildDelegationCredential, buildInvocationPreimage, buildPayrollInvocation, bytesToString, canonicaliseCredential, canonicaliseRequest, clearKeyCache, compactDidFromBytes, createDefaultHandlers, createEthAuthInput, createLogger, createMlKemPublicKeyHandler, createOidcAuthInput, createRandomHandler, decodeWasmErrorMessage, eip191Digest, ethRecoverEip191, eth_get_address, extractWasmError, fetchDkgAttestation, fetchMlKemPublicKey, generateRandomString, generateUUID, getEnvironment, getEnvironmentName, getGlobalLogLevel, getLogger, getNodeUrl, getScriptVersion, loadConfig, loadWasmComponent, metamask_get_address, metamask_sign, parseContractResponse, redactSecrets, redactSecretsFromJson, requestHash, setEnvironment, setGlobalLogLevel, setNodeUrl, signAgentInvocation, signCredential, stringToBytes, validateConfig, validateCredentialBody, verifyDkgAttestation, verifyTdxQuote };
|
|
1937
|
+
export type { AuthInput, BuildDelegationCredentialOpts, BuildPayrollInvocationOpts, ClientAuth, ClientHandshake, ConfigValidationResult, ContractResponseSchema, DelegationCredential, DelegationEnvelope, Did, DkgAttestation, DkgVerifyResult, Environment, EthAuthInput, GuestToHostHandler, GuestToHostHandlers, HandshakeResult, JsonRpcRequest, JsonRpcResponse, KycPollCadence, KycPollOptions, KycStatus, KycStatusKind, Logger, OidcAuthInput, OidcCredentials, OtpChannel, OtpMergeSuggestion, OtpRequestInput, OtpRequestResult, OtpVerifyInput, OtpVerifyResult, PayrollInvocation, PayrollRunRequest, PeerQuoteResult, QuoteVerifyResult, SdkConfig, SessionCrypto, SessionId, SignDelegationResponse, SubmitUserInputArgs, SubmitUserInputResult, T3nClientConfig, Transport, UserInputProfile, UserUpsertErrorKind, WasmComponent, WasmNextResult };
|