@oxyhq/contracts 0.4.0 → 0.6.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.
package/dist/esm/index.js CHANGED
@@ -31,3 +31,6 @@ export {
31
31
  publicCardSchema, signedPublicCardSchema, realLifeAttestationRecordSchema, realLifeAttestationResultSchema, validationVerdictRecordSchema, validationOpenRequestSchema, validationOpenResultSchema, validationRequestSummarySchema, validationVoteResultSchema, personhoodVouchRecordSchema, personhoodBreakdownSchema, personhoodStatusResultSchema, vouchResultSchema,
32
32
  // Verifiable Credentials (Fase 4 — NEW)
33
33
  credentialRecordSchema, verifiableCredentialResponseSchema, credentialIssueResultSchema, credentialListResultSchema, credentialVerifyResultSchema, } from './civic.js';
34
+ export {
35
+ // Schemas
36
+ linkPreviewSchema, linkPreviewBatchRequestSchema, linkPreviewBatchResponseSchema, linkPreviewResponseSchema, } from './links.js';
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Link-preview / unfurl API contracts.
3
+ *
4
+ * SINGLE SOURCE OF TRUTH for the wire shape of Oxy's link-preview ("unfurl")
5
+ * resolution surface: the single `GET` lookup and the `POST` batch lookup that
6
+ * every app calls through the SDK so apps stop duplicating their own
7
+ * link-metadata fetching. The API validates its OUTPUT against these schemas;
8
+ * every consumer (`@oxyhq/core`'s link mixin and the apps that call it)
9
+ * validates its INPUT against the same definitions, so producer and consumers
10
+ * cannot drift.
11
+ *
12
+ * Design anchors:
13
+ * - Oxy owns resolution. The `image` (and `favicon`) URLs a preview carries are
14
+ * re-hosted on Oxy media (`cloud.oxy.so/<fileId>`), never raw remote URLs —
15
+ * apps render them directly with no per-app proxy.
16
+ * - Resolution is best-effort and asynchronous. A preview is `'resolved'` once
17
+ * metadata is materialised, `'pending'` while a first-seen URL is being
18
+ * fetched in the background, or `'empty'` when the target yielded no usable
19
+ * metadata. `resolvedAt` (ISO datetime) is present only once `'resolved'`.
20
+ * - The batch response is keyed by the REQUESTED url (the exact string the
21
+ * caller sent), not the canonical/final URL, so a caller can always look its
22
+ * own input back up; the canonical URL lives on `LinkPreview.url`.
23
+ *
24
+ * The `LinkPreview` / `LinkPreviewBatchResponse` exports are declared as explicit
25
+ * `interface`s (with their runtime schemas annotated `z.ZodType<Interface>`),
26
+ * following the same rationale as `UserNameResponse` in `./userResponse`: a
27
+ * `z.infer<>` of a nested-object schema can degrade to `{}` under a consumer's
28
+ * `moduleResolution: "node"` (node10) resolution. A literal interface emits the
29
+ * field types verbatim in the `.d.ts` and survives BOTH `node` and `bundler`
30
+ * resolution. The flat batch-request schema (no nested-object hazard) is inferred
31
+ * via `z.infer<>`.
32
+ *
33
+ * Platform-agnostic — zod only, no react/react-native/expo. ESM-safe (no
34
+ * `require()`).
35
+ */
36
+ import { z } from 'zod';
37
+ export const linkPreviewSchema = z.object({
38
+ url: z.string(),
39
+ status: z.enum(['resolved', 'pending', 'empty']),
40
+ title: z.string().optional(),
41
+ description: z.string().optional(),
42
+ image: z.string().optional(),
43
+ siteName: z.string().optional(),
44
+ favicon: z.string().optional(),
45
+ resolvedAt: z.string().optional(),
46
+ });
47
+ /* -------------------------------------------------------------------------- */
48
+ /* Batch request / response */
49
+ /* -------------------------------------------------------------------------- */
50
+ /**
51
+ * Request body for the batch unfurl endpoint. Between 1 and 50 URLs per call;
52
+ * the server resolves each (returning a `'pending'` placeholder for any URL it
53
+ * has not seen before and is fetching in the background).
54
+ */
55
+ export const linkPreviewBatchRequestSchema = z.object({
56
+ urls: z.array(z.string().max(2048)).min(1).max(50),
57
+ });
58
+ export const linkPreviewBatchResponseSchema = z.object({
59
+ data: z.record(z.string(), linkPreviewSchema),
60
+ });
61
+ /**
62
+ * Wire shape of the single-URL unfurl lookup (`GET`) — a bare
63
+ * {@link LinkPreview}.
64
+ */
65
+ export const linkPreviewResponseSchema = linkPreviewSchema;
@@ -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}.