@hypercerts-org/lexicon 0.10.0 → 0.11.1
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/CHANGELOG.md +218 -0
- package/README.md +392 -393
- package/SCHEMAS.md +539 -81
- package/dist/exports.d.ts +900 -10
- package/dist/exports.d.ts.map +1 -1
- package/dist/generated/exports.d.ts +900 -10
- package/dist/generated/exports.d.ts.map +1 -1
- package/dist/generated/lexicons.d.ts +2684 -1094
- package/dist/generated/lexicons.d.ts.map +1 -1
- package/dist/generated/types/app/bsky/richtext/facet.d.ts +44 -7
- package/dist/generated/types/app/bsky/richtext/facet.d.ts.map +1 -1
- package/dist/generated/types/app/certified/badge/award.d.ts +2 -3
- package/dist/generated/types/app/certified/badge/award.d.ts.map +1 -1
- package/dist/generated/types/app/certified/badge/definition.d.ts +3 -3
- package/dist/generated/types/app/certified/badge/definition.d.ts.map +1 -1
- package/dist/generated/types/app/certified/badge/response.d.ts +2 -2
- package/dist/generated/types/app/certified/badge/response.d.ts.map +1 -1
- package/dist/generated/types/app/certified/link/evm.d.ts +45 -0
- package/dist/generated/types/app/certified/link/evm.d.ts.map +1 -0
- package/dist/generated/types/org/hypercerts/claim/activity.d.ts +6 -3
- package/dist/generated/types/org/hypercerts/claim/activity.d.ts.map +1 -1
- package/dist/generated/types/org/hypercerts/collection.d.ts +11 -5
- package/dist/generated/types/org/hypercerts/collection.d.ts.map +1 -1
- package/dist/generated/types/org/hypercerts/context/attachment.d.ts +5 -3
- package/dist/generated/types/org/hypercerts/context/attachment.d.ts.map +1 -1
- package/dist/generated/types/org/hypercerts/context/evaluation.d.ts +6 -6
- package/dist/generated/types/org/hypercerts/context/evaluation.d.ts.map +1 -1
- package/dist/generated/types/org/hypercerts/defs.d.ts +11 -0
- package/dist/generated/types/org/hypercerts/defs.d.ts.map +1 -1
- package/dist/generated/types/org/hypercerts/funding/receipt.d.ts +17 -5
- package/dist/generated/types/org/hypercerts/funding/receipt.d.ts.map +1 -1
- package/dist/generated/types/pub/leaflet/blocks/blockquote.d.ts +13 -0
- package/dist/generated/types/pub/leaflet/blocks/blockquote.d.ts.map +1 -0
- package/dist/generated/types/pub/leaflet/blocks/bskyPost.d.ts +13 -0
- package/dist/generated/types/pub/leaflet/blocks/bskyPost.d.ts.map +1 -0
- package/dist/generated/types/pub/leaflet/blocks/button.d.ts +12 -0
- package/dist/generated/types/pub/leaflet/blocks/button.d.ts.map +1 -0
- package/dist/generated/types/pub/leaflet/blocks/code.d.ts +13 -0
- package/dist/generated/types/pub/leaflet/blocks/code.d.ts.map +1 -0
- package/dist/generated/types/pub/leaflet/blocks/header.d.ts +14 -0
- package/dist/generated/types/pub/leaflet/blocks/header.d.ts.map +1 -0
- package/dist/generated/types/pub/leaflet/blocks/horizontalRule.d.ts +10 -0
- package/dist/generated/types/pub/leaflet/blocks/horizontalRule.d.ts.map +1 -0
- package/dist/generated/types/pub/leaflet/blocks/iframe.d.ts +12 -0
- package/dist/generated/types/pub/leaflet/blocks/iframe.d.ts.map +1 -0
- package/dist/generated/types/pub/leaflet/blocks/image.d.ts +21 -0
- package/dist/generated/types/pub/leaflet/blocks/image.d.ts.map +1 -0
- package/dist/generated/types/pub/leaflet/blocks/math.d.ts +11 -0
- package/dist/generated/types/pub/leaflet/blocks/math.d.ts.map +1 -0
- package/dist/generated/types/pub/leaflet/blocks/orderedList.d.ts +31 -0
- package/dist/generated/types/pub/leaflet/blocks/orderedList.d.ts.map +1 -0
- package/dist/generated/types/pub/leaflet/blocks/page.d.ts +11 -0
- package/dist/generated/types/pub/leaflet/blocks/page.d.ts.map +1 -0
- package/dist/generated/types/pub/leaflet/blocks/poll.d.ts +12 -0
- package/dist/generated/types/pub/leaflet/blocks/poll.d.ts.map +1 -0
- package/dist/generated/types/pub/leaflet/blocks/text.d.ts +14 -0
- package/dist/generated/types/pub/leaflet/blocks/text.d.ts.map +1 -0
- package/dist/generated/types/pub/leaflet/blocks/unorderedList.d.ts +29 -0
- package/dist/generated/types/pub/leaflet/blocks/unorderedList.d.ts.map +1 -0
- package/dist/generated/types/pub/leaflet/blocks/website.d.ts +14 -0
- package/dist/generated/types/pub/leaflet/blocks/website.d.ts.map +1 -0
- package/dist/generated/types/pub/leaflet/pages/linearDocument.d.ts +54 -1
- package/dist/generated/types/pub/leaflet/pages/linearDocument.d.ts.map +1 -1
- package/dist/generated/types/pub/leaflet/richtext/facet.d.ts +97 -0
- package/dist/generated/types/pub/leaflet/richtext/facet.d.ts.map +1 -0
- package/dist/index.cjs +4487 -1808
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +4408 -1805
- package/dist/index.mjs.map +1 -1
- package/dist/lexicons.cjs +928 -36
- package/dist/lexicons.cjs.map +1 -1
- package/dist/lexicons.d.ts +2684 -1094
- package/dist/lexicons.d.ts.map +1 -1
- package/dist/lexicons.mjs +928 -36
- package/dist/lexicons.mjs.map +1 -1
- package/dist/types/app/bsky/richtext/facet.d.ts +44 -7
- package/dist/types/app/bsky/richtext/facet.d.ts.map +1 -1
- package/dist/types/app/certified/badge/award.d.ts +2 -3
- package/dist/types/app/certified/badge/award.d.ts.map +1 -1
- package/dist/types/app/certified/badge/definition.d.ts +3 -3
- package/dist/types/app/certified/badge/definition.d.ts.map +1 -1
- package/dist/types/app/certified/badge/response.d.ts +2 -2
- package/dist/types/app/certified/badge/response.d.ts.map +1 -1
- package/dist/types/app/certified/link/evm.d.ts +45 -0
- package/dist/types/app/certified/link/evm.d.ts.map +1 -0
- package/dist/types/org/hypercerts/claim/activity.d.ts +6 -3
- package/dist/types/org/hypercerts/claim/activity.d.ts.map +1 -1
- package/dist/types/org/hypercerts/collection.d.ts +11 -5
- package/dist/types/org/hypercerts/collection.d.ts.map +1 -1
- package/dist/types/org/hypercerts/context/attachment.d.ts +5 -3
- package/dist/types/org/hypercerts/context/attachment.d.ts.map +1 -1
- package/dist/types/org/hypercerts/context/evaluation.d.ts +6 -6
- package/dist/types/org/hypercerts/context/evaluation.d.ts.map +1 -1
- package/dist/types/org/hypercerts/defs.d.ts +11 -0
- package/dist/types/org/hypercerts/defs.d.ts.map +1 -1
- package/dist/types/org/hypercerts/funding/receipt.d.ts +17 -5
- package/dist/types/org/hypercerts/funding/receipt.d.ts.map +1 -1
- package/dist/types/pub/leaflet/blocks/blockquote.d.ts +13 -0
- package/dist/types/pub/leaflet/blocks/blockquote.d.ts.map +1 -0
- package/dist/types/pub/leaflet/blocks/bskyPost.d.ts +13 -0
- package/dist/types/pub/leaflet/blocks/bskyPost.d.ts.map +1 -0
- package/dist/types/pub/leaflet/blocks/button.d.ts +12 -0
- package/dist/types/pub/leaflet/blocks/button.d.ts.map +1 -0
- package/dist/types/pub/leaflet/blocks/code.d.ts +13 -0
- package/dist/types/pub/leaflet/blocks/code.d.ts.map +1 -0
- package/dist/types/pub/leaflet/blocks/header.d.ts +14 -0
- package/dist/types/pub/leaflet/blocks/header.d.ts.map +1 -0
- package/dist/types/pub/leaflet/blocks/horizontalRule.d.ts +10 -0
- package/dist/types/pub/leaflet/blocks/horizontalRule.d.ts.map +1 -0
- package/dist/types/pub/leaflet/blocks/iframe.d.ts +12 -0
- package/dist/types/pub/leaflet/blocks/iframe.d.ts.map +1 -0
- package/dist/types/pub/leaflet/blocks/image.d.ts +21 -0
- package/dist/types/pub/leaflet/blocks/image.d.ts.map +1 -0
- package/dist/types/pub/leaflet/blocks/math.d.ts +11 -0
- package/dist/types/pub/leaflet/blocks/math.d.ts.map +1 -0
- package/dist/types/pub/leaflet/blocks/orderedList.d.ts +31 -0
- package/dist/types/pub/leaflet/blocks/orderedList.d.ts.map +1 -0
- package/dist/types/pub/leaflet/blocks/page.d.ts +11 -0
- package/dist/types/pub/leaflet/blocks/page.d.ts.map +1 -0
- package/dist/types/pub/leaflet/blocks/poll.d.ts +12 -0
- package/dist/types/pub/leaflet/blocks/poll.d.ts.map +1 -0
- package/dist/types/pub/leaflet/blocks/text.d.ts +14 -0
- package/dist/types/pub/leaflet/blocks/text.d.ts.map +1 -0
- package/dist/types/pub/leaflet/blocks/unorderedList.d.ts +29 -0
- package/dist/types/pub/leaflet/blocks/unorderedList.d.ts.map +1 -0
- package/dist/types/pub/leaflet/blocks/website.d.ts +14 -0
- package/dist/types/pub/leaflet/blocks/website.d.ts.map +1 -0
- package/dist/types/pub/leaflet/pages/linearDocument.d.ts +54 -1
- package/dist/types/pub/leaflet/pages/linearDocument.d.ts.map +1 -1
- package/dist/types/pub/leaflet/richtext/facet.d.ts +97 -0
- package/dist/types/pub/leaflet/richtext/facet.d.ts.map +1 -0
- package/lexicons/app/bsky/richtext/facet.json +51 -0
- package/lexicons/app/certified/badge/award.json +2 -2
- package/lexicons/app/certified/badge/definition.json +10 -2
- package/lexicons/app/certified/badge/response.json +2 -2
- package/lexicons/app/certified/link/evm.json +88 -0
- package/lexicons/org/hyperboards/board.json +1 -1
- package/lexicons/org/hypercerts/claim/activity.json +8 -4
- package/lexicons/org/hypercerts/collection.json +19 -5
- package/lexicons/org/hypercerts/context/attachment.json +16 -5
- package/lexicons/org/hypercerts/context/evaluation.json +9 -6
- package/lexicons/org/hypercerts/defs.json +21 -0
- package/lexicons/org/hypercerts/funding/receipt.json +30 -10
- package/lexicons/pub/leaflet/blocks/blockquote.json +22 -0
- package/lexicons/pub/leaflet/blocks/bskyPost.json +19 -0
- package/lexicons/pub/leaflet/blocks/button.json +19 -0
- package/lexicons/pub/leaflet/blocks/code.json +21 -0
- package/lexicons/pub/leaflet/blocks/header.json +27 -0
- package/lexicons/pub/leaflet/blocks/horizontalRule.json +11 -0
- package/lexicons/pub/leaflet/blocks/iframe.json +21 -0
- package/lexicons/pub/leaflet/blocks/image.json +37 -0
- package/lexicons/pub/leaflet/blocks/math.json +15 -0
- package/lexicons/pub/leaflet/blocks/orderedList.json +54 -0
- package/lexicons/pub/leaflet/blocks/page.json +15 -0
- package/lexicons/pub/leaflet/blocks/poll.json +16 -0
- package/lexicons/pub/leaflet/blocks/text.json +26 -0
- package/lexicons/pub/leaflet/blocks/unorderedList.json +50 -0
- package/lexicons/pub/leaflet/blocks/website.json +27 -0
- package/lexicons/pub/leaflet/pages/linearDocument.json +98 -0
- package/lexicons/pub/leaflet/richtext/facet.json +149 -0
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -1,39 +1,181 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
Hypercerts protocol
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
# @hypercerts-org/lexicon
|
|
2
|
+
|
|
3
|
+
ATProto lexicon definitions and TypeScript types for the
|
|
4
|
+
[Hypercerts](https://hypercerts.org) protocol — a system for tracking,
|
|
5
|
+
evaluating, and funding impact work on the
|
|
6
|
+
[AT Protocol](https://atproto.com) network.
|
|
7
|
+
|
|
8
|
+
## Lexicon Map
|
|
9
|
+
|
|
10
|
+
```text
|
|
11
|
+
CLAIMS ─ the core impact record and its parts
|
|
12
|
+
──────────────────────────────────────────────────────────────────────
|
|
13
|
+
activity ──────────┬──► collection ◄──┐ (recursive nesting)
|
|
14
|
+
(the hypercert) │ │ │
|
|
15
|
+
│ ▼ │
|
|
16
|
+
├──► contribution (role, timeframe)
|
|
17
|
+
├──► contributorInformation (identity, image)
|
|
18
|
+
├──► rights (licensing terms)
|
|
19
|
+
└──► workScope
|
|
20
|
+
├── cel ───► tag (CEL expression referencing tags)
|
|
21
|
+
└── string (free-form scope)
|
|
22
|
+
|
|
23
|
+
CONTEXT ─ evidence, data, and social verification
|
|
24
|
+
──────────────────────────────────────────────────────────────────────
|
|
25
|
+
attachment ─────────────► any record (activity, evaluation, …)
|
|
26
|
+
measurement ────────────► any record (activity, …)
|
|
27
|
+
evaluation ─────────────► any record (activity, measurement, …)
|
|
28
|
+
└──────► measurement
|
|
29
|
+
acknowledgement ────────► any record (bidirectional link)
|
|
30
|
+
|
|
31
|
+
FUNDING ─ payment records
|
|
32
|
+
──────────────────────────────────────────────────────────────────────
|
|
33
|
+
receipt ────────────────► activity (from funder → to recipient)
|
|
34
|
+
|
|
35
|
+
HYPERBOARDS ─ visual display layer (hyperboards.org)
|
|
36
|
+
──────────────────────────────────────────────────────────────────────
|
|
37
|
+
board ──────────────────► activity / collection
|
|
38
|
+
└── contributorConfig ► contributorInformation
|
|
39
|
+
displayProfile (per-user visual defaults)
|
|
40
|
+
|
|
41
|
+
CERTIFIED ─ shared lexicons (certified.app)
|
|
42
|
+
──────────────────────────────────────────────────────────────────────
|
|
43
|
+
location (geo coordinates, GeoJSON, H3, …)
|
|
44
|
+
link/evm (ATProto DID ↔ EVM wallet link)
|
|
45
|
+
actor/profile (user profile)
|
|
46
|
+
actor/organization (org metadata)
|
|
47
|
+
badge/response ──► badge/award ──► badge/definition
|
|
48
|
+
```
|
|
8
49
|
|
|
9
|
-
|
|
50
|
+
Every arrow (`►`) is a `strongRef` or union reference stored on the
|
|
51
|
+
AT Protocol network. Full field-level documentation is in
|
|
52
|
+
[SCHEMAS.md](SCHEMAS.md).
|
|
10
53
|
|
|
11
|
-
|
|
12
|
-
sets relating to hypercerts
|
|
54
|
+
## Consuming These Lexicons
|
|
13
55
|
|
|
14
|
-
|
|
15
|
-
|
|
56
|
+
If you are building a downstream application on top of these lexicons,
|
|
57
|
+
we strongly recommend **NOT** reading from `main` or other development
|
|
58
|
+
branches of the repository, but instead via the following published
|
|
59
|
+
releases:
|
|
16
60
|
|
|
17
|
-
-
|
|
18
|
-
|
|
61
|
+
- **For TypeScript / JavaScript code** — use [the npm package
|
|
62
|
+
`@hypercerts-org/lexicon`](https://www.npmjs.com/package/@hypercerts-org/lexicon),
|
|
63
|
+
which includes generated types, validation helpers, and schema
|
|
64
|
+
constants.
|
|
65
|
+
- **For other languages** — use the [tagged
|
|
66
|
+
releases](https://github.com/hypercerts-org/hypercerts-lexicon/releases)
|
|
67
|
+
published in this GitHub repository.
|
|
19
68
|
|
|
20
|
-
|
|
69
|
+
Both npm releases and git tags follow [SemVer](https://semver.org/).
|
|
70
|
+
For npm, you can depend on a version range to receive compatible
|
|
71
|
+
updates automatically. For GitHub releases/tags, pin a specific tag
|
|
72
|
+
or upgrade manually to a newer compatible SemVer release.
|
|
21
73
|
|
|
22
|
-
|
|
23
|
-
|
|
74
|
+
The raw lexicons published on ATProto can also be used, but they are
|
|
75
|
+
(unavoidably) missing useful context such as full documentation
|
|
76
|
+
(including changelogs), TypeScript type definitions, SemVer
|
|
77
|
+
guarantees, git history, and other tooling provided by the packaged
|
|
78
|
+
releases.
|
|
24
79
|
|
|
25
|
-
|
|
26
|
-
- "E" means "entity"
|
|
27
|
-
- "P" means "protocol"
|
|
80
|
+
### AI Agent Skill
|
|
28
81
|
|
|
29
|
-
|
|
82
|
+
If you use AI coding assistants (e.g. Claude Code, OpenCode), you can
|
|
83
|
+
install a skill that teaches your agent how to build with these
|
|
84
|
+
lexicons:
|
|
30
85
|
|
|
31
|
-
|
|
32
|
-
|
|
86
|
+
```bash
|
|
87
|
+
npx skills add hypercerts-org/hypercerts-lexicon
|
|
88
|
+
```
|
|
33
89
|
|
|
34
|
-
|
|
90
|
+
This installs the
|
|
91
|
+
[`building-with-hypercerts-lexicons`](.agents/skills/building-with-hypercerts-lexicons/SKILL.md)
|
|
92
|
+
skill, which provides your agent with guidance on package entry points,
|
|
93
|
+
TypeScript types, validation, all lexicon schemas, code examples, and
|
|
94
|
+
AT Protocol conventions.
|
|
95
|
+
|
|
96
|
+
## Maintenance and publishing releases
|
|
97
|
+
|
|
98
|
+
Clearly stability and predictability for users and developers are
|
|
99
|
+
essential.
|
|
100
|
+
|
|
101
|
+
Unfortunately AT Protocol doesn't support any kind of native
|
|
102
|
+
versioning or migrations which could support lexicon schema changes.
|
|
103
|
+
Instead, the AT Protocol community recommends minimising changes to
|
|
104
|
+
lexicons in general, and to avoid breaking changes wherever possible:
|
|
105
|
+
|
|
106
|
+
- https://atproto.com/guides/lexicon-style-guide
|
|
107
|
+
- https://www.pfrazee.com/blog/lexicon-guidance
|
|
108
|
+
|
|
109
|
+
This project intends to follow that guidance as much as possible
|
|
110
|
+
whilst retaining a pragmatic approach. In practice that means:
|
|
111
|
+
|
|
112
|
+
- Changes to other tooling within this repository which _do not touch
|
|
113
|
+
lexicons_ may be made at any time as long as they follow
|
|
114
|
+
[SemVer](https://semver.org/) to avoid negative impact on
|
|
115
|
+
developers.
|
|
116
|
+
|
|
117
|
+
- Non-breaking changes to lexicons, such as adding an optional
|
|
118
|
+
property or updating a `description`, may be made sparingly. While
|
|
119
|
+
these changes are backwards-compatible at the protocol level, they
|
|
120
|
+
may still require consuming applications and indexers to update
|
|
121
|
+
their schemas for consistent UX.
|
|
122
|
+
|
|
123
|
+
- Breaking changes to lexicons will only be made in exceptional
|
|
124
|
+
circumstances. Specifically, a breaking change will only proceed
|
|
125
|
+
**if and only if**:
|
|
126
|
+
- the broader community — not just the Hypercerts core team —
|
|
127
|
+
agrees that the benefits clearly outweigh the cost of the
|
|
128
|
+
breakage, **and**
|
|
129
|
+
- full consideration is given to all affected parties across the
|
|
130
|
+
community and wider ecosystem, not only those involved in the
|
|
131
|
+
decision, **and**
|
|
132
|
+
- no viable alternative exists, such as releasing a new `.v2`
|
|
133
|
+
version of the lexicon or introducing a `v2` field.
|
|
134
|
+
|
|
135
|
+
To date, breaking changes have only occurred during the early
|
|
136
|
+
stages of launching Hypercerts on AT Protocol, before external
|
|
137
|
+
consumers were building against the lexicons. We intend to keep
|
|
138
|
+
it that way.
|
|
139
|
+
|
|
140
|
+
It is also worth noting that members of the ATProto community have
|
|
141
|
+
been working on tooling to make these problems easier to deal with in
|
|
142
|
+
future, e.g. see https://panproto.dev/
|
|
143
|
+
|
|
144
|
+
## Use of branches
|
|
145
|
+
|
|
146
|
+
`main` is the only evergreen branch and the default branch on GitHub.
|
|
147
|
+
We aim to minimise deviations between `main` and versions published on
|
|
148
|
+
npm and ATProto. However the publishing processes involve several
|
|
149
|
+
moving parts (including third-party systems), and it is technically
|
|
150
|
+
impossible to update all three at the same time. So **please do not
|
|
151
|
+
assume they will always be perfectly in sync**.
|
|
152
|
+
|
|
153
|
+
See [docs/PUBLISHING.md](docs/PUBLISHING.md) for the full release workflow.
|
|
154
|
+
|
|
155
|
+
> If you see a `develop` branch, it is a stale leftover from a
|
|
156
|
+
> previous workflow and is no longer used; do not open pull requests
|
|
157
|
+
> against it.
|
|
158
|
+
|
|
159
|
+
## Contributing / development
|
|
160
|
+
|
|
161
|
+
Please see [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
162
|
+
|
|
163
|
+
### Project Structure
|
|
164
|
+
|
|
165
|
+
```text
|
|
166
|
+
lexicons/ Source of truth (committed)
|
|
167
|
+
org/hypercerts/ Hypercerts protocol lexicons
|
|
168
|
+
org/hyperboards/ Hyperboards visual layer lexicons
|
|
169
|
+
app/certified/ Shared/certified lexicons
|
|
170
|
+
com/atproto/ ATProto external references
|
|
171
|
+
|
|
172
|
+
generated/ Auto-generated TypeScript (gitignored)
|
|
173
|
+
dist/ Built bundles (gitignored)
|
|
174
|
+
scripts/ Build and codegen scripts
|
|
175
|
+
```
|
|
35
176
|
|
|
36
|
-
|
|
177
|
+
> **Never edit `generated/` or `dist/` directly** — they are
|
|
178
|
+
> regenerated from lexicon JSON files.
|
|
37
179
|
|
|
38
180
|
## Installation
|
|
39
181
|
|
|
@@ -41,9 +183,7 @@ following icons:
|
|
|
41
183
|
npm install @hypercerts-org/lexicon
|
|
42
184
|
```
|
|
43
185
|
|
|
44
|
-
##
|
|
45
|
-
|
|
46
|
-
### Basic Import
|
|
186
|
+
## Quick Start
|
|
47
187
|
|
|
48
188
|
```typescript
|
|
49
189
|
import {
|
|
@@ -51,8 +191,6 @@ import {
|
|
|
51
191
|
ACTIVITY_NSID,
|
|
52
192
|
validate,
|
|
53
193
|
} from "@hypercerts-org/lexicon";
|
|
54
|
-
|
|
55
|
-
// Use with AT Protocol Agent
|
|
56
194
|
import { Agent } from "@atproto/api";
|
|
57
195
|
|
|
58
196
|
const agent = new Agent({ service: "https://bsky.social" });
|
|
@@ -60,222 +198,155 @@ const agent = new Agent({ service: "https://bsky.social" });
|
|
|
60
198
|
// Register lexicons with the agent
|
|
61
199
|
agent.api.lex.add(...HYPERCERTS_SCHEMAS);
|
|
62
200
|
|
|
63
|
-
//
|
|
64
|
-
const
|
|
201
|
+
// Build a record
|
|
202
|
+
const record = {
|
|
65
203
|
$type: ACTIVITY_NSID,
|
|
66
|
-
title: "
|
|
67
|
-
shortDescription: "
|
|
68
|
-
// workScope can be a CEL expression (structured, machine-evaluable):
|
|
69
|
-
workScope: {
|
|
70
|
-
$type: "org.hypercerts.workscope.cel",
|
|
71
|
-
expression:
|
|
72
|
-
"scope.hasAll(['mangrove_restoration', 'environmental_education']) && location.country == 'KE'",
|
|
73
|
-
usedTags: [
|
|
74
|
-
{
|
|
75
|
-
uri: "at://did:plc:alice/org.hypercerts.workscope.tag/3k2abc",
|
|
76
|
-
cid: "...",
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
uri: "at://did:plc:alice/org.hypercerts.workscope.tag/7x9def",
|
|
80
|
-
cid: "...",
|
|
81
|
-
},
|
|
82
|
-
],
|
|
83
|
-
version: "v1",
|
|
84
|
-
createdAt: new Date().toISOString(),
|
|
85
|
-
},
|
|
86
|
-
// OR a strongRef to a single work scope tag:
|
|
87
|
-
// workScope: { uri: "at://did:plc:alice/org.hypercerts.workscope.tag/abc123", cid: "..." },
|
|
88
|
-
// OR a simple string: workScope: { $type: "org.hypercerts.claim.activity#workScopeString", scope: "Environmental conservation" },
|
|
89
|
-
startDate: "2023-01-01T00:00:00Z",
|
|
90
|
-
endDate: "2023-12-31T23:59:59Z",
|
|
204
|
+
title: "Reforestation in Amazon Basin 2024",
|
|
205
|
+
shortDescription: "Planted 5,000 native trees across 12 hectares",
|
|
91
206
|
createdAt: new Date().toISOString(),
|
|
92
207
|
};
|
|
93
208
|
|
|
94
|
-
// Validate before
|
|
95
|
-
const
|
|
96
|
-
if (!
|
|
97
|
-
console.error("Validation failed:", validation.errors);
|
|
98
|
-
}
|
|
209
|
+
// Validate before writing
|
|
210
|
+
const result = validate(record, ACTIVITY_NSID, "main");
|
|
211
|
+
if (!result.success) throw new Error(String(result.error));
|
|
99
212
|
|
|
213
|
+
// Write to the network
|
|
100
214
|
await agent.api.com.atproto.repo.createRecord({
|
|
101
215
|
repo: agent.session?.did,
|
|
102
216
|
collection: ACTIVITY_NSID,
|
|
103
|
-
record
|
|
217
|
+
record,
|
|
104
218
|
});
|
|
105
219
|
```
|
|
106
220
|
|
|
107
|
-
|
|
221
|
+
## Lexicon Reference
|
|
108
222
|
|
|
109
|
-
|
|
110
|
-
using geographic coordinates or other location formats. They can be referenced
|
|
111
|
-
by activities, collections, attachments, measurements, and evaluations.
|
|
223
|
+
### Claims (`org.hypercerts.claim.*`)
|
|
112
224
|
|
|
113
|
-
|
|
114
|
-
|
|
225
|
+
| Lexicon | NSID | Description |
|
|
226
|
+
| --------------------------- | --------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
|
|
227
|
+
| **Activity** | `org.hypercerts.claim.activity` | The main hypercert record — describes impact work with title, description, contributors, work scope, timeframe, locations, and rights. |
|
|
228
|
+
| **Contribution** | `org.hypercerts.claim.contribution` | Details about a specific contribution: role, description, and timeframe. |
|
|
229
|
+
| **Contributor Information** | `org.hypercerts.claim.contributorInformation` | Identity record for a contributor: identifier (DID or URI), display name, and image. |
|
|
230
|
+
| **Rights** | `org.hypercerts.claim.rights` | Licensing and rights terms (e.g. "CC BY-SA 4.0") attached to an activity. |
|
|
115
231
|
|
|
116
|
-
|
|
117
|
-
$type: LOCATION_NSID,
|
|
118
|
-
lpVersion: "1.0", // Location Protocol version
|
|
119
|
-
srs: "http://www.opengis.net/def/crs/OGC/1.3/CRS84", // Spatial Reference System
|
|
120
|
-
locationType: "coordinate-decimal", // or "geojson-point", "geojson", "h3", "geohash", "wkt", "address", etc.
|
|
121
|
-
location: {
|
|
122
|
-
uri: "https://example.com/location-data.geojson",
|
|
123
|
-
},
|
|
124
|
-
// Optional fields
|
|
125
|
-
name: "Project Site A",
|
|
126
|
-
description: "Primary research facility in the Amazon rainforest",
|
|
127
|
-
createdAt: new Date().toISOString(),
|
|
128
|
-
};
|
|
129
|
-
```
|
|
232
|
+
### Collections (`org.hypercerts.*`)
|
|
130
233
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
- `location` (required): Location data as URI, blob, or string
|
|
135
|
-
- `name` (optional): Human-readable name for the location
|
|
136
|
-
- `description` (optional): Additional context about the location
|
|
137
|
-
- `createdAt` (required): Timestamp when the record was created
|
|
234
|
+
| Lexicon | NSID | Description |
|
|
235
|
+
| -------------- | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
236
|
+
| **Collection** | `org.hypercerts.collection` | A named, weighted group of activities and/or other collections. Supports recursive nesting. Used for projects, portfolios, favourites, funding rounds, etc. |
|
|
138
237
|
|
|
139
|
-
|
|
238
|
+
### Context (`org.hypercerts.context.*`)
|
|
140
239
|
|
|
141
|
-
|
|
240
|
+
| Lexicon | NSID | Description |
|
|
241
|
+
| ------------------- | ---------------------------------------- | --------------------------------------------------------------------------------------- |
|
|
242
|
+
| **Attachment** | `org.hypercerts.context.attachment` | Documents, reports, evidence, or other files linked to a record. |
|
|
243
|
+
| **Measurement** | `org.hypercerts.context.measurement` | Quantitative data point (metric + unit + value) linked to one or more records. |
|
|
244
|
+
| **Evaluation** | `org.hypercerts.context.evaluation` | An assessment of a record with evaluators, summary, score, and supporting measurements. |
|
|
245
|
+
| **Acknowledgement** | `org.hypercerts.context.acknowledgement` | Bidirectional link: confirms or rejects inclusion of a record in another context. |
|
|
142
246
|
|
|
143
|
-
|
|
144
|
-
2. **Small blob**: Embedded location data (up to 10MB)
|
|
145
|
-
3. **Location string**: Inline string wrapped in an object, containing coordinates or GeoJSON
|
|
247
|
+
### Work Scope (`org.hypercerts.workscope.*`)
|
|
146
248
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
lpVersion: "1.0",
|
|
152
|
-
srs: "http://www.opengis.net/def/crs/OGC/1.3/CRS84",
|
|
153
|
-
locationType: "geojson-point",
|
|
154
|
-
location: {
|
|
155
|
-
blob: {
|
|
156
|
-
$type: "blob",
|
|
157
|
-
ref: {
|
|
158
|
-
$link: "bafyrei...", // CID of the uploaded blob
|
|
159
|
-
},
|
|
160
|
-
mimeType: "application/geo+json",
|
|
161
|
-
size: 123,
|
|
162
|
-
},
|
|
163
|
-
},
|
|
164
|
-
name: "Amazon Research Station",
|
|
165
|
-
createdAt: new Date().toISOString(),
|
|
166
|
-
};
|
|
249
|
+
| Lexicon | NSID | Description |
|
|
250
|
+
| ------------------ | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------- |
|
|
251
|
+
| **Tag** | `org.hypercerts.workscope.tag` | Reusable scope atom (topic, domain, method, …) with taxonomy support, aliases, and linked ontologies. |
|
|
252
|
+
| **CEL Expression** | `org.hypercerts.workscope.cel` | Structured work scope using [CEL](https://github.com/google/cel-spec) expressions over tags. Embedded inline in activity records. |
|
|
167
253
|
|
|
168
|
-
|
|
169
|
-
const locationWithCoordinates = {
|
|
170
|
-
$type: LOCATION_NSID,
|
|
171
|
-
lpVersion: "1.0",
|
|
172
|
-
srs: "http://www.opengis.net/def/crs/OGC/1.3/CRS84",
|
|
173
|
-
locationType: "coordinate-decimal",
|
|
174
|
-
location: {
|
|
175
|
-
string: "-3.4653, -62.2159", // lat, lon
|
|
176
|
-
},
|
|
177
|
-
name: "Amazon Research Site",
|
|
178
|
-
description: "Field station coordinates",
|
|
179
|
-
createdAt: new Date().toISOString(),
|
|
180
|
-
};
|
|
254
|
+
### Funding (`org.hypercerts.funding.*`)
|
|
181
255
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
lpVersion: "1.0",
|
|
186
|
-
srs: "http://www.opengis.net/def/crs/OGC/1.3/CRS84",
|
|
187
|
-
locationType: "geojson-point",
|
|
188
|
-
location: {
|
|
189
|
-
string: '{"type":"Point","coordinates":[-62.2159,-3.4653]}',
|
|
190
|
-
},
|
|
191
|
-
name: "Research Station Alpha",
|
|
192
|
-
createdAt: new Date().toISOString(),
|
|
193
|
-
};
|
|
194
|
-
```
|
|
256
|
+
| Lexicon | NSID | Description |
|
|
257
|
+
| ----------- | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
258
|
+
| **Receipt** | `org.hypercerts.funding.receipt` | Records a payment to a recipient, with amount, currency, payment rail, and optional transaction ID. The sender (`from`) is optional to support anonymous funders. |
|
|
195
259
|
|
|
196
|
-
###
|
|
260
|
+
### Hyperboards (`org.hyperboards.*`)
|
|
197
261
|
|
|
198
|
-
|
|
262
|
+
| Lexicon | NSID | Description |
|
|
263
|
+
| ------------------- | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
|
264
|
+
| **Board** | `org.hyperboards.board` | Visual presentation layer wrapping an activity or collection with background, colors, aspect ratio, and per-contributor styling. |
|
|
265
|
+
| **Display Profile** | `org.hyperboards.displayProfile` | Per-user visual defaults (avatar, hover image, video, click-through URL) reusable across boards. Singleton record (`literal:self`). |
|
|
199
266
|
|
|
200
|
-
|
|
201
|
-
import { ACTIVITY_NSID, COLLECTION_NSID } from "@hypercerts-org/lexicon";
|
|
267
|
+
### Certified (`app.certified.*`)
|
|
202
268
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
269
|
+
| Lexicon | NSID | Description |
|
|
270
|
+
| -------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
|
271
|
+
| **Location** | `app.certified.location` | Geographic reference using the [Location Protocol](https://spec.decentralizedgeo.org) (coordinates, GeoJSON, H3, WKT, etc.). |
|
|
272
|
+
| **Profile** | `app.certified.actor.profile` | User account profile with display name, bio, avatar, and banner. |
|
|
273
|
+
| **Organization** | `app.certified.actor.organization` | Organization metadata: legal structure, URLs, location, founding date. |
|
|
274
|
+
| **Badge Definition** | `app.certified.badge.definition` | Defines a badge with type, title, icon, and optional issuer allowlist. |
|
|
275
|
+
| **Badge Award** | `app.certified.badge.award` | Awards a badge to a user, project, or activity. |
|
|
276
|
+
| **Badge Response** | `app.certified.badge.response` | Recipient accepts or rejects a badge award. |
|
|
277
|
+
| **EVM Link** | `app.certified.link.evm` | Verifiable ATProto DID ↔ EVM wallet link via EIP-712 signature. Extensible for future proof methods (e.g. ERC-1271, ERC-6492). |
|
|
278
|
+
|
|
279
|
+
> **Full property tables** → [SCHEMAS.md](SCHEMAS.md)
|
|
280
|
+
|
|
281
|
+
## Entity Relationship Diagram
|
|
282
|
+
|
|
283
|
+

|
|
284
|
+
|
|
285
|
+
<details>
|
|
286
|
+
<summary>View ERD with field details</summary>
|
|
287
|
+
|
|
288
|
+

|
|
289
|
+
|
|
290
|
+
</details>
|
|
291
|
+
|
|
292
|
+
## Usage
|
|
293
|
+
|
|
294
|
+
### Accessing NSIDs
|
|
295
|
+
|
|
296
|
+
Individual constants (recommended):
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
import {
|
|
300
|
+
ACTIVITY_NSID,
|
|
301
|
+
HYPERCERTS_COLLECTION_NSID,
|
|
302
|
+
} from "@hypercerts-org/lexicon";
|
|
208
303
|
```
|
|
209
304
|
|
|
210
|
-
|
|
305
|
+
Semantic object:
|
|
211
306
|
|
|
212
307
|
```typescript
|
|
213
308
|
import { HYPERCERTS_NSIDS } from "@hypercerts-org/lexicon";
|
|
214
309
|
|
|
215
|
-
|
|
216
|
-
const activityId = HYPERCERTS_NSIDS.ACTIVITY;
|
|
217
|
-
const collectionId = HYPERCERTS_NSIDS.COLLECTION;
|
|
218
|
-
const rightsId = HYPERCERTS_NSIDS.RIGHTS;
|
|
310
|
+
const id = HYPERCERTS_NSIDS.ACTIVITY;
|
|
219
311
|
```
|
|
220
312
|
|
|
221
|
-
|
|
313
|
+
Type-based mapping:
|
|
222
314
|
|
|
223
315
|
```typescript
|
|
224
316
|
import { HYPERCERTS_NSIDS_BY_TYPE } from "@hypercerts-org/lexicon";
|
|
225
317
|
|
|
226
|
-
|
|
227
|
-
const activityId = HYPERCERTS_NSIDS_BY_TYPE.OrgHypercertsClaimActivity;
|
|
228
|
-
const collectionId = HYPERCERTS_NSIDS_BY_TYPE.OrgHypercertsCollection;
|
|
318
|
+
const id = HYPERCERTS_NSIDS_BY_TYPE.OrgHypercertsClaimActivity;
|
|
229
319
|
```
|
|
230
320
|
|
|
231
|
-
|
|
321
|
+
Lightweight bundle (no TypeScript types, smaller bundle):
|
|
232
322
|
|
|
233
323
|
```typescript
|
|
234
324
|
import { schemas, validate, ids } from "@hypercerts-org/lexicon/lexicons";
|
|
235
|
-
|
|
236
|
-
// Lighter bundle, type-based namespace access
|
|
237
|
-
const result = validate(ids.OrgHypercertsClaimActivity, record);
|
|
238
325
|
```
|
|
239
326
|
|
|
240
|
-
**Note**: Individual constants (e.g., `ACTIVITY_NSID`) are the recommended approach for most use cases as they provide the best developer experience with clear, concise naming.
|
|
241
|
-
|
|
242
327
|
### TypeScript Types
|
|
243
328
|
|
|
244
|
-
All lexicon types are exported as namespaces:
|
|
245
|
-
|
|
246
329
|
```typescript
|
|
247
330
|
import { OrgHypercertsClaimActivity } from "@hypercerts-org/lexicon";
|
|
248
331
|
|
|
249
|
-
// Use the Main type
|
|
250
332
|
const activity: OrgHypercertsClaimActivity.Main = {
|
|
251
333
|
$type: "org.hypercerts.claim.activity",
|
|
252
334
|
title: "My Impact Work",
|
|
253
|
-
|
|
335
|
+
shortDescription: "...",
|
|
336
|
+
createdAt: new Date().toISOString(),
|
|
254
337
|
};
|
|
255
338
|
```
|
|
256
339
|
|
|
257
|
-
###
|
|
258
|
-
|
|
259
|
-
Each lexicon is available in two forms as individual constants:
|
|
340
|
+
### Lexicon Documents
|
|
260
341
|
|
|
261
342
|
```typescript
|
|
262
343
|
import {
|
|
263
|
-
//
|
|
264
|
-
|
|
265
|
-
RIGHTS_LEXICON_JSON,
|
|
266
|
-
|
|
267
|
-
// Typed LexiconDoc - from lexicons.get() at module initialization
|
|
268
|
-
ACTIVITY_LEXICON_DOC,
|
|
269
|
-
RIGHTS_LEXICON_DOC,
|
|
344
|
+
ACTIVITY_LEXICON_JSON, // raw JSON (untyped)
|
|
345
|
+
ACTIVITY_LEXICON_DOC, // LexiconDoc (typed)
|
|
270
346
|
} from "@hypercerts-org/lexicon";
|
|
271
347
|
```
|
|
272
348
|
|
|
273
|
-
|
|
274
|
-
| ------- | -------------------- | ------------------------- | ------------------------------ |
|
|
275
|
-
| `_JSON` | Untyped JSON | Direct JSON import | Raw schema data |
|
|
276
|
-
| `_DOC` | `LexiconDoc` (typed) | `lexicons.get()` instance | Type-safe lexicon manipulation |
|
|
277
|
-
|
|
278
|
-
Or access all lexicons via semantic mapping objects:
|
|
349
|
+
Or via semantic mapping objects:
|
|
279
350
|
|
|
280
351
|
```typescript
|
|
281
352
|
import {
|
|
@@ -283,289 +354,217 @@ import {
|
|
|
283
354
|
HYPERCERTS_LEXICON_DOC,
|
|
284
355
|
} from "@hypercerts-org/lexicon";
|
|
285
356
|
|
|
286
|
-
|
|
287
|
-
const activityJSON = HYPERCERTS_LEXICON_JSON.ACTIVITY;
|
|
288
|
-
const activityDoc = HYPERCERTS_LEXICON_DOC.ACTIVITY;
|
|
289
|
-
const rightsJSON = HYPERCERTS_LEXICON_JSON.RIGHTS;
|
|
290
|
-
const rightsDoc = HYPERCERTS_LEXICON_DOC.RIGHTS;
|
|
357
|
+
const doc = HYPERCERTS_LEXICON_DOC.ACTIVITY;
|
|
291
358
|
```
|
|
292
359
|
|
|
293
|
-
## Schema Documentation
|
|
294
|
-
|
|
295
|
-
For complete schema documentation with all lexicon definitions and
|
|
296
|
-
property tables, see [SCHEMAS.md](SCHEMAS.md).
|
|
297
|
-
|
|
298
360
|
## Examples
|
|
299
361
|
|
|
300
|
-
###
|
|
301
|
-
|
|
302
|
-
Collections (`org.hypercerts.collection`) are named sets of references to
|
|
303
|
-
other records, for any purpose the creator chooses. They live at the
|
|
304
|
-
top-level namespace (not under `claim`) because they can contain more than
|
|
305
|
-
just claims.
|
|
306
|
-
|
|
307
|
-
#### Use Cases
|
|
308
|
-
|
|
309
|
-
- Defining which activity claims belong to a project
|
|
310
|
-
- Collections of projects
|
|
311
|
-
- Favourites lists
|
|
312
|
-
- Items associated with a particular funding round or funder
|
|
313
|
-
- Portfolios of work by a contributor or organization
|
|
314
|
-
- Thematic groupings (by work scope/topic)
|
|
315
|
-
- Curated showcases for display (e.g. a hyperboard)
|
|
316
|
-
- Milestone groupings (activities in a sprint/cycle)
|
|
317
|
-
- Geographic groupings (projects or locations in a region)
|
|
318
|
-
- Collections for reporting (e.g. all claims in a grant report)
|
|
319
|
-
|
|
320
|
-
**Note**: Hyperboards are a separate concern — they are visualisations
|
|
321
|
-
built on top of collections, not collections themselves.
|
|
322
|
-
|
|
323
|
-
#### Creating a Collection with Nested Items
|
|
362
|
+
### Creating Activities with Work Scope
|
|
324
363
|
|
|
325
364
|
```typescript
|
|
326
|
-
import {
|
|
365
|
+
import { ACTIVITY_NSID } from "@hypercerts-org/lexicon";
|
|
327
366
|
|
|
328
|
-
const
|
|
329
|
-
$type:
|
|
330
|
-
title: "
|
|
331
|
-
shortDescription:
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
},
|
|
349
|
-
],
|
|
367
|
+
const activity = {
|
|
368
|
+
$type: ACTIVITY_NSID,
|
|
369
|
+
title: "Mangrove Restoration in Mombasa",
|
|
370
|
+
shortDescription: "Restored 3 hectares of mangrove forest",
|
|
371
|
+
// Structured work scope via CEL expression:
|
|
372
|
+
workScope: {
|
|
373
|
+
$type: "org.hypercerts.workscope.cel",
|
|
374
|
+
expression:
|
|
375
|
+
"scope.hasAll(['mangrove_restoration']) && location.country == 'KE'",
|
|
376
|
+
usedTags: [
|
|
377
|
+
{
|
|
378
|
+
uri: "at://did:plc:alice/org.hypercerts.workscope.tag/3k2abc",
|
|
379
|
+
cid: "...",
|
|
380
|
+
},
|
|
381
|
+
],
|
|
382
|
+
version: "v1",
|
|
383
|
+
createdAt: new Date().toISOString(),
|
|
384
|
+
},
|
|
385
|
+
startDate: "2024-01-01T00:00:00Z",
|
|
386
|
+
endDate: "2024-12-31T23:59:59Z",
|
|
350
387
|
createdAt: new Date().toISOString(),
|
|
351
388
|
};
|
|
352
389
|
```
|
|
353
390
|
|
|
354
|
-
### Creating
|
|
355
|
-
|
|
356
|
-
Projects are collections with a `type` field set to "project" and can
|
|
357
|
-
include rich-text descriptions:
|
|
391
|
+
### Creating Collections (Projects, Portfolios, etc.)
|
|
358
392
|
|
|
359
393
|
```typescript
|
|
360
|
-
|
|
361
|
-
|
|
394
|
+
import { HYPERCERTS_COLLECTION_NSID } from "@hypercerts-org/lexicon";
|
|
395
|
+
|
|
396
|
+
const project = {
|
|
397
|
+
$type: HYPERCERTS_COLLECTION_NSID,
|
|
362
398
|
type: "project",
|
|
363
399
|
title: "Carbon Offset Initiative",
|
|
364
|
-
shortDescription: "
|
|
365
|
-
description: {
|
|
366
|
-
uri: "at://did:plc:alice/pub.leaflet.pages.linearDocument/abc123",
|
|
367
|
-
cid: "...",
|
|
368
|
-
},
|
|
400
|
+
shortDescription: "Activities focused on carbon reduction and reforestation",
|
|
369
401
|
items: [
|
|
370
402
|
{
|
|
371
|
-
|
|
372
|
-
|
|
403
|
+
itemIdentifier: {
|
|
404
|
+
uri: "at://did:plc:alice/org.hypercerts.claim.activity/3k2abc",
|
|
405
|
+
cid: "...",
|
|
406
|
+
},
|
|
373
407
|
},
|
|
374
408
|
{
|
|
375
|
-
|
|
376
|
-
|
|
409
|
+
itemIdentifier: {
|
|
410
|
+
uri: "at://did:plc:bob/org.hypercerts.claim.activity/7x9def",
|
|
411
|
+
cid: "...",
|
|
412
|
+
},
|
|
413
|
+
},
|
|
414
|
+
// Collections can contain other collections (recursive nesting):
|
|
415
|
+
{
|
|
416
|
+
itemIdentifier: {
|
|
417
|
+
uri: "at://did:plc:carol/org.hypercerts.collection/4m5ghi",
|
|
418
|
+
cid: "...",
|
|
419
|
+
},
|
|
377
420
|
},
|
|
378
421
|
],
|
|
379
422
|
createdAt: new Date().toISOString(),
|
|
380
423
|
};
|
|
381
424
|
```
|
|
382
425
|
|
|
383
|
-
|
|
384
|
-
"favorites", or any other collection type. The `description` field
|
|
385
|
-
supports rich-text via Leaflet linear documents.
|
|
386
|
-
|
|
387
|
-
### Adding Visual Representation to Collections
|
|
388
|
-
|
|
389
|
-
Collections can include `avatar` and `banner` fields for visual representation:
|
|
426
|
+
### Creating Location Records
|
|
390
427
|
|
|
391
428
|
```typescript
|
|
392
|
-
import {
|
|
429
|
+
import { LOCATION_NSID } from "@hypercerts-org/lexicon";
|
|
393
430
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
431
|
+
// Decimal coordinates
|
|
432
|
+
const location = {
|
|
433
|
+
$type: LOCATION_NSID,
|
|
434
|
+
lpVersion: "1.0",
|
|
435
|
+
srs: "http://www.opengis.net/def/crs/OGC/1.3/CRS84",
|
|
436
|
+
locationType: "coordinate-decimal",
|
|
437
|
+
location: {
|
|
438
|
+
$type: "app.certified.location#string",
|
|
439
|
+
string: "-3.4653, -62.2159",
|
|
399
440
|
},
|
|
400
|
-
|
|
401
|
-
|
|
441
|
+
name: "Amazon Research Station",
|
|
442
|
+
createdAt: new Date().toISOString(),
|
|
443
|
+
};
|
|
444
|
+
|
|
445
|
+
// GeoJSON
|
|
446
|
+
const geoLocation = {
|
|
447
|
+
$type: LOCATION_NSID,
|
|
448
|
+
lpVersion: "1.0",
|
|
449
|
+
srs: "http://www.opengis.net/def/crs/OGC/1.3/CRS84",
|
|
450
|
+
locationType: "geojson-point",
|
|
451
|
+
location: {
|
|
452
|
+
$type: "app.certified.location#string",
|
|
453
|
+
string: '{"type":"Point","coordinates":[-62.2159,-3.4653]}',
|
|
402
454
|
},
|
|
403
|
-
|
|
404
|
-
// ... collection items
|
|
405
|
-
],
|
|
455
|
+
name: "Research Station Alpha",
|
|
406
456
|
createdAt: new Date().toISOString(),
|
|
407
457
|
};
|
|
408
458
|
```
|
|
409
459
|
|
|
410
|
-
**Note**: Both `avatar` (up to 5MB) and `banner` (up to 10MB) fields
|
|
411
|
-
are optional and support either embedded image blobs or URI references to
|
|
412
|
-
external images.
|
|
413
|
-
|
|
414
460
|
### Acknowledging Inclusion
|
|
415
461
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
one user includes another user's record (e.g. adding an activity to a
|
|
419
|
-
collection), the owner of the included record can create an
|
|
420
|
-
acknowledgement to confirm or reject the inclusion. This forms a
|
|
421
|
-
two-way link that an AppView can verify.
|
|
422
|
-
|
|
423
|
-
Each acknowledgement uses `com.atproto.repo.strongRef` fields to
|
|
424
|
-
reference both the **subject** (the record being included) and the
|
|
425
|
-
**context** (the record it's being included in).
|
|
426
|
-
|
|
427
|
-
See [SCHEMAS.md](SCHEMAS.md) for the full property reference.
|
|
428
|
-
|
|
429
|
-
#### Use Case: Activity Included in a Collection
|
|
430
|
-
|
|
431
|
-
A project organizer (Alice) creates a collection and adds Bob's
|
|
432
|
-
activity to it via a `strongRef` in the collection's `items[]` array.
|
|
433
|
-
Bob then creates an acknowledgement in his own repo to confirm:
|
|
462
|
+
When one user includes another's record (e.g. adding an activity to a
|
|
463
|
+
collection), the owner can confirm or reject with an acknowledgement:
|
|
434
464
|
|
|
435
465
|
```typescript
|
|
436
|
-
import {
|
|
466
|
+
import { CONTEXT_ACKNOWLEDGEMENT_NSID } from "@hypercerts-org/lexicon";
|
|
437
467
|
|
|
438
|
-
// Bob acknowledges that his activity is included in Alice's collection
|
|
439
468
|
const ack = {
|
|
440
|
-
$type:
|
|
469
|
+
$type: CONTEXT_ACKNOWLEDGEMENT_NSID,
|
|
441
470
|
subject: {
|
|
442
471
|
uri: "at://did:plc:bob/org.hypercerts.claim.activity/3k2abc",
|
|
443
472
|
cid: "bafy...",
|
|
444
473
|
},
|
|
474
|
+
// context is a union — use $type to specify the variant
|
|
445
475
|
context: {
|
|
476
|
+
$type: "com.atproto.repo.strongRef",
|
|
446
477
|
uri: "at://did:plc:alice/org.hypercerts.collection/7x9def",
|
|
447
478
|
cid: "bafy...",
|
|
448
479
|
},
|
|
449
|
-
acknowledged: true,
|
|
450
|
-
createdAt: new Date().toISOString(),
|
|
451
|
-
};
|
|
452
|
-
```
|
|
453
|
-
|
|
454
|
-
#### Use Case: Contributor Included in an Activity
|
|
455
|
-
|
|
456
|
-
Alice creates an activity that lists Bob as a contributor. Bob creates
|
|
457
|
-
an acknowledgement in his own repo to confirm his participation:
|
|
458
|
-
|
|
459
|
-
```typescript
|
|
460
|
-
const ack = {
|
|
461
|
-
$type: ACKNOWLEDGEMENT_NSID,
|
|
462
|
-
subject: {
|
|
463
|
-
// Bob's contributor information record
|
|
464
|
-
uri: "at://did:plc:bob/org.hypercerts.claim.contributorInformation/abc123",
|
|
465
|
-
cid: "bafy...",
|
|
466
|
-
},
|
|
467
|
-
context: {
|
|
468
|
-
// Alice's activity that lists Bob as contributor
|
|
469
|
-
uri: "at://did:plc:alice/org.hypercerts.claim.activity/3k2abc",
|
|
470
|
-
cid: "bafy...",
|
|
471
|
-
},
|
|
472
|
-
acknowledged: true,
|
|
473
|
-
comment: "Confirming my contribution to this reforestation project",
|
|
474
|
-
createdAt: new Date().toISOString(),
|
|
475
|
-
};
|
|
476
|
-
```
|
|
477
|
-
|
|
478
|
-
Setting `acknowledged: false` explicitly rejects inclusion, which an
|
|
479
|
-
AppView can use to flag disputed associations.
|
|
480
|
-
|
|
481
|
-
### Adding Locations to Activities
|
|
482
|
-
|
|
483
|
-
The `locations` field in activity records is an array of strong references
|
|
484
|
-
(`com.atproto.repo.strongRef`) pointing to `app.certified.location` records.
|
|
485
|
-
Each strong reference contains two required fields:
|
|
486
|
-
|
|
487
|
-
- `uri`: The ATProto URI of the location record (e.g., `at://did:plc:alice/app.certified.location/abc123`)
|
|
488
|
-
- `cid`: The content identifier (CID) of the location record, ensuring referential integrity
|
|
489
|
-
|
|
490
|
-
**Validation and Expectations**:
|
|
491
|
-
|
|
492
|
-
- All location records referenced in the `locations` array must conform to the
|
|
493
|
-
`app.certified.location` lexicon schema
|
|
494
|
-
- The `uri` field must be a valid ATProto URI pointing to an existing location record
|
|
495
|
-
- The `cid` field must match the current CID of the referenced location record
|
|
496
|
-
- The `locations` field is optional; activities can be created without location data
|
|
497
|
-
|
|
498
|
-
### Adding Location to Collections
|
|
499
|
-
|
|
500
|
-
Collections can include an optional `location` field to specify where the collection's activities were performed:
|
|
501
|
-
|
|
502
|
-
```typescript
|
|
503
|
-
const collectionRecord = {
|
|
504
|
-
$type: "org.hypercerts.collection",
|
|
505
|
-
title: "Climate Action Projects",
|
|
506
|
-
shortDescription: "A collection of climate-related activities",
|
|
507
|
-
location: {
|
|
508
|
-
uri: "at://did:plc:alice/app.certified.location/xyz789",
|
|
509
|
-
cid: "...",
|
|
510
|
-
},
|
|
511
|
-
items: [
|
|
512
|
-
// ... collection items
|
|
513
|
-
],
|
|
480
|
+
acknowledged: true, // false to reject
|
|
514
481
|
createdAt: new Date().toISOString(),
|
|
515
482
|
};
|
|
516
483
|
```
|
|
517
484
|
|
|
518
|
-
The `location` field is a strong reference to an `app.certified.location` record containing the same `uri` and `cid` fields as described above for activities.
|
|
519
|
-
|
|
520
485
|
### Creating Attachments
|
|
521
486
|
|
|
522
|
-
Attachments provide commentary, context, evidence, or documentary material
|
|
523
|
-
related to hypercert records. They can be linked to activities, evaluations,
|
|
524
|
-
measurements, or even other attachments:
|
|
525
|
-
|
|
526
487
|
```typescript
|
|
527
|
-
import {
|
|
488
|
+
import { CONTEXT_ATTACHMENT_NSID } from "@hypercerts-org/lexicon";
|
|
528
489
|
|
|
529
|
-
const
|
|
530
|
-
$type:
|
|
490
|
+
const attachment = {
|
|
491
|
+
$type: CONTEXT_ATTACHMENT_NSID,
|
|
531
492
|
title: "Field Survey Report",
|
|
493
|
+
contentType: "report",
|
|
532
494
|
subjects: [
|
|
533
495
|
{
|
|
534
496
|
uri: "at://did:plc:alice/org.hypercerts.claim.activity/abc123",
|
|
535
497
|
cid: "...",
|
|
536
498
|
},
|
|
537
499
|
],
|
|
538
|
-
|
|
500
|
+
// content items are a union — use $type to specify the variant
|
|
539
501
|
content: [
|
|
540
|
-
{
|
|
541
|
-
|
|
502
|
+
{
|
|
503
|
+
$type: "org.hypercerts.defs#uri",
|
|
504
|
+
uri: "https://example.com/reports/survey-2024.pdf",
|
|
505
|
+
},
|
|
506
|
+
{ $type: "org.hypercerts.defs#uri", uri: "ipfs://Qm..." },
|
|
542
507
|
],
|
|
543
508
|
shortDescription: "Quarterly field survey documenting project progress",
|
|
544
509
|
createdAt: new Date().toISOString(),
|
|
545
510
|
};
|
|
546
511
|
```
|
|
547
512
|
|
|
548
|
-
|
|
513
|
+
## Development
|
|
549
514
|
|
|
550
|
-
|
|
551
|
-
- `shortDescription`/`description`: Support rich text via facet annotations
|
|
552
|
-
- `subjects` (optional): Array of strong references to records this attachment relates to
|
|
553
|
-
- `contentType` (optional): Type descriptor (e.g., "report", "audit", "evidence", "testimonial")
|
|
554
|
-
- `content` (required): Array of URIs or blobs containing the attachment files
|
|
555
|
-
- `location` (optional): Strong reference to an `app.certified.location` record
|
|
556
|
-
- `createdAt` (required): Timestamp when the attachment was created
|
|
515
|
+
### Commands
|
|
557
516
|
|
|
558
|
-
|
|
517
|
+
```bash
|
|
518
|
+
npm run gen-api # Regenerate TypeScript types from lexicons
|
|
519
|
+
npm run build # Build distributable bundles (ESM, CJS, types)
|
|
520
|
+
npm run check # Validate + typecheck + build (run before committing)
|
|
521
|
+
npm run lint # Check formatting (Prettier + ESLint)
|
|
522
|
+
npm run format # Auto-fix formatting
|
|
523
|
+
npm run gen-schemas-md # Regenerate SCHEMAS.md
|
|
524
|
+
npm run test # Run tests
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
### Linking ATProto Identity to EVM Wallets
|
|
528
|
+
|
|
529
|
+
The `app.certified.link.evm` record enables verifiable linking between
|
|
530
|
+
an ATProto DID and an EVM wallet address. The link is proven via a
|
|
531
|
+
cryptographic signature, allowing any verifier to confirm that the
|
|
532
|
+
wallet owner authorized the binding. Currently supports EOA wallets
|
|
533
|
+
via EIP-712 typed data signatures; the `proof` field is an open union
|
|
534
|
+
to allow future signature methods (e.g. ERC-1271, ERC-6492).
|
|
559
535
|
|
|
560
536
|
```typescript
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
537
|
+
import { LINK_EVM_NSID } from "@hypercerts-org/lexicon";
|
|
538
|
+
|
|
539
|
+
const evmLinkRecord = {
|
|
540
|
+
$type: LINK_EVM_NSID,
|
|
541
|
+
address: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
|
|
542
|
+
proof: {
|
|
543
|
+
$type: "app.certified.link.evm#eip712Proof",
|
|
544
|
+
signature: "0xabc123...", // truncated for readability; real signatures are 130-132 hex chars
|
|
545
|
+
message: {
|
|
546
|
+
$type: "app.certified.link.evm#eip712Message",
|
|
547
|
+
did: "did:plc:alice",
|
|
548
|
+
evmAddress: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
|
|
549
|
+
chainId: "1",
|
|
550
|
+
timestamp: "1709500000",
|
|
551
|
+
nonce: "0",
|
|
552
|
+
},
|
|
568
553
|
},
|
|
569
554
|
createdAt: new Date().toISOString(),
|
|
570
555
|
};
|
|
571
556
|
```
|
|
557
|
+
|
|
558
|
+
**Key fields:**
|
|
559
|
+
|
|
560
|
+
- `address` (required): 0x-prefixed EVM wallet address (EIP-55
|
|
561
|
+
checksummed, 42 chars)
|
|
562
|
+
- `proof` (required): Open union containing the cryptographic proof of
|
|
563
|
+
wallet ownership. Each variant bundles its signature with the
|
|
564
|
+
corresponding message format. Currently the only variant is
|
|
565
|
+
`#eip712Proof` for EOA wallets.
|
|
566
|
+
- `createdAt` (required): Timestamp when the record was created
|
|
567
|
+
|
|
568
|
+
## License
|
|
569
|
+
|
|
570
|
+
MIT
|