@proveanything/smartlinks 1.15.18 → 1.15.20
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 +2 -2
- package/dist/api/authKit.d.ts +27 -3
- package/dist/api/authKit.js +24 -0
- package/dist/api/proof.d.ts +58 -2
- package/dist/api/proof.js +74 -2
- package/dist/docs/API_SUMMARY.md +162 -18
- package/dist/docs/auth-kit.md +107 -0
- package/dist/docs/overview.md +3 -0
- package/dist/docs/proof-ownership-transfer.md +114 -0
- package/dist/index.d.ts +2 -2
- package/dist/openapi.yaml +189 -10
- package/dist/types/authKit.d.ts +84 -1
- package/dist/types/proof.d.ts +117 -5
- package/docs/API_SUMMARY.md +162 -18
- package/docs/auth-kit.md +107 -0
- package/docs/overview.md +3 -0
- package/docs/proof-ownership-transfer.md +114 -0
- package/openapi.yaml +189 -10
- package/package.json +1 -1
package/dist/docs/auth-kit.md
CHANGED
|
@@ -502,6 +502,113 @@ await authKit.completePasswordReset(clientId, tokenFromUrl, 'newSecurePassword')
|
|
|
502
502
|
|
|
503
503
|
---
|
|
504
504
|
|
|
505
|
+
## Account security policy
|
|
506
|
+
|
|
507
|
+
Each collection can configure account-security rules. **The API enforces all of it**; your
|
|
508
|
+
login UI reads the policy for UX only (a live password checklist, idle sign-out). There are
|
|
509
|
+
two sides: an **admin** writes the policy, and the **login UI** reads the public subset.
|
|
510
|
+
|
|
511
|
+
**Read (login UI, public — no auth):**
|
|
512
|
+
|
|
513
|
+
```ts
|
|
514
|
+
const config = await authKit.load(clientId);
|
|
515
|
+
const policy = config.security?.passwordPolicy; // min length, char classes, block-common
|
|
516
|
+
const session = config.security?.session; // inactivity + absolute timeouts, rememberMe
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
`lockout` values are admin-only and never returned by `load`.
|
|
520
|
+
|
|
521
|
+
**Write (admin):** set the whole `security` block with `authKit.update` (or `authKit.create`).
|
|
522
|
+
The shape is {@link AuthKitSecurityConfig}; see {@link AuthKitConfigInput}.
|
|
523
|
+
|
|
524
|
+
```ts
|
|
525
|
+
await authKit.update(collectionId, clientId, {
|
|
526
|
+
security: {
|
|
527
|
+
passwordPolicy: {
|
|
528
|
+
minLength: 8, // hard floor enforced server-side
|
|
529
|
+
blockCommonPasswords: true, // reject the common/breached list
|
|
530
|
+
requireUppercase: false, requireLowercase: false,
|
|
531
|
+
requireNumber: false, requireSymbol: false,
|
|
532
|
+
expiryDays: 0, // 0 = never expires
|
|
533
|
+
historyCount: 0, // 0 = reuse allowed
|
|
534
|
+
},
|
|
535
|
+
lockout: { // admin-only; enforced server-side
|
|
536
|
+
enabled: true, maxFailedAttempts: 5,
|
|
537
|
+
attemptWindowMinutes: 15, lockoutMinutes: 15,
|
|
538
|
+
notifyUserOnLockout: true,
|
|
539
|
+
},
|
|
540
|
+
session: {
|
|
541
|
+
inactivityTimeoutMinutes: 0, // 0 = disabled (client-enforced when set)
|
|
542
|
+
inactivityWarningSeconds: 60,
|
|
543
|
+
absoluteTimeoutHours: 0, // 0 = use token lifetime (server-enforced)
|
|
544
|
+
rememberMe: true,
|
|
545
|
+
},
|
|
546
|
+
},
|
|
547
|
+
});
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
Defaults if a collection has never set a policy: 8-char minimum + block-common for everyone,
|
|
551
|
+
lockout disabled, no expiry/history, no idle/absolute timeout. Omit any field to take its default.
|
|
552
|
+
|
|
553
|
+
### Password policy
|
|
554
|
+
|
|
555
|
+
`register`, `completePasswordReset`, and `changePassword` validate the new password
|
|
556
|
+
server-side and throw a `SmartlinksApiError` with a {@link PasswordPolicyErrorCode}:
|
|
557
|
+
|
|
558
|
+
| `errorCode` (400) | Meaning |
|
|
559
|
+
|---|---|
|
|
560
|
+
| `PASSWORD_TOO_SHORT` | below `minLength` |
|
|
561
|
+
| `PASSWORD_REQUIREMENTS_NOT_MET` | missing a required character class |
|
|
562
|
+
| `PASSWORD_TOO_COMMON` | on the common/breached list |
|
|
563
|
+
| `PASSWORD_RECENTLY_USED` | matched one of the last `historyCount` passwords |
|
|
564
|
+
|
|
565
|
+
Render a live checklist from `policy` so users see the rules before submitting.
|
|
566
|
+
|
|
567
|
+
### Lockout
|
|
568
|
+
|
|
569
|
+
After too many failed logins the account is temporarily locked. `login` throws:
|
|
570
|
+
|
|
571
|
+
```ts
|
|
572
|
+
try {
|
|
573
|
+
await authKit.login(clientId, email, password);
|
|
574
|
+
} catch (err) {
|
|
575
|
+
if (err.errorCode === 'ACCOUNT_TEMPORARILY_LOCKED') {
|
|
576
|
+
const mins = Math.ceil(err.details.retryAfterSeconds / 60);
|
|
577
|
+
show(`Too many attempts. Try again in ${mins} minute(s).`);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
Failed MFA challenges count toward the same lock. Locking responds identically for unknown
|
|
583
|
+
accounts (no enumeration).
|
|
584
|
+
|
|
585
|
+
### Password expiry
|
|
586
|
+
|
|
587
|
+
If a password is older than `passwordPolicy.expiryDays`, a valid login is refused with
|
|
588
|
+
**403 `PASSWORD_EXPIRED`** carrying a short-lived `resetToken` — send the user straight into
|
|
589
|
+
the reset form to change it in place:
|
|
590
|
+
|
|
591
|
+
```ts
|
|
592
|
+
catch (err) {
|
|
593
|
+
if (err.errorCode === 'PASSWORD_EXPIRED') {
|
|
594
|
+
await authKit.completePasswordReset(clientId, err.details.resetToken, newPassword);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
### Session lifetime
|
|
600
|
+
|
|
601
|
+
- **Absolute timeout** (`session.absoluteTimeoutHours`) is enforced server-side on the native
|
|
602
|
+
refresh path: once the session is too old, `refreshToken` throws **401 `SESSION_EXPIRED`**
|
|
603
|
+
(see {@link RefreshErrorCode}) — clear storage and route to login. Web sessions use the
|
|
604
|
+
stateless bearer token and rely on inactivity sign-out below.
|
|
605
|
+
- **Inactivity timeout** (`session.inactivityTimeoutMinutes` / `inactivityWarningSeconds`) is
|
|
606
|
+
**client-enforced** — sign the user out after idle, warning first. Sync across tabs.
|
|
607
|
+
- **`session.rememberMe: false`** → don't persist tokens to durable storage; treat the session
|
|
608
|
+
as browser-scoped.
|
|
609
|
+
|
|
610
|
+
---
|
|
611
|
+
|
|
505
612
|
## Relationship to other parts of the SDK
|
|
506
613
|
|
|
507
614
|
| Concern | Where it lives |
|
package/dist/docs/overview.md
CHANGED
|
@@ -81,6 +81,9 @@ The SmartLinks SDK (`@proveanything/smartlinks`) includes comprehensive document
|
|
|
81
81
|
| **App Records Pattern** | `docs/app-records-pattern.md` | Standard pattern for per-product/facet/variant/batch admin + public widget UIs |
|
|
82
82
|
| **UI Utils** | `docs/ui-utils.md` | `@proveanything/smartlinks-utils-ui` — React shells, hooks, and primitives for records-based apps |
|
|
83
83
|
| **Product/Proof Data Scoping** | `docs/proof-product-data-scoping.md` | Canonical spec for `product.data`/`.admin` and `proof.data`/`.admin`/`.values` (owner/personal) — who can read and write each bucket |
|
|
84
|
+
| **Proof Claiming** | `docs/proof-claiming-methods.md` | The ways a user claims a proof (serial, NFC, claim-set, auto-generate) |
|
|
85
|
+
| **Proof Share Grants** | `docs/proof-share-grants.md` | Delegated, scoped, revocable bearer access to a single proof (read/comment/verify-owner) |
|
|
86
|
+
| **Proof Ownership Transfer** | `docs/proof-ownership-transfer.md` | Moving a proof's single owner (directed transfer / open release), accept/cancel, and the state machine |
|
|
84
87
|
| **appConfig / Feature Flags** | `docs/appConfig.md` | `appConfig` settings contract — installed apps, `system.features`/`entitledAppGroups`/`meters`, `isFeatureEnabled()` helper |
|
|
85
88
|
|
|
86
89
|
---
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# Proof Ownership Transfer
|
|
2
|
+
|
|
3
|
+
Every proof has exactly **one owner** (`proof.userId`). A *transfer* moves that
|
|
4
|
+
owner from A to B — for a resale, a gift, or handing an item on. Ownership carries
|
|
5
|
+
the owner-scoped data with it and voids the previous owner's private access.
|
|
6
|
+
|
|
7
|
+
This covers **push (owner-initiated) transfers** — the current owner consents to the
|
|
8
|
+
move. Contested pull-claims and dispute resolution (where a holder claims ownership
|
|
9
|
+
the owner never released) are a later addition; the state machine below already
|
|
10
|
+
reserves states for them.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Two ways to push
|
|
15
|
+
|
|
16
|
+
| Mode | How | Who completes it |
|
|
17
|
+
|------|-----|------------------|
|
|
18
|
+
| **Directed** | Owner names a recipient (`toEmail` / `toUserId`). The proof is earmarked for them (`claimUserId`) and they're emailed a link. | The named recipient calls `acceptTransfer`. |
|
|
19
|
+
| **Open release** | Owner marks the proof `claimable`. | Anyone claims it via the normal claim flow. |
|
|
20
|
+
|
|
21
|
+
Only the current owner (or a collection admin) can start a transfer. A proof can
|
|
22
|
+
have **one active transfer at a time**.
|
|
23
|
+
|
|
24
|
+
### What completion does
|
|
25
|
+
|
|
26
|
+
When a directed transfer is accepted (or an admin resolves one), the move is
|
|
27
|
+
authoritative and atomic:
|
|
28
|
+
|
|
29
|
+
- `proof.userId` becomes the new owner; `claimable` is cleared.
|
|
30
|
+
- The **previous owner's private zones are removed** — `values.owner`,
|
|
31
|
+
`values.personal[oldOwner]`, and their `roles` entry.
|
|
32
|
+
- Every **share grant auto-voids** (grants are bound to the owner at issue), so
|
|
33
|
+
stale "I own this" links stop resolving.
|
|
34
|
+
- An append-only **`ownership_transfer` attestation** records `from → to`, so the
|
|
35
|
+
chain of custody is verifiable.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Owner flow
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { proof } from '@proveanything/smartlinks'
|
|
43
|
+
|
|
44
|
+
// Directed — hand it to a named buyer (they must accept)
|
|
45
|
+
const { transfer } = await proof.transfer(collectionId, productId, proofId, {
|
|
46
|
+
toEmail: 'buyer@example.com',
|
|
47
|
+
message: 'Enjoy the watch!',
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
// …or an open release — anyone can now claim it
|
|
51
|
+
await proof.transfer(collectionId, productId, proofId, { release: true })
|
|
52
|
+
|
|
53
|
+
// Check status at any time
|
|
54
|
+
const { transfer: active } = await proof.getTransfer(collectionId, productId, proofId)
|
|
55
|
+
|
|
56
|
+
// Change your mind before it's accepted
|
|
57
|
+
await proof.cancelTransfer(collectionId, productId, proofId)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Recipient flow (directed)
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
// Only the named recipient can accept — a third party is rejected.
|
|
64
|
+
const { proof: mine } = await proof.acceptTransfer(collectionId, productId, proofId)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The recipient sees the pending transfer on their account (a pending claim) and via
|
|
68
|
+
the email link. Until they accept, the proof still belongs to the seller.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## State machine
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
transfer({toEmail}) accept
|
|
76
|
+
(owned) ────────────────────────▶ pending ─────────────▶ completed
|
|
77
|
+
│ │
|
|
78
|
+
│ transfer({release}) │ cancel
|
|
79
|
+
└────────────────────────────────▶├─────────────────▶ cancelled
|
|
80
|
+
│
|
|
81
|
+
│ (later: dispute / escalation)
|
|
82
|
+
└─────────▶ disputed / escalated / rejected
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
- `pending` — a transfer is in flight (directed earmark or open release).
|
|
86
|
+
- `completed` — ownership moved.
|
|
87
|
+
- `cancelled` — the owner withdrew it before acceptance.
|
|
88
|
+
- `expired` / `disputed` / `escalated` / `rejected` — reserved for contested
|
|
89
|
+
claims + dispute resolution (later).
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Security notes
|
|
94
|
+
|
|
95
|
+
- **Directed accept is access-controlled.** Only the earmarked recipient
|
|
96
|
+
(`transfer.toUserId`) can accept; the claim endpoint also rejects anyone whose
|
|
97
|
+
id ≠ `claimUserId` while a directed transfer is pending. A directed transfer
|
|
98
|
+
can't be grabbed by a bystander.
|
|
99
|
+
- **Ownership only moves one way** — through completion. There is no path that
|
|
100
|
+
silently strips an active owner without their consent (contested claims, when
|
|
101
|
+
added, are dispute-protected and never auto-transfer by default).
|
|
102
|
+
- **Every state change is audited** as an append-only attestation on the proof.
|
|
103
|
+
|
|
104
|
+
## API
|
|
105
|
+
|
|
106
|
+
| Method | Endpoint |
|
|
107
|
+
|--------|----------|
|
|
108
|
+
| `proof.transfer(c, p, id, opts)` | `POST …/proof/:id/transfer` |
|
|
109
|
+
| `proof.acceptTransfer(c, p, id)` | `POST …/proof/:id/transfer/accept` |
|
|
110
|
+
| `proof.cancelTransfer(c, p, id)` | `POST …/proof/:id/transfer/cancel` |
|
|
111
|
+
| `proof.getTransfer(c, p, id)` | `GET …/proof/:id/transfer` |
|
|
112
|
+
|
|
113
|
+
See also [Proof Share Grants](./proof-share-grants.md) and
|
|
114
|
+
[Proof Claiming Methods](./proof-claiming-methods.md).
|
package/dist/index.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ export type { AdditionalGtin, ISODateString, JsonPrimitive, JsonValue, ProductCr
|
|
|
17
17
|
export type { TranslationLookupMode, TranslationContentType, TranslationQuality, TranslationItemStatus, TranslationContextValue, TranslationContext, TranslationLookupRequestBase, TranslationLookupSingleRequest, TranslationLookupBatchRequest, TranslationLookupRequest, TranslationLookupItem, TranslationLookupResponse, ResolvedTranslationItem, ResolvedTranslationResponse, TranslationHashOptions, TranslationResolveOptions, TranslationRecord, TranslationListParams, TranslationListResponse, TranslationUpdateRequest, } from "./types/translations";
|
|
18
18
|
export type { FacetBucket, FacetDefinition, FacetDefinitionWriteInput, FacetGetParams, FacetListParams, FacetListResponse, FacetNamespaceListResponse, FacetQueryRequest, FacetQueryResponse, FacetValue, FacetValueDefinition, FacetValueGetParams, FacetValueListParams, FacetValueListResponse, FacetValueResponse, FacetValueWriteInput, PublicFacetListParams, } from "./types/facets";
|
|
19
19
|
export type { Collection, CollectionResponse, CollectionCreateRequest, CollectionUpdateRequest, DomainTarget, HubAvailabilityResponse, } from "./types/collection";
|
|
20
|
-
export type { Proof, ProofResponse, ProofCreateRequest, ProofUpdateRequest, ProofClaimRequest, ProofGrant, GrantScope, GrantAudience, CreateGrantOptions, RedeemGrantOptions, RedeemGrantResult, } from "./types/proof";
|
|
20
|
+
export type { Proof, ProofResponse, ProofWrite, ProofCreateRequest, ProofUpdateRequest, ProofClaimRequest, ProofGrant, GrantScope, GrantAudience, CreateGrantOptions, RedeemGrantOptions, RedeemGrantResult, ProofTransfer, ProofTransferType, ProofTransferState, TransferProofOptions, TransferProofResult, } from "./types/proof";
|
|
21
21
|
export type { QrShortCodeLookupResponse, } from "./types/qr";
|
|
22
22
|
export type { ReverseTagLookupParams, ReverseTagLookupResponse, } from "./types/tags";
|
|
23
23
|
export type { AdminMobileCapability, ActionableCapability, AdminMobileHostId, AdminMobileEvent, AdminMobileEventCallback, AdminMobileEventSubscriber, ScannerEventSubscriber, // @deprecated — use AdminMobileEventCallback
|
|
@@ -25,4 +25,4 @@ AdminMobileHostContext, AdminMobileComponentManifest, AdminMobileBundleManifest,
|
|
|
25
25
|
MobileAdminBundleManifest, } from './mobile-admin/types';
|
|
26
26
|
export { HostCapabilityUnavailableError, HostPermissionDeniedError, HostTimeoutError, } from './mobile-admin/errors';
|
|
27
27
|
export type { NativeCapability, NativeFacade, ShareFacade, ClipboardFacade, HapticImpactStyle, HapticNotificationStyle, HapticsFacade, NetworkStatus, NetworkFacade, DeviceInfo, DeviceFacade, StorageFacade, QrScanOptions, QrFacade, AuthFacade, NfcReadResult, NfcFacade, RfidScanOptions, RfidFacade, EventsFacade, WebSourceMode, WebSourceConfig, WebSourceFacade, } from './native/types';
|
|
28
|
-
export type { AuthKitUser, UserProfile, ProfileUpdateData, UpdateProfileResponse, SuccessResponse, AuthLoginResponse, AppleLoginOptions, AuthKitErrorCode, RefreshResponse, LogoutResponse, RefreshErrorCode, MagicLinkSendResponse, MagicLinkVerifyResponse, PhoneSendCodeResponse, PhoneVerifyResponse, PasswordResetRequestResponse, VerifyResetTokenResponse, PasswordResetCompleteResponse, EmailVerificationActionResponse, EmailVerifyTokenResponse, VerifyStatus, WhatsAppReplyCta, WhatsAppReplyOptions, WhatsAppContactData, SendWhatsAppRequest, SendWhatsAppResponse, ExchangeWhatsAppSessionResponse, VerifyWhatsAppResponse, WhatsAppStatusResponse, SendSmsVerifyRequest, SendSmsVerifyResponse, VerifySmsResponse, UpsertContactRequest, UpsertContactResponse, AuthKitBrandingConfig, AuthKitConfig, } from './types/authKit';
|
|
28
|
+
export type { AuthKitUser, UserProfile, ProfileUpdateData, UpdateProfileResponse, SuccessResponse, AuthLoginResponse, AppleLoginOptions, AuthKitErrorCode, RefreshResponse, LogoutResponse, RefreshErrorCode, MagicLinkSendResponse, MagicLinkVerifyResponse, PhoneSendCodeResponse, PhoneVerifyResponse, PasswordResetRequestResponse, VerifyResetTokenResponse, PasswordResetCompleteResponse, EmailVerificationActionResponse, EmailVerifyTokenResponse, VerifyStatus, WhatsAppReplyCta, WhatsAppReplyOptions, WhatsAppContactData, SendWhatsAppRequest, SendWhatsAppResponse, ExchangeWhatsAppSessionResponse, VerifyWhatsAppResponse, WhatsAppStatusResponse, SendSmsVerifyRequest, SendSmsVerifyResponse, VerifySmsResponse, UpsertContactRequest, UpsertContactResponse, AuthKitBrandingConfig, AuthKitConfig, AuthKitConfigInput, AuthKitSecurityConfig, AuthKitPasswordPolicy, AuthKitSessionPolicy, AuthKitLockoutPolicy, PasswordPolicyErrorCode, LoginSecurityErrorCode, } from './types/authKit';
|
package/dist/openapi.yaml
CHANGED
|
@@ -1579,7 +1579,7 @@ paths:
|
|
|
1579
1579
|
post:
|
|
1580
1580
|
tags:
|
|
1581
1581
|
- authKit
|
|
1582
|
-
summary:
|
|
1582
|
+
summary: Create an AuthKit client config (admin).
|
|
1583
1583
|
operationId: authKit_create
|
|
1584
1584
|
security:
|
|
1585
1585
|
- bearerAuth: []
|
|
@@ -1602,11 +1602,17 @@ paths:
|
|
|
1602
1602
|
description: Unauthorized
|
|
1603
1603
|
404:
|
|
1604
1604
|
description: Not found
|
|
1605
|
+
requestBody:
|
|
1606
|
+
required: true
|
|
1607
|
+
content:
|
|
1608
|
+
application/json:
|
|
1609
|
+
schema:
|
|
1610
|
+
$ref: "#/components/schemas/AuthKitConfigInput"
|
|
1605
1611
|
/admin/collection/{collectionId}/authKit/{authKitId}:
|
|
1606
1612
|
get:
|
|
1607
1613
|
tags:
|
|
1608
1614
|
- authKit
|
|
1609
|
-
summary:
|
|
1615
|
+
summary: "Get the full AuthKit config, including admin-only fields like `security.lockout` (admin auth)."
|
|
1610
1616
|
operationId: authKit_get
|
|
1611
1617
|
security:
|
|
1612
1618
|
- bearerAuth: []
|
|
@@ -1637,7 +1643,7 @@ paths:
|
|
|
1637
1643
|
put:
|
|
1638
1644
|
tags:
|
|
1639
1645
|
- authKit
|
|
1640
|
-
summary:
|
|
1646
|
+
summary: Update an AuthKit client config (admin).
|
|
1641
1647
|
operationId: authKit_update
|
|
1642
1648
|
security:
|
|
1643
1649
|
- bearerAuth: []
|
|
@@ -1665,6 +1671,12 @@ paths:
|
|
|
1665
1671
|
description: Unauthorized
|
|
1666
1672
|
404:
|
|
1667
1673
|
description: Not found
|
|
1674
|
+
requestBody:
|
|
1675
|
+
required: true
|
|
1676
|
+
content:
|
|
1677
|
+
application/json:
|
|
1678
|
+
schema:
|
|
1679
|
+
$ref: "#/components/schemas/AuthKitConfigInput"
|
|
1668
1680
|
delete:
|
|
1669
1681
|
tags:
|
|
1670
1682
|
- authKit
|
|
@@ -8077,7 +8089,7 @@ paths:
|
|
|
8077
8089
|
get:
|
|
8078
8090
|
tags:
|
|
8079
8091
|
- authKit
|
|
8080
|
-
summary:
|
|
8092
|
+
summary: "Load the **public** AuthKit config for a client (no auth)."
|
|
8081
8093
|
operationId: authKit_load
|
|
8082
8094
|
security: []
|
|
8083
8095
|
parameters:
|
|
@@ -8401,7 +8413,7 @@ paths:
|
|
|
8401
8413
|
post:
|
|
8402
8414
|
tags:
|
|
8403
8415
|
- authKit
|
|
8404
|
-
summary:
|
|
8416
|
+
summary: authKit.login
|
|
8405
8417
|
operationId: authKit_login
|
|
8406
8418
|
security: []
|
|
8407
8419
|
parameters:
|
|
@@ -19381,8 +19393,74 @@ components:
|
|
|
19381
19393
|
type: string
|
|
19382
19394
|
updatedAt:
|
|
19383
19395
|
type: string
|
|
19396
|
+
security:
|
|
19397
|
+
$ref: "#/components/schemas/AuthKitSecurityConfig"
|
|
19384
19398
|
required:
|
|
19385
19399
|
- id
|
|
19400
|
+
AuthKitSecurityConfig:
|
|
19401
|
+
type: object
|
|
19402
|
+
properties:
|
|
19403
|
+
passwordPolicy:
|
|
19404
|
+
$ref: "#/components/schemas/AuthKitPasswordPolicy"
|
|
19405
|
+
session:
|
|
19406
|
+
$ref: "#/components/schemas/AuthKitSessionPolicy"
|
|
19407
|
+
lockout:
|
|
19408
|
+
$ref: "#/components/schemas/AuthKitLockoutPolicy"
|
|
19409
|
+
AuthKitPasswordPolicy:
|
|
19410
|
+
type: object
|
|
19411
|
+
properties:
|
|
19412
|
+
minLength:
|
|
19413
|
+
type: number
|
|
19414
|
+
requireUppercase:
|
|
19415
|
+
type: boolean
|
|
19416
|
+
requireLowercase:
|
|
19417
|
+
type: boolean
|
|
19418
|
+
requireNumber:
|
|
19419
|
+
type: boolean
|
|
19420
|
+
requireSymbol:
|
|
19421
|
+
type: boolean
|
|
19422
|
+
blockCommonPasswords:
|
|
19423
|
+
type: boolean
|
|
19424
|
+
expiryDays:
|
|
19425
|
+
type: number
|
|
19426
|
+
historyCount:
|
|
19427
|
+
type: number
|
|
19428
|
+
AuthKitSessionPolicy:
|
|
19429
|
+
type: object
|
|
19430
|
+
properties:
|
|
19431
|
+
inactivityTimeoutMinutes:
|
|
19432
|
+
type: number
|
|
19433
|
+
inactivityWarningSeconds:
|
|
19434
|
+
type: number
|
|
19435
|
+
absoluteTimeoutHours:
|
|
19436
|
+
type: number
|
|
19437
|
+
rememberMe:
|
|
19438
|
+
type: boolean
|
|
19439
|
+
AuthKitLockoutPolicy:
|
|
19440
|
+
type: object
|
|
19441
|
+
properties:
|
|
19442
|
+
enabled:
|
|
19443
|
+
type: boolean
|
|
19444
|
+
maxFailedAttempts:
|
|
19445
|
+
type: number
|
|
19446
|
+
attemptWindowMinutes:
|
|
19447
|
+
type: number
|
|
19448
|
+
lockoutMinutes:
|
|
19449
|
+
type: number
|
|
19450
|
+
notifyUserOnLockout:
|
|
19451
|
+
type: boolean
|
|
19452
|
+
AuthKitConfigInput:
|
|
19453
|
+
type: string
|
|
19454
|
+
enum:
|
|
19455
|
+
- id
|
|
19456
|
+
- updatedAt
|
|
19457
|
+
PasswordPolicyErrorCode:
|
|
19458
|
+
type: string
|
|
19459
|
+
enum:
|
|
19460
|
+
- PASSWORD_TOO_SHORT
|
|
19461
|
+
- PASSWORD_REQUIREMENTS_NOT_MET
|
|
19462
|
+
- PASSWORD_TOO_COMMON
|
|
19463
|
+
- PASSWORD_RECENTLY_USED
|
|
19386
19464
|
FirebaseTimestamp:
|
|
19387
19465
|
type: object
|
|
19388
19466
|
properties:
|
|
@@ -24994,9 +25072,11 @@ components:
|
|
|
24994
25072
|
- tokenId
|
|
24995
25073
|
- userId
|
|
24996
25074
|
- values
|
|
24997
|
-
|
|
25075
|
+
ProofWrite:
|
|
24998
25076
|
type: object
|
|
24999
25077
|
properties:
|
|
25078
|
+
id:
|
|
25079
|
+
type: string
|
|
25000
25080
|
values:
|
|
25001
25081
|
$ref: "#/components/schemas/ProofValues"
|
|
25002
25082
|
data:
|
|
@@ -25007,12 +25087,33 @@ components:
|
|
|
25007
25087
|
type: object
|
|
25008
25088
|
additionalProperties:
|
|
25009
25089
|
$ref: "#/components/schemas/JsonValue"
|
|
25090
|
+
owner:
|
|
25091
|
+
type: object
|
|
25092
|
+
additionalProperties:
|
|
25093
|
+
$ref: "#/components/schemas/JsonValue"
|
|
25094
|
+
claimable:
|
|
25095
|
+
type: boolean
|
|
25096
|
+
ProofCreateRequest:
|
|
25097
|
+
type: object
|
|
25098
|
+
properties:
|
|
25099
|
+
proof:
|
|
25100
|
+
$ref: "#/components/schemas/ProofWrite"
|
|
25101
|
+
values:
|
|
25102
|
+
$ref: "#/components/schemas/ProofValues"
|
|
25010
25103
|
claimable:
|
|
25011
25104
|
type: boolean
|
|
25012
25105
|
virtual:
|
|
25013
25106
|
type: boolean
|
|
25014
|
-
|
|
25015
|
-
|
|
25107
|
+
core:
|
|
25108
|
+
$ref: "#/components/schemas/ProofWrite"
|
|
25109
|
+
data:
|
|
25110
|
+
type: object
|
|
25111
|
+
additionalProperties:
|
|
25112
|
+
$ref: "#/components/schemas/JsonValue"
|
|
25113
|
+
admin:
|
|
25114
|
+
type: object
|
|
25115
|
+
additionalProperties:
|
|
25116
|
+
$ref: "#/components/schemas/JsonValue"
|
|
25016
25117
|
ProofFieldsConfig:
|
|
25017
25118
|
type: object
|
|
25018
25119
|
properties:
|
|
@@ -25096,9 +25197,87 @@ components:
|
|
|
25096
25197
|
properties:
|
|
25097
25198
|
guestName:
|
|
25098
25199
|
type: string
|
|
25099
|
-
|
|
25200
|
+
ProofTransfer:
|
|
25100
25201
|
type: object
|
|
25101
|
-
|
|
25202
|
+
properties:
|
|
25203
|
+
id:
|
|
25204
|
+
type: string
|
|
25205
|
+
proofId:
|
|
25206
|
+
type: string
|
|
25207
|
+
productId:
|
|
25208
|
+
type: string
|
|
25209
|
+
type:
|
|
25210
|
+
$ref: "#/components/schemas/ProofTransferType"
|
|
25211
|
+
state:
|
|
25212
|
+
$ref: "#/components/schemas/ProofTransferState"
|
|
25213
|
+
fromUserId:
|
|
25214
|
+
type: string
|
|
25215
|
+
toUserId:
|
|
25216
|
+
type: string
|
|
25217
|
+
toEmail:
|
|
25218
|
+
type: string
|
|
25219
|
+
initiatedByUserId:
|
|
25220
|
+
type: string
|
|
25221
|
+
initiatedByRole:
|
|
25222
|
+
type: string
|
|
25223
|
+
enum:
|
|
25224
|
+
- owner
|
|
25225
|
+
- claimant
|
|
25226
|
+
- admin
|
|
25227
|
+
disputeReason:
|
|
25228
|
+
type: string
|
|
25229
|
+
disputeDeadline:
|
|
25230
|
+
type: string
|
|
25231
|
+
completedAt:
|
|
25232
|
+
type: string
|
|
25233
|
+
createdAt:
|
|
25234
|
+
type: string
|
|
25235
|
+
updatedAt:
|
|
25236
|
+
type: string
|
|
25237
|
+
required:
|
|
25238
|
+
- id
|
|
25239
|
+
- proofId
|
|
25240
|
+
- type
|
|
25241
|
+
- state
|
|
25242
|
+
- createdAt
|
|
25243
|
+
- updatedAt
|
|
25244
|
+
TransferProofOptions:
|
|
25245
|
+
type: object
|
|
25246
|
+
properties:
|
|
25247
|
+
toEmail:
|
|
25248
|
+
type: string
|
|
25249
|
+
toUserId:
|
|
25250
|
+
type: string
|
|
25251
|
+
toName:
|
|
25252
|
+
type: string
|
|
25253
|
+
release:
|
|
25254
|
+
type: boolean
|
|
25255
|
+
message:
|
|
25256
|
+
type: string
|
|
25257
|
+
notify:
|
|
25258
|
+
type: boolean
|
|
25259
|
+
TransferProofResult:
|
|
25260
|
+
type: object
|
|
25261
|
+
properties:
|
|
25262
|
+
ok:
|
|
25263
|
+
type: boolean
|
|
25264
|
+
mode:
|
|
25265
|
+
type: string
|
|
25266
|
+
enum:
|
|
25267
|
+
- directed
|
|
25268
|
+
- open_release
|
|
25269
|
+
transfer:
|
|
25270
|
+
$ref: "#/components/schemas/ProofTransfer"
|
|
25271
|
+
required:
|
|
25272
|
+
- ok
|
|
25273
|
+
- mode
|
|
25274
|
+
- transfer
|
|
25275
|
+
ProofTransferType:
|
|
25276
|
+
type: string
|
|
25277
|
+
enum:
|
|
25278
|
+
- directed
|
|
25279
|
+
- open_release
|
|
25280
|
+
- contested
|
|
25102
25281
|
QrShortCodeLookupResponse:
|
|
25103
25282
|
type: object
|
|
25104
25283
|
properties:
|
package/dist/types/authKit.d.ts
CHANGED
|
@@ -89,8 +89,11 @@ export interface LogoutResponse {
|
|
|
89
89
|
* - `INVALID_REFRESH_TOKEN` (401) — unknown / expired / revoked / wrong client → `logout()` + route to login.
|
|
90
90
|
* - `REFRESH_TOKEN_REUSE_DETECTED` (401) — a consumed token was replayed; the **entire session
|
|
91
91
|
* family was revoked server-side**. Hard logout: clear storage, force re-login.
|
|
92
|
+
* - `SESSION_EXPIRED` (401) — the session hit the collection's absolute session timeout
|
|
93
|
+
* (`security.session.absoluteTimeoutHours`). Clear storage and route to login. Distinct from
|
|
94
|
+
* `INVALID_REFRESH_TOKEN` so the UI can message "your session expired" rather than an error.
|
|
92
95
|
*/
|
|
93
|
-
export type RefreshErrorCode = 'MISSING_REFRESH_TOKEN' | 'INVALID_REFRESH_TOKEN' | 'REFRESH_TOKEN_REUSE_DETECTED';
|
|
96
|
+
export type RefreshErrorCode = 'MISSING_REFRESH_TOKEN' | 'INVALID_REFRESH_TOKEN' | 'REFRESH_TOKEN_REUSE_DETECTED' | 'SESSION_EXPIRED';
|
|
94
97
|
/**
|
|
95
98
|
* Options for {@link authKit.appleLogin}. All fields are optional — only the
|
|
96
99
|
* `identityToken` (passed as a positional argument) is required by the server.
|
|
@@ -397,4 +400,84 @@ export interface AuthKitConfig {
|
|
|
397
400
|
supportEmail?: string;
|
|
398
401
|
redirectUrl?: string;
|
|
399
402
|
updatedAt?: string;
|
|
403
|
+
/**
|
|
404
|
+
* Per-collection security policy. On the public config endpoint only
|
|
405
|
+
* `passwordPolicy` + `session` are returned (the client renders password
|
|
406
|
+
* checklists / idle sign-out from them); `lockout` is admin-only and enforced
|
|
407
|
+
* server-side. See {@link AuthKitSecurityConfig}.
|
|
408
|
+
*/
|
|
409
|
+
security?: AuthKitSecurityConfig;
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Writable shape for `authKit.create` / `authKit.update` (admin). Known fields are
|
|
413
|
+
* typed — importantly `security?: AuthKitSecurityConfig` for the account security
|
|
414
|
+
* policy — while additional admin-console fields are still permitted. `id` and
|
|
415
|
+
* `updatedAt` are server-owned and omitted.
|
|
416
|
+
*
|
|
417
|
+
* ```ts
|
|
418
|
+
* await authKit.update(collectionId, authKitId, {
|
|
419
|
+
* security: {
|
|
420
|
+
* passwordPolicy: { minLength: 10, blockCommonPasswords: true },
|
|
421
|
+
* lockout: { enabled: true, maxFailedAttempts: 5, lockoutMinutes: 15 },
|
|
422
|
+
* session: { inactivityTimeoutMinutes: 30, absoluteTimeoutHours: 12 },
|
|
423
|
+
* },
|
|
424
|
+
* })
|
|
425
|
+
* ```
|
|
426
|
+
*/
|
|
427
|
+
export type AuthKitConfigInput = Partial<Omit<AuthKitConfig, 'id' | 'updatedAt'>> & Record<string, any>;
|
|
428
|
+
/**
|
|
429
|
+
* Per-collection account-security policy. The API **enforces** all of this; the
|
|
430
|
+
* client uses `passwordPolicy` (live checklist) and `session` (idle sign-out) for UX.
|
|
431
|
+
*/
|
|
432
|
+
export interface AuthKitSecurityConfig {
|
|
433
|
+
passwordPolicy?: AuthKitPasswordPolicy;
|
|
434
|
+
session?: AuthKitSessionPolicy;
|
|
435
|
+
/** Admin-only; never returned on the public config endpoint. */
|
|
436
|
+
lockout?: AuthKitLockoutPolicy;
|
|
437
|
+
}
|
|
438
|
+
export interface AuthKitPasswordPolicy {
|
|
439
|
+
minLength?: number;
|
|
440
|
+
requireUppercase?: boolean;
|
|
441
|
+
requireLowercase?: boolean;
|
|
442
|
+
requireNumber?: boolean;
|
|
443
|
+
requireSymbol?: boolean;
|
|
444
|
+
blockCommonPasswords?: boolean;
|
|
445
|
+
/** 0 = never expires. */
|
|
446
|
+
expiryDays?: number;
|
|
447
|
+
/** 0 = reuse allowed. */
|
|
448
|
+
historyCount?: number;
|
|
449
|
+
}
|
|
450
|
+
export interface AuthKitSessionPolicy {
|
|
451
|
+
/** 0 = never (client-enforced idle sign-out). */
|
|
452
|
+
inactivityTimeoutMinutes?: number;
|
|
453
|
+
inactivityWarningSeconds?: number;
|
|
454
|
+
/** 0 = use token lifetime. Enforced server-side on the native refresh path (→ `SESSION_EXPIRED`). */
|
|
455
|
+
absoluteTimeoutHours?: number;
|
|
456
|
+
rememberMe?: boolean;
|
|
457
|
+
}
|
|
458
|
+
/** Admin-only lockout policy (operational; not exposed publicly). */
|
|
459
|
+
export interface AuthKitLockoutPolicy {
|
|
460
|
+
enabled?: boolean;
|
|
461
|
+
maxFailedAttempts?: number;
|
|
462
|
+
attemptWindowMinutes?: number;
|
|
463
|
+
lockoutMinutes?: number;
|
|
464
|
+
notifyUserOnLockout?: boolean;
|
|
400
465
|
}
|
|
466
|
+
/**
|
|
467
|
+
* Password-policy validation errors (400) returned by `register`, `completePasswordReset`,
|
|
468
|
+
* and `changePassword`. Surfaced via `SmartlinksApiError.errorCode`.
|
|
469
|
+
* - `PASSWORD_TOO_SHORT` — below `passwordPolicy.minLength`.
|
|
470
|
+
* - `PASSWORD_REQUIREMENTS_NOT_MET` — missing a required character class.
|
|
471
|
+
* - `PASSWORD_TOO_COMMON` — matched the common/breached list.
|
|
472
|
+
* - `PASSWORD_RECENTLY_USED` — matched one of the last `historyCount` passwords.
|
|
473
|
+
*/
|
|
474
|
+
export type PasswordPolicyErrorCode = 'PASSWORD_TOO_SHORT' | 'PASSWORD_REQUIREMENTS_NOT_MET' | 'PASSWORD_TOO_COMMON' | 'PASSWORD_RECENTLY_USED';
|
|
475
|
+
/**
|
|
476
|
+
* Security errors returned by `login`. Surfaced via `SmartlinksApiError.errorCode`,
|
|
477
|
+
* with extra fields in `SmartlinksApiError.details`:
|
|
478
|
+
* - `ACCOUNT_TEMPORARILY_LOCKED` (429) — too many failed attempts; `details.retryAfterSeconds`
|
|
479
|
+
* says how long to wait. Show a "try again in N minutes" message.
|
|
480
|
+
* - `PASSWORD_EXPIRED` (403) — password older than `passwordPolicy.expiryDays`; `details.resetToken`
|
|
481
|
+
* is a short-lived token — send the user straight into `completePasswordReset()` to change it in place.
|
|
482
|
+
*/
|
|
483
|
+
export type LoginSecurityErrorCode = 'ACCOUNT_TEMPORARILY_LOCKED' | 'PASSWORD_EXPIRED';
|