@oxyhq/contracts 0.21.0 → 0.23.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.
@@ -1,83 +1,238 @@
1
1
  /**
2
- * Account graph wire contracts — organization taxonomy and create-account input.
2
+ * Account graph wire contracts — the account-kind vocabulary, the account
3
+ * category taxonomy, and the create-account input.
3
4
  *
4
- * `organizationCategory` classifies `kind: 'organization'` accounts (agency,
5
- * cooperative, landlord, …) without polluting `User.kind`. Meaningful only when
6
- * `kind === 'organization'`.
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.
7
8
  */
8
9
  import { z } from 'zod';
9
- export declare const ORGANIZATION_CATEGORIES: readonly ["agency", "cooperative", "landlord", "other"];
10
- export type OrganizationCategory = (typeof ORGANIZATION_CATEGORIES)[number];
11
- export declare const organizationCategorySchema: z.ZodEnum<["agency", "cooperative", "landlord", "other"]>;
10
+ /**
11
+ * Account-graph classification the ONE authority for the kind vocabulary.
12
+ *
13
+ * `personal` is the only kind minted by signup and the only one that carries
14
+ * its own credentials; every other kind is a child account created under a
15
+ * parent and operated through `account_members`. The API schema, the Mongoose
16
+ * model and the SDK all derive from this list rather than restating it, so a
17
+ * new kind is one edit here instead of four literals that can drift.
18
+ */
19
+ export type AccountKind = 'personal' | 'organization' | 'project' | 'bot' | 'channel';
20
+ /**
21
+ * The union is spelled out above and the array proves coverage BOTH ways
22
+ * (`satisfies` here, the `Gap` alias below) — the same shape this package's
23
+ * `ACCOUNT_CATEGORY_IDS` / `TRUST_TIERS` pairs use, and the one
24
+ * `db/schema/users.ts` mirrors to keep the `users_kind_check` CHECK honest.
25
+ *
26
+ * Deriving the union from the array instead would cost nothing here and be paid
27
+ * by consumers: `kind` travels into `@oxyhq/services` through
28
+ * `SwitchableAccount`, where an indexed-access type is materially more
29
+ * expensive to check than a literal union.
30
+ */
31
+ export declare const ACCOUNT_KINDS: readonly ["personal", "organization", "project", "bot", "channel"];
32
+ /** `never` while `ACCOUNT_KINDS` covers the union. */
33
+ export type AccountKindGap = Exclude<AccountKind, (typeof ACCOUNT_KINDS)[number]>;
34
+ export declare const accountKindSchema: z.ZodEnum<["personal", "organization", "project", "bot", "channel"]>;
35
+ /**
36
+ * Kinds that may be CREATED as children of another account. Exactly
37
+ * `ACCOUNT_KINDS` minus `personal`, which is always a tree root.
38
+ */
39
+ export type ChildAccountKind = Exclude<AccountKind, 'personal'>;
40
+ export declare const CHILD_ACCOUNT_KINDS: readonly ["organization", "project", "bot", "channel"];
41
+ /** `never` while `CHILD_ACCOUNT_KINDS` covers the child union. */
42
+ export type ChildAccountKindGap = Exclude<ChildAccountKind, (typeof CHILD_ACCOUNT_KINDS)[number]>;
43
+ export declare const childAccountKindSchema: z.ZodEnum<["organization", "project", "bot", "channel"]>;
44
+ /**
45
+ * Whether an operator may ACT AS an account of this kind — switch the whole app
46
+ * into it (`POST /accounts/:id/switch`) or authorise an app to act as it
47
+ * (an OAuth delegated subject).
48
+ *
49
+ * Two kinds are refused, for opposite reasons:
50
+ *
51
+ * - `personal` is a human login, so assuming it would be impersonation.
52
+ * - `channel` is a CONTENT identity, not an operating one. A channel exists so
53
+ * that posts can be authored BY it; it is never a seat anybody occupies. Its
54
+ * operators act on it through their own membership, and an application
55
+ * publishes to it with its own credential. Refusing act-as is what makes
56
+ * "no login, ever" structural rather than incidental: no session can be
57
+ * minted whose subject is a channel, so no bearer exists that could add an
58
+ * auth method to one (every auth-method write resolves its target from the
59
+ * authenticated subject, never from a parameter).
60
+ *
61
+ * Consumers must gate on this predicate rather than testing `kind === 'personal'`,
62
+ * which silently admits every kind added after it was written.
63
+ */
64
+ export declare function isActAsEligibleKind(kind: AccountKind | null | undefined): boolean;
65
+ /**
66
+ * Narrow an unknown value to an {@link AccountKind}.
67
+ *
68
+ * The user-DTO serializers read from structurally-permissive `unknown` sources
69
+ * (a Drizzle row, a Mongo document, an already-formatted object), so each one
70
+ * would otherwise hand-roll this check and they would drift on what counts.
71
+ */
72
+ export declare function isAccountKind(value: unknown): value is AccountKind;
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;
12
178
  /**
13
179
  * POST /accounts — create a non-personal account under the caller's tree.
14
- * `organizationCategory` is accepted only when `kind` is `organization`.
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.
15
188
  */
16
- export declare const createAccountRequestSchema: z.ZodEffects<z.ZodObject<{
189
+ export declare const createAccountRequestSchema: z.ZodObject<{
17
190
  parentAccountId: z.ZodOptional<z.ZodString>;
18
- kind: z.ZodEnum<["organization", "project", "bot"]>;
191
+ kind: z.ZodEnum<["organization", "project", "bot", "channel"]>;
19
192
  username: z.ZodString;
20
193
  name: z.ZodOptional<z.ZodObject<{
21
194
  first: z.ZodOptional<z.ZodString>;
22
195
  last: z.ZodOptional<z.ZodString>;
196
+ displayName: z.ZodOptional<z.ZodString>;
23
197
  }, "strip", z.ZodTypeAny, {
24
198
  first?: string | undefined;
25
199
  last?: string | undefined;
200
+ displayName?: string | undefined;
26
201
  }, {
27
202
  first?: string | undefined;
28
203
  last?: string | undefined;
204
+ displayName?: string | undefined;
29
205
  }>>;
30
206
  bio: z.ZodOptional<z.ZodString>;
31
207
  avatar: z.ZodOptional<z.ZodString>;
32
208
  description: z.ZodOptional<z.ZodString>;
33
- organizationCategory: z.ZodOptional<z.ZodEnum<["agency", "cooperative", "landlord", "other"]>>;
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")[]>>;
34
211
  }, "strip", z.ZodTypeAny, {
35
- kind: "organization" | "project" | "bot";
36
- username: string;
37
- parentAccountId?: string | undefined;
38
- name?: {
39
- first?: string | undefined;
40
- last?: string | undefined;
41
- } | undefined;
42
- bio?: string | undefined;
43
- avatar?: string | undefined;
44
- description?: string | undefined;
45
- organizationCategory?: "agency" | "cooperative" | "landlord" | "other" | undefined;
46
- }, {
47
- kind: "organization" | "project" | "bot";
48
- username: string;
49
- parentAccountId?: string | undefined;
50
- name?: {
51
- first?: string | undefined;
52
- last?: string | undefined;
53
- } | undefined;
54
- bio?: string | undefined;
55
- avatar?: string | undefined;
56
- description?: string | undefined;
57
- organizationCategory?: "agency" | "cooperative" | "landlord" | "other" | undefined;
58
- }>, {
59
- kind: "organization" | "project" | "bot";
212
+ kind: "organization" | "project" | "bot" | "channel";
60
213
  username: string;
61
214
  parentAccountId?: string | undefined;
62
215
  name?: {
63
216
  first?: string | undefined;
64
217
  last?: string | undefined;
218
+ displayName?: string | undefined;
65
219
  } | undefined;
66
220
  bio?: string | undefined;
67
221
  avatar?: string | undefined;
68
222
  description?: string | undefined;
69
- 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;
70
224
  }, {
71
- kind: "organization" | "project" | "bot";
225
+ kind: "organization" | "project" | "bot" | "channel";
72
226
  username: string;
73
227
  parentAccountId?: string | undefined;
74
228
  name?: {
75
229
  first?: string | undefined;
76
230
  last?: string | undefined;
231
+ displayName?: string | undefined;
77
232
  } | undefined;
78
233
  bio?: string | undefined;
79
234
  avatar?: string | undefined;
80
235
  description?: string | undefined;
81
- organizationCategory?: "agency" | "cooperative" | "landlord" | "other" | undefined;
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;
82
237
  }>;
83
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 NEXT rotating
197
- * device secret the client must persist (rotation-in-use — the presented secret
198
- * stays valid for a short grace so multi-tab races don't lock out), and the
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;
@@ -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 { ORGANIZATION_CATEGORIES, organizationCategorySchema, createAccountRequestSchema, } from './accountGraph';
13
- export type { OrganizationCategory, CreateAccountRequest, } from './accountGraph';
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';
@@ -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: {