@proveanything/smartlinks 2.0.0-alpha.2 → 2.0.0-alpha.3

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.
@@ -1,6 +1,6 @@
1
1
  # Smartlinks API Summary
2
2
 
3
- Version: 2.0.0-alpha.2 | Generated: 2026-09-14T14:13:56.533Z
3
+ Version: 2.0.0-alpha.3 | Generated: 2026-09-14T14:38:59.597Z
4
4
 
5
5
  This is a concise summary of all available API functions and types.
6
6
 
@@ -54,6 +54,7 @@ For detailed guides on specific features:
54
54
  - **[Forms](forms.md)** - Platform-managed form definitions, submissions, and schema-driven React form UI
55
55
  - **[App Objects: Cases, Threads & Records](app-objects.md)** - Generic app-scoped building blocks for support cases, discussions, bookings, registrations, and more
56
56
  - **[App Records Pattern](app-records-pattern.md)** - Canonical pattern for storing per-product, per-facet, or rule-targeted app data
57
+ - **[Sequences & Claim-Order](sequences.md)** - Allocate a guaranteed-unique, monotonic number (raffle tickets, "Nth to claim", queue positions) and stamp it onto a record — atomic app-config counter + idempotent per-subject stamping, concurrency-safe at stadium scale
57
58
  - **[Communications](comms.md)** - Transactional sends, multi-channel broadcasts, consent management, push registration, and analytics
58
59
  - **[Interactions & Event Tracking](interactions.md)** - Log user events, count outcomes, query history, and define interaction types with permissions
59
60
  - **[Analytics](analytics.md)** - Web analytics, link-click tracking, QR/tag scan telemetry, and event reporting
@@ -0,0 +1,91 @@
1
+ # Sequences & claim-order allocation
2
+
3
+ > **Preview — SmartLinks SDK 2.0.0-alpha.** APIs may change before 2.0.0 stable.
4
+
5
+ A **sequence** hands out a guaranteed-unique, monotonic number — `1, 2, 3, …` — and stamps it
6
+ onto a record. It's the primitive behind raffle tickets, "you're the Nth to claim", queue
7
+ positions, and limited-edition numbering: cases where you need *the next number*, exactly
8
+ once per subject, even with a whole room (or stadium) acting at the same instant.
9
+
10
+ ## The model: allocate, then stamp — and the target is the ledger
11
+
12
+ Two steps, one call:
13
+
14
+ 1. **Allocate** — get the next number from an **atomic counter**. The counter lives inside
15
+ your **app-config** doc at `data.sequences.<key>`, so it's scoped exactly like your other
16
+ app config (per collection / product / variant / batch) and needs no dedicated storage.
17
+ It's incremented in a single statement, so 250 simultaneous taps each get a distinct
18
+ number in microseconds — never two the same.
19
+ 2. **Stamp** — write that number onto the **subject's own record** (a claim set, a proof, or
20
+ an app record). **That record is the ledger** — there's no separate bookkeeping table.
21
+ Next time you read the subject, the number is just there.
22
+
23
+ Because the target is the ledger, allocation is **idempotent**: on a re-tap we read the
24
+ subject first and return the number it already has, rather than allocating a second one.
25
+
26
+ ## Guarantees
27
+
28
+ - **Unique + monotonic** — the counter is an atomic increment, never a read-modify-write, so
29
+ there are no duplicates and no lost updates under load.
30
+ - **Idempotent per subject** — one number per subject; a re-tap returns the same number.
31
+ - **Concurrency-safe at scale** — the only shared hot spot is the one counter row (Postgres
32
+ serializes it); the stamp is per-subject (its own record), so the model holds from 250 in a
33
+ room to 60,000 in a stadium. A concurrent double-tap on the *same* subject at worst skips
34
+ one number (a harmless gap) — never puts two numbers on one person.
35
+
36
+ ## Scoping
37
+
38
+ - **Counter scope** — the app-config doc it lives on: collection-wide, or per product /
39
+ variant / batch. All wristbands mapped to one product? Scope the counter to that product.
40
+ - **`key`** — a name within that doc (e.g. `raffle:2026-cup`), so one config doc can hold
41
+ several independent sequences.
42
+ - **`start`** — the first number (default `1`); use it to reserve a block (start at `51` and
43
+ tell people it's `1`, or just filter `< N` at draw time).
44
+
45
+ ## Idempotency subject — use a *stable* id
46
+
47
+ The number is deduped by the **subject id** you pass, so it must be the **stable** identity:
48
+ - **Claim set id** (the wristband's permanent record) — the right key when people aren't
49
+ logged in. A re-tap resolves to the same claim set → same number.
50
+ - The authenticated **user/contact** — if they sign in / claim.
51
+
52
+ Do **not** key on a value that changes per interaction (e.g. a virtual proof id minted fresh
53
+ on each tap) — that would let one person take several numbers.
54
+
55
+ ## Where the number is stored (the sink)
56
+
57
+ The stamp target is configurable — the number lives wherever you'll read it:
58
+
59
+ | Target | Use |
60
+ |---|---|
61
+ | `claimSet` | The Firestore wristband record — fast, no proof mint on the hot path. |
62
+ | `proof` | A minted proof (value or attestation) — when the number should travel with the proof. |
63
+ | `appRecord` | A structured app record — for queryable, per-app data. |
64
+
65
+ ## Worked example — a free raffle on NFC wristbands
66
+
67
+ Everyone taps a wristband and hits **Enter the raffle**. Each tap allocates the next number
68
+ and writes it onto that wristband's claim set — fast, unique, no proof mint:
69
+
70
+ ```jsonc
71
+ // allocate-and-stamp (conceptual shape)
72
+ {
73
+ "appId": "raffle-app",
74
+ "productId": "wristbands-2026", // the counter's scope
75
+ "key": "raffle:2026-cup", // the named sequence
76
+ "start": 1,
77
+ "subjectId": "<claim set id>", // STABLE identity — re-taps collapse to one number
78
+ "target": "claimSet",
79
+ "field": "raffleNumber"
80
+ }
81
+ // → { "number": 42, "isNew": true } (re-tap → { "number": 42, "isNew": false })
82
+ ```
83
+
84
+ Drawing the winner needs no separate ledger either — query the claim sets (or proofs) where
85
+ `raffleNumber` is set; that field is your entry list, in allocation order.
86
+
87
+ ## Status
88
+
89
+ The allocator + stamping run server-side today. The **public "enter" action** an app widget
90
+ calls on tap (and its SDK wrapper) is being wired in the 2.0.0-alpha line — this doc is the
91
+ contract it will expose.
@@ -1,6 +1,6 @@
1
1
  # Smartlinks API Summary
2
2
 
3
- Version: 2.0.0-alpha.2 | Generated: 2026-09-14T14:13:56.533Z
3
+ Version: 2.0.0-alpha.3 | Generated: 2026-09-14T14:38:59.597Z
4
4
 
5
5
  This is a concise summary of all available API functions and types.
6
6
 
@@ -54,6 +54,7 @@ For detailed guides on specific features:
54
54
  - **[Forms](forms.md)** - Platform-managed form definitions, submissions, and schema-driven React form UI
55
55
  - **[App Objects: Cases, Threads & Records](app-objects.md)** - Generic app-scoped building blocks for support cases, discussions, bookings, registrations, and more
56
56
  - **[App Records Pattern](app-records-pattern.md)** - Canonical pattern for storing per-product, per-facet, or rule-targeted app data
57
+ - **[Sequences & Claim-Order](sequences.md)** - Allocate a guaranteed-unique, monotonic number (raffle tickets, "Nth to claim", queue positions) and stamp it onto a record — atomic app-config counter + idempotent per-subject stamping, concurrency-safe at stadium scale
57
58
  - **[Communications](comms.md)** - Transactional sends, multi-channel broadcasts, consent management, push registration, and analytics
58
59
  - **[Interactions & Event Tracking](interactions.md)** - Log user events, count outcomes, query history, and define interaction types with permissions
59
60
  - **[Analytics](analytics.md)** - Web analytics, link-click tracking, QR/tag scan telemetry, and event reporting
@@ -0,0 +1,91 @@
1
+ # Sequences & claim-order allocation
2
+
3
+ > **Preview — SmartLinks SDK 2.0.0-alpha.** APIs may change before 2.0.0 stable.
4
+
5
+ A **sequence** hands out a guaranteed-unique, monotonic number — `1, 2, 3, …` — and stamps it
6
+ onto a record. It's the primitive behind raffle tickets, "you're the Nth to claim", queue
7
+ positions, and limited-edition numbering: cases where you need *the next number*, exactly
8
+ once per subject, even with a whole room (or stadium) acting at the same instant.
9
+
10
+ ## The model: allocate, then stamp — and the target is the ledger
11
+
12
+ Two steps, one call:
13
+
14
+ 1. **Allocate** — get the next number from an **atomic counter**. The counter lives inside
15
+ your **app-config** doc at `data.sequences.<key>`, so it's scoped exactly like your other
16
+ app config (per collection / product / variant / batch) and needs no dedicated storage.
17
+ It's incremented in a single statement, so 250 simultaneous taps each get a distinct
18
+ number in microseconds — never two the same.
19
+ 2. **Stamp** — write that number onto the **subject's own record** (a claim set, a proof, or
20
+ an app record). **That record is the ledger** — there's no separate bookkeeping table.
21
+ Next time you read the subject, the number is just there.
22
+
23
+ Because the target is the ledger, allocation is **idempotent**: on a re-tap we read the
24
+ subject first and return the number it already has, rather than allocating a second one.
25
+
26
+ ## Guarantees
27
+
28
+ - **Unique + monotonic** — the counter is an atomic increment, never a read-modify-write, so
29
+ there are no duplicates and no lost updates under load.
30
+ - **Idempotent per subject** — one number per subject; a re-tap returns the same number.
31
+ - **Concurrency-safe at scale** — the only shared hot spot is the one counter row (Postgres
32
+ serializes it); the stamp is per-subject (its own record), so the model holds from 250 in a
33
+ room to 60,000 in a stadium. A concurrent double-tap on the *same* subject at worst skips
34
+ one number (a harmless gap) — never puts two numbers on one person.
35
+
36
+ ## Scoping
37
+
38
+ - **Counter scope** — the app-config doc it lives on: collection-wide, or per product /
39
+ variant / batch. All wristbands mapped to one product? Scope the counter to that product.
40
+ - **`key`** — a name within that doc (e.g. `raffle:2026-cup`), so one config doc can hold
41
+ several independent sequences.
42
+ - **`start`** — the first number (default `1`); use it to reserve a block (start at `51` and
43
+ tell people it's `1`, or just filter `< N` at draw time).
44
+
45
+ ## Idempotency subject — use a *stable* id
46
+
47
+ The number is deduped by the **subject id** you pass, so it must be the **stable** identity:
48
+ - **Claim set id** (the wristband's permanent record) — the right key when people aren't
49
+ logged in. A re-tap resolves to the same claim set → same number.
50
+ - The authenticated **user/contact** — if they sign in / claim.
51
+
52
+ Do **not** key on a value that changes per interaction (e.g. a virtual proof id minted fresh
53
+ on each tap) — that would let one person take several numbers.
54
+
55
+ ## Where the number is stored (the sink)
56
+
57
+ The stamp target is configurable — the number lives wherever you'll read it:
58
+
59
+ | Target | Use |
60
+ |---|---|
61
+ | `claimSet` | The Firestore wristband record — fast, no proof mint on the hot path. |
62
+ | `proof` | A minted proof (value or attestation) — when the number should travel with the proof. |
63
+ | `appRecord` | A structured app record — for queryable, per-app data. |
64
+
65
+ ## Worked example — a free raffle on NFC wristbands
66
+
67
+ Everyone taps a wristband and hits **Enter the raffle**. Each tap allocates the next number
68
+ and writes it onto that wristband's claim set — fast, unique, no proof mint:
69
+
70
+ ```jsonc
71
+ // allocate-and-stamp (conceptual shape)
72
+ {
73
+ "appId": "raffle-app",
74
+ "productId": "wristbands-2026", // the counter's scope
75
+ "key": "raffle:2026-cup", // the named sequence
76
+ "start": 1,
77
+ "subjectId": "<claim set id>", // STABLE identity — re-taps collapse to one number
78
+ "target": "claimSet",
79
+ "field": "raffleNumber"
80
+ }
81
+ // → { "number": 42, "isNew": true } (re-tap → { "number": 42, "isNew": false })
82
+ ```
83
+
84
+ Drawing the winner needs no separate ledger either — query the claim sets (or proofs) where
85
+ `raffleNumber` is set; that field is your entry list, in allocation order.
86
+
87
+ ## Status
88
+
89
+ The allocator + stamping run server-side today. The **public "enter" action** an app widget
90
+ calls on tap (and its SDK wrapper) is being wired in the 2.0.0-alpha line — this doc is the
91
+ contract it will expose.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@proveanything/smartlinks",
3
- "version": "2.0.0-alpha.2",
3
+ "version": "2.0.0-alpha.3",
4
4
  "description": "Official JavaScript/TypeScript SDK for the Smartlinks API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",