@oxyhq/contracts 0.23.0 → 0.24.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/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/followGraph.js +28 -0
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/followGraph.js +27 -0
- package/dist/types/.tsbuildinfo +1 -1
- package/dist/types/followGraph.d.ts +144 -0
- package/dist/types/index.d.ts +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The follow graph wire contract (`/v2/follows`).
|
|
3
|
+
*
|
|
4
|
+
* These types are the boundary between the API that owns the graph and every
|
|
5
|
+
* application that reads it. They live here — not in the API and not in the
|
|
6
|
+
* SDK — because both ends have to agree, and a shape defined on one side is a
|
|
7
|
+
* shape the other side re-declares slightly differently within a release or two.
|
|
8
|
+
*
|
|
9
|
+
* ## Why the state is three fields and not a boolean
|
|
10
|
+
*
|
|
11
|
+
* A user can follow something globally and turn it off in ONE application. That
|
|
12
|
+
* is a state the user themselves created, so the client has to be able to see
|
|
13
|
+
* it and say so — "following, but not shown here" is a sentence a boolean
|
|
14
|
+
* cannot express. `globalState`, `applicationMode` and `effectiveState` are
|
|
15
|
+
* therefore reported separately, and only the last one answers "does this
|
|
16
|
+
* appear in my feed right now".
|
|
17
|
+
*
|
|
18
|
+
* ## Why kinds are strings
|
|
19
|
+
*
|
|
20
|
+
* `FollowTargetKind` is a plain `string`, not a union. Applications register
|
|
21
|
+
* their own kinds at runtime (`mercaria.store`, `syra.artist`), so a union here
|
|
22
|
+
* would mean every new application in the ecosystem needs a release of this
|
|
23
|
+
* package before it can follow anything. The namespace rule is enforced by the
|
|
24
|
+
* database, which is the one place that can enforce it for applications this
|
|
25
|
+
* package has never heard of.
|
|
26
|
+
*/
|
|
27
|
+
/**
|
|
28
|
+
* A registered target kind, always `<namespace>.<thing>`.
|
|
29
|
+
*
|
|
30
|
+
* The namespace is the owning application's, so two applications cannot define
|
|
31
|
+
* or silently redefine each other's kinds.
|
|
32
|
+
*/
|
|
33
|
+
export type FollowTargetKind = string;
|
|
34
|
+
/**
|
|
35
|
+
* Where a relationship stands globally — the user's own decision, independent
|
|
36
|
+
* of any application. Mirrors the database's own enum, which is the authority.
|
|
37
|
+
*
|
|
38
|
+
* `requested` is a real state and not a transient one: a private account has to
|
|
39
|
+
* accept, and until it does the user has asked and is waiting. A client that
|
|
40
|
+
* renders it as "not following" invites a second request that changes nothing.
|
|
41
|
+
*/
|
|
42
|
+
export type FollowState = 'none' | 'requested' | 'active' | 'rejected';
|
|
43
|
+
/**
|
|
44
|
+
* What this application should DO right now — the field a button renders.
|
|
45
|
+
*
|
|
46
|
+
* Note that "never followed" and "following, but switched off here" both come
|
|
47
|
+
* back as `not_following`, because the answer to "does this appear in my feed"
|
|
48
|
+
* is the same for both. They are still distinguishable, and a UI explaining
|
|
49
|
+
* itself must distinguish them: it is `globalState === 'active'` with
|
|
50
|
+
* `applicationMode === 'disabled'`.
|
|
51
|
+
*/
|
|
52
|
+
export type FollowEffectiveState = 'not_following' | 'requested' | 'following';
|
|
53
|
+
/**
|
|
54
|
+
* What ONE application does with a relationship.
|
|
55
|
+
*
|
|
56
|
+
* `inherit` is the default and means "whatever the user decided globally".
|
|
57
|
+
* `disabled` is the interesting one: the user still follows, this application
|
|
58
|
+
* just does not act on it — which is what makes "follow everywhere, mute here"
|
|
59
|
+
* possible without the user losing the follow.
|
|
60
|
+
*/
|
|
61
|
+
export type FollowApplicationMode = 'inherit' | 'enabled' | 'disabled';
|
|
62
|
+
/** A thing that can be followed. */
|
|
63
|
+
export interface FollowTarget {
|
|
64
|
+
id: string;
|
|
65
|
+
/**
|
|
66
|
+
* The stable, global identity of the thing — an Oxy URI for local objects, an
|
|
67
|
+
* ActivityPub actor URI for remote ones. What makes "the same target" the
|
|
68
|
+
* same across applications and across servers.
|
|
69
|
+
*/
|
|
70
|
+
uri: string;
|
|
71
|
+
kind: FollowTargetKind;
|
|
72
|
+
/**
|
|
73
|
+
* A cached display snapshot (name, handle, avatar). Present so a follow list
|
|
74
|
+
* can render without one lookup per row; never authoritative — the owning
|
|
75
|
+
* application always holds the current version.
|
|
76
|
+
*/
|
|
77
|
+
metadata?: Record<string, unknown>;
|
|
78
|
+
}
|
|
79
|
+
/** One row of the user's central follow list. */
|
|
80
|
+
export interface FollowRecord {
|
|
81
|
+
relationshipId: string;
|
|
82
|
+
target: FollowTarget;
|
|
83
|
+
globalState: FollowState;
|
|
84
|
+
applicationMode: FollowApplicationMode;
|
|
85
|
+
/**
|
|
86
|
+
* Where the user was when they followed. Provenance for the audit trail and
|
|
87
|
+
* for notification routing — never authority: this application cannot undo
|
|
88
|
+
* what another one recorded.
|
|
89
|
+
*/
|
|
90
|
+
originApplicationId: string | null;
|
|
91
|
+
/** Set only on a timed follow. ISO-8601. */
|
|
92
|
+
expiresAt?: string;
|
|
93
|
+
createdAt: string;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* The three-part answer to "am I following this".
|
|
97
|
+
*
|
|
98
|
+
* `effectiveState` is what a button renders. The other two are what an
|
|
99
|
+
* explanation renders, and a client that shows a disabled follow as "not
|
|
100
|
+
* following" will be asked why the button does nothing.
|
|
101
|
+
*/
|
|
102
|
+
export interface FollowStatus {
|
|
103
|
+
/** Absent when nothing has ever been followed. Every other operation needs it. */
|
|
104
|
+
relationshipId?: string;
|
|
105
|
+
globalState: FollowState;
|
|
106
|
+
applicationMode: FollowApplicationMode;
|
|
107
|
+
/** `following` only when followed globally AND not disabled here. */
|
|
108
|
+
effectiveState: FollowEffectiveState;
|
|
109
|
+
expiresAt?: string;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* `PUT /v2/follows/:targetId` — `created: false` means it already existed.
|
|
113
|
+
*
|
|
114
|
+
* Carries the whole resulting status rather than a couple of fields off it, so
|
|
115
|
+
* a client can store the answer instead of reconstructing one. Reconstructing
|
|
116
|
+
* is where an optimistic update and the settled value drift: the derivation of
|
|
117
|
+
* `effectiveState` lives on the server, and a client recomputing it is a second
|
|
118
|
+
* implementation of a rule that has one.
|
|
119
|
+
*/
|
|
120
|
+
export interface FollowMutation {
|
|
121
|
+
relationshipId: string;
|
|
122
|
+
created: boolean;
|
|
123
|
+
status: FollowStatus;
|
|
124
|
+
}
|
|
125
|
+
/** `DELETE /v2/follows/:relationshipId` — `removed: false` means it was already gone. */
|
|
126
|
+
export interface UnfollowMutation {
|
|
127
|
+
removed: boolean;
|
|
128
|
+
}
|
|
129
|
+
/** `GET /v2/me/follows` */
|
|
130
|
+
export interface FollowListPage {
|
|
131
|
+
follows: FollowRecord[];
|
|
132
|
+
/** Absent when the last page has been reached. */
|
|
133
|
+
nextCursor?: string;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Options for `PUT /v2/follows/:targetId`.
|
|
137
|
+
*
|
|
138
|
+
* `expiresIn` is the timed follow — seconds from now. Bounded server-side,
|
|
139
|
+
* because an unbounded value is indistinguishable from a permanent follow the
|
|
140
|
+
* user believes will end.
|
|
141
|
+
*/
|
|
142
|
+
export interface FollowOptions {
|
|
143
|
+
expiresIn?: number;
|
|
144
|
+
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -37,6 +37,7 @@ export { MODERATION_SEVERITIES, MODERATION_FINDING_SCOPES, MODERATION_ATTRIBUTIO
|
|
|
37
37
|
export type { ModerationSeverity, ModerationFindingScope, ModerationAttribution, ModerationDecisionStatus, ModerationEffectType, ModerationEffectStatus, ModerationEffectSkipReason, ConductStrikeStatus, ConductStanding, ContributionTier, PersonhoodStatusValue, IdentityBindingType, IdentityBindingStatus, ApplicationModerationStanding, ModerationFinding, ModerationDecisionEventSubject, ModerationPolicyVersions, ModerationDecisionEvent, FinalizeModerationDecisionInput, ReverseModerationEffectInput, ModerationEffect, ApplyModerationDecisionResult, ReverseModerationEffectResult, RegisterIdentityBindingInput, IdentityBinding, ReputationPersonhood, ReputationContribution, ReputationConduct, ReputationReporting, ReputationReviewing, ReputationContextualInfluence, ApplicationModerationTrust, } from './moderationReputation';
|
|
38
38
|
export { linkPreviewSchema, linkPreviewBatchRequestSchema, linkPreviewBatchResponseSchema, linkPreviewResponseSchema, } from './links';
|
|
39
39
|
export type { LinkPreviewStatus, LinkPreview, LinkPreviewBatchRequest, LinkPreviewBatchResponse, } from './links';
|
|
40
|
+
export type { FollowTargetKind, FollowState, FollowEffectiveState, FollowApplicationMode, FollowTarget, FollowRecord, FollowStatus, FollowMutation, UnfollowMutation, FollowListPage, FollowOptions, } from './followGraph';
|
|
40
41
|
export { sessionAccountSchema, deviceSessionStateSchema, activeTokenSchema, deviceSessionSyncSchema, deviceTokenMintRequestSchema, deviceTokenMintResponseSchema, deviceBackgroundCredentialResponseSchema, deviceBackgroundTokenRequestSchema, deviceBackgroundTokenResponseSchema, SESSION_ACCOUNTS_CHANGED_EVENT, sessionAccountsChangedReasonSchema, sessionAccountsChangedEventSchema, } from './deviceSession';
|
|
41
42
|
export type { SessionAccount, DeviceSessionState, ActiveToken, DeviceSessionSync, DeviceTokenMintRequest, DeviceTokenMintResponse, DeviceBackgroundCredentialResponse, DeviceBackgroundTokenRequest, DeviceBackgroundTokenResponse, SessionAccountsChangedReason, SessionAccountsChangedEvent, } from './deviceSession';
|
|
42
43
|
export { loginResultSchema, } from './deviceBoot';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oxyhq/contracts",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.0",
|
|
4
4
|
"description": "OxyHQ API contracts — single source of truth for request/response Zod schemas and inferred types, shared by the backend and the client SDKs",
|
|
5
5
|
"main": "dist/cjs/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|