@proveanything/smartlinks 1.15.18 → 1.15.19

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 CHANGED
@@ -41,10 +41,10 @@ If you're new to the SDK, this is the easiest path:
41
41
  - **Fetch collections/products** → see [Quick start](README.md#quick-start)
42
42
  - **Authenticate admins or end users** → see [Authentication](README.md#authentication)
43
43
  - **Upload and manage files** → see [Assets](README.md#assets)
44
- - **Browse the full surface area** → use [API_SUMMARY.md](API_SUMMARY.md) as reference
44
+ - **Browse the full surface area** → use [API_SUMMARY.md](docs/API_SUMMARY.md) as reference
45
45
 
46
46
  For the full list of functions and types, see the API summary:
47
- → [API Summary](API_SUMMARY.md)
47
+ → [API Summary](docs/API_SUMMARY.md)
48
48
 
49
49
  **Documentation:**
50
50
  - [AI & Chat Completions](docs/ai.md) - Chat completions, RAG, voice integration
@@ -18,6 +18,11 @@ export declare namespace authKit {
18
18
  * `trustDevice: true`), pass it here to skip the challenge entirely as long as it's
19
19
  * still valid. If it's revoked/expired, the server silently falls back to requiring a
20
20
  * fresh challenge — `login()` just returns `MFA_REQUIRED` again, no special handling.
21
+ *
22
+ * Security errors (thrown as `SmartlinksApiError`, see {@link LoginSecurityErrorCode}):
23
+ * - `ACCOUNT_TEMPORARILY_LOCKED` (429) — `err.details.retryAfterSeconds` says how long to wait.
24
+ * - `PASSWORD_EXPIRED` (403) — `err.details.resetToken` is short-lived; route into
25
+ * {@link completePasswordReset} to change the password in place.
21
26
  */
22
27
  function login(clientId: string, email: string, password: string, trustedDeviceToken?: string): Promise<AuthLoginResponse>;
23
28
  /**
@@ -25,6 +30,11 @@ export declare namespace authKit {
25
30
  *
26
31
  * Not gated by step-up MFA — a brand-new user has no enrolled factors yet, so there's
27
32
  * nothing to challenge against.
33
+ *
34
+ * The new password is validated against the collection's `passwordPolicy` — may throw
35
+ * a {@link PasswordPolicyErrorCode} (400). The same validation applies to
36
+ * {@link completePasswordReset} and {@link changePassword}. Read the policy for a live
37
+ * checklist from `authKit.load(clientId)` → `config.security.passwordPolicy`.
28
38
  */
29
39
  function register(clientId: string, data: {
30
40
  email: string;
@@ -22,6 +22,11 @@ export var authKit;
22
22
  * `trustDevice: true`), pass it here to skip the challenge entirely as long as it's
23
23
  * still valid. If it's revoked/expired, the server silently falls back to requiring a
24
24
  * fresh challenge — `login()` just returns `MFA_REQUIRED` again, no special handling.
25
+ *
26
+ * Security errors (thrown as `SmartlinksApiError`, see {@link LoginSecurityErrorCode}):
27
+ * - `ACCOUNT_TEMPORARILY_LOCKED` (429) — `err.details.retryAfterSeconds` says how long to wait.
28
+ * - `PASSWORD_EXPIRED` (403) — `err.details.resetToken` is short-lived; route into
29
+ * {@link completePasswordReset} to change the password in place.
25
30
  */
26
31
  async function login(clientId, email, password, trustedDeviceToken) {
27
32
  const body = { email, password };
@@ -40,6 +45,11 @@ export var authKit;
40
45
  *
41
46
  * Not gated by step-up MFA — a brand-new user has no enrolled factors yet, so there's
42
47
  * nothing to challenge against.
48
+ *
49
+ * The new password is validated against the collection's `passwordPolicy` — may throw
50
+ * a {@link PasswordPolicyErrorCode} (400). The same validation applies to
51
+ * {@link completePasswordReset} and {@link changePassword}. Read the policy for a live
52
+ * checklist from `authKit.load(clientId)` → `config.security.passwordPolicy`.
43
53
  */
44
54
  async function register(clientId, data) {
45
55
  return post(`/authkit/${encodeURIComponent(clientId)}/auth/register`, data);
@@ -12,11 +12,34 @@ export declare namespace proof {
12
12
  /**
13
13
  * Create a proof for a product (admin only).
14
14
  * POST /admin/collection/:collectionId/product/:productId/proof
15
+ *
16
+ * Pass the proof's content in a `proof` block, keyed by zone (see {@link ProofWrite}):
17
+ * ```ts
18
+ * proof.create(collectionId, productId, {
19
+ * proof: {
20
+ * values: { colour: 'red' }, // public + owner readable, owner + admin writable
21
+ * data: { serialNo: 1001 }, // public + owner readable, ADMIN-only writable
22
+ * admin: { costPrice: 4.20 }, // admin-only
23
+ * },
24
+ * claimable: true,
25
+ * })
26
+ * ```
27
+ * Note: a top-level `data`/`admin` on the request body is legacy — top-level
28
+ * `data` gets folded into the values bag, so use `proof.data` for `proof.data`.
15
29
  */
16
- function create(collectionId: string, productId: string, values: ProofCreateRequest): Promise<ProofResponse>;
30
+ function create(collectionId: string, productId: string, request: ProofCreateRequest): Promise<ProofResponse>;
17
31
  /**
18
32
  * Update a proof for a product (admin only).
19
33
  * PUT /admin/collection/:collectionId/product/:productId/proof/:proofId
34
+ *
35
+ * Pass the fields to change **at the root**, keyed by zone (see {@link ProofWrite}):
36
+ * ```ts
37
+ * proof.update(collectionId, productId, proofId, {
38
+ * data: { serialNo: 1002 }, // → proof.data (admin-only writable)
39
+ * values: { colour: 'blue' }, // → proof.values
40
+ * })
41
+ * ```
42
+ * Object zones deep-merge, so you can change one field without wiping the rest.
20
43
  */
21
44
  function update(collectionId: string, productId: string, proofId: string, values: ProofUpdateRequest): Promise<ProofResponse>;
22
45
  /**
package/dist/api/proof.js CHANGED
@@ -26,15 +26,38 @@ export var proof;
26
26
  /**
27
27
  * Create a proof for a product (admin only).
28
28
  * POST /admin/collection/:collectionId/product/:productId/proof
29
+ *
30
+ * Pass the proof's content in a `proof` block, keyed by zone (see {@link ProofWrite}):
31
+ * ```ts
32
+ * proof.create(collectionId, productId, {
33
+ * proof: {
34
+ * values: { colour: 'red' }, // public + owner readable, owner + admin writable
35
+ * data: { serialNo: 1001 }, // public + owner readable, ADMIN-only writable
36
+ * admin: { costPrice: 4.20 }, // admin-only
37
+ * },
38
+ * claimable: true,
39
+ * })
40
+ * ```
41
+ * Note: a top-level `data`/`admin` on the request body is legacy — top-level
42
+ * `data` gets folded into the values bag, so use `proof.data` for `proof.data`.
29
43
  */
30
- async function create(collectionId, productId, values) {
44
+ async function create(collectionId, productId, request) {
31
45
  const path = `/admin/collection/${encodeURIComponent(collectionId)}/product/${encodeURIComponent(productId)}/proof`;
32
- return post(path, values);
46
+ return post(path, request);
33
47
  }
34
48
  proof.create = create;
35
49
  /**
36
50
  * Update a proof for a product (admin only).
37
51
  * PUT /admin/collection/:collectionId/product/:productId/proof/:proofId
52
+ *
53
+ * Pass the fields to change **at the root**, keyed by zone (see {@link ProofWrite}):
54
+ * ```ts
55
+ * proof.update(collectionId, productId, proofId, {
56
+ * data: { serialNo: 1002 }, // → proof.data (admin-only writable)
57
+ * values: { colour: 'blue' }, // → proof.values
58
+ * })
59
+ * ```
60
+ * Object zones deep-merge, so you can change one field without wiping the rest.
38
61
  */
39
62
  async function update(collectionId, productId, proofId, values) {
40
63
  const path = `/admin/collection/${encodeURIComponent(collectionId)}/product/${encodeURIComponent(productId)}/proof/${encodeURIComponent(proofId)}`;
@@ -1,6 +1,6 @@
1
1
  # Smartlinks API Summary
2
2
 
3
- Version: 1.15.18 | Generated: 2026-08-19T06:40:47.505Z
3
+ Version: 1.15.19 | Generated: 2026-08-20T18:06:08.134Z
4
4
 
5
5
  This is a concise summary of all available API functions and types.
6
6
 
@@ -3464,6 +3464,55 @@ interface AuthKitConfig {
3464
3464
  supportEmail?: string
3465
3465
  redirectUrl?: string
3466
3466
  updatedAt?: string
3467
+ * Per-collection security policy. On the public config endpoint only
3468
+ * `passwordPolicy` + `session` are returned (the client renders password
3469
+ * checklists / idle sign-out from them); `lockout` is admin-only and enforced
3470
+ * server-side. See {@link AuthKitSecurityConfig}.
3471
+ security?: AuthKitSecurityConfig
3472
+ }
3473
+ ```
3474
+
3475
+ **AuthKitSecurityConfig** (interface)
3476
+ ```typescript
3477
+ interface AuthKitSecurityConfig {
3478
+ passwordPolicy?: AuthKitPasswordPolicy
3479
+ session?: AuthKitSessionPolicy
3480
+ lockout?: AuthKitLockoutPolicy
3481
+ }
3482
+ ```
3483
+
3484
+ **AuthKitPasswordPolicy** (interface)
3485
+ ```typescript
3486
+ interface AuthKitPasswordPolicy {
3487
+ minLength?: number
3488
+ requireUppercase?: boolean
3489
+ requireLowercase?: boolean
3490
+ requireNumber?: boolean
3491
+ requireSymbol?: boolean
3492
+ blockCommonPasswords?: boolean
3493
+ expiryDays?: number
3494
+ historyCount?: number
3495
+ }
3496
+ ```
3497
+
3498
+ **AuthKitSessionPolicy** (interface)
3499
+ ```typescript
3500
+ interface AuthKitSessionPolicy {
3501
+ inactivityTimeoutMinutes?: number
3502
+ inactivityWarningSeconds?: number
3503
+ absoluteTimeoutHours?: number
3504
+ rememberMe?: boolean
3505
+ }
3506
+ ```
3507
+
3508
+ **AuthKitLockoutPolicy** (interface)
3509
+ ```typescript
3510
+ interface AuthKitLockoutPolicy {
3511
+ enabled?: boolean
3512
+ maxFailedAttempts?: number
3513
+ attemptWindowMinutes?: number
3514
+ lockoutMinutes?: number
3515
+ notifyUserOnLockout?: boolean
3467
3516
  }
3468
3517
  ```
3469
3518
 
@@ -3475,6 +3524,10 @@ interface AuthKitConfig {
3475
3524
 
3476
3525
  **VerifyStatus** = `'pending' | 'verified' | 'failed' | 'expired' | 'unknown'`
3477
3526
 
3527
+ **PasswordPolicyErrorCode** = ``
3528
+
3529
+ **LoginSecurityErrorCode** = ``
3530
+
3478
3531
  ### batch
3479
3532
 
3480
3533
  **FirebaseTimestamp** (interface)
@@ -7279,14 +7332,36 @@ interface Proof {
7279
7332
  }
7280
7333
  ```
7281
7334
 
7282
- **ProofCreateRequest** (interface)
7335
+ **ProofWrite** (interface)
7283
7336
  ```typescript
7284
- interface ProofCreateRequest {
7285
- values: ProofValues
7337
+ interface ProofWrite {
7338
+ * Choose the proof's ID (serial, NFC id, etc.). Honoured **on create only** —
7339
+ * the ledger doc becomes `{productId}-{id}`. Omit to auto-generate. Ignored on
7340
+ * update (a proof's ID is immutable).
7341
+ id?: string
7342
+ values?: ProofValues
7286
7343
  data?: Record<string, JsonValue>
7287
7344
  admin?: Record<string, JsonValue>
7345
+ owner?: Record<string, JsonValue>
7346
+ claimable?: boolean
7347
+ [key: string]: JsonValue | Record<string, JsonValue> | ProofValues | undefined
7348
+ }
7349
+ ```
7350
+
7351
+ **ProofCreateRequest** (interface)
7352
+ ```typescript
7353
+ interface ProofCreateRequest {
7354
+ * The proof to create, by zone (mirrors the proof document). This is the clear,
7355
+ * recommended shape — `create(collectionId, productId, { proof: {...} })`.
7356
+ proof?: ProofWrite
7357
+ values?: ProofValues
7288
7358
  claimable?: boolean
7289
7359
  virtual?: boolean
7360
+ core?: ProofWrite
7361
+ * @deprecated On the request body this is folded into the **values bag**
7362
+ * (public + owner-writable) — NOT `proof.data`. Use `proof.data`.
7363
+ data?: Record<string, JsonValue>
7364
+ admin?: Record<string, JsonValue>
7290
7365
  }
7291
7366
  ```
7292
7367
 
@@ -7343,7 +7418,7 @@ interface RedeemGrantOptions {
7343
7418
 
7344
7419
  **ProofResponse** = `Proof`
7345
7420
 
7346
- **ProofUpdateRequest** = `Partial<ProofCreateRequest>`
7421
+ **ProofUpdateRequest** = `Partial<ProofWrite> & { proof?: ProofWrite }`
7347
7422
 
7348
7423
  **ProofClaimRequest** = `Record<string, any>`
7349
7424
 
@@ -8748,10 +8823,10 @@ Gets current account information for the logged in user. Returns user, owner, ac
8748
8823
  ### authKit
8749
8824
 
8750
8825
  **login**(clientId: string, email: string, password: string, trustedDeviceToken?: string) → `Promise<AuthLoginResponse>`
8751
- Login with email + password (public). When the client's MFA policy requires a step-up, the server returns **403 `MFA_REQUIRED`** instead of a session — `login()` throws a `SmartlinksApiError` with `err.errorResponse?.errorCode === 'MFA_REQUIRED'` and the challenge details in `err.details` (see {@link MfaRequiredDetails}). Route the caller to {@link mfaChallengeSend} on that error; this method's return type is unchanged. returned one (via {@link mfaChallengeVerify}/{@link mfaRecoveryCode} with `trustDevice: true`), pass it here to skip the challenge entirely as long as it's still valid. If it's revoked/expired, the server silently falls back to requiring a fresh challenge — `login()` just returns `MFA_REQUIRED` again, no special handling.
8826
+ Login with email + password (public). When the client's MFA policy requires a step-up, the server returns **403 `MFA_REQUIRED`** instead of a session — `login()` throws a `SmartlinksApiError` with `err.errorResponse?.errorCode === 'MFA_REQUIRED'` and the challenge details in `err.details` (see {@link MfaRequiredDetails}). Route the caller to {@link mfaChallengeSend} on that error; this method's return type is unchanged. returned one (via {@link mfaChallengeVerify}/{@link mfaRecoveryCode} with `trustDevice: true`), pass it here to skip the challenge entirely as long as it's still valid. If it's revoked/expired, the server silently falls back to requiring a fresh challenge — `login()` just returns `MFA_REQUIRED` again, no special handling. Security errors (thrown as `SmartlinksApiError`, see {@link LoginSecurityErrorCode}): - `ACCOUNT_TEMPORARILY_LOCKED` (429) — `err.details.retryAfterSeconds` says how long to wait. - `PASSWORD_EXPIRED` (403) — `err.details.resetToken` is short-lived; route into {@link completePasswordReset} to change the password in place.
8752
8827
 
8753
8828
  **register**(clientId: string, data: { email: string; password: string; displayName?: string; accountData?: Record<string, any> }) → `Promise<AuthLoginResponse>`
8754
- Register a new user (public). Not gated by step-up MFA — a brand-new user has no enrolled factors yet, so there's nothing to challenge against.
8829
+ Register a new user (public). Not gated by step-up MFA — a brand-new user has no enrolled factors yet, so there's nothing to challenge against. The new password is validated against the collection's `passwordPolicy` — may throw a {@link PasswordPolicyErrorCode} (400). The same validation applies to {@link completePasswordReset} and {@link changePassword}. Read the policy for a live checklist from `authKit.load(clientId)` → `config.security.passwordPolicy`.
8755
8830
 
8756
8831
  **googleLogin**(clientId: string, idToken: string, trustedDeviceToken?: string) → `Promise<AuthLoginResponse>`
8757
8832
  Google OAuth login via ID token (public). Gated by step-up MFA — see {@link login} for the `MFA_REQUIRED` error shape. {@link mfaChallengeVerify}/{@link mfaRecoveryCode} (with `trustDevice: true`) to skip the challenge on this device, same as {@link login}.
@@ -9952,14 +10027,14 @@ List all Proofs for a Collection.
9952
10027
 
9953
10028
  **create**(collectionId: string,
9954
10029
  productId: string,
9955
- values: ProofCreateRequest) → `Promise<ProofResponse>`
9956
- Create a proof for a product (admin only). POST /admin/collection/:collectionId/product/:productId/proof
10030
+ request: ProofCreateRequest) → `Promise<ProofResponse>`
10031
+ Create a proof for a product (admin only). POST /admin/collection/:collectionId/product/:productId/proof Pass the proof's content in a `proof` block, keyed by zone (see {@link ProofWrite}): ```ts proof.create(collectionId, productId, { proof: { values: { colour: 'red' }, // public + owner readable, owner + admin writable data: { serialNo: 1001 }, // public + owner readable, ADMIN-only writable admin: { costPrice: 4.20 }, // admin-only }, claimable: true, }) ``` Note: a top-level `data`/`admin` on the request body is legacy — top-level `data` gets folded into the values bag, so use `proof.data` for `proof.data`.
9957
10032
 
9958
10033
  **update**(collectionId: string,
9959
10034
  productId: string,
9960
10035
  proofId: string,
9961
10036
  values: ProofUpdateRequest) → `Promise<ProofResponse>`
9962
- Update a proof for a product (admin only). PUT /admin/collection/:collectionId/product/:productId/proof/:proofId
10037
+ Update a proof for a product (admin only). PUT /admin/collection/:collectionId/product/:productId/proof/:proofId Pass the fields to change **at the root**, keyed by zone (see {@link ProofWrite}): ```ts proof.update(collectionId, productId, proofId, { data: { serialNo: 1002 }, // → proof.data (admin-only writable) values: { colour: 'blue' }, // → proof.values }) ``` Object zones deep-merge, so you can change one field without wiping the rest.
9963
10038
 
9964
10039
  **claim**(collectionId: string,
9965
10040
  productId: string,
@@ -502,6 +502,79 @@ 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 (via the admin console). **The API
508
+ enforces all of it**; your login UI reads the policy for UX only (a live password checklist,
509
+ idle sign-out). Read it from the config:
510
+
511
+ ```ts
512
+ const config = await authKit.load(clientId);
513
+ const policy = config.security?.passwordPolicy; // min length, char classes, block-common
514
+ const session = config.security?.session; // inactivity + absolute timeouts, rememberMe
515
+ ```
516
+
517
+ `lockout` values are admin-only and never returned here.
518
+
519
+ ### Password policy
520
+
521
+ `register`, `completePasswordReset`, and `changePassword` validate the new password
522
+ server-side and throw a `SmartlinksApiError` with a {@link PasswordPolicyErrorCode}:
523
+
524
+ | `errorCode` (400) | Meaning |
525
+ |---|---|
526
+ | `PASSWORD_TOO_SHORT` | below `minLength` |
527
+ | `PASSWORD_REQUIREMENTS_NOT_MET` | missing a required character class |
528
+ | `PASSWORD_TOO_COMMON` | on the common/breached list |
529
+ | `PASSWORD_RECENTLY_USED` | matched one of the last `historyCount` passwords |
530
+
531
+ Render a live checklist from `policy` so users see the rules before submitting.
532
+
533
+ ### Lockout
534
+
535
+ After too many failed logins the account is temporarily locked. `login` throws:
536
+
537
+ ```ts
538
+ try {
539
+ await authKit.login(clientId, email, password);
540
+ } catch (err) {
541
+ if (err.errorCode === 'ACCOUNT_TEMPORARILY_LOCKED') {
542
+ const mins = Math.ceil(err.details.retryAfterSeconds / 60);
543
+ show(`Too many attempts. Try again in ${mins} minute(s).`);
544
+ }
545
+ }
546
+ ```
547
+
548
+ Failed MFA challenges count toward the same lock. Locking responds identically for unknown
549
+ accounts (no enumeration).
550
+
551
+ ### Password expiry
552
+
553
+ If a password is older than `passwordPolicy.expiryDays`, a valid login is refused with
554
+ **403 `PASSWORD_EXPIRED`** carrying a short-lived `resetToken` — send the user straight into
555
+ the reset form to change it in place:
556
+
557
+ ```ts
558
+ catch (err) {
559
+ if (err.errorCode === 'PASSWORD_EXPIRED') {
560
+ await authKit.completePasswordReset(clientId, err.details.resetToken, newPassword);
561
+ }
562
+ }
563
+ ```
564
+
565
+ ### Session lifetime
566
+
567
+ - **Absolute timeout** (`session.absoluteTimeoutHours`) is enforced server-side on the native
568
+ refresh path: once the session is too old, `refreshToken` throws **401 `SESSION_EXPIRED`**
569
+ (see {@link RefreshErrorCode}) — clear storage and route to login. Web sessions use the
570
+ stateless bearer token and rely on inactivity sign-out below.
571
+ - **Inactivity timeout** (`session.inactivityTimeoutMinutes` / `inactivityWarningSeconds`) is
572
+ **client-enforced** — sign the user out after idle, warning first. Sync across tabs.
573
+ - **`session.rememberMe: false`** → don't persist tokens to durable storage; treat the session
574
+ as browser-scoped.
575
+
576
+ ---
577
+
505
578
  ## Relationship to other parts of the SDK
506
579
 
507
580
  | Concern | Where it lives |
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, } 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, AuthKitSecurityConfig, AuthKitPasswordPolicy, AuthKitSessionPolicy, AuthKitLockoutPolicy, PasswordPolicyErrorCode, LoginSecurityErrorCode, } from './types/authKit';
package/dist/openapi.yaml CHANGED
@@ -8401,7 +8401,7 @@ paths:
8401
8401
  post:
8402
8402
  tags:
8403
8403
  - authKit
8404
- summary: Login with email + password (public).
8404
+ summary: authKit.login
8405
8405
  operationId: authKit_login
8406
8406
  security: []
8407
8407
  parameters:
@@ -19381,8 +19381,69 @@ components:
19381
19381
  type: string
19382
19382
  updatedAt:
19383
19383
  type: string
19384
+ security:
19385
+ $ref: "#/components/schemas/AuthKitSecurityConfig"
19384
19386
  required:
19385
19387
  - id
19388
+ AuthKitSecurityConfig:
19389
+ type: object
19390
+ properties:
19391
+ passwordPolicy:
19392
+ $ref: "#/components/schemas/AuthKitPasswordPolicy"
19393
+ session:
19394
+ $ref: "#/components/schemas/AuthKitSessionPolicy"
19395
+ lockout:
19396
+ $ref: "#/components/schemas/AuthKitLockoutPolicy"
19397
+ AuthKitPasswordPolicy:
19398
+ type: object
19399
+ properties:
19400
+ minLength:
19401
+ type: number
19402
+ requireUppercase:
19403
+ type: boolean
19404
+ requireLowercase:
19405
+ type: boolean
19406
+ requireNumber:
19407
+ type: boolean
19408
+ requireSymbol:
19409
+ type: boolean
19410
+ blockCommonPasswords:
19411
+ type: boolean
19412
+ expiryDays:
19413
+ type: number
19414
+ historyCount:
19415
+ type: number
19416
+ AuthKitSessionPolicy:
19417
+ type: object
19418
+ properties:
19419
+ inactivityTimeoutMinutes:
19420
+ type: number
19421
+ inactivityWarningSeconds:
19422
+ type: number
19423
+ absoluteTimeoutHours:
19424
+ type: number
19425
+ rememberMe:
19426
+ type: boolean
19427
+ AuthKitLockoutPolicy:
19428
+ type: object
19429
+ properties:
19430
+ enabled:
19431
+ type: boolean
19432
+ maxFailedAttempts:
19433
+ type: number
19434
+ attemptWindowMinutes:
19435
+ type: number
19436
+ lockoutMinutes:
19437
+ type: number
19438
+ notifyUserOnLockout:
19439
+ type: boolean
19440
+ PasswordPolicyErrorCode:
19441
+ type: string
19442
+ enum:
19443
+ - PASSWORD_TOO_SHORT
19444
+ - PASSWORD_REQUIREMENTS_NOT_MET
19445
+ - PASSWORD_TOO_COMMON
19446
+ - PASSWORD_RECENTLY_USED
19386
19447
  FirebaseTimestamp:
19387
19448
  type: object
19388
19449
  properties:
@@ -24994,9 +25055,11 @@ components:
24994
25055
  - tokenId
24995
25056
  - userId
24996
25057
  - values
24997
- ProofCreateRequest:
25058
+ ProofWrite:
24998
25059
  type: object
24999
25060
  properties:
25061
+ id:
25062
+ type: string
25000
25063
  values:
25001
25064
  $ref: "#/components/schemas/ProofValues"
25002
25065
  data:
@@ -25007,12 +25070,33 @@ components:
25007
25070
  type: object
25008
25071
  additionalProperties:
25009
25072
  $ref: "#/components/schemas/JsonValue"
25073
+ owner:
25074
+ type: object
25075
+ additionalProperties:
25076
+ $ref: "#/components/schemas/JsonValue"
25077
+ claimable:
25078
+ type: boolean
25079
+ ProofCreateRequest:
25080
+ type: object
25081
+ properties:
25082
+ proof:
25083
+ $ref: "#/components/schemas/ProofWrite"
25084
+ values:
25085
+ $ref: "#/components/schemas/ProofValues"
25010
25086
  claimable:
25011
25087
  type: boolean
25012
25088
  virtual:
25013
25089
  type: boolean
25014
- required:
25015
- - values
25090
+ core:
25091
+ $ref: "#/components/schemas/ProofWrite"
25092
+ data:
25093
+ type: object
25094
+ additionalProperties:
25095
+ $ref: "#/components/schemas/JsonValue"
25096
+ admin:
25097
+ type: object
25098
+ additionalProperties:
25099
+ $ref: "#/components/schemas/JsonValue"
25016
25100
  ProofFieldsConfig:
25017
25101
  type: object
25018
25102
  properties:
@@ -25096,9 +25180,6 @@ components:
25096
25180
  properties:
25097
25181
  guestName:
25098
25182
  type: string
25099
- ProofResponse:
25100
- type: object
25101
- additionalProperties: true
25102
25183
  QrShortCodeLookupResponse:
25103
25184
  type: object
25104
25185
  properties:
@@ -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,67 @@ 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
+ * Per-collection account-security policy. The API **enforces** all of this; the
413
+ * client uses `passwordPolicy` (live checklist) and `session` (idle sign-out) for UX.
414
+ */
415
+ export interface AuthKitSecurityConfig {
416
+ passwordPolicy?: AuthKitPasswordPolicy;
417
+ session?: AuthKitSessionPolicy;
418
+ /** Admin-only; never returned on the public config endpoint. */
419
+ lockout?: AuthKitLockoutPolicy;
420
+ }
421
+ export interface AuthKitPasswordPolicy {
422
+ minLength?: number;
423
+ requireUppercase?: boolean;
424
+ requireLowercase?: boolean;
425
+ requireNumber?: boolean;
426
+ requireSymbol?: boolean;
427
+ blockCommonPasswords?: boolean;
428
+ /** 0 = never expires. */
429
+ expiryDays?: number;
430
+ /** 0 = reuse allowed. */
431
+ historyCount?: number;
432
+ }
433
+ export interface AuthKitSessionPolicy {
434
+ /** 0 = never (client-enforced idle sign-out). */
435
+ inactivityTimeoutMinutes?: number;
436
+ inactivityWarningSeconds?: number;
437
+ /** 0 = use token lifetime. Enforced server-side on the native refresh path (→ `SESSION_EXPIRED`). */
438
+ absoluteTimeoutHours?: number;
439
+ rememberMe?: boolean;
440
+ }
441
+ /** Admin-only lockout policy (operational; not exposed publicly). */
442
+ export interface AuthKitLockoutPolicy {
443
+ enabled?: boolean;
444
+ maxFailedAttempts?: number;
445
+ attemptWindowMinutes?: number;
446
+ lockoutMinutes?: number;
447
+ notifyUserOnLockout?: boolean;
400
448
  }
449
+ /**
450
+ * Password-policy validation errors (400) returned by `register`, `completePasswordReset`,
451
+ * and `changePassword`. Surfaced via `SmartlinksApiError.errorCode`.
452
+ * - `PASSWORD_TOO_SHORT` — below `passwordPolicy.minLength`.
453
+ * - `PASSWORD_REQUIREMENTS_NOT_MET` — missing a required character class.
454
+ * - `PASSWORD_TOO_COMMON` — matched the common/breached list.
455
+ * - `PASSWORD_RECENTLY_USED` — matched one of the last `historyCount` passwords.
456
+ */
457
+ export type PasswordPolicyErrorCode = 'PASSWORD_TOO_SHORT' | 'PASSWORD_REQUIREMENTS_NOT_MET' | 'PASSWORD_TOO_COMMON' | 'PASSWORD_RECENTLY_USED';
458
+ /**
459
+ * Security errors returned by `login`. Surfaced via `SmartlinksApiError.errorCode`,
460
+ * with extra fields in `SmartlinksApiError.details`:
461
+ * - `ACCOUNT_TEMPORARILY_LOCKED` (429) — too many failed attempts; `details.retryAfterSeconds`
462
+ * says how long to wait. Show a "try again in N minutes" message.
463
+ * - `PASSWORD_EXPIRED` (403) — password older than `passwordPolicy.expiryDays`; `details.resetToken`
464
+ * is a short-lived token — send the user straight into `completePasswordReset()` to change it in place.
465
+ */
466
+ export type LoginSecurityErrorCode = 'ACCOUNT_TEMPORARILY_LOCKED' | 'PASSWORD_EXPIRED';
@@ -40,16 +40,71 @@ export interface Proof {
40
40
  values: ProofValues;
41
41
  }
42
42
  export type ProofResponse = Proof;
43
- export interface ProofCreateRequest {
44
- values: ProofValues;
45
- /** Business-writable public spec data. */
43
+ /**
44
+ * The proof's writable content, addressed by zone. Its keys mirror the proof
45
+ * document, so what you pass is what the proof looks like. Each zone has its own
46
+ * read/write visibility:
47
+ *
48
+ * | Zone | Stored at | Readable by | Writable by |
49
+ * |----------|----------------|------------------------|---------------|
50
+ * | `values` | `proof.values` | public + owner + admin | owner + admin |
51
+ * | `data` | `proof.data` | public + owner + admin | admin only |
52
+ * | `admin` | `proof.admin` | admin only | admin only |
53
+ * | `owner` | `proof.owner` | admin only | admin only |
54
+ *
55
+ * Use `data` for business fields everyone should *see* but only the business
56
+ * should *set* (e.g. a serial number). Use `admin` for fields only the business
57
+ * should see at all. On update, object zones deep-merge.
58
+ */
59
+ export interface ProofWrite {
60
+ /**
61
+ * Choose the proof's ID (serial, NFC id, etc.). Honoured **on create only** —
62
+ * the ledger doc becomes `{productId}-{id}`. Omit to auto-generate. Ignored on
63
+ * update (a proof's ID is immutable).
64
+ */
65
+ id?: string;
66
+ /** Owner + business-writable consumer data. Public + owner readable. → `proof.values` */
67
+ values?: ProofValues;
68
+ /** Business spec data (e.g. serialNo). Public + owner readable, admin-only writable. → `proof.data` */
46
69
  data?: Record<string, JsonValue>;
47
- /** Business-only spec data. */
70
+ /** Business-only spec data — admin-only read & write (stripped from public + owner). → `proof.admin` */
48
71
  admin?: Record<string, JsonValue>;
72
+ /** Business-only root data — admin-only. → `proof.owner` */
73
+ owner?: Record<string, JsonValue>;
74
+ /** Is this proof available to be claimed. */
75
+ claimable?: boolean;
76
+ /** Any other named root field. */
77
+ [key: string]: JsonValue | Record<string, JsonValue> | ProofValues | undefined;
78
+ }
79
+ export interface ProofCreateRequest {
80
+ /**
81
+ * The proof to create, by zone (mirrors the proof document). This is the clear,
82
+ * recommended shape — `create(collectionId, productId, { proof: {...} })`.
83
+ */
84
+ proof?: ProofWrite;
85
+ /** Owner + business-writable consumer data (→ `proof.values`). Same as `proof.values`. */
86
+ values?: ProofValues;
87
+ /** Canonical root `claimable` flag (also accepted as `proof.claimable`). */
49
88
  claimable?: boolean;
50
89
  virtual?: boolean;
90
+ /** @deprecated Legacy alias for `proof`. Use `proof`. */
91
+ core?: ProofWrite;
92
+ /**
93
+ * @deprecated On the request body this is folded into the **values bag**
94
+ * (public + owner-writable) — NOT `proof.data`. Use `proof.data`.
95
+ */
96
+ data?: Record<string, JsonValue>;
97
+ /** @deprecated Not routed to `proof.admin` on create — use `proof.admin`. */
98
+ admin?: Record<string, JsonValue>;
51
99
  }
52
- export type ProofUpdateRequest = Partial<ProofCreateRequest>;
100
+ /**
101
+ * Update passes the proof's fields **at the root** — `update(c, p, id, { data: {...} })`
102
+ * sets `proof.data`, `{ values: {...} }` sets `proof.values`, etc. (A `proof` block is
103
+ * also accepted and routed the same way.) Object zones deep-merge.
104
+ */
105
+ export type ProofUpdateRequest = Partial<ProofWrite> & {
106
+ proof?: ProofWrite;
107
+ };
53
108
  export type ProofClaimRequest = Record<string, any>;
54
109
  /**
55
110
  * `'public'` (default, omitted) reads/writes `proof.values[key]`.
@@ -1,6 +1,6 @@
1
1
  # Smartlinks API Summary
2
2
 
3
- Version: 1.15.18 | Generated: 2026-08-19T06:40:47.505Z
3
+ Version: 1.15.19 | Generated: 2026-08-20T18:06:08.134Z
4
4
 
5
5
  This is a concise summary of all available API functions and types.
6
6
 
@@ -3464,6 +3464,55 @@ interface AuthKitConfig {
3464
3464
  supportEmail?: string
3465
3465
  redirectUrl?: string
3466
3466
  updatedAt?: string
3467
+ * Per-collection security policy. On the public config endpoint only
3468
+ * `passwordPolicy` + `session` are returned (the client renders password
3469
+ * checklists / idle sign-out from them); `lockout` is admin-only and enforced
3470
+ * server-side. See {@link AuthKitSecurityConfig}.
3471
+ security?: AuthKitSecurityConfig
3472
+ }
3473
+ ```
3474
+
3475
+ **AuthKitSecurityConfig** (interface)
3476
+ ```typescript
3477
+ interface AuthKitSecurityConfig {
3478
+ passwordPolicy?: AuthKitPasswordPolicy
3479
+ session?: AuthKitSessionPolicy
3480
+ lockout?: AuthKitLockoutPolicy
3481
+ }
3482
+ ```
3483
+
3484
+ **AuthKitPasswordPolicy** (interface)
3485
+ ```typescript
3486
+ interface AuthKitPasswordPolicy {
3487
+ minLength?: number
3488
+ requireUppercase?: boolean
3489
+ requireLowercase?: boolean
3490
+ requireNumber?: boolean
3491
+ requireSymbol?: boolean
3492
+ blockCommonPasswords?: boolean
3493
+ expiryDays?: number
3494
+ historyCount?: number
3495
+ }
3496
+ ```
3497
+
3498
+ **AuthKitSessionPolicy** (interface)
3499
+ ```typescript
3500
+ interface AuthKitSessionPolicy {
3501
+ inactivityTimeoutMinutes?: number
3502
+ inactivityWarningSeconds?: number
3503
+ absoluteTimeoutHours?: number
3504
+ rememberMe?: boolean
3505
+ }
3506
+ ```
3507
+
3508
+ **AuthKitLockoutPolicy** (interface)
3509
+ ```typescript
3510
+ interface AuthKitLockoutPolicy {
3511
+ enabled?: boolean
3512
+ maxFailedAttempts?: number
3513
+ attemptWindowMinutes?: number
3514
+ lockoutMinutes?: number
3515
+ notifyUserOnLockout?: boolean
3467
3516
  }
3468
3517
  ```
3469
3518
 
@@ -3475,6 +3524,10 @@ interface AuthKitConfig {
3475
3524
 
3476
3525
  **VerifyStatus** = `'pending' | 'verified' | 'failed' | 'expired' | 'unknown'`
3477
3526
 
3527
+ **PasswordPolicyErrorCode** = ``
3528
+
3529
+ **LoginSecurityErrorCode** = ``
3530
+
3478
3531
  ### batch
3479
3532
 
3480
3533
  **FirebaseTimestamp** (interface)
@@ -7279,14 +7332,36 @@ interface Proof {
7279
7332
  }
7280
7333
  ```
7281
7334
 
7282
- **ProofCreateRequest** (interface)
7335
+ **ProofWrite** (interface)
7283
7336
  ```typescript
7284
- interface ProofCreateRequest {
7285
- values: ProofValues
7337
+ interface ProofWrite {
7338
+ * Choose the proof's ID (serial, NFC id, etc.). Honoured **on create only** —
7339
+ * the ledger doc becomes `{productId}-{id}`. Omit to auto-generate. Ignored on
7340
+ * update (a proof's ID is immutable).
7341
+ id?: string
7342
+ values?: ProofValues
7286
7343
  data?: Record<string, JsonValue>
7287
7344
  admin?: Record<string, JsonValue>
7345
+ owner?: Record<string, JsonValue>
7346
+ claimable?: boolean
7347
+ [key: string]: JsonValue | Record<string, JsonValue> | ProofValues | undefined
7348
+ }
7349
+ ```
7350
+
7351
+ **ProofCreateRequest** (interface)
7352
+ ```typescript
7353
+ interface ProofCreateRequest {
7354
+ * The proof to create, by zone (mirrors the proof document). This is the clear,
7355
+ * recommended shape — `create(collectionId, productId, { proof: {...} })`.
7356
+ proof?: ProofWrite
7357
+ values?: ProofValues
7288
7358
  claimable?: boolean
7289
7359
  virtual?: boolean
7360
+ core?: ProofWrite
7361
+ * @deprecated On the request body this is folded into the **values bag**
7362
+ * (public + owner-writable) — NOT `proof.data`. Use `proof.data`.
7363
+ data?: Record<string, JsonValue>
7364
+ admin?: Record<string, JsonValue>
7290
7365
  }
7291
7366
  ```
7292
7367
 
@@ -7343,7 +7418,7 @@ interface RedeemGrantOptions {
7343
7418
 
7344
7419
  **ProofResponse** = `Proof`
7345
7420
 
7346
- **ProofUpdateRequest** = `Partial<ProofCreateRequest>`
7421
+ **ProofUpdateRequest** = `Partial<ProofWrite> & { proof?: ProofWrite }`
7347
7422
 
7348
7423
  **ProofClaimRequest** = `Record<string, any>`
7349
7424
 
@@ -8748,10 +8823,10 @@ Gets current account information for the logged in user. Returns user, owner, ac
8748
8823
  ### authKit
8749
8824
 
8750
8825
  **login**(clientId: string, email: string, password: string, trustedDeviceToken?: string) → `Promise<AuthLoginResponse>`
8751
- Login with email + password (public). When the client's MFA policy requires a step-up, the server returns **403 `MFA_REQUIRED`** instead of a session — `login()` throws a `SmartlinksApiError` with `err.errorResponse?.errorCode === 'MFA_REQUIRED'` and the challenge details in `err.details` (see {@link MfaRequiredDetails}). Route the caller to {@link mfaChallengeSend} on that error; this method's return type is unchanged. returned one (via {@link mfaChallengeVerify}/{@link mfaRecoveryCode} with `trustDevice: true`), pass it here to skip the challenge entirely as long as it's still valid. If it's revoked/expired, the server silently falls back to requiring a fresh challenge — `login()` just returns `MFA_REQUIRED` again, no special handling.
8826
+ Login with email + password (public). When the client's MFA policy requires a step-up, the server returns **403 `MFA_REQUIRED`** instead of a session — `login()` throws a `SmartlinksApiError` with `err.errorResponse?.errorCode === 'MFA_REQUIRED'` and the challenge details in `err.details` (see {@link MfaRequiredDetails}). Route the caller to {@link mfaChallengeSend} on that error; this method's return type is unchanged. returned one (via {@link mfaChallengeVerify}/{@link mfaRecoveryCode} with `trustDevice: true`), pass it here to skip the challenge entirely as long as it's still valid. If it's revoked/expired, the server silently falls back to requiring a fresh challenge — `login()` just returns `MFA_REQUIRED` again, no special handling. Security errors (thrown as `SmartlinksApiError`, see {@link LoginSecurityErrorCode}): - `ACCOUNT_TEMPORARILY_LOCKED` (429) — `err.details.retryAfterSeconds` says how long to wait. - `PASSWORD_EXPIRED` (403) — `err.details.resetToken` is short-lived; route into {@link completePasswordReset} to change the password in place.
8752
8827
 
8753
8828
  **register**(clientId: string, data: { email: string; password: string; displayName?: string; accountData?: Record<string, any> }) → `Promise<AuthLoginResponse>`
8754
- Register a new user (public). Not gated by step-up MFA — a brand-new user has no enrolled factors yet, so there's nothing to challenge against.
8829
+ Register a new user (public). Not gated by step-up MFA — a brand-new user has no enrolled factors yet, so there's nothing to challenge against. The new password is validated against the collection's `passwordPolicy` — may throw a {@link PasswordPolicyErrorCode} (400). The same validation applies to {@link completePasswordReset} and {@link changePassword}. Read the policy for a live checklist from `authKit.load(clientId)` → `config.security.passwordPolicy`.
8755
8830
 
8756
8831
  **googleLogin**(clientId: string, idToken: string, trustedDeviceToken?: string) → `Promise<AuthLoginResponse>`
8757
8832
  Google OAuth login via ID token (public). Gated by step-up MFA — see {@link login} for the `MFA_REQUIRED` error shape. {@link mfaChallengeVerify}/{@link mfaRecoveryCode} (with `trustDevice: true`) to skip the challenge on this device, same as {@link login}.
@@ -9952,14 +10027,14 @@ List all Proofs for a Collection.
9952
10027
 
9953
10028
  **create**(collectionId: string,
9954
10029
  productId: string,
9955
- values: ProofCreateRequest) → `Promise<ProofResponse>`
9956
- Create a proof for a product (admin only). POST /admin/collection/:collectionId/product/:productId/proof
10030
+ request: ProofCreateRequest) → `Promise<ProofResponse>`
10031
+ Create a proof for a product (admin only). POST /admin/collection/:collectionId/product/:productId/proof Pass the proof's content in a `proof` block, keyed by zone (see {@link ProofWrite}): ```ts proof.create(collectionId, productId, { proof: { values: { colour: 'red' }, // public + owner readable, owner + admin writable data: { serialNo: 1001 }, // public + owner readable, ADMIN-only writable admin: { costPrice: 4.20 }, // admin-only }, claimable: true, }) ``` Note: a top-level `data`/`admin` on the request body is legacy — top-level `data` gets folded into the values bag, so use `proof.data` for `proof.data`.
9957
10032
 
9958
10033
  **update**(collectionId: string,
9959
10034
  productId: string,
9960
10035
  proofId: string,
9961
10036
  values: ProofUpdateRequest) → `Promise<ProofResponse>`
9962
- Update a proof for a product (admin only). PUT /admin/collection/:collectionId/product/:productId/proof/:proofId
10037
+ Update a proof for a product (admin only). PUT /admin/collection/:collectionId/product/:productId/proof/:proofId Pass the fields to change **at the root**, keyed by zone (see {@link ProofWrite}): ```ts proof.update(collectionId, productId, proofId, { data: { serialNo: 1002 }, // → proof.data (admin-only writable) values: { colour: 'blue' }, // → proof.values }) ``` Object zones deep-merge, so you can change one field without wiping the rest.
9963
10038
 
9964
10039
  **claim**(collectionId: string,
9965
10040
  productId: string,
package/docs/auth-kit.md CHANGED
@@ -502,6 +502,79 @@ 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 (via the admin console). **The API
508
+ enforces all of it**; your login UI reads the policy for UX only (a live password checklist,
509
+ idle sign-out). Read it from the config:
510
+
511
+ ```ts
512
+ const config = await authKit.load(clientId);
513
+ const policy = config.security?.passwordPolicy; // min length, char classes, block-common
514
+ const session = config.security?.session; // inactivity + absolute timeouts, rememberMe
515
+ ```
516
+
517
+ `lockout` values are admin-only and never returned here.
518
+
519
+ ### Password policy
520
+
521
+ `register`, `completePasswordReset`, and `changePassword` validate the new password
522
+ server-side and throw a `SmartlinksApiError` with a {@link PasswordPolicyErrorCode}:
523
+
524
+ | `errorCode` (400) | Meaning |
525
+ |---|---|
526
+ | `PASSWORD_TOO_SHORT` | below `minLength` |
527
+ | `PASSWORD_REQUIREMENTS_NOT_MET` | missing a required character class |
528
+ | `PASSWORD_TOO_COMMON` | on the common/breached list |
529
+ | `PASSWORD_RECENTLY_USED` | matched one of the last `historyCount` passwords |
530
+
531
+ Render a live checklist from `policy` so users see the rules before submitting.
532
+
533
+ ### Lockout
534
+
535
+ After too many failed logins the account is temporarily locked. `login` throws:
536
+
537
+ ```ts
538
+ try {
539
+ await authKit.login(clientId, email, password);
540
+ } catch (err) {
541
+ if (err.errorCode === 'ACCOUNT_TEMPORARILY_LOCKED') {
542
+ const mins = Math.ceil(err.details.retryAfterSeconds / 60);
543
+ show(`Too many attempts. Try again in ${mins} minute(s).`);
544
+ }
545
+ }
546
+ ```
547
+
548
+ Failed MFA challenges count toward the same lock. Locking responds identically for unknown
549
+ accounts (no enumeration).
550
+
551
+ ### Password expiry
552
+
553
+ If a password is older than `passwordPolicy.expiryDays`, a valid login is refused with
554
+ **403 `PASSWORD_EXPIRED`** carrying a short-lived `resetToken` — send the user straight into
555
+ the reset form to change it in place:
556
+
557
+ ```ts
558
+ catch (err) {
559
+ if (err.errorCode === 'PASSWORD_EXPIRED') {
560
+ await authKit.completePasswordReset(clientId, err.details.resetToken, newPassword);
561
+ }
562
+ }
563
+ ```
564
+
565
+ ### Session lifetime
566
+
567
+ - **Absolute timeout** (`session.absoluteTimeoutHours`) is enforced server-side on the native
568
+ refresh path: once the session is too old, `refreshToken` throws **401 `SESSION_EXPIRED`**
569
+ (see {@link RefreshErrorCode}) — clear storage and route to login. Web sessions use the
570
+ stateless bearer token and rely on inactivity sign-out below.
571
+ - **Inactivity timeout** (`session.inactivityTimeoutMinutes` / `inactivityWarningSeconds`) is
572
+ **client-enforced** — sign the user out after idle, warning first. Sync across tabs.
573
+ - **`session.rememberMe: false`** → don't persist tokens to durable storage; treat the session
574
+ as browser-scoped.
575
+
576
+ ---
577
+
505
578
  ## Relationship to other parts of the SDK
506
579
 
507
580
  | Concern | Where it lives |
package/openapi.yaml CHANGED
@@ -8401,7 +8401,7 @@ paths:
8401
8401
  post:
8402
8402
  tags:
8403
8403
  - authKit
8404
- summary: Login with email + password (public).
8404
+ summary: authKit.login
8405
8405
  operationId: authKit_login
8406
8406
  security: []
8407
8407
  parameters:
@@ -19381,8 +19381,69 @@ components:
19381
19381
  type: string
19382
19382
  updatedAt:
19383
19383
  type: string
19384
+ security:
19385
+ $ref: "#/components/schemas/AuthKitSecurityConfig"
19384
19386
  required:
19385
19387
  - id
19388
+ AuthKitSecurityConfig:
19389
+ type: object
19390
+ properties:
19391
+ passwordPolicy:
19392
+ $ref: "#/components/schemas/AuthKitPasswordPolicy"
19393
+ session:
19394
+ $ref: "#/components/schemas/AuthKitSessionPolicy"
19395
+ lockout:
19396
+ $ref: "#/components/schemas/AuthKitLockoutPolicy"
19397
+ AuthKitPasswordPolicy:
19398
+ type: object
19399
+ properties:
19400
+ minLength:
19401
+ type: number
19402
+ requireUppercase:
19403
+ type: boolean
19404
+ requireLowercase:
19405
+ type: boolean
19406
+ requireNumber:
19407
+ type: boolean
19408
+ requireSymbol:
19409
+ type: boolean
19410
+ blockCommonPasswords:
19411
+ type: boolean
19412
+ expiryDays:
19413
+ type: number
19414
+ historyCount:
19415
+ type: number
19416
+ AuthKitSessionPolicy:
19417
+ type: object
19418
+ properties:
19419
+ inactivityTimeoutMinutes:
19420
+ type: number
19421
+ inactivityWarningSeconds:
19422
+ type: number
19423
+ absoluteTimeoutHours:
19424
+ type: number
19425
+ rememberMe:
19426
+ type: boolean
19427
+ AuthKitLockoutPolicy:
19428
+ type: object
19429
+ properties:
19430
+ enabled:
19431
+ type: boolean
19432
+ maxFailedAttempts:
19433
+ type: number
19434
+ attemptWindowMinutes:
19435
+ type: number
19436
+ lockoutMinutes:
19437
+ type: number
19438
+ notifyUserOnLockout:
19439
+ type: boolean
19440
+ PasswordPolicyErrorCode:
19441
+ type: string
19442
+ enum:
19443
+ - PASSWORD_TOO_SHORT
19444
+ - PASSWORD_REQUIREMENTS_NOT_MET
19445
+ - PASSWORD_TOO_COMMON
19446
+ - PASSWORD_RECENTLY_USED
19386
19447
  FirebaseTimestamp:
19387
19448
  type: object
19388
19449
  properties:
@@ -24994,9 +25055,11 @@ components:
24994
25055
  - tokenId
24995
25056
  - userId
24996
25057
  - values
24997
- ProofCreateRequest:
25058
+ ProofWrite:
24998
25059
  type: object
24999
25060
  properties:
25061
+ id:
25062
+ type: string
25000
25063
  values:
25001
25064
  $ref: "#/components/schemas/ProofValues"
25002
25065
  data:
@@ -25007,12 +25070,33 @@ components:
25007
25070
  type: object
25008
25071
  additionalProperties:
25009
25072
  $ref: "#/components/schemas/JsonValue"
25073
+ owner:
25074
+ type: object
25075
+ additionalProperties:
25076
+ $ref: "#/components/schemas/JsonValue"
25077
+ claimable:
25078
+ type: boolean
25079
+ ProofCreateRequest:
25080
+ type: object
25081
+ properties:
25082
+ proof:
25083
+ $ref: "#/components/schemas/ProofWrite"
25084
+ values:
25085
+ $ref: "#/components/schemas/ProofValues"
25010
25086
  claimable:
25011
25087
  type: boolean
25012
25088
  virtual:
25013
25089
  type: boolean
25014
- required:
25015
- - values
25090
+ core:
25091
+ $ref: "#/components/schemas/ProofWrite"
25092
+ data:
25093
+ type: object
25094
+ additionalProperties:
25095
+ $ref: "#/components/schemas/JsonValue"
25096
+ admin:
25097
+ type: object
25098
+ additionalProperties:
25099
+ $ref: "#/components/schemas/JsonValue"
25016
25100
  ProofFieldsConfig:
25017
25101
  type: object
25018
25102
  properties:
@@ -25096,9 +25180,6 @@ components:
25096
25180
  properties:
25097
25181
  guestName:
25098
25182
  type: string
25099
- ProofResponse:
25100
- type: object
25101
- additionalProperties: true
25102
25183
  QrShortCodeLookupResponse:
25103
25184
  type: object
25104
25185
  properties:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@proveanything/smartlinks",
3
- "version": "1.15.18",
3
+ "version": "1.15.19",
4
4
  "description": "Official JavaScript/TypeScript SDK for the Smartlinks API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",