@oxy.so/contracts 1.0.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/LICENSE +202 -0
- package/NOTICE +16 -0
- package/dist/cjs/.tsbuildinfo +1 -0
- package/dist/cjs/accountGraph.js +489 -0
- package/dist/cjs/agency.js +439 -0
- package/dist/cjs/browserHub.js +215 -0
- package/dist/cjs/civic.js +163 -0
- package/dist/cjs/commonsSignIn.js +59 -0
- package/dist/cjs/deviceBoot.js +50 -0
- package/dist/cjs/deviceDirectory.js +189 -0
- package/dist/cjs/devicePairing.js +138 -0
- package/dist/cjs/deviceSession.js +164 -0
- package/dist/cjs/emailAgentContext.js +32 -0
- package/dist/cjs/followGraph.js +28 -0
- package/dist/cjs/identity.js +258 -0
- package/dist/cjs/inboxPush.js +24 -0
- package/dist/cjs/index.js +618 -0
- package/dist/cjs/inference/accountBilling.js +334 -0
- package/dist/cjs/inference/aliaModelRelease.js +262 -0
- package/dist/cjs/inference/attribution.js +106 -0
- package/dist/cjs/inference/catalogue.js +487 -0
- package/dist/cjs/inference/entitlement.js +217 -0
- package/dist/cjs/inference/errors.js +309 -0
- package/dist/cjs/inference/identifiers.js +224 -0
- package/dist/cjs/inference/inbox.js +105 -0
- package/dist/cjs/inference/modelDocumentation.js +433 -0
- package/dist/cjs/inference/money.js +188 -0
- package/dist/cjs/inference/priceVersion.js +110 -0
- package/dist/cjs/inference/providerConnection.js +455 -0
- package/dist/cjs/inference/request.js +477 -0
- package/dist/cjs/inference/routingPolicy.js +318 -0
- package/dist/cjs/inference/streamEvents.js +258 -0
- package/dist/cjs/inference/usage.js +329 -0
- package/dist/cjs/inference/version.js +105 -0
- package/dist/cjs/keyRecovery.js +91 -0
- package/dist/cjs/keyRotation.js +75 -0
- package/dist/cjs/links.js +68 -0
- package/dist/cjs/moderationReputation.js +298 -0
- package/dist/cjs/oauth.js +66 -0
- package/dist/cjs/oxyRecordTypes.js +71 -0
- package/dist/cjs/protocol.js +53 -0
- package/dist/cjs/recommendations.js +168 -0
- package/dist/cjs/reputation.js +297 -0
- package/dist/cjs/sessionStatus.js +121 -0
- package/dist/cjs/transparency.js +89 -0
- package/dist/cjs/updates.js +252 -0
- package/dist/cjs/userInvalidation.js +89 -0
- package/dist/cjs/userResponse.js +245 -0
- package/dist/cjs/username.js +290 -0
- package/dist/cjs/webauthn.js +71 -0
- package/dist/esm/.tsbuildinfo +1 -0
- package/dist/esm/accountGraph.js +480 -0
- package/dist/esm/agency.js +436 -0
- package/dist/esm/browserHub.js +212 -0
- package/dist/esm/civic.js +160 -0
- package/dist/esm/commonsSignIn.js +56 -0
- package/dist/esm/deviceBoot.js +47 -0
- package/dist/esm/deviceDirectory.js +186 -0
- package/dist/esm/devicePairing.js +135 -0
- package/dist/esm/deviceSession.js +161 -0
- package/dist/esm/emailAgentContext.js +29 -0
- package/dist/esm/followGraph.js +27 -0
- package/dist/esm/identity.js +255 -0
- package/dist/esm/inboxPush.js +21 -0
- package/dist/esm/index.js +172 -0
- package/dist/esm/inference/accountBilling.js +331 -0
- package/dist/esm/inference/aliaModelRelease.js +259 -0
- package/dist/esm/inference/attribution.js +103 -0
- package/dist/esm/inference/catalogue.js +484 -0
- package/dist/esm/inference/entitlement.js +214 -0
- package/dist/esm/inference/errors.js +306 -0
- package/dist/esm/inference/identifiers.js +221 -0
- package/dist/esm/inference/inbox.js +102 -0
- package/dist/esm/inference/modelDocumentation.js +430 -0
- package/dist/esm/inference/money.js +185 -0
- package/dist/esm/inference/priceVersion.js +107 -0
- package/dist/esm/inference/providerConnection.js +452 -0
- package/dist/esm/inference/request.js +474 -0
- package/dist/esm/inference/routingPolicy.js +315 -0
- package/dist/esm/inference/streamEvents.js +255 -0
- package/dist/esm/inference/usage.js +326 -0
- package/dist/esm/inference/version.js +102 -0
- package/dist/esm/keyRecovery.js +88 -0
- package/dist/esm/keyRotation.js +72 -0
- package/dist/esm/links.js +65 -0
- package/dist/esm/moderationReputation.js +295 -0
- package/dist/esm/oauth.js +63 -0
- package/dist/esm/oxyRecordTypes.js +68 -0
- package/dist/esm/protocol.js +50 -0
- package/dist/esm/recommendations.js +165 -0
- package/dist/esm/reputation.js +293 -0
- package/dist/esm/sessionStatus.js +118 -0
- package/dist/esm/transparency.js +86 -0
- package/dist/esm/updates.js +249 -0
- package/dist/esm/userInvalidation.js +85 -0
- package/dist/esm/userResponse.js +240 -0
- package/dist/esm/username.js +283 -0
- package/dist/esm/webauthn.js +68 -0
- package/dist/types/.tsbuildinfo +1 -0
- package/dist/types/accountGraph.d.ts +378 -0
- package/dist/types/agency.d.ts +2162 -0
- package/dist/types/browserHub.d.ts +856 -0
- package/dist/types/civic.d.ts +338 -0
- package/dist/types/commonsSignIn.d.ts +58 -0
- package/dist/types/deviceBoot.d.ts +74 -0
- package/dist/types/deviceDirectory.d.ts +1317 -0
- package/dist/types/devicePairing.d.ts +130 -0
- package/dist/types/deviceSession.d.ts +411 -0
- package/dist/types/emailAgentContext.d.ts +248 -0
- package/dist/types/followGraph.d.ts +150 -0
- package/dist/types/identity.d.ts +402 -0
- package/dist/types/inboxPush.d.ts +30 -0
- package/dist/types/index.d.ts +100 -0
- package/dist/types/inference/accountBilling.d.ts +738 -0
- package/dist/types/inference/aliaModelRelease.d.ts +609 -0
- package/dist/types/inference/attribution.d.ts +176 -0
- package/dist/types/inference/catalogue.d.ts +1618 -0
- package/dist/types/inference/entitlement.d.ts +519 -0
- package/dist/types/inference/errors.d.ts +242 -0
- package/dist/types/inference/identifiers.d.ts +182 -0
- package/dist/types/inference/inbox.d.ts +374 -0
- package/dist/types/inference/modelDocumentation.d.ts +1603 -0
- package/dist/types/inference/money.d.ts +185 -0
- package/dist/types/inference/priceVersion.d.ts +182 -0
- package/dist/types/inference/providerConnection.d.ts +968 -0
- package/dist/types/inference/request.d.ts +2800 -0
- package/dist/types/inference/routingPolicy.d.ts +616 -0
- package/dist/types/inference/streamEvents.d.ts +950 -0
- package/dist/types/inference/usage.d.ts +1164 -0
- package/dist/types/inference/version.d.ts +102 -0
- package/dist/types/keyRecovery.d.ts +138 -0
- package/dist/types/keyRotation.d.ts +103 -0
- package/dist/types/links.d.ts +96 -0
- package/dist/types/moderationReputation.d.ts +487 -0
- package/dist/types/oauth.d.ts +86 -0
- package/dist/types/oxyRecordTypes.d.ts +62 -0
- package/dist/types/protocol.d.ts +86 -0
- package/dist/types/recommendations.d.ts +542 -0
- package/dist/types/reputation.d.ts +457 -0
- package/dist/types/sessionStatus.d.ts +231 -0
- package/dist/types/transparency.d.ts +392 -0
- package/dist/types/updates.d.ts +545 -0
- package/dist/types/userInvalidation.d.ts +94 -0
- package/dist/types/userResponse.d.ts +1706 -0
- package/dist/types/username.d.ts +265 -0
- package/dist/types/webauthn.d.ts +77 -0
- package/package.json +87 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Version rule for the Oxy↔data-plane inference contracts.
|
|
3
|
+
*
|
|
4
|
+
* Oxy is the control plane; the inference data plane is a separate service.
|
|
5
|
+
* They are deployed independently, in different repositories, possibly in
|
|
6
|
+
* different languages.
|
|
7
|
+
* Every shape they exchange therefore carries its version IN THE PARSED DATA,
|
|
8
|
+
* never as a comment or an out-of-band assumption, so a producer running ahead
|
|
9
|
+
* of a consumer fails loudly at the parse instead of being silently reinterpreted.
|
|
10
|
+
*
|
|
11
|
+
* The rule, enforced by `src/__tests__/inference.compatibility.test.ts`:
|
|
12
|
+
*
|
|
13
|
+
* - A schema carries `schemaVersion: z.literal(<n>)` **if and only if** it can
|
|
14
|
+
* appear on the wire as a whole message — a request envelope, a stream event,
|
|
15
|
+
* a catalogue descriptor, a ledger record, an error body.
|
|
16
|
+
* - A schema that only ever appears EMBEDDED inside such a message (the
|
|
17
|
+
* attribution block, one message part, one usage quantity, a data-retention
|
|
18
|
+
* policy) carries no version of its own: it inherits the version of the
|
|
19
|
+
* envelope it rides in. Versioning it separately would create two versions
|
|
20
|
+
* that can disagree about one byte stream.
|
|
21
|
+
* - A shape that is BOTH — `inferenceErrorSchema` is returned as an HTTP body
|
|
22
|
+
* and also rides inside the stream's error event — keeps its own version.
|
|
23
|
+
* The envelope's version then governs the envelope and the payload's governs
|
|
24
|
+
* the payload, which is two versions of two things rather than two versions
|
|
25
|
+
* of one.
|
|
26
|
+
* - Every exported object schema in `src/inference/` must fall into exactly one
|
|
27
|
+
* of those groups. The compatibility test holds both lists as exact
|
|
28
|
+
* equalities, so a new shape that is in neither fails the build rather than
|
|
29
|
+
* quietly shipping unversioned.
|
|
30
|
+
*
|
|
31
|
+
* A shape's own version is bumped when its meaning changes in a way a consumer
|
|
32
|
+
* pinned to the previous version would misread — a field removed, a field's
|
|
33
|
+
* units changed, a closed enum's member given a new meaning. Adding an OPTIONAL
|
|
34
|
+
* field is additive and does not bump it, because a consumer on the previous
|
|
35
|
+
* version parses the message correctly and simply does not read the new field.
|
|
36
|
+
*
|
|
37
|
+
* ## Which shapes reject an unknown field
|
|
38
|
+
*
|
|
39
|
+
* That last rule is why the shapes EXCHANGED WITH THE DATA PLANE are not
|
|
40
|
+
* `.strict()` at their top level — the request envelope, the four usage records,
|
|
41
|
+
* the stream events, the error body, the catalogue descriptors, the price
|
|
42
|
+
* version. The split is a decision rather than an omission: `.strict()` and
|
|
43
|
+
* "adding an optional field is additive" cannot both hold on one shape, because
|
|
44
|
+
* a producer one minor version ahead would have its whole message REFUSED
|
|
45
|
+
* rather than its new field ignored. For a usage report that means a request
|
|
46
|
+
* already served upstream can never be settled and Oxy absorbs its cost, which
|
|
47
|
+
* is a worse failure than the one strictness would have caught.
|
|
48
|
+
*
|
|
49
|
+
* Their LEAVES are strict, and that is where the protection lives: a stripped
|
|
50
|
+
* field is the worse outcome exactly where it would be a leak or a second
|
|
51
|
+
* source of truth, because it disappears at this parse and survives in the
|
|
52
|
+
* producer, which is where somebody eventually reads it. So
|
|
53
|
+
* `clientRequestMetadataSchema` (no IP, ever), `moneySchema` (no convenience
|
|
54
|
+
* float beside the exact decimal), `providerErrorPassthroughSchema` (no
|
|
55
|
+
* upstream request or headers beside the message), `usageQuantitySchema` and
|
|
56
|
+
* `unitPriceSchema` all refuse an unknown field, while the envelope carrying
|
|
57
|
+
* them tolerates an additive one.
|
|
58
|
+
*
|
|
59
|
+
* A shape Oxy does NOT exchange with the data plane is strict at its top level
|
|
60
|
+
* too, since nothing there can run ahead of this package:
|
|
61
|
+
* `providerConnectionSchema`, where an unknown field is how a BYOK credential
|
|
62
|
+
* escapes, and the billing and entitlement records, where one is a second
|
|
63
|
+
* number beside an exact amount.
|
|
64
|
+
*
|
|
65
|
+
* A SIGNED document is strict at its top level for a third reason, and there it
|
|
66
|
+
* is forced rather than chosen. `aliaModelReleaseManifestSchema` carries
|
|
67
|
+
* signatures over its own canonical bytes, so a field stripped at this parse is a
|
|
68
|
+
* field missing from the bytes a verifier re-canonicalizes: a tolerant parse
|
|
69
|
+
* would report an invalid SIGNATURE where the truth is that this build does not
|
|
70
|
+
* understand the DOCUMENT. Its producer can run ahead of this package — Alia's
|
|
71
|
+
* release tooling is deployed independently — so the usual argument applies here
|
|
72
|
+
* and is outweighed, because the refusal costs an operator one retry after Oxy
|
|
73
|
+
* takes the newer contract, while the tolerant parse costs a misdiagnosis of a
|
|
74
|
+
* cryptographic failure.
|
|
75
|
+
*
|
|
76
|
+
* Decided in: docs/adr/0006-oxy-kaana-boundary.md,
|
|
77
|
+
* docs/adr/0010-public-api-compatibility.md,
|
|
78
|
+
* docs/adr/0017-authorized-routes-in-the-envelope.md.
|
|
79
|
+
*/
|
|
80
|
+
/**
|
|
81
|
+
* Version of the contract SET as a whole — the value the control plane and the
|
|
82
|
+
* data plane exchange in a startup/health handshake to establish that they were built against
|
|
83
|
+
* compatible definitions before a single inference request is served.
|
|
84
|
+
*
|
|
85
|
+
* MAJOR is bumped when any individual shape's `schemaVersion` increments (at
|
|
86
|
+
* least one message is now read differently by the two sides); MINOR when a
|
|
87
|
+
* shape or an optional field is added, when a CLOSED ENUM gains a member, or
|
|
88
|
+
* when a refinement changes which bytes parse; PATCH for documentation-only
|
|
89
|
+
* changes that leave every parsed byte identical.
|
|
90
|
+
*
|
|
91
|
+
* The last two are MINOR rather than PATCH because both produce the same
|
|
92
|
+
* failure: a producer on the newer set emits something the older set refuses,
|
|
93
|
+
* with no `schemaVersion` difference to explain it. A new enum member and a
|
|
94
|
+
* loosened refinement are exactly what the handshake exists to surface — a
|
|
95
|
+
* skew the per-message version cannot express.
|
|
96
|
+
*
|
|
97
|
+
* This constant is deliberately NOT embedded in the request envelope. Pinning a
|
|
98
|
+
* request to the version of the whole set would make an unrelated additive
|
|
99
|
+
* change to, say, the catalogue reject every in-flight inference request; the
|
|
100
|
+
* per-shape `schemaVersion` is what a message is validated against.
|
|
101
|
+
*/
|
|
102
|
+
export declare const INFERENCE_CONTRACT_VERSION = "2.0.0";
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Encrypted off-device identity backup contract (b3 Feature 1).
|
|
3
|
+
*
|
|
4
|
+
* SINGLE SOURCE OF TRUTH for the "encrypted identity backup" flow, where a
|
|
5
|
+
* client stores an encrypted copy of its self-custody identity key off-device so
|
|
6
|
+
* a lost/wiped device can be recovered from the recovery phrase ALONE — without
|
|
7
|
+
* the platform ever seeing the phrase, the derived encryption key, or the
|
|
8
|
+
* plaintext private key.
|
|
9
|
+
*
|
|
10
|
+
* Zero-knowledge design (mirrors the zero-cookie `DeviceSession.secretHash`
|
|
11
|
+
* pattern): the client derives, from the FULL 64-byte BIP-39 seed, both an
|
|
12
|
+
* encryption key (`backupKey`) and a locator (`lookupId`) via HKDF with
|
|
13
|
+
* domain-separated `info` labels. It uploads ONLY the XChaCha20-Poly1305
|
|
14
|
+
* ciphertext plus the raw `lookupId`; the server stores the ciphertext and
|
|
15
|
+
* `sha256(lookupId)` (never the raw `lookupId`). Restoration re-derives both
|
|
16
|
+
* from the phrase, fetches the envelope by `lookupId`, and decrypts locally.
|
|
17
|
+
*
|
|
18
|
+
* The server can neither locate a backup (it lacks the seed to compute the
|
|
19
|
+
* lookup id) nor decrypt one (it lacks the seed to compute the backup key) — a
|
|
20
|
+
* DB dump yields only opaque ciphertext keyed by an un-invertible hash.
|
|
21
|
+
*
|
|
22
|
+
* The producer (`@oxy.so/api`) validates its request/response against these
|
|
23
|
+
* schemas; the consumer (`@oxy.so/core` identity-backup mixin) validates its
|
|
24
|
+
* input against the same definitions, so the wire shape cannot drift.
|
|
25
|
+
*
|
|
26
|
+
* All shapes here are FLAT (no nested objects), so `z.infer<>` is safe under a
|
|
27
|
+
* consumer's node10 `moduleResolution`. Platform-agnostic — zod only, ESM-safe
|
|
28
|
+
* (no `require()`).
|
|
29
|
+
*/
|
|
30
|
+
import { z } from 'zod';
|
|
31
|
+
/** 256-bit backup locator (32 bytes), lowercase/uppercase hex. */
|
|
32
|
+
export declare const backupLookupIdSchema: z.ZodString;
|
|
33
|
+
/**
|
|
34
|
+
* The stored, self-describing encrypted backup as it lives at rest and travels
|
|
35
|
+
* on the public restore endpoint. Contains NO secret and NO locator: the
|
|
36
|
+
* `lookupId` is uploaded separately (see {@link backupUploadRequestSchema}) and
|
|
37
|
+
* only its hash is ever persisted.
|
|
38
|
+
*
|
|
39
|
+
* - `version` — envelope/KDF version, so a future scheme migration is
|
|
40
|
+
* distinguishable at rest.
|
|
41
|
+
* - `algorithm` — the AEAD used. Pinned literal so a mismatched decryptor
|
|
42
|
+
* fails loudly rather than silently.
|
|
43
|
+
* - `kdfInfo` — the HKDF `info` label used to derive the encryption key
|
|
44
|
+
* (domain-separation tag; documents exactly which context produced the key).
|
|
45
|
+
* - `nonce` — the 24-byte XChaCha20-Poly1305 nonce, hex.
|
|
46
|
+
* - `ciphertext` — the encrypted `{privateKey, publicKey, createdAt}` payload
|
|
47
|
+
* with the appended Poly1305 tag, hex.
|
|
48
|
+
* - `publicKeyHint` — a short, non-sensitive prefix of the backed-up identity's
|
|
49
|
+
* public key, so the owner can recognise WHICH identity a backup belongs to
|
|
50
|
+
* without exposing the full key. Bound into the AEAD associated data.
|
|
51
|
+
* - `createdAt` — ISO-8601 creation timestamp.
|
|
52
|
+
*/
|
|
53
|
+
export declare const encryptedBackupEnvelopeSchema: z.ZodObject<{
|
|
54
|
+
version: z.ZodNumber;
|
|
55
|
+
algorithm: z.ZodLiteral<"xchacha20poly1305">;
|
|
56
|
+
kdfInfo: z.ZodString;
|
|
57
|
+
nonce: z.ZodString;
|
|
58
|
+
ciphertext: z.ZodString;
|
|
59
|
+
publicKeyHint: z.ZodString;
|
|
60
|
+
createdAt: z.ZodString;
|
|
61
|
+
}, "strip", z.ZodTypeAny, {
|
|
62
|
+
createdAt: string;
|
|
63
|
+
version: number;
|
|
64
|
+
nonce: string;
|
|
65
|
+
ciphertext: string;
|
|
66
|
+
algorithm: "xchacha20poly1305";
|
|
67
|
+
kdfInfo: string;
|
|
68
|
+
publicKeyHint: string;
|
|
69
|
+
}, {
|
|
70
|
+
createdAt: string;
|
|
71
|
+
version: number;
|
|
72
|
+
nonce: string;
|
|
73
|
+
ciphertext: string;
|
|
74
|
+
algorithm: "xchacha20poly1305";
|
|
75
|
+
kdfInfo: string;
|
|
76
|
+
publicKeyHint: string;
|
|
77
|
+
}>;
|
|
78
|
+
export type EncryptedBackupEnvelope = z.infer<typeof encryptedBackupEnvelopeSchema>;
|
|
79
|
+
/**
|
|
80
|
+
* Request body of `POST /identity/backup` — the envelope PLUS the raw
|
|
81
|
+
* `lookupId`. The server sha256-hashes `lookupId` before storing it (it never
|
|
82
|
+
* persists the raw value), and upserts by the authenticated user id so a
|
|
83
|
+
* re-upload REPLACES the prior backup rather than accumulating duplicates.
|
|
84
|
+
*/
|
|
85
|
+
export declare const backupUploadRequestSchema: z.ZodObject<{
|
|
86
|
+
version: z.ZodNumber;
|
|
87
|
+
algorithm: z.ZodLiteral<"xchacha20poly1305">;
|
|
88
|
+
kdfInfo: z.ZodString;
|
|
89
|
+
nonce: z.ZodString;
|
|
90
|
+
ciphertext: z.ZodString;
|
|
91
|
+
publicKeyHint: z.ZodString;
|
|
92
|
+
createdAt: z.ZodString;
|
|
93
|
+
} & {
|
|
94
|
+
/**
|
|
95
|
+
* The raw 256-bit backup locator (hex), derived client-side from the seed
|
|
96
|
+
* with a domain-separated HKDF `info`. The server stores ONLY its sha256; a
|
|
97
|
+
* DB dump therefore cannot recompute a locator to enumerate backups.
|
|
98
|
+
*/
|
|
99
|
+
lookupId: z.ZodString;
|
|
100
|
+
}, "strip", z.ZodTypeAny, {
|
|
101
|
+
createdAt: string;
|
|
102
|
+
version: number;
|
|
103
|
+
nonce: string;
|
|
104
|
+
ciphertext: string;
|
|
105
|
+
algorithm: "xchacha20poly1305";
|
|
106
|
+
kdfInfo: string;
|
|
107
|
+
publicKeyHint: string;
|
|
108
|
+
lookupId: string;
|
|
109
|
+
}, {
|
|
110
|
+
createdAt: string;
|
|
111
|
+
version: number;
|
|
112
|
+
nonce: string;
|
|
113
|
+
ciphertext: string;
|
|
114
|
+
algorithm: "xchacha20poly1305";
|
|
115
|
+
kdfInfo: string;
|
|
116
|
+
publicKeyHint: string;
|
|
117
|
+
lookupId: string;
|
|
118
|
+
}>;
|
|
119
|
+
export type BackupUploadRequest = z.infer<typeof backupUploadRequestSchema>;
|
|
120
|
+
/**
|
|
121
|
+
* Response of `GET /identity/backup/status` (and the write/delete acks): whether
|
|
122
|
+
* the authenticated user has a stored backup, plus the non-sensitive hint +
|
|
123
|
+
* timestamp when one exists. Carries no ciphertext and no locator.
|
|
124
|
+
*/
|
|
125
|
+
export declare const backupStatusResponseSchema: z.ZodObject<{
|
|
126
|
+
exists: z.ZodBoolean;
|
|
127
|
+
publicKeyHint: z.ZodOptional<z.ZodString>;
|
|
128
|
+
createdAt: z.ZodOptional<z.ZodString>;
|
|
129
|
+
}, "strip", z.ZodTypeAny, {
|
|
130
|
+
exists: boolean;
|
|
131
|
+
createdAt?: string | undefined;
|
|
132
|
+
publicKeyHint?: string | undefined;
|
|
133
|
+
}, {
|
|
134
|
+
exists: boolean;
|
|
135
|
+
createdAt?: string | undefined;
|
|
136
|
+
publicKeyHint?: string | undefined;
|
|
137
|
+
}>;
|
|
138
|
+
export type BackupStatusResponse = z.infer<typeof backupStatusResponseSchema>;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Key-rotation contract (b3 Feature 3 — key rotation + last-credential replacement).
|
|
3
|
+
*
|
|
4
|
+
* SINGLE SOURCE OF TRUTH for the atomic key-rotation flow:
|
|
5
|
+
* - `POST /auth/rotate/challenge` — mint a single-use `rotate_key` challenge.
|
|
6
|
+
* - `POST /auth/rotate/complete` — prove control of the CURRENT (old) key and
|
|
7
|
+
* atomically swap in the new one.
|
|
8
|
+
*
|
|
9
|
+
* Rotation is an atomic REPLACE of the single identity key, never a
|
|
10
|
+
* remove-then-add, so it never passes through a zero-auth-method state and is
|
|
11
|
+
* independent of the unlink guards. Because the client proves possession of the
|
|
12
|
+
* current key (from SecureStore OR a recovery-phrase re-derivation), the LAST
|
|
13
|
+
* remaining credential can be replaced — the server only cares that the
|
|
14
|
+
* signature validates against the current `publicKey`.
|
|
15
|
+
*
|
|
16
|
+
* The API validates its output against these schemas; `@oxy.so/core`'s identity
|
|
17
|
+
* mixin validates its input against the same definitions, so producer and
|
|
18
|
+
* consumer cannot drift.
|
|
19
|
+
*
|
|
20
|
+
* All shapes here are FLAT (no nested objects), so `z.infer<>` is safe under a
|
|
21
|
+
* consumer's node10 `moduleResolution` — no interface-pinning needed.
|
|
22
|
+
*
|
|
23
|
+
* Platform-agnostic — zod only, ESM-safe (no `require()`).
|
|
24
|
+
*/
|
|
25
|
+
import { z } from 'zod';
|
|
26
|
+
/**
|
|
27
|
+
* Response of `POST /auth/rotate/challenge`: the single-use `rotate_key`
|
|
28
|
+
* challenge the client must sign with its CURRENT key, plus its expiry.
|
|
29
|
+
*/
|
|
30
|
+
export declare const rotateKeyChallengeResponseSchema: z.ZodObject<{
|
|
31
|
+
challenge: z.ZodString;
|
|
32
|
+
/** ISO-8601 expiry timestamp. */
|
|
33
|
+
expiresAt: z.ZodString;
|
|
34
|
+
}, "strip", z.ZodTypeAny, {
|
|
35
|
+
expiresAt: string;
|
|
36
|
+
challenge: string;
|
|
37
|
+
}, {
|
|
38
|
+
expiresAt: string;
|
|
39
|
+
challenge: string;
|
|
40
|
+
}>;
|
|
41
|
+
export type RotateKeyChallengeResponse = z.infer<typeof rotateKeyChallengeResponseSchema>;
|
|
42
|
+
/**
|
|
43
|
+
* Request body of `POST /auth/rotate/complete`.
|
|
44
|
+
*
|
|
45
|
+
* Two proofs are required:
|
|
46
|
+
* - `signature` — the CURRENT (old) key signs
|
|
47
|
+
* `JSON.stringify({ action: 'rotate_key', userId, oldPublicKey, newPublicKey,
|
|
48
|
+
* challenge, timestamp })` (proves control of the key being replaced).
|
|
49
|
+
* - `newKeyProof` — the NEW key signs
|
|
50
|
+
* `JSON.stringify({ action: 'rotate_key_new', userId, newPublicKey, challenge,
|
|
51
|
+
* timestamp })` (proof-of-possession of the key being rotated IN; prevents an
|
|
52
|
+
* attacker rotating their account to a re-encoding of someone else's key they
|
|
53
|
+
* do not control).
|
|
54
|
+
*
|
|
55
|
+
* The request carries ONLY `newPublicKey` — `oldPublicKey` and `userId` are
|
|
56
|
+
* derived server-side from the authenticated user document (never
|
|
57
|
+
* client-supplied), so a caller cannot prove control of key X while rotating
|
|
58
|
+
* key Y.
|
|
59
|
+
*/
|
|
60
|
+
export declare const rotateKeyCompleteRequestSchema: z.ZodObject<{
|
|
61
|
+
newPublicKey: z.ZodString;
|
|
62
|
+
challenge: z.ZodString;
|
|
63
|
+
signature: z.ZodString;
|
|
64
|
+
/** Proof-of-possession: the NEW key signs the rotate_key_new payload. */
|
|
65
|
+
newKeyProof: z.ZodString;
|
|
66
|
+
timestamp: z.ZodNumber;
|
|
67
|
+
/**
|
|
68
|
+
* When true, all OTHER active sessions for the account are revoked after a
|
|
69
|
+
* successful rotation (the rotating device stays signed in). Use it when the
|
|
70
|
+
* old key is presumed compromised.
|
|
71
|
+
*/
|
|
72
|
+
signOutEverywhere: z.ZodOptional<z.ZodBoolean>;
|
|
73
|
+
}, "strip", z.ZodTypeAny, {
|
|
74
|
+
signature: string;
|
|
75
|
+
timestamp: number;
|
|
76
|
+
challenge: string;
|
|
77
|
+
newPublicKey: string;
|
|
78
|
+
newKeyProof: string;
|
|
79
|
+
signOutEverywhere?: boolean | undefined;
|
|
80
|
+
}, {
|
|
81
|
+
signature: string;
|
|
82
|
+
timestamp: number;
|
|
83
|
+
challenge: string;
|
|
84
|
+
newPublicKey: string;
|
|
85
|
+
newKeyProof: string;
|
|
86
|
+
signOutEverywhere?: boolean | undefined;
|
|
87
|
+
}>;
|
|
88
|
+
export type RotateKeyCompleteRequest = z.infer<typeof rotateKeyCompleteRequestSchema>;
|
|
89
|
+
/** Response of `POST /auth/rotate/complete`: the account's new (rotated) public key. */
|
|
90
|
+
export declare const rotateKeyCompleteResponseSchema: z.ZodObject<{
|
|
91
|
+
success: z.ZodBoolean;
|
|
92
|
+
publicKey: z.ZodString;
|
|
93
|
+
message: z.ZodString;
|
|
94
|
+
}, "strip", z.ZodTypeAny, {
|
|
95
|
+
message: string;
|
|
96
|
+
publicKey: string;
|
|
97
|
+
success: boolean;
|
|
98
|
+
}, {
|
|
99
|
+
message: string;
|
|
100
|
+
publicKey: string;
|
|
101
|
+
success: boolean;
|
|
102
|
+
}>;
|
|
103
|
+
export type RotateKeyCompleteResponse = z.infer<typeof rotateKeyCompleteResponseSchema>;
|
|
@@ -0,0 +1,96 @@
|
|
|
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 (`@oxy.so/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
|
+
/**
|
|
38
|
+
* Resolution state of a {@link LinkPreview}.
|
|
39
|
+
*
|
|
40
|
+
* - `resolved` — metadata materialised; `resolvedAt` is present.
|
|
41
|
+
* - `pending` — a first-seen URL is being fetched in the background; metadata
|
|
42
|
+
* fields and `resolvedAt` may be absent. The caller may re-fetch shortly.
|
|
43
|
+
* - `empty` — the target yielded no usable metadata (e.g. a bare binary, a
|
|
44
|
+
* 404, or an opted-out host); the negative result is cached.
|
|
45
|
+
*/
|
|
46
|
+
export type LinkPreviewStatus = 'resolved' | 'pending' | 'empty';
|
|
47
|
+
/**
|
|
48
|
+
* A single resolved (or in-flight) link preview.
|
|
49
|
+
*
|
|
50
|
+
* `url` is the canonical / final resolved URL (after redirects). The optional
|
|
51
|
+
* metadata fields are present on a best-effort basis once `status` is
|
|
52
|
+
* `'resolved'`. `image` and `favicon` are absolute Oxy-hosted
|
|
53
|
+
* (`cloud.oxy.so/<fileId>`) URLs — render them directly, never proxy them.
|
|
54
|
+
*/
|
|
55
|
+
export interface LinkPreview {
|
|
56
|
+
/** Canonical / final resolved URL (after following redirects). */
|
|
57
|
+
url: string;
|
|
58
|
+
status: LinkPreviewStatus;
|
|
59
|
+
title?: string;
|
|
60
|
+
description?: string;
|
|
61
|
+
/** Absolute Oxy-hosted (`cloud.oxy.so`) image URL. */
|
|
62
|
+
image?: string;
|
|
63
|
+
siteName?: string;
|
|
64
|
+
/** Absolute Oxy-hosted (`cloud.oxy.so`) favicon URL. */
|
|
65
|
+
favicon?: string;
|
|
66
|
+
/** ISO 8601 datetime of resolution; absent while `status` is `'pending'`. */
|
|
67
|
+
resolvedAt?: string;
|
|
68
|
+
}
|
|
69
|
+
export declare const linkPreviewSchema: z.ZodType<LinkPreview>;
|
|
70
|
+
/**
|
|
71
|
+
* Request body for the batch unfurl endpoint. Between 1 and 50 URLs per call;
|
|
72
|
+
* the server resolves each (returning a `'pending'` placeholder for any URL it
|
|
73
|
+
* has not seen before and is fetching in the background).
|
|
74
|
+
*/
|
|
75
|
+
export declare const linkPreviewBatchRequestSchema: z.ZodObject<{
|
|
76
|
+
urls: z.ZodArray<z.ZodString, "many">;
|
|
77
|
+
}, "strip", z.ZodTypeAny, {
|
|
78
|
+
urls: string[];
|
|
79
|
+
}, {
|
|
80
|
+
urls: string[];
|
|
81
|
+
}>;
|
|
82
|
+
export type LinkPreviewBatchRequest = z.infer<typeof linkPreviewBatchRequestSchema>;
|
|
83
|
+
/**
|
|
84
|
+
* Batch unfurl response. `data` is keyed by the REQUESTED url (the exact string
|
|
85
|
+
* the caller sent in `urls`), so a caller can always look its own input back up;
|
|
86
|
+
* the canonical/final URL is on each {@link LinkPreview}'s `url` field.
|
|
87
|
+
*/
|
|
88
|
+
export interface LinkPreviewBatchResponse {
|
|
89
|
+
data: Record<string, LinkPreview>;
|
|
90
|
+
}
|
|
91
|
+
export declare const linkPreviewBatchResponseSchema: z.ZodType<LinkPreviewBatchResponse>;
|
|
92
|
+
/**
|
|
93
|
+
* Wire shape of the single-URL unfurl lookup (`GET`) — a bare
|
|
94
|
+
* {@link LinkPreview}.
|
|
95
|
+
*/
|
|
96
|
+
export declare const linkPreviewResponseSchema: z.ZodType<LinkPreview, z.ZodTypeDef, LinkPreview>;
|