@proveanything/smartlinks 1.16.4 → 1.16.6
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/dist/api/attestations.d.ts +24 -4
- package/dist/api/attestations.js +27 -3
- package/dist/api/proof.d.ts +7 -0
- package/dist/api/proof.js +7 -0
- package/dist/docs/API_SUMMARY.md +35 -3
- package/dist/docs/attestations.md +9 -0
- package/dist/docs/proof-comms-triggers.md +5 -0
- package/dist/docs/proof-ownership-transfer.md +12 -1
- package/dist/openapi.yaml +73 -0
- package/dist/types/attestations.d.ts +22 -0
- package/dist/types/proof.d.ts +9 -2
- package/docs/API_SUMMARY.md +35 -3
- package/docs/attestations.md +9 -0
- package/docs/proof-comms-triggers.md +5 -0
- package/docs/proof-ownership-transfer.md +12 -1
- package/openapi.yaml +73 -0
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Attestation, CreateAttestationInput, ListAttestationsParams, ListAttestationsResponse, AttestationSummaryParams, AttestationSummaryResponse, PublicAttestationSummaryResponse, AttestationLatestParams, AttestationLatestResponse, PublicAttestationLatestResponse, AttestationVerifyParams, ChainVerifyResult, AttestationTreeSummaryParams, AttestationTreeSummaryResponse, PublicAttestationTreeSummaryResponse, AttestationTreeLatestParams, AttestationTreeLatestResponse, PublicAttestationTreeLatestResponse, PublicListAttestationsResponse } from "../types/attestations";
|
|
1
|
+
import type { Attestation, CreateAttestationInput, ListAttestationsParams, ListAttestationsResponse, AttestationSummaryParams, AttestationSummaryResponse, PublicAttestationSummaryResponse, AttestationLatestParams, AttestationLatestResponse, PublicAttestationLatestResponse, AttestationVerifyParams, ChainVerifyResult, AttestationTreeSummaryParams, AttestationTreeSummaryResponse, PublicAttestationTreeSummaryResponse, AttestationTreeLatestParams, AttestationTreeLatestResponse, PublicAttestationTreeLatestResponse, PublicListAttestationsResponse, OwnerAttestationInput, CreateOwnerAttestationResponse } from "../types/attestations";
|
|
2
2
|
/**
|
|
3
3
|
* Postgres-backed Attestations API (v2).
|
|
4
4
|
*
|
|
@@ -10,9 +10,12 @@ import type { Attestation, CreateAttestationInput, ListAttestationsParams, ListA
|
|
|
10
10
|
*
|
|
11
11
|
* ### Admin vs Public
|
|
12
12
|
* - **Admin** endpoints (`/admin/collection/:id/attestations`) require a valid
|
|
13
|
-
* admin session or bearer token. All three data zones are returned
|
|
14
|
-
*
|
|
15
|
-
*
|
|
13
|
+
* admin session or bearer token. All three data zones are returned, and the
|
|
14
|
+
* business can write any zone/visibility ({@link create}).
|
|
15
|
+
* - **Public** endpoints (`/public/collection/:id/attestations`) are read-only,
|
|
16
|
+
* EXCEPT {@link publicCreate}: the proof OWNER may author an attestation on
|
|
17
|
+
* their own item (value + ownerData, visibility public|owner — never the admin
|
|
18
|
+
* zone). Owner elevation is via `Authorization: Bearer <Firebase ID token>`.
|
|
16
19
|
*
|
|
17
20
|
* @see docs/attestations.md
|
|
18
21
|
*/
|
|
@@ -207,6 +210,23 @@ export declare namespace attestations {
|
|
|
207
210
|
* ```
|
|
208
211
|
*/
|
|
209
212
|
function publicList(collectionId: string, params: ListAttestationsParams): Promise<PublicListAttestationsResponse>;
|
|
213
|
+
/**
|
|
214
|
+
* Create an OWNER-authored attestation (public write) — the counterpart to the
|
|
215
|
+
* admin {@link create}. The authenticated caller must OWN the linked proof
|
|
216
|
+
* (identity, not a read grant). Guardrails enforced server-side: they may write
|
|
217
|
+
* `value` + `ownerData` only (`adminData` is dropped), `visibility` is clamped
|
|
218
|
+
* to `'public' | 'owner'`, and `authorId` is forced to the caller. The record
|
|
219
|
+
* joins the same tamper-evident hash chain.
|
|
220
|
+
* POST /public/collection/:collectionId/attestations
|
|
221
|
+
* ```ts
|
|
222
|
+
* await attestations.publicCreate('coll_123', {
|
|
223
|
+
* subjectType: 'proof', subjectId: 'proof_1',
|
|
224
|
+
* attestationType: 'condition-report',
|
|
225
|
+
* value: { grade: 'excellent' }, visibility: 'public',
|
|
226
|
+
* })
|
|
227
|
+
* ```
|
|
228
|
+
*/
|
|
229
|
+
function publicCreate(collectionId: string, data: OwnerAttestationInput): Promise<CreateOwnerAttestationResponse>;
|
|
210
230
|
/**
|
|
211
231
|
* Time-series summary (public).
|
|
212
232
|
*
|
package/dist/api/attestations.js
CHANGED
|
@@ -23,9 +23,12 @@ function buildAttestationQuery(params) {
|
|
|
23
23
|
*
|
|
24
24
|
* ### Admin vs Public
|
|
25
25
|
* - **Admin** endpoints (`/admin/collection/:id/attestations`) require a valid
|
|
26
|
-
* admin session or bearer token. All three data zones are returned
|
|
27
|
-
*
|
|
28
|
-
*
|
|
26
|
+
* admin session or bearer token. All three data zones are returned, and the
|
|
27
|
+
* business can write any zone/visibility ({@link create}).
|
|
28
|
+
* - **Public** endpoints (`/public/collection/:id/attestations`) are read-only,
|
|
29
|
+
* EXCEPT {@link publicCreate}: the proof OWNER may author an attestation on
|
|
30
|
+
* their own item (value + ownerData, visibility public|owner — never the admin
|
|
31
|
+
* zone). Owner elevation is via `Authorization: Bearer <Firebase ID token>`.
|
|
29
32
|
*
|
|
30
33
|
* @see docs/attestations.md
|
|
31
34
|
*/
|
|
@@ -273,6 +276,27 @@ export var attestations;
|
|
|
273
276
|
return request(path);
|
|
274
277
|
}
|
|
275
278
|
attestations.publicList = publicList;
|
|
279
|
+
/**
|
|
280
|
+
* Create an OWNER-authored attestation (public write) — the counterpart to the
|
|
281
|
+
* admin {@link create}. The authenticated caller must OWN the linked proof
|
|
282
|
+
* (identity, not a read grant). Guardrails enforced server-side: they may write
|
|
283
|
+
* `value` + `ownerData` only (`adminData` is dropped), `visibility` is clamped
|
|
284
|
+
* to `'public' | 'owner'`, and `authorId` is forced to the caller. The record
|
|
285
|
+
* joins the same tamper-evident hash chain.
|
|
286
|
+
* POST /public/collection/:collectionId/attestations
|
|
287
|
+
* ```ts
|
|
288
|
+
* await attestations.publicCreate('coll_123', {
|
|
289
|
+
* subjectType: 'proof', subjectId: 'proof_1',
|
|
290
|
+
* attestationType: 'condition-report',
|
|
291
|
+
* value: { grade: 'excellent' }, visibility: 'public',
|
|
292
|
+
* })
|
|
293
|
+
* ```
|
|
294
|
+
*/
|
|
295
|
+
async function publicCreate(collectionId, data) {
|
|
296
|
+
const path = `/public/collection/${encodeURIComponent(collectionId)}/attestations`;
|
|
297
|
+
return post(path, data);
|
|
298
|
+
}
|
|
299
|
+
attestations.publicCreate = publicCreate;
|
|
276
300
|
/**
|
|
277
301
|
* Time-series summary (public).
|
|
278
302
|
*
|
package/dist/api/proof.d.ts
CHANGED
|
@@ -187,6 +187,13 @@ export declare namespace proof {
|
|
|
187
187
|
* },
|
|
188
188
|
* })
|
|
189
189
|
* ```
|
|
190
|
+
* Direct to an SMS recipient by phone (E.164) and notify them by text:
|
|
191
|
+
* ```ts
|
|
192
|
+
* await proof.transfer(collectionId, productId, proofId, {
|
|
193
|
+
* toPhone: '+14155551234',
|
|
194
|
+
* comms: { recipient: { templateId: 'transfer-incoming', channel: 'sms' } },
|
|
195
|
+
* })
|
|
196
|
+
* ```
|
|
190
197
|
*/
|
|
191
198
|
function transfer(collectionId: string, productId: string, proofId: string, options: TransferProofOptions): Promise<TransferProofResult>;
|
|
192
199
|
/**
|
package/dist/api/proof.js
CHANGED
|
@@ -280,6 +280,13 @@ export var proof;
|
|
|
280
280
|
* },
|
|
281
281
|
* })
|
|
282
282
|
* ```
|
|
283
|
+
* Direct to an SMS recipient by phone (E.164) and notify them by text:
|
|
284
|
+
* ```ts
|
|
285
|
+
* await proof.transfer(collectionId, productId, proofId, {
|
|
286
|
+
* toPhone: '+14155551234',
|
|
287
|
+
* comms: { recipient: { templateId: 'transfer-incoming', channel: 'sms' } },
|
|
288
|
+
* })
|
|
289
|
+
* ```
|
|
283
290
|
*/
|
|
284
291
|
async function transfer(collectionId, productId, proofId, options) {
|
|
285
292
|
return post(transferBase(collectionId, productId, proofId), Object.assign({}, options));
|
package/dist/docs/API_SUMMARY.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Smartlinks API Summary
|
|
2
2
|
|
|
3
|
-
Version: 1.16.
|
|
3
|
+
Version: 1.16.6 | Generated: 2026-09-06T07:49:21.444Z
|
|
4
4
|
|
|
5
5
|
This is a concise summary of all available API functions and types.
|
|
6
6
|
|
|
@@ -2797,6 +2797,22 @@ interface CreateAttestationInput {
|
|
|
2797
2797
|
}
|
|
2798
2798
|
```
|
|
2799
2799
|
|
|
2800
|
+
**OwnerAttestationInput** (interface)
|
|
2801
|
+
```typescript
|
|
2802
|
+
interface OwnerAttestationInput {
|
|
2803
|
+
subjectType: AttestationSubjectType
|
|
2804
|
+
subjectId: string
|
|
2805
|
+
attestationType: string
|
|
2806
|
+
recordedAt?: string
|
|
2807
|
+
visibility?: 'public' | 'owner'
|
|
2808
|
+
value?: Record<string, any>
|
|
2809
|
+
ownerData?: Record<string, any>
|
|
2810
|
+
unit?: string
|
|
2811
|
+
source?: string
|
|
2812
|
+
metadata?: Record<string, any>
|
|
2813
|
+
}
|
|
2814
|
+
```
|
|
2815
|
+
|
|
2800
2816
|
**ListAttestationsResponse** (interface)
|
|
2801
2817
|
```typescript
|
|
2802
2818
|
interface ListAttestationsResponse {
|
|
@@ -2804,6 +2820,13 @@ interface ListAttestationsResponse {
|
|
|
2804
2820
|
}
|
|
2805
2821
|
```
|
|
2806
2822
|
|
|
2823
|
+
**CreateOwnerAttestationResponse** (interface)
|
|
2824
|
+
```typescript
|
|
2825
|
+
interface CreateOwnerAttestationResponse {
|
|
2826
|
+
attestation: Attestation
|
|
2827
|
+
}
|
|
2828
|
+
```
|
|
2829
|
+
|
|
2807
2830
|
**PublicListAttestationsResponse** (interface)
|
|
2808
2831
|
```typescript
|
|
2809
2832
|
interface PublicListAttestationsResponse {
|
|
@@ -7605,9 +7628,14 @@ interface CommsTrigger {
|
|
|
7605
7628
|
```typescript
|
|
7606
7629
|
interface TransferProofOptions {
|
|
7607
7630
|
* Comms to send. Roles: `recipient` (the named new owner) and `sender` (the
|
|
7608
|
-
* initiator) for a directed transfer; `owner` for an open release.
|
|
7631
|
+
* initiator) for a directed transfer; `owner` for an open release. For an
|
|
7632
|
+
* SMS recipient, set `comms.recipient.channel = 'sms'`.
|
|
7609
7633
|
comms?: CommsTriggerMap
|
|
7610
7634
|
toEmail?: string
|
|
7635
|
+
* Directed: recipient phone in E.164 (e.g. `+14155551234`). Resolves to the same
|
|
7636
|
+
* user they log in as via SMS OTP (created if needed). Pair with an SMS comms
|
|
7637
|
+
* trigger to notify them: `comms.recipient.channel = 'sms'`.
|
|
7638
|
+
toPhone?: string
|
|
7611
7639
|
toUserId?: string
|
|
7612
7640
|
toName?: string
|
|
7613
7641
|
release?: boolean
|
|
@@ -9058,6 +9086,10 @@ Tree latest snapshot — most-recent record per type across a container subtree
|
|
|
9058
9086
|
params: ListAttestationsParams) → `Promise<PublicListAttestationsResponse>`
|
|
9059
9087
|
List attestations for a subject (public). Records with `visibility='admin'` are always excluded. Records with `visibility='owner'` are included only when the caller provides a valid Firebase ID token that resolves to the subject owner. The `audience` field in the response indicates the tier that was served. ```typescript const { attestations: records, audience } = await attestations.publicList('coll_123', { subjectType: 'proof', subjectId: 'proof-uuid', }) ```
|
|
9060
9088
|
|
|
9089
|
+
**publicCreate**(collectionId: string,
|
|
9090
|
+
data: OwnerAttestationInput) → `Promise<CreateOwnerAttestationResponse>`
|
|
9091
|
+
Create an OWNER-authored attestation (public write) — the counterpart to the admin {@link create}. The authenticated caller must OWN the linked proof (identity, not a read grant). Guardrails enforced server-side: they may write `value` + `ownerData` only (`adminData` is dropped), `visibility` is clamped to `'public' | 'owner'`, and `authorId` is forced to the caller. The record joins the same tamper-evident hash chain. POST /public/collection/:collectionId/attestations ```ts await attestations.publicCreate('coll_123', { subjectType: 'proof', subjectId: 'proof_1', attestationType: 'condition-report', value: { grade: 'excellent' }, visibility: 'public', }) ```
|
|
9092
|
+
|
|
9061
9093
|
**publicSummary**(collectionId: string,
|
|
9062
9094
|
params: AttestationSummaryParams) → `Promise<PublicAttestationSummaryResponse>`
|
|
9063
9095
|
Time-series summary (public). Always served at `audience='public'`. Same parameters as the admin version. `attestationType` are required
|
|
@@ -10470,7 +10502,7 @@ Redeem a grant token (anonymous or signed-in). Records the redemption and return
|
|
|
10470
10502
|
productId: string,
|
|
10471
10503
|
proofId: string,
|
|
10472
10504
|
options: TransferProofOptions) → `Promise<TransferProofResult>`
|
|
10473
|
-
Start a push transfer of a proof (current owner / collection admin only). Directed — hand it to a named recipient who then calls {@link acceptTransfer}: ```ts await proof.transfer(collectionId, productId, proofId, { toEmail: 'buyer@example.com' }) ``` Open release — make the proof claimable by anyone: ```ts await proof.transfer(collectionId, productId, proofId, { release: true }) ``` Send comms by naming templates per role (server decides who receives each): ```ts await proof.transfer(collectionId, productId, proofId, { toEmail: 'buyer@example.com', comms: { recipient: { templateId: 'transfer-incoming', props: { note: 'Enjoy!' } }, sender: { templateId: 'transfer-sent' }, }, }) ```
|
|
10505
|
+
Start a push transfer of a proof (current owner / collection admin only). Directed — hand it to a named recipient who then calls {@link acceptTransfer}: ```ts await proof.transfer(collectionId, productId, proofId, { toEmail: 'buyer@example.com' }) ``` Open release — make the proof claimable by anyone: ```ts await proof.transfer(collectionId, productId, proofId, { release: true }) ``` Send comms by naming templates per role (server decides who receives each): ```ts await proof.transfer(collectionId, productId, proofId, { toEmail: 'buyer@example.com', comms: { recipient: { templateId: 'transfer-incoming', props: { note: 'Enjoy!' } }, sender: { templateId: 'transfer-sent' }, }, }) ``` Direct to an SMS recipient by phone (E.164) and notify them by text: ```ts await proof.transfer(collectionId, productId, proofId, { toPhone: '+14155551234', comms: { recipient: { templateId: 'transfer-incoming', channel: 'sms' } }, }) ```
|
|
10474
10506
|
|
|
10475
10507
|
**acceptTransfer**(collectionId: string,
|
|
10476
10508
|
productId: string,
|
|
@@ -159,6 +159,15 @@ The middleware resolves the UID and checks ownership:
|
|
|
159
159
|
|
|
160
160
|
When ownership is confirmed the request is served at `audience='owner'`, which includes `ownerData`.
|
|
161
161
|
|
|
162
|
+
**Owner write** — the proof owner may also *author* an attestation on their own item via `POST /api/v1/public/collection/:collectionId/attestations` (`attestations.publicCreate`). It is the public counterpart to the admin write, with tight guardrails:
|
|
163
|
+
|
|
164
|
+
- the caller must be authenticated and **own the linked proof** (identity — a read grant is not enough); a subject with no linked proof is rejected;
|
|
165
|
+
- they may write `value` and `ownerData` only — **`adminData` is dropped** (the business zone);
|
|
166
|
+
- `visibility` is clamped to `'public' | 'owner'` (never `'admin'`), defaulting to `'owner'`;
|
|
167
|
+
- `authorId` is forced to the caller and `metadata.authorType = 'owner'` is stamped.
|
|
168
|
+
|
|
169
|
+
The record joins the same append-only, hash-chained log as business/system writes. Business writes (any zone/visibility) remain admin-only.
|
|
170
|
+
|
|
162
171
|
### Visibility vs audience
|
|
163
172
|
|
|
164
173
|
`visibility` is a property of an **individual record** set at write time. `audience` describes the **caller's tier** resolved at read time. The server applies:
|
|
@@ -128,6 +128,11 @@ Omit `comms` entirely and nothing is sent — comms are **opt-in**.
|
|
|
128
128
|
|
|
129
129
|
- **Email-only recipients work.** A directed transfer to a `toEmail` that isn't a
|
|
130
130
|
contact yet resolves/creates a contact before sending.
|
|
131
|
+
- **SMS recipients work the same way.** A directed transfer to a `toPhone` (E.164)
|
|
132
|
+
resolves the recipient by phone and gives their contact a phone identity, so an
|
|
133
|
+
SMS-channel trigger (`channel: 'sms'`) reaches them. Because the phone maps to a
|
|
134
|
+
stable Firebase uid, they accept by logging in via SMS OTP — the accept is still
|
|
135
|
+
auth-gated exactly as with email.
|
|
131
136
|
- **Consent + suppression apply.** Transactional sends still respect the contact's
|
|
132
137
|
channel consent and suppression list; a template's `topic` governs this.
|
|
133
138
|
- **Delivery is logged** to comms history (with your `appId` and a `ref`), so sends
|
|
@@ -15,9 +15,20 @@ reserves states for them.
|
|
|
15
15
|
|
|
16
16
|
| Mode | How | Who completes it |
|
|
17
17
|
|------|-----|------------------|
|
|
18
|
-
| **Directed** | Owner names a recipient (`toEmail` / `toUserId`). The proof is earmarked for them (`claimUserId`); you notify them with a comms trigger. | The named recipient calls `acceptTransfer`. |
|
|
18
|
+
| **Directed** | Owner names a recipient (`toEmail` / `toPhone` / `toUserId`). The proof is earmarked for them (`claimUserId`); you notify them with a comms trigger. | The named recipient calls `acceptTransfer`. |
|
|
19
19
|
| **Open release** | Owner marks the proof `claimable`. | Anyone claims it via the normal claim flow. |
|
|
20
20
|
|
|
21
|
+
A `toPhone` recipient (E.164) resolves to the **same user they log in as via SMS
|
|
22
|
+
OTP** — Firebase keys the uid by phone number, so the earmark matches when they
|
|
23
|
+
sign in. Pair it with an SMS comms trigger to notify them by text:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
await proof.transfer(collectionId, productId, proofId, {
|
|
27
|
+
toPhone: '+14155551234',
|
|
28
|
+
comms: { recipient: { templateId: 'transfer-incoming', channel: 'sms' } },
|
|
29
|
+
})
|
|
30
|
+
```
|
|
31
|
+
|
|
21
32
|
Only the current owner (or a collection admin) can start a transfer. A proof can
|
|
22
33
|
have **one active transfer at a time**.
|
|
23
34
|
|
package/dist/openapi.yaml
CHANGED
|
@@ -10270,6 +10270,37 @@ paths:
|
|
|
10270
10270
|
description: Unauthorized
|
|
10271
10271
|
404:
|
|
10272
10272
|
description: Not found
|
|
10273
|
+
post:
|
|
10274
|
+
tags:
|
|
10275
|
+
- attestations
|
|
10276
|
+
summary: "Create an OWNER-authored attestation (public write) — the counterpart to the admin {@link create}."
|
|
10277
|
+
operationId: attestations_publicCreate
|
|
10278
|
+
security: []
|
|
10279
|
+
parameters:
|
|
10280
|
+
- name: collectionId
|
|
10281
|
+
in: path
|
|
10282
|
+
required: true
|
|
10283
|
+
schema:
|
|
10284
|
+
type: string
|
|
10285
|
+
responses:
|
|
10286
|
+
200:
|
|
10287
|
+
description: Success
|
|
10288
|
+
content:
|
|
10289
|
+
application/json:
|
|
10290
|
+
schema:
|
|
10291
|
+
$ref: "#/components/schemas/CreateOwnerAttestationResponse"
|
|
10292
|
+
400:
|
|
10293
|
+
description: Bad request
|
|
10294
|
+
401:
|
|
10295
|
+
description: Unauthorized
|
|
10296
|
+
404:
|
|
10297
|
+
description: Not found
|
|
10298
|
+
requestBody:
|
|
10299
|
+
required: true
|
|
10300
|
+
content:
|
|
10301
|
+
application/json:
|
|
10302
|
+
schema:
|
|
10303
|
+
$ref: "#/components/schemas/OwnerAttestationInput"
|
|
10273
10304
|
/public/collection/{collectionId}/attestations/latest:
|
|
10274
10305
|
get:
|
|
10275
10306
|
tags:
|
|
@@ -18782,6 +18813,39 @@ components:
|
|
|
18782
18813
|
- subjectType
|
|
18783
18814
|
- subjectId
|
|
18784
18815
|
- attestationType
|
|
18816
|
+
OwnerAttestationInput:
|
|
18817
|
+
type: object
|
|
18818
|
+
properties:
|
|
18819
|
+
subjectType:
|
|
18820
|
+
$ref: "#/components/schemas/AttestationSubjectType"
|
|
18821
|
+
subjectId:
|
|
18822
|
+
type: string
|
|
18823
|
+
attestationType:
|
|
18824
|
+
type: string
|
|
18825
|
+
recordedAt:
|
|
18826
|
+
type: string
|
|
18827
|
+
visibility:
|
|
18828
|
+
type: string
|
|
18829
|
+
enum:
|
|
18830
|
+
- public
|
|
18831
|
+
- owner
|
|
18832
|
+
value:
|
|
18833
|
+
type: object
|
|
18834
|
+
additionalProperties: true
|
|
18835
|
+
ownerData:
|
|
18836
|
+
type: object
|
|
18837
|
+
additionalProperties: true
|
|
18838
|
+
unit:
|
|
18839
|
+
type: string
|
|
18840
|
+
source:
|
|
18841
|
+
type: string
|
|
18842
|
+
metadata:
|
|
18843
|
+
type: object
|
|
18844
|
+
additionalProperties: true
|
|
18845
|
+
required:
|
|
18846
|
+
- subjectType
|
|
18847
|
+
- subjectId
|
|
18848
|
+
- attestationType
|
|
18785
18849
|
ListAttestationsResponse:
|
|
18786
18850
|
type: object
|
|
18787
18851
|
properties:
|
|
@@ -18791,6 +18855,13 @@ components:
|
|
|
18791
18855
|
$ref: "#/components/schemas/Attestation"
|
|
18792
18856
|
required:
|
|
18793
18857
|
- attestations
|
|
18858
|
+
CreateOwnerAttestationResponse:
|
|
18859
|
+
type: object
|
|
18860
|
+
properties:
|
|
18861
|
+
attestation:
|
|
18862
|
+
$ref: "#/components/schemas/Attestation"
|
|
18863
|
+
required:
|
|
18864
|
+
- attestation
|
|
18794
18865
|
PublicListAttestationsResponse:
|
|
18795
18866
|
type: object
|
|
18796
18867
|
properties:
|
|
@@ -25882,6 +25953,8 @@ components:
|
|
|
25882
25953
|
$ref: "#/components/schemas/CommsTriggerMap"
|
|
25883
25954
|
toEmail:
|
|
25884
25955
|
type: string
|
|
25956
|
+
toPhone:
|
|
25957
|
+
type: string
|
|
25885
25958
|
toUserId:
|
|
25886
25959
|
type: string
|
|
25887
25960
|
toName:
|
|
@@ -128,9 +128,31 @@ export interface CreateAttestationInput {
|
|
|
128
128
|
authorId?: string;
|
|
129
129
|
metadata?: Record<string, any>;
|
|
130
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* Owner-authored attestation input (public write). The proof OWNER adds an
|
|
133
|
+
* attestation to their own item. Restricted vs {@link CreateAttestationInput}:
|
|
134
|
+
* no `adminData` (business-only zone), `visibility` limited to `'public' | 'owner'`,
|
|
135
|
+
* and `authorId` is forced to the caller by the server (so it's omitted here).
|
|
136
|
+
*/
|
|
137
|
+
export interface OwnerAttestationInput {
|
|
138
|
+
subjectType: AttestationSubjectType;
|
|
139
|
+
subjectId: string;
|
|
140
|
+
attestationType: string;
|
|
141
|
+
recordedAt?: string;
|
|
142
|
+
/** `'public'` | `'owner'` only — defaults to `'owner'`. */
|
|
143
|
+
visibility?: 'public' | 'owner';
|
|
144
|
+
value?: Record<string, any>;
|
|
145
|
+
ownerData?: Record<string, any>;
|
|
146
|
+
unit?: string;
|
|
147
|
+
source?: string;
|
|
148
|
+
metadata?: Record<string, any>;
|
|
149
|
+
}
|
|
131
150
|
export interface ListAttestationsResponse {
|
|
132
151
|
attestations: Attestation[];
|
|
133
152
|
}
|
|
153
|
+
export interface CreateOwnerAttestationResponse {
|
|
154
|
+
attestation: Attestation;
|
|
155
|
+
}
|
|
134
156
|
export interface PublicListAttestationsResponse {
|
|
135
157
|
attestations: Attestation[];
|
|
136
158
|
/** Resolved audience tier; governs which data zones are populated */
|
package/dist/types/proof.d.ts
CHANGED
|
@@ -280,17 +280,24 @@ export interface CommsTrigger {
|
|
|
280
280
|
export type CommsTriggerMap = Record<string, CommsTrigger>;
|
|
281
281
|
/**
|
|
282
282
|
* Start a push transfer. Provide **one** of:
|
|
283
|
-
* - `toEmail` / `toUserId` — a directed transfer to a named recipient (they accept).
|
|
283
|
+
* - `toEmail` / `toPhone` / `toUserId` — a directed transfer to a named recipient (they accept).
|
|
284
284
|
* - `release: true` — an open release (the proof becomes claimable by anyone).
|
|
285
285
|
*/
|
|
286
286
|
export interface TransferProofOptions {
|
|
287
287
|
/**
|
|
288
288
|
* Comms to send. Roles: `recipient` (the named new owner) and `sender` (the
|
|
289
|
-
* initiator) for a directed transfer; `owner` for an open release.
|
|
289
|
+
* initiator) for a directed transfer; `owner` for an open release. For an
|
|
290
|
+
* SMS recipient, set `comms.recipient.channel = 'sms'`.
|
|
290
291
|
*/
|
|
291
292
|
comms?: CommsTriggerMap;
|
|
292
293
|
/** Directed: recipient email (created/looked up if needed). */
|
|
293
294
|
toEmail?: string;
|
|
295
|
+
/**
|
|
296
|
+
* Directed: recipient phone in E.164 (e.g. `+14155551234`). Resolves to the same
|
|
297
|
+
* user they log in as via SMS OTP (created if needed). Pair with an SMS comms
|
|
298
|
+
* trigger to notify them: `comms.recipient.channel = 'sms'`.
|
|
299
|
+
*/
|
|
300
|
+
toPhone?: string;
|
|
294
301
|
/** Directed: recipient user id, if already known. */
|
|
295
302
|
toUserId?: string;
|
|
296
303
|
/** Directed: display name for a newly-created recipient. */
|
package/docs/API_SUMMARY.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Smartlinks API Summary
|
|
2
2
|
|
|
3
|
-
Version: 1.16.
|
|
3
|
+
Version: 1.16.6 | Generated: 2026-09-06T07:49:21.444Z
|
|
4
4
|
|
|
5
5
|
This is a concise summary of all available API functions and types.
|
|
6
6
|
|
|
@@ -2797,6 +2797,22 @@ interface CreateAttestationInput {
|
|
|
2797
2797
|
}
|
|
2798
2798
|
```
|
|
2799
2799
|
|
|
2800
|
+
**OwnerAttestationInput** (interface)
|
|
2801
|
+
```typescript
|
|
2802
|
+
interface OwnerAttestationInput {
|
|
2803
|
+
subjectType: AttestationSubjectType
|
|
2804
|
+
subjectId: string
|
|
2805
|
+
attestationType: string
|
|
2806
|
+
recordedAt?: string
|
|
2807
|
+
visibility?: 'public' | 'owner'
|
|
2808
|
+
value?: Record<string, any>
|
|
2809
|
+
ownerData?: Record<string, any>
|
|
2810
|
+
unit?: string
|
|
2811
|
+
source?: string
|
|
2812
|
+
metadata?: Record<string, any>
|
|
2813
|
+
}
|
|
2814
|
+
```
|
|
2815
|
+
|
|
2800
2816
|
**ListAttestationsResponse** (interface)
|
|
2801
2817
|
```typescript
|
|
2802
2818
|
interface ListAttestationsResponse {
|
|
@@ -2804,6 +2820,13 @@ interface ListAttestationsResponse {
|
|
|
2804
2820
|
}
|
|
2805
2821
|
```
|
|
2806
2822
|
|
|
2823
|
+
**CreateOwnerAttestationResponse** (interface)
|
|
2824
|
+
```typescript
|
|
2825
|
+
interface CreateOwnerAttestationResponse {
|
|
2826
|
+
attestation: Attestation
|
|
2827
|
+
}
|
|
2828
|
+
```
|
|
2829
|
+
|
|
2807
2830
|
**PublicListAttestationsResponse** (interface)
|
|
2808
2831
|
```typescript
|
|
2809
2832
|
interface PublicListAttestationsResponse {
|
|
@@ -7605,9 +7628,14 @@ interface CommsTrigger {
|
|
|
7605
7628
|
```typescript
|
|
7606
7629
|
interface TransferProofOptions {
|
|
7607
7630
|
* Comms to send. Roles: `recipient` (the named new owner) and `sender` (the
|
|
7608
|
-
* initiator) for a directed transfer; `owner` for an open release.
|
|
7631
|
+
* initiator) for a directed transfer; `owner` for an open release. For an
|
|
7632
|
+
* SMS recipient, set `comms.recipient.channel = 'sms'`.
|
|
7609
7633
|
comms?: CommsTriggerMap
|
|
7610
7634
|
toEmail?: string
|
|
7635
|
+
* Directed: recipient phone in E.164 (e.g. `+14155551234`). Resolves to the same
|
|
7636
|
+
* user they log in as via SMS OTP (created if needed). Pair with an SMS comms
|
|
7637
|
+
* trigger to notify them: `comms.recipient.channel = 'sms'`.
|
|
7638
|
+
toPhone?: string
|
|
7611
7639
|
toUserId?: string
|
|
7612
7640
|
toName?: string
|
|
7613
7641
|
release?: boolean
|
|
@@ -9058,6 +9086,10 @@ Tree latest snapshot — most-recent record per type across a container subtree
|
|
|
9058
9086
|
params: ListAttestationsParams) → `Promise<PublicListAttestationsResponse>`
|
|
9059
9087
|
List attestations for a subject (public). Records with `visibility='admin'` are always excluded. Records with `visibility='owner'` are included only when the caller provides a valid Firebase ID token that resolves to the subject owner. The `audience` field in the response indicates the tier that was served. ```typescript const { attestations: records, audience } = await attestations.publicList('coll_123', { subjectType: 'proof', subjectId: 'proof-uuid', }) ```
|
|
9060
9088
|
|
|
9089
|
+
**publicCreate**(collectionId: string,
|
|
9090
|
+
data: OwnerAttestationInput) → `Promise<CreateOwnerAttestationResponse>`
|
|
9091
|
+
Create an OWNER-authored attestation (public write) — the counterpart to the admin {@link create}. The authenticated caller must OWN the linked proof (identity, not a read grant). Guardrails enforced server-side: they may write `value` + `ownerData` only (`adminData` is dropped), `visibility` is clamped to `'public' | 'owner'`, and `authorId` is forced to the caller. The record joins the same tamper-evident hash chain. POST /public/collection/:collectionId/attestations ```ts await attestations.publicCreate('coll_123', { subjectType: 'proof', subjectId: 'proof_1', attestationType: 'condition-report', value: { grade: 'excellent' }, visibility: 'public', }) ```
|
|
9092
|
+
|
|
9061
9093
|
**publicSummary**(collectionId: string,
|
|
9062
9094
|
params: AttestationSummaryParams) → `Promise<PublicAttestationSummaryResponse>`
|
|
9063
9095
|
Time-series summary (public). Always served at `audience='public'`. Same parameters as the admin version. `attestationType` are required
|
|
@@ -10470,7 +10502,7 @@ Redeem a grant token (anonymous or signed-in). Records the redemption and return
|
|
|
10470
10502
|
productId: string,
|
|
10471
10503
|
proofId: string,
|
|
10472
10504
|
options: TransferProofOptions) → `Promise<TransferProofResult>`
|
|
10473
|
-
Start a push transfer of a proof (current owner / collection admin only). Directed — hand it to a named recipient who then calls {@link acceptTransfer}: ```ts await proof.transfer(collectionId, productId, proofId, { toEmail: 'buyer@example.com' }) ``` Open release — make the proof claimable by anyone: ```ts await proof.transfer(collectionId, productId, proofId, { release: true }) ``` Send comms by naming templates per role (server decides who receives each): ```ts await proof.transfer(collectionId, productId, proofId, { toEmail: 'buyer@example.com', comms: { recipient: { templateId: 'transfer-incoming', props: { note: 'Enjoy!' } }, sender: { templateId: 'transfer-sent' }, }, }) ```
|
|
10505
|
+
Start a push transfer of a proof (current owner / collection admin only). Directed — hand it to a named recipient who then calls {@link acceptTransfer}: ```ts await proof.transfer(collectionId, productId, proofId, { toEmail: 'buyer@example.com' }) ``` Open release — make the proof claimable by anyone: ```ts await proof.transfer(collectionId, productId, proofId, { release: true }) ``` Send comms by naming templates per role (server decides who receives each): ```ts await proof.transfer(collectionId, productId, proofId, { toEmail: 'buyer@example.com', comms: { recipient: { templateId: 'transfer-incoming', props: { note: 'Enjoy!' } }, sender: { templateId: 'transfer-sent' }, }, }) ``` Direct to an SMS recipient by phone (E.164) and notify them by text: ```ts await proof.transfer(collectionId, productId, proofId, { toPhone: '+14155551234', comms: { recipient: { templateId: 'transfer-incoming', channel: 'sms' } }, }) ```
|
|
10474
10506
|
|
|
10475
10507
|
**acceptTransfer**(collectionId: string,
|
|
10476
10508
|
productId: string,
|
package/docs/attestations.md
CHANGED
|
@@ -159,6 +159,15 @@ The middleware resolves the UID and checks ownership:
|
|
|
159
159
|
|
|
160
160
|
When ownership is confirmed the request is served at `audience='owner'`, which includes `ownerData`.
|
|
161
161
|
|
|
162
|
+
**Owner write** — the proof owner may also *author* an attestation on their own item via `POST /api/v1/public/collection/:collectionId/attestations` (`attestations.publicCreate`). It is the public counterpart to the admin write, with tight guardrails:
|
|
163
|
+
|
|
164
|
+
- the caller must be authenticated and **own the linked proof** (identity — a read grant is not enough); a subject with no linked proof is rejected;
|
|
165
|
+
- they may write `value` and `ownerData` only — **`adminData` is dropped** (the business zone);
|
|
166
|
+
- `visibility` is clamped to `'public' | 'owner'` (never `'admin'`), defaulting to `'owner'`;
|
|
167
|
+
- `authorId` is forced to the caller and `metadata.authorType = 'owner'` is stamped.
|
|
168
|
+
|
|
169
|
+
The record joins the same append-only, hash-chained log as business/system writes. Business writes (any zone/visibility) remain admin-only.
|
|
170
|
+
|
|
162
171
|
### Visibility vs audience
|
|
163
172
|
|
|
164
173
|
`visibility` is a property of an **individual record** set at write time. `audience` describes the **caller's tier** resolved at read time. The server applies:
|
|
@@ -128,6 +128,11 @@ Omit `comms` entirely and nothing is sent — comms are **opt-in**.
|
|
|
128
128
|
|
|
129
129
|
- **Email-only recipients work.** A directed transfer to a `toEmail` that isn't a
|
|
130
130
|
contact yet resolves/creates a contact before sending.
|
|
131
|
+
- **SMS recipients work the same way.** A directed transfer to a `toPhone` (E.164)
|
|
132
|
+
resolves the recipient by phone and gives their contact a phone identity, so an
|
|
133
|
+
SMS-channel trigger (`channel: 'sms'`) reaches them. Because the phone maps to a
|
|
134
|
+
stable Firebase uid, they accept by logging in via SMS OTP — the accept is still
|
|
135
|
+
auth-gated exactly as with email.
|
|
131
136
|
- **Consent + suppression apply.** Transactional sends still respect the contact's
|
|
132
137
|
channel consent and suppression list; a template's `topic` governs this.
|
|
133
138
|
- **Delivery is logged** to comms history (with your `appId` and a `ref`), so sends
|
|
@@ -15,9 +15,20 @@ reserves states for them.
|
|
|
15
15
|
|
|
16
16
|
| Mode | How | Who completes it |
|
|
17
17
|
|------|-----|------------------|
|
|
18
|
-
| **Directed** | Owner names a recipient (`toEmail` / `toUserId`). The proof is earmarked for them (`claimUserId`); you notify them with a comms trigger. | The named recipient calls `acceptTransfer`. |
|
|
18
|
+
| **Directed** | Owner names a recipient (`toEmail` / `toPhone` / `toUserId`). The proof is earmarked for them (`claimUserId`); you notify them with a comms trigger. | The named recipient calls `acceptTransfer`. |
|
|
19
19
|
| **Open release** | Owner marks the proof `claimable`. | Anyone claims it via the normal claim flow. |
|
|
20
20
|
|
|
21
|
+
A `toPhone` recipient (E.164) resolves to the **same user they log in as via SMS
|
|
22
|
+
OTP** — Firebase keys the uid by phone number, so the earmark matches when they
|
|
23
|
+
sign in. Pair it with an SMS comms trigger to notify them by text:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
await proof.transfer(collectionId, productId, proofId, {
|
|
27
|
+
toPhone: '+14155551234',
|
|
28
|
+
comms: { recipient: { templateId: 'transfer-incoming', channel: 'sms' } },
|
|
29
|
+
})
|
|
30
|
+
```
|
|
31
|
+
|
|
21
32
|
Only the current owner (or a collection admin) can start a transfer. A proof can
|
|
22
33
|
have **one active transfer at a time**.
|
|
23
34
|
|
package/openapi.yaml
CHANGED
|
@@ -10270,6 +10270,37 @@ paths:
|
|
|
10270
10270
|
description: Unauthorized
|
|
10271
10271
|
404:
|
|
10272
10272
|
description: Not found
|
|
10273
|
+
post:
|
|
10274
|
+
tags:
|
|
10275
|
+
- attestations
|
|
10276
|
+
summary: "Create an OWNER-authored attestation (public write) — the counterpart to the admin {@link create}."
|
|
10277
|
+
operationId: attestations_publicCreate
|
|
10278
|
+
security: []
|
|
10279
|
+
parameters:
|
|
10280
|
+
- name: collectionId
|
|
10281
|
+
in: path
|
|
10282
|
+
required: true
|
|
10283
|
+
schema:
|
|
10284
|
+
type: string
|
|
10285
|
+
responses:
|
|
10286
|
+
200:
|
|
10287
|
+
description: Success
|
|
10288
|
+
content:
|
|
10289
|
+
application/json:
|
|
10290
|
+
schema:
|
|
10291
|
+
$ref: "#/components/schemas/CreateOwnerAttestationResponse"
|
|
10292
|
+
400:
|
|
10293
|
+
description: Bad request
|
|
10294
|
+
401:
|
|
10295
|
+
description: Unauthorized
|
|
10296
|
+
404:
|
|
10297
|
+
description: Not found
|
|
10298
|
+
requestBody:
|
|
10299
|
+
required: true
|
|
10300
|
+
content:
|
|
10301
|
+
application/json:
|
|
10302
|
+
schema:
|
|
10303
|
+
$ref: "#/components/schemas/OwnerAttestationInput"
|
|
10273
10304
|
/public/collection/{collectionId}/attestations/latest:
|
|
10274
10305
|
get:
|
|
10275
10306
|
tags:
|
|
@@ -18782,6 +18813,39 @@ components:
|
|
|
18782
18813
|
- subjectType
|
|
18783
18814
|
- subjectId
|
|
18784
18815
|
- attestationType
|
|
18816
|
+
OwnerAttestationInput:
|
|
18817
|
+
type: object
|
|
18818
|
+
properties:
|
|
18819
|
+
subjectType:
|
|
18820
|
+
$ref: "#/components/schemas/AttestationSubjectType"
|
|
18821
|
+
subjectId:
|
|
18822
|
+
type: string
|
|
18823
|
+
attestationType:
|
|
18824
|
+
type: string
|
|
18825
|
+
recordedAt:
|
|
18826
|
+
type: string
|
|
18827
|
+
visibility:
|
|
18828
|
+
type: string
|
|
18829
|
+
enum:
|
|
18830
|
+
- public
|
|
18831
|
+
- owner
|
|
18832
|
+
value:
|
|
18833
|
+
type: object
|
|
18834
|
+
additionalProperties: true
|
|
18835
|
+
ownerData:
|
|
18836
|
+
type: object
|
|
18837
|
+
additionalProperties: true
|
|
18838
|
+
unit:
|
|
18839
|
+
type: string
|
|
18840
|
+
source:
|
|
18841
|
+
type: string
|
|
18842
|
+
metadata:
|
|
18843
|
+
type: object
|
|
18844
|
+
additionalProperties: true
|
|
18845
|
+
required:
|
|
18846
|
+
- subjectType
|
|
18847
|
+
- subjectId
|
|
18848
|
+
- attestationType
|
|
18785
18849
|
ListAttestationsResponse:
|
|
18786
18850
|
type: object
|
|
18787
18851
|
properties:
|
|
@@ -18791,6 +18855,13 @@ components:
|
|
|
18791
18855
|
$ref: "#/components/schemas/Attestation"
|
|
18792
18856
|
required:
|
|
18793
18857
|
- attestations
|
|
18858
|
+
CreateOwnerAttestationResponse:
|
|
18859
|
+
type: object
|
|
18860
|
+
properties:
|
|
18861
|
+
attestation:
|
|
18862
|
+
$ref: "#/components/schemas/Attestation"
|
|
18863
|
+
required:
|
|
18864
|
+
- attestation
|
|
18794
18865
|
PublicListAttestationsResponse:
|
|
18795
18866
|
type: object
|
|
18796
18867
|
properties:
|
|
@@ -25882,6 +25953,8 @@ components:
|
|
|
25882
25953
|
$ref: "#/components/schemas/CommsTriggerMap"
|
|
25883
25954
|
toEmail:
|
|
25884
25955
|
type: string
|
|
25956
|
+
toPhone:
|
|
25957
|
+
type: string
|
|
25885
25958
|
toUserId:
|
|
25886
25959
|
type: string
|
|
25887
25960
|
toName:
|