Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/contributor-information-view-ref.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@hypercerts-org/hypercerts-api': patch
---

Contributor-information query schemas now share their response-view definition from `getContributorInformation`. Response JSON is unchanged.
5 changes: 3 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pnpm build

## HTTP runtime tests

`pnpm test:http` runs the suites in `api/tests/http` against the activity, badge-definition, badge-query, acknowledgement, collection, context attachment and evaluation, funding, location, profile, organization, work-scope-tag, vocabulary-tag, graph, and contribution query XRPC endpoints installed from this checkout. These tests exercise real HTTP behavior against PostgreSQL, not only Lua handlers with a fake database.
`pnpm test:http` runs the suites in `api/tests/http` against the activity, badge-definition, badge-query, acknowledgement, collection, context attachment and evaluation, contributor-information, funding, location, profile, organization, work-scope-tag, vocabulary-tag, graph, and contribution query XRPC endpoints installed from this checkout. These tests exercise real HTTP behavior against PostgreSQL, not only Lua handlers with a fake database.

The local runner requires a local Docker Compose daemon, `psql`, and the pinned PostgreSQL and HappyView images already cached locally. Set `PSQL_PATH` to the absolute path of a trusted `psql` executable:

Expand All @@ -33,6 +33,7 @@ The HTTP gate fails if it discovers no suites, executes no `node:test` cases, or

- Funding record retrieval, repeated filters, and pagination.
- Badge-definition retrieval with an icon and allowed-issuer list, publisher-sidecar hydration, author and badge-type filters, `createdAt`/URI pagination ties, and named error responses.
- Contributor-information retrieval by exact AT-URI and listing with repeated-author filters, cursor pagination, hydrated and missing author sidecars, and named runtime errors.
- Work-scope-tag exact-URI retrieval, repeated-author filtering with an empty-result case, hydrated and null publisher sidecars, middle-position `indexedAt` fallback, tied pagination in both directions, and named error responses.
- Acknowledgement exact retrieval and full-record preservation, hydrated and absent publisher sidecars, repeated author/subject filters, ascending and descending pagination across timestamp ties, and named errors.
- Badge-query baseline-aware definition feeds and discriminating filters, exact-version award/response lookups, recipient status, raw response history, bidirectional tied pagination, nullable sidecars, and named runtime errors.
Expand All @@ -45,7 +46,7 @@ The HTTP gate fails if it discovers no suites, executes no `node:test` cases, or
- Contribution exact-record retrieval, repeated publisher filters, tied ascending/descending cursor pagination, nullable publisher sidecars, and named errors.
- Badge and contribution fixtures with CBOR-derived record CIDs; contribution DIDs are distinct from baseline fixture identities.
- Location retrieval with nullable sidecars, repeated author/URI/location-type filters, unsupported-search errors, tied pagination in both directions, malformed/absent `createdAt` handling, and named errors.
- HTTP fixtures for activity, collection, funding, badge-definition, badge-query, acknowledgement, work-scope-tag, contribution, actor, context attachment and evaluation, graph, location, and vocabulary-tag records use CBOR-derived CIDs.
- HTTP fixtures for activity, collection, funding, badge-definition, badge-query, acknowledgement, work-scope-tag, contribution, contributor-information, actor, context attachment and evaluation, graph, location, and vocabulary-tag records use CBOR-derived CIDs.

For the pinned HappyView release, ordinary Lua `error()` exceptions return HTTP 500 JSON with `error: "script_error"` and `errorType: "runtime"`; the error name appears in `message`. Negative HTTP tests assert this observed behavior. It is not a statement of the ideal public HTTP status contract, and does not guarantee 4xx mapping for `RecordNotFound` or `InvalidRequest`.

Expand Down
17 changes: 12 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
# Hypercerts API workspace

This repository combines the shared HappyView installer, pinned Lexicon dependencies, reusable Lua projections, fixtures, offline checks, and independently owned capability modules. This composed checkout includes public query modules for actor profiles and organizations, activity, badge definitions and queries, collections, context attachments and evaluations, actor and entity follows, recent follows, funding receipts, locations, work-scope tags, contribution records, vocabulary tags, and acknowledgements. The `org.hypercerts.vocab.getVocabTag` and `org.hypercerts.vocab.listVocabTags` handlers are bundled and registered through `api/modules/vocab/manifest.json`.
This repository combines the shared HappyView installer, pinned Lexicon dependencies, reusable Lua projections, fixtures, offline checks, and independently owned capability modules. This composed checkout includes public query modules for actor profiles and organizations, activity, badge definitions and queries, collections, context attachments and evaluations, actor and entity follows, recent follows, funding receipts, locations, work-scope tags, contribution records, contributor information, vocabulary tags, and acknowledgements. The `org.hypercerts.vocab.getVocabTag` and `org.hypercerts.vocab.listVocabTags` handlers are bundled and registered through `api/modules/vocab/manifest.json`.

This checkout is one of the additive local sibling branches used to compose the API:

- `tooling/api-foundation` owns the shared installer, pinned schemas, projections, fixtures, and offline checks.
- Capability branches add their independently owned endpoint modules.
- `tooling/docs` adds the endpoint explorer and full schema snapshots.
Included query endpoints:

`api/manifest.json` is authoritative for the API modules included in this checkout. The docs explorer is present on the docs branch.
- Badge definitions: `app.certified.badge.getBadgeDefinition`, `app.certified.badge.listBadgeDefinitions`
- Badge queries: `app.certified.badge.searchBadgeDefinitions`, `app.certified.badge.getBadgeAward`, `app.certified.badge.listBadgeAwards`, `app.certified.badge.getBadgeResponse`, `app.certified.badge.listBadgeResponses`
- Funding receipts: `org.hypercerts.funding.getReceipt`, `org.hypercerts.funding.listReceipts`
- Acknowledgements: `org.hypercerts.context.getAcknowledgement`, `org.hypercerts.context.listAcknowledgements`
- Contributions: `org.hypercerts.claim.getContribution`, `org.hypercerts.claim.listContributions`
- Contributor information: `org.hypercerts.claim.getContributorInformation`, `org.hypercerts.claim.listContributorInformation`
- Vocabulary tags: `org.hypercerts.vocab.getVocabTag`, `org.hypercerts.vocab.listVocabTags`

`api/manifest.json` is authoritative for the modules and validation Lexicons included in this checkout. The `docs/` workspace contains the endpoint explorer and full schema snapshots.

```sh
pnpm install --frozen-lockfile
Expand All @@ -27,6 +33,7 @@ pnpm build
| Funding receipts | `org.hypercerts.funding.getReceipt`, `org.hypercerts.funding.listReceipts` | Record retrieval, repeated filters, stable pagination, and named runtime errors |
| Badge definitions | `app.certified.badge.getBadgeDefinition`, `app.certified.badge.listBadgeDefinitions` | Record/CID retrieval, publisher sidecars, filters, tied pagination, and named runtime errors |
| Badge queries | `app.certified.badge.searchBadgeDefinitions`, `app.certified.badge.getBadgeAward`, `app.certified.badge.listBadgeAwards`, `app.certified.badge.getBadgeResponse`, `app.certified.badge.listBadgeResponses` | Baseline-aware definition search, exact-version award/response lookups, recipient status, raw response history, filters, and cursor pagination |
| Contributor information | `org.hypercerts.claim.getContributorInformation`, `org.hypercerts.claim.listContributorInformation` | Exact-URI retrieval, repeated-author filters, cursor pagination, hydrated and missing author sidecars, and named runtime errors |
| Work-scope tags | `org.hypercerts.workscope.getWorkscopeTag`, `org.hypercerts.workscope.listWorkscopeTags` | Exact-URI retrieval, author filters, hydrated and null sidecars, middle-position `indexedAt` fallback, tied pagination in both directions, and named runtime errors |
| Contributions | `org.hypercerts.claim.getContribution`, `org.hypercerts.claim.listContributions` | Exact-record retrieval, publisher filters, hydrated and null sidecars, createdAt/indexedAt fallback, tied pagination in both directions, and named runtime errors |
| Vocabulary tags | `org.hypercerts.vocab.getVocabTag`, `org.hypercerts.vocab.listVocabTags` | Exact-URI retrieval, publisher filters, hydrated and nullable sidecars, timestamp/URI pagination, and named errors |
Expand Down
43 changes: 43 additions & 0 deletions api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,32 @@ The shared module registers the contribution record Lexicon with backfill enable

See [CONTRIBUTING.md](../CONTRIBUTING.md) for local validation commands, HTTP test prerequisites and safety boundaries, endpoint coverage, and task-owned resource cleanup.

## Local checks

From the repository root:

```sh
pnpm install --frozen-lockfile
pnpm test:unit
pnpm check
pnpm build
PSQL_PATH="$(command -v psql)" pnpm test:http
```

`pnpm test:unit` and `pnpm check` run the recursively discovered tests under `api/tests/unit`; unit tests do not require HappyView or PostgreSQL. `pnpm check` also validates generated-source freshness, JavaScript/Lua lint, and types. `pnpm build` emits only Lua handlers declared by the root and module manifests. Shared Lua files are bundled into capability handlers but are not installed independently.

`pnpm test:http` requires a local Docker Compose daemon, `psql`, and the pinned PostgreSQL and HappyView images already present in the local image cache. The local runner never pulls images. The CI workflow explicitly pulls only the two digest-pinned test images before running the same command. Set `PSQL_PATH` to the absolute path returned by `command -v psql`.

## HTTP runtime tests

HTTP runtime coverage and shared runner requirements are documented in [CONTRIBUTING.md](../CONTRIBUTING.md).

HTTP suites live in `api/tests/http` and call the installed activity, collection, funding (`org.hypercerts.funding.getReceipt`, `org.hypercerts.funding.listReceipts`), badge-definition (`app.certified.badge.getBadgeDefinition`, `app.certified.badge.listBadgeDefinitions`), badge-query, acknowledgement (`org.hypercerts.context.getAcknowledgement`, `org.hypercerts.context.listAcknowledgements`), profile, organization, contributor-information (`org.hypercerts.claim.getContributorInformation`, `org.hypercerts.claim.listContributorInformation`), contribution, context attachment and evaluation, vocabulary-tag, graph, and location XRPC endpoints. `pnpm test:http` discovers `*.http.test.js` suites and fixture modules named `*.fixture.js`, then creates a random Compose project with loopback-only dynamic ports, PostgreSQL data on tmpfs, and a task-owned default bridge network. Bridge networking permits container egress. HappyView receives loopback placeholder upstream URLs and proxy variables pointing to `127.0.0.1:9`; these are application-level settings, not network-hard egress isolation. The installer and HTTP suites target only the task-owned loopback service. The runner installs this checkout's manifest, seeds shared and HTTP fixtures, runs the suites, and tears down only that generated Compose project and its temporary credentials. Locally, Compose uses `--pull never`; missing cached images fail before service startup.

The HTTP gate fails when it discovers zero suites, executes zero `node:test` cases, or runs only skipped cases. These checks cover real HTTP behavior against PostgreSQL, not just Lua handlers with a fake database. Funding coverage exercises record retrieval, repeated filters, and pagination. Badge-definition coverage exercises retrieval with an icon and allowed-issuer list, publisher-sidecar hydration, author and badge-type filters, createdAt/URI pagination ties, and named error responses. Contributor-information coverage exercises both endpoints: exact AT-URI retrieval with its CBOR-derived CID returned but not supplied in the request; repeated-author filtering; tied createdAt/URI pagination in both ascending and descending directions; hydrated and null author sidecars; and named `RecordNotFound` and `InvalidRequest` runtime errors. Contributor fixtures are seeded only into the task-owned disposable database.

For the pinned HappyView release, ordinary Lua `error()` exceptions are returned as HTTP 500 JSON with `error: "script_error"` and `errorType: "runtime"`; the error name appears in `message`. The negative HTTP tests assert this observed runtime behavior. They do not define an ideal public HTTP status contract or guarantee 4xx mapping for `RecordNotFound` and `InvalidRequest`.

## Install a released API bundle

Releases version the installable API bundle in this package; they do not publish to npm or deploy to a HappyView instance. This public repository's GitHub Releases and tagged source archives are the distribution channel. Choose an `@hypercerts-org/hypercerts-api@X.Y.Z` release tag, clone that snapshot, install its pinned workspace dependencies from the repository root, then run the installer from `api/`:
Expand All @@ -55,6 +81,23 @@ Review that release's notes and target only an explicitly approved HappyView ins

The reusable installer validates every local asset and dependency before making admin requests. `pnpm install:api` contacts a HappyView instance and uploads declared assets; do not run it without an explicitly approved target and token. It does not roll back writes if a later asset fails.

Fixture SQL helpers require an explicit disposable loopback database opt-in. Unit tests use local fixture data and fake process/network adapters; they do not seed a database or call an external HappyView service.

## Contributor-information queries

The shared module provides two public queries for `org.hypercerts.claim.contributorInformation` records:

- `org.hypercerts.claim.getContributorInformation({ uri })` returns `{ contributorInformation }` for the exact full record AT-URI. The authority must be a DID. An unindexed URI returns `RecordNotFound`.
- `org.hypercerts.claim.listContributorInformation({ authors?, sortDirection?, limit?, cursor? })` returns `{ contributorInformation, cursor? }`. `authors` filters publisher repository DIDs (OR semantics), supplied as repeated unbracketed query keys, with at most 100 values.

Both responses use the `contributorInformationView` definition declared by `org.hypercerts.claim.getContributorInformation`: record metadata (`uri`, `cid`, nullable `indexedAt`, and publisher `did`), an `author` actor view, and the original full indexed `record`. The activity endpoint keeps its separate exact-reference contributor-information view. The older proposal snippet that omits `nullable` for `indexedAt` is stale; the accepted API design requires this field to remain present as JSON `null` when the database timestamp is null. The author contains the publisher's current Certified profile and raw organization sidecar; each is `null` when missing. The record's contributor identifier is not resolved, and referencing activities are not expanded. Operational query or required hydration failures return errors rather than empty or partial results.

Listings default to 25 records and accept limits from 1 through 100. They sort by `(createdAt, uri)` in descending order unless `sortDirection` is `asc`; cursors are opaque and direction-bound. Keep filters and direction unchanged when continuing a page. The `cursor` property is omitted when there is no next page. A singular `RecordNotFound` means HappyView has no indexed row at that URI; it does not prove the record is absent or deleted from its PDS.

### Operator notes

Both queries require the HappyView PostgreSQL backend, including the profile and organization lookups used to hydrate publishers. A missing sidecar is normal and returned as `null`; a backend or lookup failure is an endpoint error. Build and validate locally with `pnpm build:lua` and `pnpm check`. Register these assets through the existing `pnpm install:api` workflow only after confirming the intended HappyView target and credentials; the installer performs external admin writes.

## Vocabulary tag queries

The default API bundle registers two public, unauthenticated endpoints for indexed `org.hypercerts.vocab.tag` records:
Expand Down
54 changes: 54 additions & 0 deletions api/lexicons/org.hypercerts.claim.getContributorInformation.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"lexicon": 1,
"id": "org.hypercerts.claim.getContributorInformation",
"defs": {
"main": {
"type": "query",
"description": "Publicly looks up one indexed contributor-information record by exact AT-URI and includes its publisher.",
"parameters": {
"type": "params",
"required": ["uri"],
"properties": {
"uri": {
"type": "string",
"format": "at-uri",
"description": "Full contributor-information record AT-URI with a DID authority."
}
}
},
"output": {
"encoding": "application/json",
"schema": { "type": "ref", "ref": "#output" }
},
"errors": [
{ "name": "InvalidRequest", "description": "The URI is invalid or is not a contributor-information record AT-URI." },
{ "name": "RecordNotFound", "description": "No indexed contributor-information record exists at this AT-URI." },
{ "name": "ContributorInformationQueryFailed", "description": "The record or required publisher hydration lookup failed." }
]
},
"output": {
"type": "object",
"required": ["contributorInformation"],
"properties": {
"contributorInformation": {
"type": "ref",
"ref": "#contributorInformationView"
}
}
},
"contributorInformationView": {
"type": "object",
"description": "Contributor-information record with its full source payload and hydrated publishing actor.",
"required": ["uri", "cid", "indexedAt", "did", "author", "record"],
"nullable": ["indexedAt"],
"properties": {
"uri": { "type": "string", "format": "at-uri" },
"cid": { "type": "string", "format": "cid" },
"indexedAt": { "type": "string", "format": "datetime" },
"did": { "type": "string", "format": "did" },
"author": { "type": "ref", "ref": "org.hypercerts.api.defs#actorView" },
"record": { "type": "ref", "ref": "org.hypercerts.claim.contributorInformation" }
}
}
}
}
Loading
Loading