@oxyhq/contracts 0.5.0 → 0.7.0

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.
@@ -62,16 +62,9 @@ export const didDocumentSchema = z.object({
62
62
  export const signedRecordEnvelopeSchema = z
63
63
  .object({
64
64
  version: z.union([z.literal(1), z.literal(2)]),
65
- type: z.enum([
66
- 'identity',
67
- 'profile',
68
- 'reputation_attestation',
69
- 'real_life_attestation',
70
- 'validation_verdict',
71
- 'personhood_vouch',
72
- 'credential',
73
- 'node',
74
- ]),
65
+ // Open, app-defined category (see the `type` doc above). The Oxy STORE
66
+ // re-narrows to `oxySignedRecordTypeSchema`; an app to its own constant.
67
+ type: z.string().min(1),
75
68
  subject: z.string(),
76
69
  issuer: z.string(),
77
70
  record: z.record(z.unknown()),
package/dist/esm/index.js CHANGED
@@ -28,6 +28,12 @@ export {
28
28
  verificationMethodSchema, didServiceSchema, didDocumentSchema, signedRecordEnvelopeSchema, verifiedDomainSchema, domainVerificationRequestSchema, domainVerificationInstructionsSchema, authMethodEntrySchema, authMethodsResponseSchema, exportAttestationSchema, exportBundleSchema, } from './identity.js';
29
29
  export {
30
30
  // Schemas
31
+ oxySignedRecordTypeSchema, } from './oxyRecordTypes.js';
32
+ export {
33
+ // Schemas
34
+ chainHeadResponseSchema, logPageResponseSchema, } from './protocol.js';
35
+ export {
36
+ // Schemas
31
37
  publicCardSchema, signedPublicCardSchema, realLifeAttestationRecordSchema, realLifeAttestationResultSchema, validationVerdictRecordSchema, validationOpenRequestSchema, validationOpenResultSchema, validationRequestSummarySchema, validationVoteResultSchema, personhoodVouchRecordSchema, personhoodBreakdownSchema, personhoodStatusResultSchema, vouchResultSchema,
32
38
  // Verifiable Credentials (Fase 4 — NEW)
33
39
  credentialRecordSchema, verifiableCredentialResponseSchema, credentialIssueResultSchema, credentialListResultSchema, credentialVerifyResultSchema, } from './civic.js';
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Oxy-scoped signed-record types.
3
+ *
4
+ * The base `signedRecordEnvelopeSchema` (`./identity`) now treats `type` as an
5
+ * OPEN, non-empty string so ANY Oxy app may define its own record categories
6
+ * (e.g. `app.mention.*`'s `app_record`) on the shared envelope grammar. The Oxy
7
+ * identity/civic/node STORE, however, accepts ONLY the closed set of categories
8
+ * it knows how to verify and materialize — this module is that closed set.
9
+ *
10
+ * `oxySignedRecordTypeSchema` is the runtime gate the Oxy store re-narrows with
11
+ * (the API's `verifyEnvelope` rejects any `type` outside it; the Mongoose
12
+ * `SignedRecord.type` enum is derived from `.options`); `OxySignedRecordType` is
13
+ * the matching compile-time union the SDK identity/civic mixins type against.
14
+ *
15
+ * The signing input INCLUDES `type`, so this set is part of the signed bytes —
16
+ * a record cannot have its category swapped after signing.
17
+ *
18
+ * v1 only ever carried `identity` / `profile` (already in production); v2 added
19
+ * the civic record types (reputation attestations, real-life / peer validations,
20
+ * personhood vouches, verifiable credentials) and the user-node registration
21
+ * record. Every value here is an Oxy `app.oxy.*` (or legacy v1) category — an
22
+ * app's own `type` (e.g. `app_record`) is intentionally NOT in this set and is
23
+ * rejected by the Oxy store.
24
+ *
25
+ * Platform-agnostic — zod only, no react/react-native/expo, ESM-safe.
26
+ */
27
+ import { z } from 'zod';
28
+ export const oxySignedRecordTypeSchema = z.enum([
29
+ 'identity',
30
+ 'profile',
31
+ 'reputation_attestation',
32
+ 'real_life_attestation',
33
+ 'validation_verdict',
34
+ 'personhood_vouch',
35
+ 'credential',
36
+ 'node',
37
+ ]);
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Generic "Oxy Protocol" record surface — the app-agnostic conventions every app
3
+ * follows to decentralize its own content on the shared signed-record substrate.
4
+ *
5
+ * The base `signedRecordEnvelopeSchema` (`./identity`) is the WIRE grammar: a
6
+ * signed envelope whose `type` is an open string and whose `record` is an opaque
7
+ * `Record<string, unknown>`. An app layers its own LEXICON on top of that
8
+ * grammar — a typed projection of the `record` payload, addressed by an
9
+ * AtProto-style `(collection, rkey)` key — WITHOUT forking the envelope schema.
10
+ *
11
+ * ## Recipe — defining an app lexicon record
12
+ *
13
+ * For each record kind an app wants to publish:
14
+ *
15
+ * 1. Define the `record` PAYLOAD schema as a `z.ZodType<XPayload>` (e.g.
16
+ * `app.mention.feed.post` → `mentionPostRecordSchema: z.ZodType<MentionPost>`).
17
+ * This validates ONLY the inner `record`, not the envelope.
18
+ * 2. Declare the `collection` NSID as a constant (e.g.
19
+ * `export const MENTION_POST_COLLECTION = 'app.mention.feed.post'`).
20
+ * 3. Reuse the UNCHANGED {@link signedRecordEnvelopeSchema} for the envelope. The
21
+ * base treats `record` as `z.record(z.unknown())`, so the app validates the
22
+ * envelope with the base schema first, then parses `envelope.record` with its
23
+ * own payload schema. {@link LexiconRecord} is the typed projection that pairs
24
+ * the `(collection, rkey)` key with the parsed payload.
25
+ *
26
+ * The Oxy civic contracts (`./civic`) already follow this convention implicitly:
27
+ * each civic record (`real_life_attestation`, `personhood_vouch`, `credential`,
28
+ * …) ships a `record`-payload schema and is carried by the base envelope.
29
+ *
30
+ * ## Chain-wire shapes
31
+ *
32
+ * {@link ChainHeadResponse} and {@link LogPageResponse} are the shared response
33
+ * shapes every chain store exposes (Oxy's `GET /identity/records/:userId/chain/head`,
34
+ * `GET /identity/head/:userId`, `GET /identity/log/:userId`, and any app node's
35
+ * equivalents). They are defined ONCE here so producers and consumers (the API
36
+ * handlers, the SDK identity/nodes mixins, app nodes) cannot drift.
37
+ *
38
+ * Platform-agnostic — zod only, no react/react-native/expo, ESM-safe.
39
+ */
40
+ import { z } from 'zod';
41
+ import { signedRecordEnvelopeSchema } from './identity.js';
42
+ export const chainHeadResponseSchema = z.object({
43
+ headRecordId: z.string().nullable(),
44
+ seq: z.number().int(),
45
+ recordCount: z.number().int().nonnegative(),
46
+ });
47
+ export const logPageResponseSchema = z.object({
48
+ records: z.array(signedRecordEnvelopeSchema),
49
+ count: z.number().int().nonnegative(),
50
+ });
@@ -37,14 +37,16 @@ export const userNameSchema = z
37
37
  first: z.string().optional(),
38
38
  last: z.string().optional(),
39
39
  full: z.string().optional(),
40
- displayName: z.string(),
40
+ displayName: z.string().optional(),
41
41
  })
42
42
  .passthrough();
43
43
  /**
44
44
  * The canonical user object emitted by `formatUserResponse`.
45
45
  *
46
- * `id` and `name.displayName` are guaranteed on formatted user DTOs. The rest
47
- * is forwarded from the user document and may be absent depending on the query's
46
+ * `id` is present on formatted user DTOs. `name.displayName` is OPTIONAL on the
47
+ * contract the API still synthesizes a default today, but consumers must not
48
+ * assume it is present and should fall back to a handle when it is absent. The
49
+ * rest is forwarded from the user document and may be absent depending on the query's
48
50
  * `.select(...)`/`.lean()` projection. Both `id` and `_id` are accepted because
49
51
  * some raw-document responses carry `_id` instead of `id`; resolve the
50
52
  * identifier with {@link resolveUserId}.