@oxyhq/contracts 0.22.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/accountGraph.js +257 -23
- package/dist/cjs/deviceSession.js +5 -4
- package/dist/cjs/followGraph.js +28 -0
- package/dist/cjs/index.js +15 -7
- package/dist/cjs/userResponse.js +17 -3
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/accountGraph.js +253 -22
- package/dist/esm/deviceSession.js +5 -4
- package/dist/esm/followGraph.js +27 -0
- package/dist/esm/index.js +1 -1
- package/dist/esm/userResponse.js +18 -4
- package/dist/types/.tsbuildinfo +1 -1
- package/dist/types/accountGraph.d.ts +124 -40
- package/dist/types/deviceSession.d.ts +5 -4
- package/dist/types/followGraph.d.ts +144 -0
- package/dist/types/index.d.ts +3 -2
- package/dist/types/recommendations.d.ts +14 -14
- package/dist/types/updates.d.ts +2 -2
- package/dist/types/userResponse.d.ts +286 -62
- package/package.json +1 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Account graph wire contracts — the account-kind vocabulary,
|
|
3
|
-
* taxonomy, and create-account input.
|
|
2
|
+
* Account graph wire contracts — the account-kind vocabulary, the account
|
|
3
|
+
* category taxonomy, and the create-account input.
|
|
4
4
|
*
|
|
5
|
-
* `
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* `accountCategories` classifies a NON-PERSONAL account — what it is about, what
|
|
6
|
+
* it does — without polluting `User.kind`. See the block above
|
|
7
|
+
* {@link ACCOUNT_CATEGORY_IDS} for the four rules that govern it.
|
|
8
8
|
*/
|
|
9
9
|
import { z } from 'zod';
|
|
10
10
|
/**
|
|
@@ -20,7 +20,7 @@ export type AccountKind = 'personal' | 'organization' | 'project' | 'bot' | 'cha
|
|
|
20
20
|
/**
|
|
21
21
|
* The union is spelled out above and the array proves coverage BOTH ways
|
|
22
22
|
* (`satisfies` here, the `Gap` alias below) — the same shape this package's
|
|
23
|
-
* `
|
|
23
|
+
* `ACCOUNT_CATEGORY_IDS` / `TRUST_TIERS` pairs use, and the one
|
|
24
24
|
* `db/schema/users.ts` mirrors to keep the `users_kind_check` CHECK honest.
|
|
25
25
|
*
|
|
26
26
|
* Deriving the union from the array instead would cost nothing here and be paid
|
|
@@ -70,14 +70,123 @@ export declare function isActAsEligibleKind(kind: AccountKind | null | undefined
|
|
|
70
70
|
* would otherwise hand-roll this check and they would drift on what counts.
|
|
71
71
|
*/
|
|
72
72
|
export declare function isAccountKind(value: unknown): value is AccountKind;
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
/**
|
|
74
|
+
* Every account category, by stable id.
|
|
75
|
+
*
|
|
76
|
+
* Grouped by comment for readability only; the storage, the wire and the picker
|
|
77
|
+
* all treat this as one flat list. `other` is the escape hatch for an account
|
|
78
|
+
* that fits nothing here.
|
|
79
|
+
*
|
|
80
|
+
* TO ADD ONE: append an id (lowercase ASCII, `snake_case`) here, publish
|
|
81
|
+
* `@oxyhq/contracts`, then ship a migration that widens
|
|
82
|
+
* `users_account_categories_check` — never edit an existing migration — and add
|
|
83
|
+
* an `accounts.accountCategory.<id>` label to each client's locales.
|
|
84
|
+
*
|
|
85
|
+
* TO WITHDRAW ONE: leave the id here and add it to
|
|
86
|
+
* {@link RETIRED_ACCOUNT_CATEGORY_IDS}. See rule 3 above.
|
|
87
|
+
*/
|
|
88
|
+
export declare const ACCOUNT_CATEGORY_IDS: readonly ["news", "politics", "business", "startup", "finance", "crypto", "marketplace", "retail", "real_estate", "agency", "landlord", "cooperative", "architecture", "technology", "software", "ai", "security", "automation", "science", "education", "books", "health", "fitness", "sports", "gaming", "music", "film", "podcast", "art", "photography", "comedy", "food", "travel", "fashion", "home_garden", "diy", "automotive", "animals", "family", "nonprofit", "government", "community", "activism", "environment", "religion", "other"];
|
|
89
|
+
export type AccountCategoryId = (typeof ACCOUNT_CATEGORY_IDS)[number];
|
|
90
|
+
/**
|
|
91
|
+
* Accepts EVERY id, withdrawn ones included — see rule 3.
|
|
92
|
+
*
|
|
93
|
+
* A schema that rejected a withdrawn id would 400 the whole request whenever a
|
|
94
|
+
* client round-trips the categories it was served, so an account that had
|
|
95
|
+
* picked one could no longer save its bio either. That is the same failure the
|
|
96
|
+
* nullable `bio` / `avatar` fix addressed, wearing a different hat.
|
|
97
|
+
*/
|
|
98
|
+
export declare const accountCategoryIdSchema: z.ZodEnum<["news", "politics", "business", "startup", "finance", "crypto", "marketplace", "retail", "real_estate", "agency", "landlord", "cooperative", "architecture", "technology", "software", "ai", "security", "automation", "science", "education", "books", "health", "fitness", "sports", "gaming", "music", "film", "podcast", "art", "photography", "comedy", "food", "travel", "fashion", "home_garden", "diy", "automotive", "animals", "family", "nonprofit", "government", "community", "activism", "environment", "religion", "other"]>;
|
|
99
|
+
/**
|
|
100
|
+
* Ids withdrawn from the picker. Empty today.
|
|
101
|
+
*
|
|
102
|
+
* A withdrawn id keeps working everywhere it is already stored: it validates,
|
|
103
|
+
* it survives a round-trip save, it still renders from its label key, and it
|
|
104
|
+
* stays PRIMARY if it was primary. Nothing rewrites a stored list — a read-time
|
|
105
|
+
* or migration-time demotion would silently replace a choice its owner made,
|
|
106
|
+
* which is precisely what stable ids exist to prevent. The owner drops it on
|
|
107
|
+
* their next edit; until then it is honoured.
|
|
108
|
+
*
|
|
109
|
+
* What withdrawal changes is only this: the id leaves
|
|
110
|
+
* {@link SELECTABLE_ACCOUNT_CATEGORY_IDS}, so no picker offers it, and
|
|
111
|
+
* {@link newlyAddedRetiredCategories} refuses to let a write ADD it to an
|
|
112
|
+
* account that did not already have it.
|
|
113
|
+
*/
|
|
114
|
+
export declare const RETIRED_ACCOUNT_CATEGORY_IDS: readonly AccountCategoryId[];
|
|
115
|
+
/** Whether a category may still be OFFERED. A stored one is readable either way. */
|
|
116
|
+
export declare function isSelectableAccountCategoryId(id: AccountCategoryId): boolean;
|
|
117
|
+
/** The ids a picker may offer, in declaration order. */
|
|
118
|
+
export declare const SELECTABLE_ACCOUNT_CATEGORY_IDS: readonly AccountCategoryId[];
|
|
119
|
+
/**
|
|
120
|
+
* Which of `next` are withdrawn ids the account did not already carry — i.e.
|
|
121
|
+
* the ones a write must be refused for.
|
|
122
|
+
*
|
|
123
|
+
* `retired` is a parameter rather than a module read so the rule can be
|
|
124
|
+
* exercised against a non-empty set while the production one is empty; a test
|
|
125
|
+
* over `RETIRED_ACCOUNT_CATEGORY_IDS` alone would pass vacuously today and stay
|
|
126
|
+
* passing if the rule were deleted.
|
|
127
|
+
*/
|
|
128
|
+
export declare function newlyAddedRetiredCategories(next: readonly AccountCategoryId[], previous: readonly AccountCategoryId[], retired: readonly AccountCategoryId[]): AccountCategoryId[];
|
|
129
|
+
/**
|
|
130
|
+
* How many categories one account may carry.
|
|
131
|
+
*
|
|
132
|
+
* Four, not "as many as you like". Three reasons, in the order they bind:
|
|
133
|
+
*
|
|
134
|
+
* - The primary has to MEAN something. At ten categories the first element
|
|
135
|
+
* reads as a sort artifact rather than a choice, and rule 2 above is the
|
|
136
|
+
* entire mechanism by which a primary exists.
|
|
137
|
+
* - The profile RENDERS them as a row of chips; four labels of this length is
|
|
138
|
+
* what fits a phone-width profile header before the row wraps or truncates.
|
|
139
|
+
* - Four is enough to place a genuinely compound account without a tag cloud:
|
|
140
|
+
* a housing cooperative that is also a non-profit serving a local community
|
|
141
|
+
* spends `cooperative`, `nonprofit`, `community`, `real_estate` — and is the
|
|
142
|
+
* most compound real example in the ecosystem.
|
|
143
|
+
*
|
|
144
|
+
* One constant, read by the wire schema, the database CHECK and the picker, so
|
|
145
|
+
* changing it is one edit plus a migration.
|
|
146
|
+
*/
|
|
147
|
+
export declare const MAX_ACCOUNT_CATEGORIES = 4;
|
|
148
|
+
/**
|
|
149
|
+
* An account's categories on the wire. ORDER IS MEANINGFUL — index 0 is the
|
|
150
|
+
* primary (rule 2).
|
|
151
|
+
*
|
|
152
|
+
* A duplicate is REJECTED rather than silently collapsed. De-duplicating would
|
|
153
|
+
* rewrite the caller's list, and any rewrite of this list can move which id sits
|
|
154
|
+
* at index 0 — so the one repair available here is the one that would break the
|
|
155
|
+
* property the list exists to carry. A duplicate only ever comes from a client
|
|
156
|
+
* bug, and a 400 naming the index is how that bug gets found.
|
|
157
|
+
*/
|
|
158
|
+
export declare const accountCategoriesSchema: z.ZodEffects<z.ZodArray<z.ZodEnum<["news", "politics", "business", "startup", "finance", "crypto", "marketplace", "retail", "real_estate", "agency", "landlord", "cooperative", "architecture", "technology", "software", "ai", "security", "automation", "science", "education", "books", "health", "fitness", "sports", "gaming", "music", "film", "podcast", "art", "photography", "comedy", "food", "travel", "fashion", "home_garden", "diy", "automotive", "animals", "family", "nonprofit", "government", "community", "activism", "environment", "religion", "other"]>, "many">, ("news" | "politics" | "business" | "startup" | "finance" | "crypto" | "marketplace" | "retail" | "real_estate" | "agency" | "landlord" | "cooperative" | "architecture" | "technology" | "software" | "ai" | "security" | "automation" | "science" | "education" | "books" | "health" | "fitness" | "sports" | "gaming" | "music" | "film" | "podcast" | "art" | "photography" | "comedy" | "food" | "travel" | "fashion" | "home_garden" | "diy" | "automotive" | "animals" | "family" | "nonprofit" | "government" | "community" | "activism" | "environment" | "religion" | "other")[], ("news" | "politics" | "business" | "startup" | "finance" | "crypto" | "marketplace" | "retail" | "real_estate" | "agency" | "landlord" | "cooperative" | "architecture" | "technology" | "software" | "ai" | "security" | "automation" | "science" | "education" | "books" | "health" | "fitness" | "sports" | "gaming" | "music" | "film" | "podcast" | "art" | "photography" | "comedy" | "food" | "travel" | "fashion" | "home_garden" | "diy" | "automotive" | "animals" | "family" | "nonprofit" | "government" | "community" | "activism" | "environment" | "religion" | "other")[]>;
|
|
159
|
+
/**
|
|
160
|
+
* Kinds that may carry categories: every kind EXCEPT `personal`.
|
|
161
|
+
*
|
|
162
|
+
* A person has interests, not a sector — and their interests are not a
|
|
163
|
+
* classification anybody else gets to read off their profile. Spelled out
|
|
164
|
+
* positively, like {@link isActAsEligibleKind} and for the same reason: a `kind
|
|
165
|
+
* !== 'personal'` test silently admits every kind invented after it was
|
|
166
|
+
* written, whereas this list forces whoever adds one to decide.
|
|
167
|
+
*/
|
|
168
|
+
export declare const ACCOUNT_CATEGORY_KINDS: readonly ["organization", "project", "bot", "channel"];
|
|
169
|
+
export type AccountCategoryKind = (typeof ACCOUNT_CATEGORY_KINDS)[number];
|
|
170
|
+
/**
|
|
171
|
+
* Whether an account of this kind may carry categories.
|
|
172
|
+
*
|
|
173
|
+
* The API refuses the write and the `users_account_categories_kind_check`
|
|
174
|
+
* constraint makes it unrepresentable; both derive from
|
|
175
|
+
* {@link ACCOUNT_CATEGORY_KINDS}, so they cannot disagree.
|
|
176
|
+
*/
|
|
177
|
+
export declare function kindAcceptsAccountCategories(kind: AccountKind | null | undefined): boolean;
|
|
76
178
|
/**
|
|
77
179
|
* POST /accounts — create a non-personal account under the caller's tree.
|
|
78
|
-
*
|
|
180
|
+
*
|
|
181
|
+
* No cross-field refinement guards `accountCategories`, and that is not an
|
|
182
|
+
* omission: `kind` here is a CHILD kind, and every child kind is in
|
|
183
|
+
* {@link ACCOUNT_CATEGORY_KINDS}, so `personal` is already unrepresentable on
|
|
184
|
+
* this route. The refinement the single-valued predecessor needed disappeared
|
|
185
|
+
* along with the restriction that made it necessary. A child kind that does NOT
|
|
186
|
+
* accept categories would break that reasoning silently, so
|
|
187
|
+
* `__tests__/accountGraph.test.ts` asserts the two lists agree.
|
|
79
188
|
*/
|
|
80
|
-
export declare const createAccountRequestSchema: z.
|
|
189
|
+
export declare const createAccountRequestSchema: z.ZodObject<{
|
|
81
190
|
parentAccountId: z.ZodOptional<z.ZodString>;
|
|
82
191
|
kind: z.ZodEnum<["organization", "project", "bot", "channel"]>;
|
|
83
192
|
username: z.ZodString;
|
|
@@ -97,7 +206,8 @@ export declare const createAccountRequestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
97
206
|
bio: z.ZodOptional<z.ZodString>;
|
|
98
207
|
avatar: z.ZodOptional<z.ZodString>;
|
|
99
208
|
description: z.ZodOptional<z.ZodString>;
|
|
100
|
-
|
|
209
|
+
/** Ordered, PRIMARY FIRST — see rule 2 above {@link ACCOUNT_CATEGORY_IDS}. */
|
|
210
|
+
accountCategories: z.ZodOptional<z.ZodEffects<z.ZodArray<z.ZodEnum<["news", "politics", "business", "startup", "finance", "crypto", "marketplace", "retail", "real_estate", "agency", "landlord", "cooperative", "architecture", "technology", "software", "ai", "security", "automation", "science", "education", "books", "health", "fitness", "sports", "gaming", "music", "film", "podcast", "art", "photography", "comedy", "food", "travel", "fashion", "home_garden", "diy", "automotive", "animals", "family", "nonprofit", "government", "community", "activism", "environment", "religion", "other"]>, "many">, ("news" | "politics" | "business" | "startup" | "finance" | "crypto" | "marketplace" | "retail" | "real_estate" | "agency" | "landlord" | "cooperative" | "architecture" | "technology" | "software" | "ai" | "security" | "automation" | "science" | "education" | "books" | "health" | "fitness" | "sports" | "gaming" | "music" | "film" | "podcast" | "art" | "photography" | "comedy" | "food" | "travel" | "fashion" | "home_garden" | "diy" | "automotive" | "animals" | "family" | "nonprofit" | "government" | "community" | "activism" | "environment" | "religion" | "other")[], ("news" | "politics" | "business" | "startup" | "finance" | "crypto" | "marketplace" | "retail" | "real_estate" | "agency" | "landlord" | "cooperative" | "architecture" | "technology" | "software" | "ai" | "security" | "automation" | "science" | "education" | "books" | "health" | "fitness" | "sports" | "gaming" | "music" | "film" | "podcast" | "art" | "photography" | "comedy" | "food" | "travel" | "fashion" | "home_garden" | "diy" | "automotive" | "animals" | "family" | "nonprofit" | "government" | "community" | "activism" | "environment" | "religion" | "other")[]>>;
|
|
101
211
|
}, "strip", z.ZodTypeAny, {
|
|
102
212
|
kind: "organization" | "project" | "bot" | "channel";
|
|
103
213
|
username: string;
|
|
@@ -110,33 +220,7 @@ export declare const createAccountRequestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
110
220
|
bio?: string | undefined;
|
|
111
221
|
avatar?: string | undefined;
|
|
112
222
|
description?: string | undefined;
|
|
113
|
-
|
|
114
|
-
}, {
|
|
115
|
-
kind: "organization" | "project" | "bot" | "channel";
|
|
116
|
-
username: string;
|
|
117
|
-
parentAccountId?: string | undefined;
|
|
118
|
-
name?: {
|
|
119
|
-
first?: string | undefined;
|
|
120
|
-
last?: string | undefined;
|
|
121
|
-
displayName?: string | undefined;
|
|
122
|
-
} | undefined;
|
|
123
|
-
bio?: string | undefined;
|
|
124
|
-
avatar?: string | undefined;
|
|
125
|
-
description?: string | undefined;
|
|
126
|
-
organizationCategory?: "agency" | "cooperative" | "landlord" | "other" | undefined;
|
|
127
|
-
}>, {
|
|
128
|
-
kind: "organization" | "project" | "bot" | "channel";
|
|
129
|
-
username: string;
|
|
130
|
-
parentAccountId?: string | undefined;
|
|
131
|
-
name?: {
|
|
132
|
-
first?: string | undefined;
|
|
133
|
-
last?: string | undefined;
|
|
134
|
-
displayName?: string | undefined;
|
|
135
|
-
} | undefined;
|
|
136
|
-
bio?: string | undefined;
|
|
137
|
-
avatar?: string | undefined;
|
|
138
|
-
description?: string | undefined;
|
|
139
|
-
organizationCategory?: "agency" | "cooperative" | "landlord" | "other" | undefined;
|
|
223
|
+
accountCategories?: ("news" | "politics" | "business" | "startup" | "finance" | "crypto" | "marketplace" | "retail" | "real_estate" | "agency" | "landlord" | "cooperative" | "architecture" | "technology" | "software" | "ai" | "security" | "automation" | "science" | "education" | "books" | "health" | "fitness" | "sports" | "gaming" | "music" | "film" | "podcast" | "art" | "photography" | "comedy" | "food" | "travel" | "fashion" | "home_garden" | "diy" | "automotive" | "animals" | "family" | "nonprofit" | "government" | "community" | "activism" | "environment" | "religion" | "other")[] | undefined;
|
|
140
224
|
}, {
|
|
141
225
|
kind: "organization" | "project" | "bot" | "channel";
|
|
142
226
|
username: string;
|
|
@@ -149,6 +233,6 @@ export declare const createAccountRequestSchema: z.ZodEffects<z.ZodObject<{
|
|
|
149
233
|
bio?: string | undefined;
|
|
150
234
|
avatar?: string | undefined;
|
|
151
235
|
description?: string | undefined;
|
|
152
|
-
|
|
236
|
+
accountCategories?: ("news" | "politics" | "business" | "startup" | "finance" | "crypto" | "marketplace" | "retail" | "real_estate" | "agency" | "landlord" | "cooperative" | "architecture" | "technology" | "software" | "ai" | "security" | "automation" | "science" | "education" | "books" | "health" | "fitness" | "sports" | "gaming" | "music" | "film" | "podcast" | "art" | "photography" | "comedy" | "food" | "travel" | "fashion" | "home_garden" | "diy" | "automotive" | "animals" | "family" | "nonprofit" | "government" | "community" | "activism" | "environment" | "religion" | "other")[] | undefined;
|
|
153
237
|
}>;
|
|
154
238
|
export type CreateAccountRequest = z.infer<typeof createAccountRequestSchema>;
|
|
@@ -193,10 +193,11 @@ export declare const deviceTokenMintRequestSchema: z.ZodObject<{
|
|
|
193
193
|
}>;
|
|
194
194
|
/**
|
|
195
195
|
* Wire shape of a successful `POST /session/device/token`: the freshly-minted
|
|
196
|
-
* short access token for the active account, its expiry, the
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
* projected device-session state.
|
|
196
|
+
* short access token for the active account, its expiry, the device secret the
|
|
197
|
+
* client must persist (`nextDeviceSecret` — on mint this echoes the presented
|
|
198
|
+
* secret unchanged so concurrent refreshes from multiple origins do not race),
|
|
199
|
+
* and the projected device-session state. Sign-in rotates the secret via
|
|
200
|
+
* `issueDeviceSecret`; mint does not.
|
|
200
201
|
*/
|
|
201
202
|
export declare const deviceTokenMintResponseSchema: z.ZodObject<{
|
|
202
203
|
accessToken: z.ZodString;
|
|
@@ -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
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
* Platform-agnostic — zod is the only runtime dependency. No react/react-native/
|
|
10
10
|
* expo, no `require()` in the ESM build.
|
|
11
11
|
*/
|
|
12
|
-
export { ACCOUNT_KINDS, accountKindSchema, CHILD_ACCOUNT_KINDS, childAccountKindSchema, isAccountKind, isActAsEligibleKind,
|
|
13
|
-
export type { AccountKind,
|
|
12
|
+
export { ACCOUNT_KINDS, accountKindSchema, CHILD_ACCOUNT_KINDS, childAccountKindSchema, isAccountKind, isActAsEligibleKind, ACCOUNT_CATEGORY_IDS, ACCOUNT_CATEGORY_KINDS, accountCategoriesSchema, accountCategoryIdSchema, isSelectableAccountCategoryId, kindAcceptsAccountCategories, MAX_ACCOUNT_CATEGORIES, newlyAddedRetiredCategories, RETIRED_ACCOUNT_CATEGORY_IDS, SELECTABLE_ACCOUNT_CATEGORY_IDS, createAccountRequestSchema, } from './accountGraph';
|
|
13
|
+
export type { AccountKind, AccountCategoryId, AccountCategoryKind, ChildAccountKind, CreateAccountRequest, } from './accountGraph';
|
|
14
14
|
export { userNameSchema, userRelationshipSchema, themePreferenceSchema, userResponseSchema, userProfileUpdateSchema, currentUserResponseSchema, deviceLinkedSessionSchema, deviceLinkedSessionsResponseSchema, resolveUserId, safeParseContract, } from './userResponse';
|
|
15
15
|
export type { UserNameResponse, UserRelationship, ThemePreference, UserResponse, UserProfileUpdate, CurrentUserResponseContract, DeviceLinkedSessionResponse, DeviceLinkedSessionsResponseContract, } from './userResponse';
|
|
16
16
|
export { applicationTypeSchema, publicApplicationSchema, sessionStatusSchema, } from './sessionStatus';
|
|
@@ -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';
|
|
@@ -172,11 +172,11 @@ export declare const recommendationCountSchema: z.ZodObject<{
|
|
|
172
172
|
followers: z.ZodNumber;
|
|
173
173
|
following: z.ZodNumber;
|
|
174
174
|
}, "strip", z.ZodTypeAny, {
|
|
175
|
-
followers: number;
|
|
176
175
|
following: number;
|
|
177
|
-
}, {
|
|
178
176
|
followers: number;
|
|
177
|
+
}, {
|
|
179
178
|
following: number;
|
|
179
|
+
followers: number;
|
|
180
180
|
}>;
|
|
181
181
|
export type RecommendationCount = z.infer<typeof recommendationCountSchema>;
|
|
182
182
|
/**
|
|
@@ -205,11 +205,11 @@ export declare const recommendationItemSchema: z.ZodObject<{
|
|
|
205
205
|
followers: z.ZodNumber;
|
|
206
206
|
following: z.ZodNumber;
|
|
207
207
|
}, "strip", z.ZodTypeAny, {
|
|
208
|
-
followers: number;
|
|
209
208
|
following: number;
|
|
210
|
-
}, {
|
|
211
209
|
followers: number;
|
|
210
|
+
}, {
|
|
212
211
|
following: number;
|
|
212
|
+
followers: number;
|
|
213
213
|
}>;
|
|
214
214
|
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
215
215
|
id: z.ZodString;
|
|
@@ -230,11 +230,11 @@ export declare const recommendationItemSchema: z.ZodObject<{
|
|
|
230
230
|
followers: z.ZodNumber;
|
|
231
231
|
following: z.ZodNumber;
|
|
232
232
|
}, "strip", z.ZodTypeAny, {
|
|
233
|
-
followers: number;
|
|
234
233
|
following: number;
|
|
235
|
-
}, {
|
|
236
234
|
followers: number;
|
|
235
|
+
}, {
|
|
237
236
|
following: number;
|
|
237
|
+
followers: number;
|
|
238
238
|
}>;
|
|
239
239
|
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
240
240
|
id: z.ZodString;
|
|
@@ -255,11 +255,11 @@ export declare const recommendationItemSchema: z.ZodObject<{
|
|
|
255
255
|
followers: z.ZodNumber;
|
|
256
256
|
following: z.ZodNumber;
|
|
257
257
|
}, "strip", z.ZodTypeAny, {
|
|
258
|
-
followers: number;
|
|
259
258
|
following: number;
|
|
260
|
-
}, {
|
|
261
259
|
followers: number;
|
|
260
|
+
}, {
|
|
262
261
|
following: number;
|
|
262
|
+
followers: number;
|
|
263
263
|
}>;
|
|
264
264
|
}, z.ZodTypeAny, "passthrough">>;
|
|
265
265
|
export type RecommendationItem = z.infer<typeof recommendationItemSchema>;
|
|
@@ -283,11 +283,11 @@ export declare const recommendationResponseSchema: z.ZodArray<z.ZodObject<{
|
|
|
283
283
|
followers: z.ZodNumber;
|
|
284
284
|
following: z.ZodNumber;
|
|
285
285
|
}, "strip", z.ZodTypeAny, {
|
|
286
|
-
followers: number;
|
|
287
286
|
following: number;
|
|
288
|
-
}, {
|
|
289
287
|
followers: number;
|
|
288
|
+
}, {
|
|
290
289
|
following: number;
|
|
290
|
+
followers: number;
|
|
291
291
|
}>;
|
|
292
292
|
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
293
293
|
id: z.ZodString;
|
|
@@ -308,11 +308,11 @@ export declare const recommendationResponseSchema: z.ZodArray<z.ZodObject<{
|
|
|
308
308
|
followers: z.ZodNumber;
|
|
309
309
|
following: z.ZodNumber;
|
|
310
310
|
}, "strip", z.ZodTypeAny, {
|
|
311
|
-
followers: number;
|
|
312
311
|
following: number;
|
|
313
|
-
}, {
|
|
314
312
|
followers: number;
|
|
313
|
+
}, {
|
|
315
314
|
following: number;
|
|
315
|
+
followers: number;
|
|
316
316
|
}>;
|
|
317
317
|
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
318
318
|
id: z.ZodString;
|
|
@@ -333,11 +333,11 @@ export declare const recommendationResponseSchema: z.ZodArray<z.ZodObject<{
|
|
|
333
333
|
followers: z.ZodNumber;
|
|
334
334
|
following: z.ZodNumber;
|
|
335
335
|
}, "strip", z.ZodTypeAny, {
|
|
336
|
-
followers: number;
|
|
337
336
|
following: number;
|
|
338
|
-
}, {
|
|
339
337
|
followers: number;
|
|
338
|
+
}, {
|
|
340
339
|
following: number;
|
|
340
|
+
followers: number;
|
|
341
341
|
}>;
|
|
342
342
|
}, z.ZodTypeAny, "passthrough">>, "many">;
|
|
343
343
|
export type RecommendationResponse = z.infer<typeof recommendationResponseSchema>;
|
package/dist/types/updates.d.ts
CHANGED
|
@@ -337,6 +337,7 @@ export declare const createUpdateRequestSchema: z.ZodObject<{
|
|
|
337
337
|
/** Human-readable publish message (console display). */
|
|
338
338
|
message: z.ZodOptional<z.ZodString>;
|
|
339
339
|
}, "strip", z.ZodTypeAny, {
|
|
340
|
+
channel: string;
|
|
340
341
|
applicationId: string;
|
|
341
342
|
assets: {
|
|
342
343
|
sha256: string;
|
|
@@ -344,7 +345,6 @@ export declare const createUpdateRequestSchema: z.ZodObject<{
|
|
|
344
345
|
key: string;
|
|
345
346
|
fileExtension?: string | undefined;
|
|
346
347
|
}[];
|
|
347
|
-
channel: string;
|
|
348
348
|
runtimeVersion: string;
|
|
349
349
|
platform: "ios" | "android";
|
|
350
350
|
launchAsset: {
|
|
@@ -364,6 +364,7 @@ export declare const createUpdateRequestSchema: z.ZodObject<{
|
|
|
364
364
|
gitCommit?: string | undefined;
|
|
365
365
|
gitBranch?: string | undefined;
|
|
366
366
|
}, {
|
|
367
|
+
channel: string;
|
|
367
368
|
applicationId: string;
|
|
368
369
|
assets: {
|
|
369
370
|
sha256: string;
|
|
@@ -371,7 +372,6 @@ export declare const createUpdateRequestSchema: z.ZodObject<{
|
|
|
371
372
|
key: string;
|
|
372
373
|
fileExtension?: string | undefined;
|
|
373
374
|
}[];
|
|
374
|
-
channel: string;
|
|
375
375
|
runtimeVersion: string;
|
|
376
376
|
platform: "ios" | "android";
|
|
377
377
|
launchAsset: {
|