@oxy.so/contracts 4.15.0 → 4.17.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.
Files changed (136) hide show
  1. package/dist/cjs/.tsbuildinfo +1 -1
  2. package/dist/cjs/accountEmail.js +12 -34
  3. package/dist/cjs/accountGraph.js +22 -320
  4. package/dist/cjs/agentKeys.js +11 -13
  5. package/dist/cjs/client/accountEmail.js +48 -0
  6. package/dist/cjs/client/accountGraph.js +323 -0
  7. package/dist/cjs/client/agentKeys.js +77 -0
  8. package/dist/cjs/client/check.js +466 -0
  9. package/dist/cjs/client/deviceBoot.js +22 -0
  10. package/dist/cjs/client/deviceDirectory.js +51 -0
  11. package/dist/cjs/client/deviceSession.js +63 -0
  12. package/dist/cjs/client/externalIdentity.js +19 -0
  13. package/dist/cjs/client/identity.js +45 -0
  14. package/dist/cjs/client/identityLink.js +55 -0
  15. package/dist/cjs/client/identityProof.js +109 -0
  16. package/dist/cjs/client/index.js +190 -0
  17. package/dist/cjs/client/organizations.js +114 -0
  18. package/dist/cjs/client/products.js +153 -0
  19. package/dist/cjs/client/recommendations.js +33 -0
  20. package/dist/cjs/client/reputation.js +41 -0
  21. package/dist/cjs/client/safety.js +15 -0
  22. package/dist/cjs/client/sessionStatus.js +23 -0
  23. package/dist/cjs/client/signIn.js +157 -0
  24. package/dist/cjs/client/userResponse.js +15 -0
  25. package/dist/cjs/client/username.js +173 -0
  26. package/dist/cjs/deviceSession.js +3 -16
  27. package/dist/cjs/identityLink.js +13 -34
  28. package/dist/cjs/identityProof.js +18 -106
  29. package/dist/cjs/index.js +15 -10
  30. package/dist/cjs/inference/money.js +10 -0
  31. package/dist/cjs/inference/version.js +1 -1
  32. package/dist/cjs/organizations.js +21 -41
  33. package/dist/cjs/products/billing.js +0 -1
  34. package/dist/cjs/products/checkout.js +1 -14
  35. package/dist/cjs/products/plans.js +2 -18
  36. package/dist/cjs/reputation.js +3 -34
  37. package/dist/cjs/signIn.js +57 -96
  38. package/dist/cjs/userResponse.js +1 -8
  39. package/dist/cjs/username.js +23 -158
  40. package/dist/esm/.tsbuildinfo +1 -1
  41. package/dist/esm/accountEmail.js +4 -32
  42. package/dist/esm/accountGraph.js +4 -309
  43. package/dist/esm/agentKeys.js +4 -10
  44. package/dist/esm/client/accountEmail.js +45 -0
  45. package/dist/esm/client/accountGraph.js +314 -0
  46. package/dist/esm/client/agentKeys.js +74 -0
  47. package/dist/esm/client/check.js +428 -0
  48. package/dist/esm/client/deviceBoot.js +19 -0
  49. package/dist/esm/client/deviceDirectory.js +48 -0
  50. package/dist/esm/client/deviceSession.js +60 -0
  51. package/dist/esm/client/externalIdentity.js +16 -0
  52. package/dist/esm/client/identity.js +42 -0
  53. package/dist/esm/client/identityLink.js +50 -0
  54. package/dist/esm/client/identityProof.js +104 -0
  55. package/dist/esm/client/index.js +37 -0
  56. package/dist/esm/client/organizations.js +111 -0
  57. package/dist/esm/client/products.js +150 -0
  58. package/dist/esm/client/recommendations.js +30 -0
  59. package/dist/esm/client/reputation.js +37 -0
  60. package/dist/esm/client/safety.js +12 -0
  61. package/dist/esm/client/sessionStatus.js +20 -0
  62. package/dist/esm/client/signIn.js +151 -0
  63. package/dist/esm/client/userResponse.js +12 -0
  64. package/dist/esm/client/username.js +167 -0
  65. package/dist/esm/deviceSession.js +1 -15
  66. package/dist/esm/identityLink.js +4 -27
  67. package/dist/esm/identityProof.js +4 -99
  68. package/dist/esm/index.js +2 -2
  69. package/dist/esm/inference/money.js +10 -0
  70. package/dist/esm/inference/version.js +1 -1
  71. package/dist/esm/organizations.js +4 -31
  72. package/dist/esm/products/billing.js +0 -1
  73. package/dist/esm/products/checkout.js +0 -13
  74. package/dist/esm/products/plans.js +1 -17
  75. package/dist/esm/reputation.js +1 -32
  76. package/dist/esm/signIn.js +29 -83
  77. package/dist/esm/userResponse.js +1 -8
  78. package/dist/esm/username.js +4 -148
  79. package/dist/types/.tsbuildinfo +1 -1
  80. package/dist/types/accountEmail.d.ts +2 -34
  81. package/dist/types/accountGraph.d.ts +12 -208
  82. package/dist/types/agency.d.ts +24 -24
  83. package/dist/types/agentKeys.d.ts +8 -6
  84. package/dist/types/client/accountEmail.d.ts +44 -0
  85. package/dist/types/client/accountGraph.d.ts +203 -0
  86. package/dist/types/client/agentKeys.d.ts +113 -0
  87. package/dist/types/client/check.d.ts +184 -0
  88. package/dist/types/client/deviceBoot.d.ts +6 -0
  89. package/dist/types/client/deviceDirectory.d.ts +134 -0
  90. package/dist/types/client/deviceSession.d.ts +91 -0
  91. package/dist/types/client/externalIdentity.d.ts +14 -0
  92. package/dist/types/client/identity.d.ts +8 -0
  93. package/dist/types/client/identityLink.d.ts +21 -0
  94. package/dist/types/client/identityProof.d.ts +73 -0
  95. package/dist/types/client/index.d.ts +37 -0
  96. package/dist/types/client/organizations.d.ts +167 -0
  97. package/dist/types/client/products.d.ts +145 -0
  98. package/dist/types/client/recommendations.d.ts +27 -0
  99. package/dist/types/client/reputation.d.ts +28 -0
  100. package/dist/types/client/safety.d.ts +13 -0
  101. package/dist/types/client/sessionStatus.d.ts +19 -0
  102. package/dist/types/client/signIn.d.ts +107 -0
  103. package/dist/types/client/userResponse.d.ts +7 -0
  104. package/dist/types/client/username.d.ts +126 -0
  105. package/dist/types/deviceDirectory.d.ts +28 -28
  106. package/dist/types/deviceSession.d.ts +1 -12
  107. package/dist/types/externalIdentity.d.ts +11 -44
  108. package/dist/types/identityLink.d.ts +3 -11
  109. package/dist/types/identityProof.d.ts +2 -65
  110. package/dist/types/index.d.ts +3 -3
  111. package/dist/types/inference/catalogue.d.ts +7 -7
  112. package/dist/types/inference/decisions.d.ts +41 -41
  113. package/dist/types/inference/economics.d.ts +5 -5
  114. package/dist/types/inference/embeddings.d.ts +16 -16
  115. package/dist/types/inference/errors.d.ts +8 -8
  116. package/dist/types/inference/inbox.d.ts +8 -8
  117. package/dist/types/inference/money.d.ts +17 -8
  118. package/dist/types/inference/priceVersion.d.ts +12 -12
  119. package/dist/types/inference/privateAutoExecution.d.ts +6 -6
  120. package/dist/types/inference/realtime.d.ts +54 -54
  121. package/dist/types/inference/request.d.ts +28 -28
  122. package/dist/types/inference/routingPolicy.d.ts +7 -7
  123. package/dist/types/inference/streamEvents.d.ts +26 -26
  124. package/dist/types/inference/usage.d.ts +32 -32
  125. package/dist/types/inference/version.d.ts +1 -1
  126. package/dist/types/oauth.d.ts +2 -2
  127. package/dist/types/organizations.d.ts +8 -10
  128. package/dist/types/products/billing.d.ts +3 -8
  129. package/dist/types/products/checkout.d.ts +0 -36
  130. package/dist/types/products/plans.d.ts +5 -102
  131. package/dist/types/reputation.d.ts +1 -11
  132. package/dist/types/sessionStatus.d.ts +2 -2
  133. package/dist/types/signIn.d.ts +74 -76
  134. package/dist/types/userResponse.d.ts +23 -159
  135. package/dist/types/username.d.ts +1 -96
  136. package/package.json +20 -1
@@ -18,6 +18,11 @@
18
18
  * one-use second-factor challenge instead of a session, and
19
19
  * `POST /auth/signin/second-factor` takes the TOTP (or a backup code).
20
20
  *
21
+ * An email may hold several accounts (up to `EMAIL_ACCOUNTS_MAX`). Signing in
22
+ * with the email, once the code or the link proves it, answers the accounts to
23
+ * choose from when there are several, and `POST /auth/signin/email/choose`
24
+ * names one. A username always names one account.
25
+ *
21
26
  * `POST /auth/signup` creates an account from a username and an email confirmed
22
27
  * with `POST /auth/email/verify/{start,confirm}` (purpose `signup`).
23
28
  *
@@ -27,40 +32,10 @@
27
32
  import { z } from 'zod';
28
33
  import { EMAIL_CODE_LENGTH, emailAddressSchema, emailTicketSchema } from './accountEmail.js';
29
34
  import { deviceProofSchema } from './deviceSession.js';
30
- /** How long the link in a sign-in email can be opened. */
31
- export const EMAIL_SIGNIN_LINK_TTL_MS = 15 * 60 * 1000;
32
- /** How long a second-factor challenge can be answered. */
33
- export const SIGNIN_SECOND_FACTOR_TTL_MS = 5 * 60 * 1000;
34
- /** Wrong second-factor codes one challenge accepts. */
35
- export const SIGNIN_SECOND_FACTOR_MAX_ATTEMPTS = 5;
36
- /** Shortest password Oxy accepts when one is set. */
37
- export const PASSWORD_MIN_LENGTH = 10;
38
- /** Longest password Oxy accepts (characters). */
39
- export const PASSWORD_MAX_LENGTH = 256;
40
- /** Digits in an authenticator code. */
41
- export const TOTP_DIGITS = 6;
42
- /** Seconds each authenticator code lasts. */
43
- export const TOTP_PERIOD_SECONDS = 30;
44
- /** Backup codes issued when an authenticator is enabled or they are regenerated. */
45
- export const TOTP_BACKUP_CODE_COUNT = 10;
46
- /**
47
- * The long sign-in code: ten characters of Crockford base32 without the
48
- * look-alikes (no 0, O, 1, I, L, U), shown as `XXXXX-XXXXX`. An account whose
49
- * sign-in codes were guessed at too often today (the per-account ceiling) is
50
- * sent this instead of 6 digits for the rest of the day, so its owner can still
51
- * type a code while guessing one is infeasible.
52
- */
53
- export const EMAIL_SIGNIN_LONG_CODE_ALPHABET = '23456789ABCDEFGHJKMNPQRSTVWXYZ';
54
- export const EMAIL_SIGNIN_LONG_CODE_LENGTH = 10;
55
- /**
56
- * Normalise a typed sign-in code: 6 digits stay as they are; a long code is
57
- * upper-cased with its dash and spaces removed. Anything else is returned
58
- * trimmed (and will simply be wrong).
59
- */
60
- export function normalizeEmailSignInCode(code) {
61
- const compact = code.trim().replace(/[\s-]/g, '').toUpperCase();
62
- return compact;
63
- }
35
+ // The Zod-free half of this contract lives in `./client/` (`@oxy.so/contracts/client`);
36
+ // it is re-exported here so the root entry is unchanged.
37
+ import { PASSWORD_MIN_LENGTH, PASSWORD_MAX_LENGTH, TOTP_DIGITS, TOTP_BACKUP_CODE_COUNT, EMAIL_SIGNIN_LONG_CODE_ALPHABET, EMAIL_SIGNIN_LONG_CODE_LENGTH, normalizeEmailSignInCode, EMAIL_ACCOUNTS_MAX, REAUTH_ACTIONS, } from './client/signIn.js';
38
+ export { EMAIL_SIGNIN_LINK_TTL_MS, SIGNIN_SECOND_FACTOR_TTL_MS, SIGNIN_SECOND_FACTOR_MAX_ATTEMPTS, PASSWORD_MIN_LENGTH, PASSWORD_MAX_LENGTH, TOTP_DIGITS, TOTP_PERIOD_SECONDS, TOTP_BACKUP_CODE_COUNT, EMAIL_SIGNIN_LONG_CODE_ALPHABET, EMAIL_SIGNIN_LONG_CODE_LENGTH, normalizeEmailSignInCode, EMAIL_SIGNIN_CHOICE_TTL_MS, EMAIL_ACCOUNTS_MAX, isSecondFactorRequired, isEmailSignInChooseAccount, REAUTH_ACTIONS, SIGN_IN_ERROR_CODES, } from './client/signIn.js';
64
39
  const sixDigits = z
65
40
  .string()
66
41
  .trim()
@@ -188,21 +163,26 @@ export const emailSignInPendingSchema = z.object({
188
163
  status: z.literal('pending'),
189
164
  expiresAt: z.number().int().positive(),
190
165
  });
191
- /** Narrow a {@link SignInStepResult}. */
192
- export function isSecondFactorRequired(result) {
193
- return result.secondFactorRequired === true;
194
- }
195
- /**
196
- * What a re-verification email code confirms. The code is bound to it: a code
197
- * asked for one change never authorises another, and the email names it.
198
- */
199
- export const REAUTH_ACTIONS = [
200
- 'change_password',
201
- 'totp',
202
- 'link_commons',
203
- 'delete_account',
204
- 'credentials_manage',
205
- ];
166
+ export const emailSignInAccountOptionSchema = z.object({
167
+ id: z.string().min(1).max(64),
168
+ username: z.string().min(1).optional(),
169
+ displayName: z.string().min(1).optional(),
170
+ avatar: z.string().min(1).optional(),
171
+ });
172
+ export const emailSignInChooseAccountSchema = z.object({
173
+ chooseAccount: z.literal(true),
174
+ accounts: z.array(emailSignInAccountOptionSchema).min(2).max(EMAIL_ACCOUNTS_MAX),
175
+ expiresAt: z.number().int().positive(),
176
+ });
177
+ /** `POST /auth/signin/email/choose` — the account, from those {@link EmailSignInChooseAccount} listed. */
178
+ export const emailSignInChooseRequestSchema = z
179
+ .object({
180
+ requestId: z.string().trim().min(1).max(64),
181
+ requestSecret: opaqueTokenSchema,
182
+ userId: z.string().trim().min(1).max(64),
183
+ ...sessionEnvelope,
184
+ })
185
+ .strict();
206
186
  /** `POST /users/me/reauth/email` */
207
187
  export const reauthEmailStartRequestSchema = z.object({ action: z.enum(REAUTH_ACTIONS) }).strict();
208
188
  /**
@@ -276,37 +256,3 @@ export const totpBackupCodesResponseSchema = z.object({
276
256
  .array(z.string().regex(/^[a-z2-9]{5}-[a-z2-9]{5}$/))
277
257
  .length(TOTP_BACKUP_CODE_COUNT),
278
258
  });
279
- /**
280
- * Stable error codes (`error.code` in the API error body). Clients map these
281
- * through their localization, never the English message.
282
- */
283
- export const SIGN_IN_ERROR_CODES = {
284
- /** Wrong identifier or password — never says which. */
285
- invalidCredentials: 'SIGNIN_INVALID_CREDENTIALS',
286
- /** The request is unknown, expired, spent, or its secret is wrong. */
287
- requestInvalid: 'SIGNIN_REQUEST_INVALID',
288
- /** The link is unknown, expired or already used. */
289
- linkInvalid: 'SIGNIN_LINK_INVALID',
290
- /** The link was opened in another browser: type the code in the app instead. */
291
- linkOtherDevice: 'SIGNIN_LINK_OTHER_DEVICE',
292
- /** The second-factor challenge or its code is wrong, expired or spent. */
293
- secondFactorInvalid: 'SECOND_FACTOR_INVALID',
294
- /** Too many failures for this account: wait and try again. */
295
- locked: 'SIGNIN_LOCKED',
296
- /** The step needs a fresh proof (`reauth`). */
297
- reauthRequired: 'REAUTH_REQUIRED',
298
- /** The fresh proof was wrong. */
299
- reauthInvalid: 'REAUTH_INVALID',
300
- /** The account has an authenticator: the proof must carry its code. */
301
- totpRequired: 'TOTP_REQUIRED',
302
- /** Enrolling or confirming an authenticator that is already on. */
303
- totpAlreadyEnabled: 'TOTP_ALREADY_ENABLED',
304
- /** Disabling, confirming or regenerating codes with no authenticator (or no pending one). */
305
- totpNotEnabled: 'TOTP_NOT_ENABLED',
306
- /** The code the authenticator showed at enrolment is wrong. */
307
- totpCodeInvalid: 'TOTP_CODE_INVALID',
308
- /** Only official Oxy apps and auth.oxy.so may sign people in here. */
309
- originNotAllowed: 'SIGNIN_ORIGIN_NOT_ALLOWED',
310
- /** The username is taken. */
311
- usernameTaken: 'USERNAME_TAKEN',
312
- };
@@ -241,10 +241,6 @@ export const userResponseSchema = z
241
241
  * so it is present on the current-user DTO (`GET /users/me`,
242
242
  * `GET /session/user/:sessionId`) and absent until the user sets it.
243
243
  */
244
- userPreferences: z
245
- .object({ displayCurrency: z.enum(['USD', 'EUR', 'FAIR']).optional() })
246
- .catchall(z.unknown())
247
- .optional(),
248
244
  themePreference: themePreferenceSchema.optional(),
249
245
  personalization: z
250
246
  .object({
@@ -305,10 +301,7 @@ export const userProfileUpdateSchema = z
305
301
  languages: z.array(z.string()).optional(),
306
302
  accountExpiresAfterInactivityDays: z.number().nullable().optional(),
307
303
  notificationPreferences: z.record(z.unknown()).optional(),
308
- userPreferences: z
309
- .object({ displayCurrency: z.enum(['USD', 'EUR', 'FAIR']).optional() })
310
- .catchall(z.unknown())
311
- .optional(),
304
+ userPreferences: z.record(z.unknown()).optional(),
312
305
  privacySettings: z.record(z.unknown()).optional(),
313
306
  /**
314
307
  * Portable theme preference. Written through the same `PUT /users/me`
@@ -99,100 +99,10 @@
99
99
  * knows what is taken, and it must not pretend to.
100
100
  */
101
101
  import { z } from 'zod';
102
- /** Shortest storable handle. `oxy` sets the floor. */
103
- export const USERNAME_MIN_LENGTH = 3;
104
- /** Longest storable handle, and the `maxLength` an input field should carry. */
105
- export const USERNAME_MAX_LENGTH = 30;
106
- /** The 400 / inline-validation copy for every path that rejects a handle. */
107
- export const USERNAME_INVALID_MESSAGE = 'Username must be 3-30 characters, use only letters, numbers, hyphens and underscores, ' +
108
- 'start and end with a letter or number, and never repeat a separator';
109
- /**
110
- * Exact-match handles nobody may newly claim, regardless of account kind.
111
- *
112
- * This is NOT a namespace tightening like the bot suffix — it is a list of
113
- * names withheld from `users_lower_username_key` before anybody asks for
114
- * them. Compared against the same normalization the unique index applies
115
- * (`lower(btrim(username))`), so `Admin`, ` ADMIN ` and `admin` are the one
116
- * name this list means.
117
- *
118
- * `oxy`, `mention`, `homiio`, `clarity`, `faircoin`, `astro` and `mercaria`
119
- * are deliberately NOT here: each already has an `organization`/`project`
120
- * row, so the unique index already refuses a second one, and `oxy` is the
121
- * name `USERNAME_MIN_LENGTH` is pinned against in
122
- * `__tests__/username.test.ts` — listing it would make
123
- * `usernameSchema.safeParse('oxy')` fail and falsify that comment. A brand
124
- * with no account of its own yet (measured 2026-09-18: Alia, Allo, TNP,
125
- * Kaana, Bloom) has no row to protect it, so it is listed until one exists.
126
- */
127
- export const RESERVED_USERNAMES = new Set([
128
- // Oxy product lines with no account row of their own yet.
129
- 'alia',
130
- 'allo',
131
- 'tnp',
132
- 'kaana',
133
- 'bloom',
134
- // System / role words a signup impersonating staff or Oxy itself would reach for.
135
- 'admin',
136
- 'administrator',
137
- 'root',
138
- 'superadmin',
139
- 'super',
140
- 'superuser',
141
- 'support',
142
- 'staff',
143
- 'moderator',
144
- 'mod',
145
- 'security',
146
- 'system',
147
- 'official',
148
- 'help',
149
- 'noreply',
150
- 'anonymous',
151
- 'everyone',
152
- 'owner',
153
- ]);
154
- /** The 400 / inline-validation copy for a handle on {@link RESERVED_USERNAMES}. */
155
- export const RESERVED_USERNAME_MESSAGE = 'This username is reserved and cannot be registered';
156
- /**
157
- * {@link RESERVED_USERNAMES}, minus `alia`, checked against each `-`/`_`
158
- * separated SEGMENT of a candidate rather than the whole string — so
159
- * `official-oxy`, `super-admin` and `team-kaana` are refused the same as the
160
- * bare words, without banning every word that merely CONTAINS one as a
161
- * substring (`superman`, `modern`, `grassroot`, `homeowner` all stay legal:
162
- * none of them separates the reserved word from the rest with `-` or `_`).
163
- *
164
- * `alia` is excluded because `alia-` is the live internal-cost-centre
165
- * namespace: `alia-production-chat` is a minted account and
166
- * `alia-research` / `alia-voice` / `alia-evaluations` are pinned as legal
167
- * slugs in `__tests__/username.test.ts` and `internalCostCenterSpecs.test.ts`.
168
- * Segment-matching `alia` would refuse all four. The bare word `alia` is
169
- * still refused — {@link RESERVED_USERNAMES} above catches it exactly.
170
- */
171
- const RESERVED_USERNAME_SEGMENTS = new Set([...RESERVED_USERNAMES].filter((word) => word !== 'alia'));
172
- /** The 400 / inline-validation copy for a handle that is only digits. */
173
- export const NUMERIC_USERNAME_MESSAGE = 'Username cannot be only numbers';
174
- /**
175
- * Alphanumeric runs joined by single separators, as a SOURCE string.
176
- *
177
- * A string rather than a literal because the OpenAPI docblocks that publish this
178
- * rule (`POST /auth/register`, `PUT /users/:userId`) must quote it verbatim, and
179
- * `usernamePolicySingleSource.test.ts` compares them against THIS constant. A
180
- * published `pattern:` that drifts from the enforced rule is a lie told to every
181
- * client that generates from the spec, and it is exactly the kind of copy nobody
182
- * notices going stale.
183
- *
184
- * Deliberately NOT re-exported from the package barrel: it exists for the
185
- * schema below and for that one gate. Anything validating a username uses
186
- * {@link usernameSchema}, so there is no second way to ask the question.
187
- *
188
- * Written as an unambiguous alternation rather than a lookahead: every character
189
- * belongs to exactly one branch, so matching is linear and there is no
190
- * backtracking to bound. It also carries no `\p{…}` property escape, which
191
- * mobile Hermes throws on at runtime — this module is reachable from every React
192
- * Native consumer.
193
- */
194
- export const USERNAME_PATTERN_SOURCE = '^[A-Za-z0-9]+(?:[-_][A-Za-z0-9]+)*$';
195
- const USERNAME_PATTERN = new RegExp(USERNAME_PATTERN_SOURCE);
102
+ // The Zod-free half of this contract lives in `./client/` (`@oxy.so/contracts/client`);
103
+ // it is re-exported here so the root entry is unchanged.
104
+ import { USERNAME_MIN_LENGTH, USERNAME_MAX_LENGTH, USERNAME_INVALID_MESSAGE, RESERVED_USERNAMES, RESERVED_USERNAME_MESSAGE, NUMERIC_USERNAME_MESSAGE, BOT_USERNAME_SUFFIX, BOT_USERNAME_INVALID_MESSAGE, RESERVED_USERNAME_SEGMENTS, USERNAME_PATTERN, } from './client/username.js';
105
+ export { USERNAME_MIN_LENGTH, USERNAME_MAX_LENGTH, USERNAME_INVALID_MESSAGE, RESERVED_USERNAMES, RESERVED_USERNAME_MESSAGE, NUMERIC_USERNAME_MESSAGE, USERNAME_PATTERN_SOURCE, stripDisallowedUsernameCharacters, BOT_USERNAME_SUFFIX, BOT_USERNAME_INVALID_MESSAGE, applyBotUsernameSuffix, } from './client/username.js';
196
106
  /**
197
107
  * The one username policy, as a schema.
198
108
  *
@@ -223,36 +133,6 @@ export const usernameSchema = z
223
133
  export function isValidUsername(candidate) {
224
134
  return usernameSchema.safeParse(candidate).success;
225
135
  }
226
- /**
227
- * Drop the characters the policy forbids, for an input field that filters
228
- * keystrokes.
229
- *
230
- * This is a TYPING aid and nothing else — the result still has to pass
231
- * {@link usernameSchema}, which is what decides. It does not lower-case (case is
232
- * preserved, see the header) and it cannot repair a name: a value that is too
233
- * short, edge-separated or doubly-separated comes back unchanged and fails
234
- * validation with a message, which is the outcome the coercing rules this
235
- * replaces used to hide.
236
- */
237
- export function stripDisallowedUsernameCharacters(input) {
238
- return input.replace(/[^A-Za-z0-9_-]/g, '');
239
- }
240
- /**
241
- * The label a bot's handle ends in — the ONE exception the policy carries.
242
- *
243
- * Lower-case here because it is what a generator appends; the comparison that
244
- * enforces it folds case, so `MyBot` satisfies it just as `mybot` does.
245
- *
246
- * Deliberately NOT re-exported from the package barrel, for the same reason
247
- * {@link USERNAME_PATTERN_SOURCE} is not: it exists for the schema and the
248
- * generator aid below. A consumer that wants to SAY the rule uses
249
- * {@link BOT_USERNAME_INVALID_MESSAGE}, which already quotes it, and one that
250
- * wants to APPLY it uses {@link applyBotUsernameSuffix} — so there is no second
251
- * way to spell the check.
252
- */
253
- export const BOT_USERNAME_SUFFIX = 'bot';
254
- /** The 400 / inline-validation copy for a bot handle that carries no label. */
255
- export const BOT_USERNAME_INVALID_MESSAGE = `A bot account's username must end in "${BOT_USERNAME_SUFFIX}"`;
256
136
  /**
257
137
  * The username policy for an account of kind `bot`: everything above, plus a
258
138
  * handle that ends in {@link BOT_USERNAME_SUFFIX}.
@@ -327,27 +207,3 @@ export const botUsernameSchema = usernameSchema.refine((username) => username.to
327
207
  export function usernameSchemaForAccountKind(kind) {
328
208
  return kind === 'bot' ? botUsernameSchema : usernameSchema;
329
209
  }
330
- /**
331
- * Label a proposed bot handle, so a generator PROPOSES something the server will
332
- * accept.
333
- *
334
- * Alia builds an agent's handle from its display name; without this it would
335
- * propose `garden-helper` for a bot and be 400ed on submit, which is the same
336
- * "suggest, then refuse" defect the minimum length already caused once.
337
- *
338
- * It appends and never inserts: a separator is the caller's choice, so
339
- * `garden-helper` becomes `garden-helperbot` while a caller who typed
340
- * `garden-helper-` gets `garden-helper-bot`. It truncates to leave room rather
341
- * than overflowing {@link USERNAME_MAX_LENGTH}.
342
- *
343
- * Like {@link stripDisallowedUsernameCharacters} it is an aid, not a decision: it
344
- * cannot repair a handle the base policy refuses, and the result still has to
345
- * pass {@link botUsernameSchema}.
346
- */
347
- export function applyBotUsernameSuffix(candidate) {
348
- const trimmed = candidate.trim();
349
- if (trimmed.toLowerCase().endsWith(BOT_USERNAME_SUFFIX)) {
350
- return trimmed;
351
- }
352
- return trimmed.slice(0, USERNAME_MAX_LENGTH - BOT_USERNAME_SUFFIX.length) + BOT_USERNAME_SUFFIX;
353
- }