@proveanything/smartlinks 1.15.17 → 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 +10 -2
- package/dist/api/appObjects.d.ts +6 -0
- package/dist/api/appObjects.js +10 -0
- package/dist/api/authKit.d.ts +10 -0
- package/dist/api/authKit.js +10 -0
- package/dist/api/proof.d.ts +24 -1
- package/dist/api/proof.js +25 -2
- package/dist/docs/API_SUMMARY.md +96 -10
- package/dist/docs/app-objects.md +65 -0
- package/dist/docs/assets.md +81 -0
- package/dist/docs/auth-kit.md +73 -0
- package/dist/docs/proof-share-grants.md +232 -0
- package/dist/index.d.ts +2 -2
- package/dist/openapi.yaml +161 -7
- package/dist/types/appObjects.d.ts +14 -0
- package/dist/types/authKit.d.ts +67 -1
- package/dist/types/proof.d.ts +60 -5
- package/docs/API_SUMMARY.md +96 -10
- package/docs/app-objects.md +65 -0
- package/docs/assets.md +81 -0
- package/docs/auth-kit.md +73 -0
- package/docs/proof-share-grants.md +232 -0
- package/openapi.yaml +161 -7
- package/package.json +1 -1
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# Proof Share Grants
|
|
2
|
+
|
|
3
|
+
Delegated, scoped, **revocable** bearer access to a single proof — the middle tier
|
|
4
|
+
between "public" (everyone) and "owner" (only the signed-in owner).
|
|
5
|
+
|
|
6
|
+
A grant lets an owner hand out a link that lets specific recipients **see or do
|
|
7
|
+
specific things on one proof for a limited time**, without those recipients needing
|
|
8
|
+
a SmartLinks account or a proof claim. Typical uses: sharing a private photo album,
|
|
9
|
+
letting guests comment on it, or publishing a verifiable "I own this" assertion.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Concepts
|
|
14
|
+
|
|
15
|
+
A **grant** is a row issued by the proof owner (or a collection admin) and redeemed
|
|
16
|
+
by a bearer holding an opaque token. Every data request that touches the proof
|
|
17
|
+
re-checks the grant **server-side** against the database, so revocation is immediate.
|
|
18
|
+
|
|
19
|
+
### Scopes — what a grant authorises
|
|
20
|
+
|
|
21
|
+
| Scope | Grants the bearer… |
|
|
22
|
+
|-------|--------------------|
|
|
23
|
+
| `read` | read owner-tier data on the proof (attestations, threads, records, cases) |
|
|
24
|
+
| `comment` | create threads/replies on the proof (guest comments) |
|
|
25
|
+
| `admin` | read owner-tier data (reserved for elevated share cases; never exposes the platform admin zone) |
|
|
26
|
+
| `verify_owner` | redeem a shareable ownership **assertion** (not the account) |
|
|
27
|
+
|
|
28
|
+
A grant can carry several scopes, e.g. `['read', 'comment']` for a shareable,
|
|
29
|
+
commentable album.
|
|
30
|
+
|
|
31
|
+
### Security & lifecycle
|
|
32
|
+
|
|
33
|
+
- The token is opaque, unguessable, and returned to the issuer **exactly once** (on `createGrant`). It is never returned by `listGrants`.
|
|
34
|
+
- **Revocation is immediate** — the grant is re-checked on every request, so `revokeGrant` invalidates a token across all clients at once.
|
|
35
|
+
- **Auto-invalidation on transfer** — every grant is voided the moment the proof's `ownerId` changes (e.g. a resale/re-claim), so a stale "I own this" link cannot keep resolving.
|
|
36
|
+
- A grant is scoped to **one proof**; it can never widen access to other proofs or collection-level data.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Owner flow — create, list, revoke
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
import { proof } from '@proveanything/smartlinks'
|
|
44
|
+
|
|
45
|
+
// Create a read+comment grant that expires in 7 days.
|
|
46
|
+
const grant = await proof.createGrant(collectionId, productId, proofId, {
|
|
47
|
+
scope: ['read', 'comment'],
|
|
48
|
+
audience: { kind: 'public_link' },
|
|
49
|
+
expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
// `grant.token` is available ONLY here — embed it in your share link now.
|
|
53
|
+
const shareUrl = `https://app.example.com/album?proofId=${proofId}&shareToken=${grant.token}`
|
|
54
|
+
|
|
55
|
+
// List active + past grants (tokens are never included).
|
|
56
|
+
const grants = await proof.listGrants(collectionId, productId, proofId)
|
|
57
|
+
|
|
58
|
+
// Stop sharing — takes effect on the very next request from any client.
|
|
59
|
+
await proof.revokeGrant(collectionId, productId, proofId, grant.grantId)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
`createGrant` / `listGrants` / `revokeGrant` require the caller to be the **proof
|
|
63
|
+
owner** (or a collection admin) — i.e. a signed-in user whose `bearerToken` is set.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Recipient flow — redeem, then carry the token
|
|
68
|
+
|
|
69
|
+
A recipient opens the share link, redeems the token once, then sets it as the
|
|
70
|
+
active grant token. From then on **every** SDK request carries the token
|
|
71
|
+
(`X-Grant-Token`), so all proof reads/writes are evaluated against the grant.
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
import { proof, setGrantToken } from '@proveanything/smartlinks'
|
|
75
|
+
|
|
76
|
+
const shareToken = new URLSearchParams(location.search).get('shareToken')!
|
|
77
|
+
|
|
78
|
+
// Redeem once (anonymous or signed-in). Records the redemption; optionally names the guest.
|
|
79
|
+
await proof.redeemGrant(collectionId, productId, proofId, shareToken, {
|
|
80
|
+
guestName: 'Sam', // stamped on guest activity when not signed in
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
// Attach the token to every subsequent request.
|
|
84
|
+
setGrantToken(shareToken)
|
|
85
|
+
|
|
86
|
+
// Now grant-tier reads succeed — e.g. owner-visibility memories on the proof:
|
|
87
|
+
const { attestations } = await attestation.publicList(collectionId, {
|
|
88
|
+
subjectType: 'proof', subjectId: proofId,
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
// Clear it when leaving the shared view:
|
|
92
|
+
setGrantToken(undefined)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
> **Persisting across reloads.** `setGrantToken` holds the token in memory. To keep a
|
|
96
|
+
> shared session across reloads, persist `shareToken` yourself (e.g. in `localStorage`)
|
|
97
|
+
> and call `setGrantToken` again on load.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Guest commenting
|
|
102
|
+
|
|
103
|
+
With a `comment` scope grant, a bearer can post comments even when they are not
|
|
104
|
+
signed in. The app must enable the **grant branch** of the thread create policy
|
|
105
|
+
(see [App config](#app-config)); comments are then created at `visibility: 'owner'`
|
|
106
|
+
(private to the proof) and stamped `authorType: 'guest'`.
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
import { app } from '@proveanything/smartlinks'
|
|
110
|
+
// setGrantToken(shareToken) has already been called.
|
|
111
|
+
|
|
112
|
+
// One atomic call — no separate create-then-reply round trip.
|
|
113
|
+
await app.threads.create(collectionId, 'photo-memory', {
|
|
114
|
+
parentType: 'memory',
|
|
115
|
+
parentId: memoryId, // text — SmartLinks short ids are fine (not just UUIDs)
|
|
116
|
+
proofId, // anchor to the proof so grant readers see it
|
|
117
|
+
firstReply: { text: 'Lovely photo', authorName: 'Sam' },
|
|
118
|
+
})
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Other grant holders (and the owner) see these comments because a `read` grant reveals
|
|
122
|
+
`owner`-visibility threads for the proof. See
|
|
123
|
+
[App Objects → Threads](app-objects.md#threads) for the full threads API.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Proof of ownership — `verify_owner`
|
|
128
|
+
|
|
129
|
+
Ownership itself is **not** a grant — it is `proof.ownerId`, established via the
|
|
130
|
+
existing [claim flow](proof-claiming-methods.md). A `verify_owner` grant only
|
|
131
|
+
publishes a shareable, verifiable **assertion** derived from that ownership, without
|
|
132
|
+
handing over the account:
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
const grant = await proof.createGrant(collectionId, productId, proofId, {
|
|
136
|
+
scope: ['verify_owner'],
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
// The recipient redeems it and gets the assertion — never the account:
|
|
140
|
+
const result = await proof.redeemGrant(collectionId, productId, proofId, grant.token)
|
|
141
|
+
// { proofId, assertsOwnership: true, ownerDisplayName?, issuedAt, expiresAt }
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Because grants auto-invalidate on transfer, a resale cannot leave a stale
|
|
145
|
+
"I own this" link in circulation.
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## What a grant gates
|
|
150
|
+
|
|
151
|
+
When a valid grant token is present, these public reads elevate to owner-tier for the
|
|
152
|
+
granted proof (and only that proof):
|
|
153
|
+
|
|
154
|
+
- **Attestations** — `attestation.publicList({ subjectType: 'proof', subjectId })`
|
|
155
|
+
- **Threads / Records / Cases** — `app.threads.list`, `app.records.*`, `app.cases.list`, and the single-item GETs, filtered to the granted proof
|
|
156
|
+
- **Thread creation / replies** — with a `comment` scope grant (see below)
|
|
157
|
+
|
|
158
|
+
The token never exposes the platform `admin` zone, and only reveals `owner`-visibility
|
|
159
|
+
rows for the granted `proofId`.
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## App config
|
|
164
|
+
|
|
165
|
+
Grant-based commenting is opt-in per app, configured on the app's Firestore config
|
|
166
|
+
at `sites/{collectionId}/apps/{appId}` — a `grant` branch alongside
|
|
167
|
+
`anonymous` / `authenticated`:
|
|
168
|
+
|
|
169
|
+
```jsonc
|
|
170
|
+
{
|
|
171
|
+
"publicCreate": {
|
|
172
|
+
"threads": {
|
|
173
|
+
"grant": {
|
|
174
|
+
"allow": true,
|
|
175
|
+
"requireScope": "comment",
|
|
176
|
+
"enforce": { "visibility": "owner", "status": "open" }
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
This enables grant-scoped commenting **without** opening up anonymous creation. The
|
|
184
|
+
`enforce.visibility: "owner"` keeps comments private to the proof (visible to the
|
|
185
|
+
owner and other grant holders, not the wider public).
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## API reference
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
namespace proof {
|
|
193
|
+
createGrant(collectionId, productId, proofId, options: CreateGrantOptions): Promise<ProofGrant>
|
|
194
|
+
listGrants(collectionId, productId, proofId): Promise<ProofGrant[]>
|
|
195
|
+
revokeGrant(collectionId, productId, proofId, grantId): Promise<void>
|
|
196
|
+
redeemGrant(collectionId, productId, proofId, token, options?: RedeemGrantOptions): Promise<RedeemGrantResult>
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Attach / clear the active grant token (sent as X-Grant-Token on every request).
|
|
200
|
+
function setGrantToken(token: string | undefined): void
|
|
201
|
+
function getGrantToken(): string | undefined
|
|
202
|
+
|
|
203
|
+
type GrantScope = 'read' | 'comment' | 'admin' | 'verify_owner'
|
|
204
|
+
|
|
205
|
+
interface CreateGrantOptions {
|
|
206
|
+
scope: GrantScope[] // at least one
|
|
207
|
+
audience?: { kind: 'public_link' } | { kind: 'named'; email?: string; userId?: string }
|
|
208
|
+
expiresAt?: Date | string
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
interface RedeemGrantOptions { guestName?: string }
|
|
212
|
+
|
|
213
|
+
type RedeemGrantResult =
|
|
214
|
+
| { scope: GrantScope[]; redeemedAt: string }
|
|
215
|
+
| { proofId: string; assertsOwnership: true; ownerDisplayName?: string; issuedAt?: string; expiresAt?: string }
|
|
216
|
+
|
|
217
|
+
interface ProofGrant {
|
|
218
|
+
grantId: string
|
|
219
|
+
proofId: string
|
|
220
|
+
productId?: string | null
|
|
221
|
+
scope: GrantScope[]
|
|
222
|
+
audience: { kind: 'public_link' | 'named'; email?: string; userId?: string }
|
|
223
|
+
createdBy: string
|
|
224
|
+
expiresAt?: string | null
|
|
225
|
+
revokedAt?: string | null
|
|
226
|
+
redeemedBy?: { userId?: string; guestName?: string; redeemedAt: string }
|
|
227
|
+
redeemCount: number
|
|
228
|
+
createdAt: string
|
|
229
|
+
updatedAt: string
|
|
230
|
+
token?: string // present ONLY on the createGrant response
|
|
231
|
+
}
|
|
232
|
+
```
|
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:
|
|
8404
|
+
summary: authKit.login
|
|
8405
8405
|
operationId: authKit_login
|
|
8406
8406
|
security: []
|
|
8407
8407
|
parameters:
|
|
@@ -13941,6 +13941,23 @@ paths:
|
|
|
13941
13941
|
required: false
|
|
13942
13942
|
schema:
|
|
13943
13943
|
type: string
|
|
13944
|
+
- name: parentIds
|
|
13945
|
+
in: query
|
|
13946
|
+
required: false
|
|
13947
|
+
schema:
|
|
13948
|
+
type: array
|
|
13949
|
+
items:
|
|
13950
|
+
type: string
|
|
13951
|
+
- name: proofId
|
|
13952
|
+
in: query
|
|
13953
|
+
required: false
|
|
13954
|
+
schema:
|
|
13955
|
+
type: string
|
|
13956
|
+
- name: productId
|
|
13957
|
+
in: query
|
|
13958
|
+
required: false
|
|
13959
|
+
schema:
|
|
13960
|
+
type: string
|
|
13944
13961
|
- name: tag
|
|
13945
13962
|
in: query
|
|
13946
13963
|
required: false
|
|
@@ -14182,6 +14199,52 @@ paths:
|
|
|
14182
14199
|
application/json:
|
|
14183
14200
|
schema:
|
|
14184
14201
|
$ref: "#/components/schemas/ReplyInput"
|
|
14202
|
+
/{zone}/collection/{collectionId}/app/{appId}/threads/{threadId}/reply/{replyId}:
|
|
14203
|
+
delete:
|
|
14204
|
+
tags:
|
|
14205
|
+
- threads
|
|
14206
|
+
summary: Delete a single reply from a thread by its reply id (moderation).
|
|
14207
|
+
operationId: threads_deleteReply
|
|
14208
|
+
security: []
|
|
14209
|
+
parameters:
|
|
14210
|
+
- name: zone
|
|
14211
|
+
in: path
|
|
14212
|
+
required: true
|
|
14213
|
+
schema:
|
|
14214
|
+
type: string
|
|
14215
|
+
- name: collectionId
|
|
14216
|
+
in: path
|
|
14217
|
+
required: true
|
|
14218
|
+
schema:
|
|
14219
|
+
type: string
|
|
14220
|
+
- name: appId
|
|
14221
|
+
in: path
|
|
14222
|
+
required: true
|
|
14223
|
+
schema:
|
|
14224
|
+
type: string
|
|
14225
|
+
- name: threadId
|
|
14226
|
+
in: path
|
|
14227
|
+
required: true
|
|
14228
|
+
schema:
|
|
14229
|
+
type: string
|
|
14230
|
+
- name: replyId
|
|
14231
|
+
in: path
|
|
14232
|
+
required: true
|
|
14233
|
+
schema:
|
|
14234
|
+
type: string
|
|
14235
|
+
responses:
|
|
14236
|
+
200:
|
|
14237
|
+
description: Success
|
|
14238
|
+
content:
|
|
14239
|
+
application/json:
|
|
14240
|
+
schema:
|
|
14241
|
+
$ref: "#/components/schemas/AppThread"
|
|
14242
|
+
400:
|
|
14243
|
+
description: Bad request
|
|
14244
|
+
401:
|
|
14245
|
+
description: Unauthorized
|
|
14246
|
+
404:
|
|
14247
|
+
description: Not found
|
|
14185
14248
|
components:
|
|
14186
14249
|
securitySchemes:
|
|
14187
14250
|
bearerAuth:
|
|
@@ -16967,6 +17030,8 @@ components:
|
|
|
16967
17030
|
admin:
|
|
16968
17031
|
type: object
|
|
16969
17032
|
additionalProperties: true
|
|
17033
|
+
firstReply:
|
|
17034
|
+
$ref: "#/components/schemas/ReplyInput"
|
|
16970
17035
|
UpdateThreadInput:
|
|
16971
17036
|
type: object
|
|
16972
17037
|
properties:
|
|
@@ -17012,6 +17077,14 @@ components:
|
|
|
17012
17077
|
type: string
|
|
17013
17078
|
parentId:
|
|
17014
17079
|
type: string
|
|
17080
|
+
parentIds:
|
|
17081
|
+
type: array
|
|
17082
|
+
items:
|
|
17083
|
+
type: string
|
|
17084
|
+
proofId:
|
|
17085
|
+
type: string
|
|
17086
|
+
productId:
|
|
17087
|
+
type: string
|
|
17015
17088
|
tag:
|
|
17016
17089
|
type: string
|
|
17017
17090
|
contactId:
|
|
@@ -19308,8 +19381,69 @@ components:
|
|
|
19308
19381
|
type: string
|
|
19309
19382
|
updatedAt:
|
|
19310
19383
|
type: string
|
|
19384
|
+
security:
|
|
19385
|
+
$ref: "#/components/schemas/AuthKitSecurityConfig"
|
|
19311
19386
|
required:
|
|
19312
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
|
|
19313
19447
|
FirebaseTimestamp:
|
|
19314
19448
|
type: object
|
|
19315
19449
|
properties:
|
|
@@ -24921,9 +25055,11 @@ components:
|
|
|
24921
25055
|
- tokenId
|
|
24922
25056
|
- userId
|
|
24923
25057
|
- values
|
|
24924
|
-
|
|
25058
|
+
ProofWrite:
|
|
24925
25059
|
type: object
|
|
24926
25060
|
properties:
|
|
25061
|
+
id:
|
|
25062
|
+
type: string
|
|
24927
25063
|
values:
|
|
24928
25064
|
$ref: "#/components/schemas/ProofValues"
|
|
24929
25065
|
data:
|
|
@@ -24934,12 +25070,33 @@ components:
|
|
|
24934
25070
|
type: object
|
|
24935
25071
|
additionalProperties:
|
|
24936
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"
|
|
24937
25086
|
claimable:
|
|
24938
25087
|
type: boolean
|
|
24939
25088
|
virtual:
|
|
24940
25089
|
type: boolean
|
|
24941
|
-
|
|
24942
|
-
|
|
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"
|
|
24943
25100
|
ProofFieldsConfig:
|
|
24944
25101
|
type: object
|
|
24945
25102
|
properties:
|
|
@@ -25023,9 +25180,6 @@ components:
|
|
|
25023
25180
|
properties:
|
|
25024
25181
|
guestName:
|
|
25025
25182
|
type: string
|
|
25026
|
-
ProofResponse:
|
|
25027
|
-
type: object
|
|
25028
|
-
additionalProperties: true
|
|
25029
25183
|
QrShortCodeLookupResponse:
|
|
25030
25184
|
type: object
|
|
25031
25185
|
properties:
|
|
@@ -250,6 +250,12 @@ export interface CreateThreadInput {
|
|
|
250
250
|
data?: Record<string, unknown>;
|
|
251
251
|
owner?: Record<string, unknown>;
|
|
252
252
|
admin?: Record<string, unknown>;
|
|
253
|
+
/**
|
|
254
|
+
* Optional atomic first reply. Posting a comment no longer needs a separate
|
|
255
|
+
* create-thread-then-reply round trip (which could orphan an empty thread on
|
|
256
|
+
* partial failure). The reply is stored with a generated `id` and timestamp.
|
|
257
|
+
*/
|
|
258
|
+
firstReply?: ReplyInput;
|
|
253
259
|
}
|
|
254
260
|
/**
|
|
255
261
|
* Input for updating a thread
|
|
@@ -279,8 +285,16 @@ export interface ReplyInput {
|
|
|
279
285
|
export interface ThreadListQueryParams extends ListQueryParams {
|
|
280
286
|
slug?: string;
|
|
281
287
|
authorId?: string;
|
|
288
|
+
/** Disambiguates the parent entity kind (e.g. "memory", "case", "proof"). */
|
|
282
289
|
parentType?: string;
|
|
290
|
+
/** Anchor to a single app entity id (text — SmartLinks short ids, not UUIDs). */
|
|
283
291
|
parentId?: string;
|
|
292
|
+
/** Batch-fetch threads for many app entities in one call (e.g. a memory feed). */
|
|
293
|
+
parentIds?: string[];
|
|
294
|
+
/** Anchor threads to a proof. For grant-token callers this is the enforced filter. */
|
|
295
|
+
proofId?: string;
|
|
296
|
+
/** Anchor threads to a product (one tier up from proof). */
|
|
297
|
+
productId?: string;
|
|
284
298
|
tag?: string;
|
|
285
299
|
contactId?: string;
|
|
286
300
|
}
|
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,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';
|
package/dist/types/proof.d.ts
CHANGED
|
@@ -40,16 +40,71 @@ export interface Proof {
|
|
|
40
40
|
values: ProofValues;
|
|
41
41
|
}
|
|
42
42
|
export type ProofResponse = Proof;
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
|
|
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]`.
|