@oxy.so/contracts 4.16.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 (113) 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/organizations.js +21 -41
  30. package/dist/cjs/reputation.js +3 -34
  31. package/dist/cjs/signIn.js +33 -111
  32. package/dist/cjs/username.js +23 -158
  33. package/dist/esm/.tsbuildinfo +1 -1
  34. package/dist/esm/accountEmail.js +4 -32
  35. package/dist/esm/accountGraph.js +4 -309
  36. package/dist/esm/agentKeys.js +4 -10
  37. package/dist/esm/client/accountEmail.js +45 -0
  38. package/dist/esm/client/accountGraph.js +314 -0
  39. package/dist/esm/client/agentKeys.js +74 -0
  40. package/dist/esm/client/check.js +428 -0
  41. package/dist/esm/client/deviceBoot.js +19 -0
  42. package/dist/esm/client/deviceDirectory.js +48 -0
  43. package/dist/esm/client/deviceSession.js +60 -0
  44. package/dist/esm/client/externalIdentity.js +16 -0
  45. package/dist/esm/client/identity.js +42 -0
  46. package/dist/esm/client/identityLink.js +50 -0
  47. package/dist/esm/client/identityProof.js +104 -0
  48. package/dist/esm/client/index.js +37 -0
  49. package/dist/esm/client/organizations.js +111 -0
  50. package/dist/esm/client/products.js +150 -0
  51. package/dist/esm/client/recommendations.js +30 -0
  52. package/dist/esm/client/reputation.js +37 -0
  53. package/dist/esm/client/safety.js +12 -0
  54. package/dist/esm/client/sessionStatus.js +20 -0
  55. package/dist/esm/client/signIn.js +151 -0
  56. package/dist/esm/client/userResponse.js +12 -0
  57. package/dist/esm/client/username.js +167 -0
  58. package/dist/esm/deviceSession.js +1 -15
  59. package/dist/esm/identityLink.js +4 -27
  60. package/dist/esm/identityProof.js +4 -99
  61. package/dist/esm/organizations.js +4 -31
  62. package/dist/esm/reputation.js +1 -32
  63. package/dist/esm/signIn.js +4 -96
  64. package/dist/esm/username.js +4 -148
  65. package/dist/types/.tsbuildinfo +1 -1
  66. package/dist/types/accountEmail.d.ts +2 -34
  67. package/dist/types/accountGraph.d.ts +12 -208
  68. package/dist/types/agency.d.ts +24 -24
  69. package/dist/types/agentKeys.d.ts +8 -6
  70. package/dist/types/client/accountEmail.d.ts +44 -0
  71. package/dist/types/client/accountGraph.d.ts +203 -0
  72. package/dist/types/client/agentKeys.d.ts +113 -0
  73. package/dist/types/client/check.d.ts +184 -0
  74. package/dist/types/client/deviceBoot.d.ts +6 -0
  75. package/dist/types/client/deviceDirectory.d.ts +134 -0
  76. package/dist/types/client/deviceSession.d.ts +91 -0
  77. package/dist/types/client/externalIdentity.d.ts +14 -0
  78. package/dist/types/client/identity.d.ts +8 -0
  79. package/dist/types/client/identityLink.d.ts +21 -0
  80. package/dist/types/client/identityProof.d.ts +73 -0
  81. package/dist/types/client/index.d.ts +37 -0
  82. package/dist/types/client/organizations.d.ts +167 -0
  83. package/dist/types/client/products.d.ts +145 -0
  84. package/dist/types/client/recommendations.d.ts +27 -0
  85. package/dist/types/client/reputation.d.ts +28 -0
  86. package/dist/types/client/safety.d.ts +13 -0
  87. package/dist/types/client/sessionStatus.d.ts +19 -0
  88. package/dist/types/client/signIn.d.ts +107 -0
  89. package/dist/types/client/userResponse.d.ts +7 -0
  90. package/dist/types/client/username.d.ts +126 -0
  91. package/dist/types/deviceDirectory.d.ts +28 -28
  92. package/dist/types/deviceSession.d.ts +1 -12
  93. package/dist/types/externalIdentity.d.ts +11 -11
  94. package/dist/types/identityLink.d.ts +3 -11
  95. package/dist/types/identityProof.d.ts +2 -65
  96. package/dist/types/inference/decisions.d.ts +10 -10
  97. package/dist/types/inference/embeddings.d.ts +16 -16
  98. package/dist/types/inference/errors.d.ts +8 -8
  99. package/dist/types/inference/inbox.d.ts +8 -8
  100. package/dist/types/inference/privateAutoExecution.d.ts +6 -6
  101. package/dist/types/inference/realtime.d.ts +30 -30
  102. package/dist/types/inference/request.d.ts +28 -28
  103. package/dist/types/inference/streamEvents.d.ts +16 -16
  104. package/dist/types/inference/usage.d.ts +4 -4
  105. package/dist/types/oauth.d.ts +2 -2
  106. package/dist/types/organizations.d.ts +8 -10
  107. package/dist/types/products/billing.d.ts +3 -0
  108. package/dist/types/reputation.d.ts +1 -11
  109. package/dist/types/sessionStatus.d.ts +2 -2
  110. package/dist/types/signIn.d.ts +6 -89
  111. package/dist/types/userResponse.d.ts +20 -20
  112. package/dist/types/username.d.ts +1 -96
  113. package/package.json +20 -1
@@ -1,9 +1,7 @@
1
1
  /** Autonomous runtime proof. No private key crosses this contract. */
2
2
  import { z } from 'zod';
3
- export declare const AGENT_PROOF_AUDIENCE: "oxy-api/agent";
4
- export declare const AGENT_PROOF_TTL_MS = 60000;
5
- export declare const AGENT_PROOF_ACTIONS: readonly ["agent_signin", "agent_enroll", "agent_rotate", "agent_recover", "agent_governance"];
6
- export type AgentProofAction = (typeof AGENT_PROOF_ACTIONS)[number];
3
+ export { AGENT_PROOF_AUDIENCE, AGENT_PROOF_TTL_MS, AGENT_PROOF_ACTIONS, ACCOUNT_AUTH_METHODS, } from './client/agentKeys';
4
+ export type { AgentProofAction, AccountAuthMethod } from './client/agentKeys';
7
5
  export declare const agentProofClaimsSchema: z.ZodObject<{
8
6
  version: z.ZodLiteral<1>;
9
7
  audience: z.ZodLiteral<"oxy-api/agent">;
@@ -62,6 +60,7 @@ export declare const agentChallengeRequestSchema: z.ZodObject<{
62
60
  }, {
63
61
  publicKey: string;
64
62
  }>;
63
+ export type AgentChallengeRequest = z.infer<typeof agentChallengeRequestSchema>;
65
64
  export declare const agentVerifyRequestSchema: z.ZodObject<{
66
65
  challenge: z.ZodString;
67
66
  signature: z.ZodString;
@@ -79,6 +78,7 @@ export declare const agentVerifyRequestSchema: z.ZodObject<{
79
78
  publicKey: string;
80
79
  timestamp: number;
81
80
  }>;
81
+ export type AgentVerifyRequest = z.infer<typeof agentVerifyRequestSchema>;
82
82
  export declare const agentKeyOperationSchema: z.ZodDiscriminatedUnion<"operation", [z.ZodObject<{
83
83
  publicKey: z.ZodString;
84
84
  label: z.ZodString;
@@ -393,6 +393,7 @@ export declare const executeAgentKeyOperationSchema: z.ZodObject<{
393
393
  governorSignature?: string | undefined;
394
394
  };
395
395
  }>;
396
+ export type ExecuteAgentKeyOperation = z.infer<typeof executeAgentKeyOperationSchema>;
396
397
  export declare const agentKeyOperationChallengeSchema: z.ZodObject<{
397
398
  claims: z.ZodObject<{
398
399
  version: z.ZodLiteral<1>;
@@ -458,6 +459,7 @@ export declare const agentKeyOperationChallengeSchema: z.ZodObject<{
458
459
  };
459
460
  governorPublicKey: string | null;
460
461
  }>;
462
+ export type AgentKeyOperationChallenge = z.infer<typeof agentKeyOperationChallengeSchema>;
461
463
  export declare const agentKeyOperationResultSchema: z.ZodObject<{
462
464
  methodId: z.ZodNullable<z.ZodString>;
463
465
  revokedMethodIds: z.ZodArray<z.ZodString, "many">;
@@ -468,8 +470,7 @@ export declare const agentKeyOperationResultSchema: z.ZodObject<{
468
470
  methodId: string | null;
469
471
  revokedMethodIds: string[];
470
472
  }>;
471
- export declare const ACCOUNT_AUTH_METHODS: readonly ["identity", "agent_key"];
472
- export type AccountAuthMethod = (typeof ACCOUNT_AUTH_METHODS)[number];
473
+ export type AgentKeyOperationResult = z.infer<typeof agentKeyOperationResultSchema>;
473
474
  /** Public credential inventory. Never includes a proof, bearer or private key. */
474
475
  export declare const agentKeyListResponseSchema: z.ZodObject<{
475
476
  keys: z.ZodArray<z.ZodObject<{
@@ -523,3 +524,4 @@ export declare const agentKeyListResponseSchema: z.ZodObject<{
523
524
  lastUsedAt: string | null;
524
525
  }[];
525
526
  }>;
527
+ export type AgentKeyListResponse = z.infer<typeof agentKeyListResponseSchema>;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Account-email constants and response checks, without Zod. Schemas: `../accountEmail.ts`.
3
+ *
4
+ * Part of `@oxy.so/contracts/client`: never import `zod` here (see `./check.ts`).
5
+ */
6
+ import type { EmailVerificationConfirmResponse, EmailVerificationStartResponse } from '../accountEmail';
7
+ /**
8
+ * - `signup`: above.
9
+ * - `signin`: the code (and link) of an email sign-in (`POST /auth/signin/email/start`).
10
+ * - `reauth`: a signed-in person proving it is them before a sensitive step
11
+ * (`POST /users/me/reauth/email`): a password, an authenticator, deleting the
12
+ * account, linking Commons.
13
+ */
14
+ export declare const EMAIL_VERIFICATION_PURPOSES: readonly ["signup", "signin", "reauth"];
15
+ export type EmailVerificationPurpose = (typeof EMAIL_VERIFICATION_PURPOSES)[number];
16
+ /** Digits in a code. */
17
+ export declare const EMAIL_CODE_LENGTH = 6;
18
+ /** How long a code can be confirmed. */
19
+ export declare const EMAIL_CODE_TTL_MS: number;
20
+ /** Wrong codes before a verification is spent and a new code is needed. */
21
+ export declare const EMAIL_CODE_MAX_ATTEMPTS = 5;
22
+ /** How long a confirmed code's ticket can be spent. */
23
+ export declare const EMAIL_TICKET_TTL_MS: number;
24
+ /**
25
+ * Stable error codes (`error.code` in the API error body). Clients map these
26
+ * through their localization, never the English message.
27
+ */
28
+ export declare const EMAIL_VERIFICATION_ERROR_CODES: {
29
+ /** The code is wrong, or its verification expired or was spent. */
30
+ readonly codeInvalid: "EMAIL_CODE_INVALID";
31
+ /** Too many wrong codes: request a new one. */
32
+ readonly tooManyAttempts: "EMAIL_CODE_TOO_MANY_ATTEMPTS";
33
+ /** The ticket is unknown, expired, spent, or for another email or purpose. */
34
+ readonly ticketInvalid: "EMAIL_TICKET_INVALID";
35
+ /** A sign-up without a confirmed email. */
36
+ readonly ticketRequired: "EMAIL_TICKET_REQUIRED";
37
+ /** This server cannot send mail. */
38
+ readonly unavailable: "EMAIL_UNAVAILABLE";
39
+ };
40
+ export type EmailVerificationErrorCode = (typeof EMAIL_VERIFICATION_ERROR_CODES)[keyof typeof EMAIL_VERIFICATION_ERROR_CODES];
41
+ export declare const emailAddressCheck: import("./check").Check<string>;
42
+ export declare const emailTicketCheck: import("./check").Check<string>;
43
+ export declare const emailVerificationStartResponseCheck: import("./check").Check<EmailVerificationStartResponse>;
44
+ export declare const emailVerificationConfirmResponseCheck: import("./check").Check<EmailVerificationConfirmResponse>;
@@ -0,0 +1,203 @@
1
+ /**
2
+ * Account kinds and categories, without Zod. Schemas: `../accountGraph.ts`.
3
+ *
4
+ * Part of `@oxy.so/contracts/client`: never import `zod` here (see `./check.ts`).
5
+ */
6
+ /**
7
+ * Account-graph classification — the ONE authority for the kind vocabulary.
8
+ *
9
+ * `personal` is the only kind minted by signup and the only one that signs in
10
+ * as a device principal; every other kind is a child account created under a
11
+ * parent and reached through `account_members`. The API schema, the Drizzle
12
+ * table and the SDK all derive from this list rather than restating it, so a
13
+ * new kind is one edit here instead of four literals that can drift.
14
+ *
15
+ * The kind names what an account IS. It does not, on its own, answer who may
16
+ * switch into it, who may act as it, who the actor is, or anything commercial —
17
+ * each of those has its own predicate or contract, tabulated at the top of
18
+ * `accountSubject.ts`. In particular a `bot` is a COMPLETE account (issue
19
+ * #1520): it owns resources, holds roles, plans and a balance, receives funds
20
+ * and pays for itself under the same rules as a person, and is its own actor.
21
+ */
22
+ export type AccountKind = 'personal' | 'organization' | 'project' | 'bot' | 'channel';
23
+ /**
24
+ * The union is spelled out above and the array proves coverage BOTH ways
25
+ * (`satisfies` here, the `Gap` alias below) — the same shape this package's
26
+ * `ACCOUNT_CATEGORY_IDS` / `TRUST_TIERS` pairs use, and the one
27
+ * `db/schema/users.ts` mirrors to keep the `users_kind_check` CHECK honest.
28
+ *
29
+ * Deriving the union from the array instead would cost nothing here and be paid
30
+ * by consumers: `kind` travels into `@oxy.so/services` on every device-directory
31
+ * context (`deviceContextSchema.kind` → `DeviceContext` → the switcher rows),
32
+ * and an indexed-access type is materially more expensive to check there than a
33
+ * literal union.
34
+ */
35
+ export declare const ACCOUNT_KINDS: readonly ["personal", "organization", "project", "bot", "channel"];
36
+ /** `never` while `ACCOUNT_KINDS` covers the union. */
37
+ export type AccountKindGap = Exclude<AccountKind, (typeof ACCOUNT_KINDS)[number]>;
38
+ /**
39
+ * Kinds that may be CREATED as children of another account. Exactly
40
+ * `ACCOUNT_KINDS` minus `personal`, which is always a tree root.
41
+ */
42
+ export type ChildAccountKind = Exclude<AccountKind, 'personal'>;
43
+ export declare const CHILD_ACCOUNT_KINDS: readonly ["organization", "project", "bot", "channel"];
44
+ /** `never` while `CHILD_ACCOUNT_KINDS` covers the child union. */
45
+ export type ChildAccountKindGap = Exclude<ChildAccountKind, (typeof CHILD_ACCOUNT_KINDS)[number]>;
46
+ /**
47
+ * Whether an account of this kind may be the SUBJECT OF A DELEGATION — an
48
+ * application acting as it on some person's authority. `POST /internal/accounts/
49
+ * :id/service-switch` and the OAuth delegated subject both gate on this.
50
+ *
51
+ * It is NOT the question an account switcher asks. See
52
+ * {@link isOperatorSwitchTargetKind}, and the note below on why the difference
53
+ * is `bot`.
54
+ *
55
+ * Two kinds are refused, for opposite reasons:
56
+ *
57
+ * - `personal` is a human login, so assuming it would be impersonation.
58
+ * - `channel` is a CONTENT identity, not an operating one. A channel exists so
59
+ * that posts can be authored BY it; it is never a seat anybody occupies. Its
60
+ * operators act on it through their own membership, and an application
61
+ * publishes to it with its own credential. Refusing act-as is what makes
62
+ * "no login, ever" structural rather than incidental: no session can be
63
+ * minted whose subject is a channel, so no bearer exists that could add an
64
+ * auth method to one (every auth-method write resolves its target from the
65
+ * authenticated subject, never from a parameter).
66
+ *
67
+ * Consumers must gate on this predicate rather than testing `kind === 'personal'`,
68
+ * which silently admits every kind added after it was written.
69
+ *
70
+ * Being act-as-eligible is NOT being without an identity of one's own. A bot is
71
+ * act-as-eligible AND its own actor (`accountKindActorNature` → `'agent'` in
72
+ * `accountSubject.ts`): an application acting as it on a person's authority
73
+ * records that person as the actor, and the bot acting with nobody operating it
74
+ * records the bot. Neither ever records the bot's owner in the bot's place.
75
+ */
76
+ export declare function isDelegatedActAsEligibleKind(kind: AccountKind | null | undefined): boolean;
77
+ /**
78
+ * Whether a PERSON may switch into an account of this kind — become it, in an
79
+ * account switcher, for the rest of their session.
80
+ *
81
+ * ## Why this is not the same question as {@link isDelegatedActAsEligibleKind}
82
+ *
83
+ * The two differ on exactly one kind, `bot`, and that difference is the whole
84
+ * reason both exist.
85
+ *
86
+ * **A bot is not something you become. It is somebody of its own.** It is an
87
+ * agent's identity, with its own resources, roles, plan and balance, and it is
88
+ * the actor of what it does unoperated. A person may still act AS it on their
89
+ * own authority — that is delegation, recorded with the person as actor, and it
90
+ * is what {@link isDelegatedActAsEligibleKind} admits it for. What a person
91
+ * never does is occupy its seat. This is a refusal of a SEAT, not a capability
92
+ * restriction: nothing a bot may do depends on this predicate.
93
+ *
94
+ * Handing a person the bot's seat instead inverts that. It puts a human inside
95
+ * the identity that exists to act without one, and it does so on the human's own
96
+ * device, next to their personal login — which is precisely what happened: a
97
+ * `bot` account held a live session on a person's device, offered to them by a
98
+ * switcher that had asked the delegation question by mistake.
99
+ *
100
+ * `channel` is refused here as well, for the reason set out above, and
101
+ * `personal` because assuming somebody else's login is impersonation.
102
+ *
103
+ * ## This is the narrower predicate, deliberately
104
+ *
105
+ * Everything a person may become, a service may also act as; the reverse does
106
+ * not hold. A caller that is unsure which question it is asking wants THIS one:
107
+ * being wrong here withholds an affordance, while being wrong the other way
108
+ * hands out a seat.
109
+ */
110
+ export declare function isOperatorSwitchTargetKind(kind: AccountKind | null | undefined): boolean;
111
+ /**
112
+ * Narrow an unknown value to an {@link AccountKind}.
113
+ *
114
+ * The user-DTO serializers read from structurally-permissive `unknown` sources
115
+ * (a Drizzle row, a raw document, an already-formatted object), so each one
116
+ * would otherwise hand-roll this check and they would drift on what counts.
117
+ */
118
+ export declare function isAccountKind(value: unknown): value is AccountKind;
119
+ /**
120
+ * Every account category, by stable id.
121
+ *
122
+ * Grouped by comment for readability only; the storage, the wire and the picker
123
+ * all treat this as one flat list. `other` is the escape hatch for an account
124
+ * that fits nothing here.
125
+ *
126
+ * TO ADD ONE: append an id (lowercase ASCII, `snake_case`) here, publish
127
+ * `@oxy.so/contracts`, then ship a migration that widens
128
+ * `users_account_categories_check` — never edit an existing migration — and add
129
+ * an `accounts.accountCategory.<id>` label to each client's locales.
130
+ *
131
+ * TO WITHDRAW ONE: leave the id here and add it to
132
+ * {@link RETIRED_ACCOUNT_CATEGORY_IDS}. See rule 3 above.
133
+ */
134
+ 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"];
135
+ export type AccountCategoryId = (typeof ACCOUNT_CATEGORY_IDS)[number];
136
+ /**
137
+ * Ids withdrawn from the picker. Empty today.
138
+ *
139
+ * A withdrawn id keeps working everywhere it is already stored: it validates,
140
+ * it survives a round-trip save, it still renders from its label key, and it
141
+ * stays PRIMARY if it was primary. Nothing rewrites a stored list — a read-time
142
+ * or migration-time demotion would silently replace a choice its owner made,
143
+ * which is precisely what stable ids exist to prevent. The owner drops it on
144
+ * their next edit; until then it is honoured.
145
+ *
146
+ * What withdrawal changes is only this: the id leaves
147
+ * {@link SELECTABLE_ACCOUNT_CATEGORY_IDS}, so no picker offers it, and
148
+ * {@link newlyAddedRetiredCategories} refuses to let a write ADD it to an
149
+ * account that did not already have it.
150
+ */
151
+ export declare const RETIRED_ACCOUNT_CATEGORY_IDS: readonly AccountCategoryId[];
152
+ /** Whether a category may still be OFFERED. A stored one is readable either way. */
153
+ export declare function isSelectableAccountCategoryId(id: AccountCategoryId): boolean;
154
+ /** The ids a picker may offer, in declaration order. */
155
+ export declare const SELECTABLE_ACCOUNT_CATEGORY_IDS: readonly AccountCategoryId[];
156
+ /**
157
+ * Which of `next` are withdrawn ids the account did not already carry — i.e.
158
+ * the ones a write must be refused for.
159
+ *
160
+ * `retired` is a parameter rather than a module read so the rule can be
161
+ * exercised against a non-empty set while the production one is empty; a test
162
+ * over `RETIRED_ACCOUNT_CATEGORY_IDS` alone would pass vacuously today and stay
163
+ * passing if the rule were deleted.
164
+ */
165
+ export declare function newlyAddedRetiredCategories(next: readonly AccountCategoryId[], previous: readonly AccountCategoryId[], retired: readonly AccountCategoryId[]): AccountCategoryId[];
166
+ /**
167
+ * How many categories one account may carry.
168
+ *
169
+ * Four, not "as many as you like". Three reasons, in the order they bind:
170
+ *
171
+ * - The primary has to MEAN something. At ten categories the first element
172
+ * reads as a sort artifact rather than a choice, and rule 2 above is the
173
+ * entire mechanism by which a primary exists.
174
+ * - The profile RENDERS them as a row of chips; four labels of this length is
175
+ * what fits a phone-width profile header before the row wraps or truncates.
176
+ * - Four is enough to place a genuinely compound account without a tag cloud:
177
+ * a housing cooperative that is also a non-profit serving a local community
178
+ * spends `cooperative`, `nonprofit`, `community`, `real_estate` — and is the
179
+ * most compound real example in the ecosystem.
180
+ *
181
+ * One constant, read by the wire schema, the database CHECK and the picker, so
182
+ * changing it is one edit plus a migration.
183
+ */
184
+ export declare const MAX_ACCOUNT_CATEGORIES = 4;
185
+ /**
186
+ * Kinds that may carry categories: every kind EXCEPT `personal`.
187
+ *
188
+ * A person has interests, not a sector — and their interests are not a
189
+ * classification anybody else gets to read off their profile. Spelled out
190
+ * positively, like {@link isDelegatedActAsEligibleKind} and for the same reason: a `kind
191
+ * !== 'personal'` test silently admits every kind invented after it was
192
+ * written, whereas this list forces whoever adds one to decide.
193
+ */
194
+ export declare const ACCOUNT_CATEGORY_KINDS: readonly ["organization", "project", "bot", "channel"];
195
+ export type AccountCategoryKind = (typeof ACCOUNT_CATEGORY_KINDS)[number];
196
+ /**
197
+ * Whether an account of this kind may carry categories.
198
+ *
199
+ * The API refuses the write and the `users_account_categories_kind_check`
200
+ * constraint makes it unrepresentable; both derive from
201
+ * {@link ACCOUNT_CATEGORY_KINDS}, so they cannot disagree.
202
+ */
203
+ export declare function kindAcceptsAccountCategories(kind: AccountKind | null | undefined): boolean;
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Agent-key constants and checks, without Zod. Schemas: `../agentKeys.ts`.
3
+ *
4
+ * Part of `@oxy.so/contracts/client`: never import `zod` here (see `./check.ts`).
5
+ */
6
+ export declare const AGENT_PROOF_AUDIENCE: "oxy-api/agent";
7
+ export declare const AGENT_PROOF_TTL_MS = 60000;
8
+ export declare const AGENT_PROOF_ACTIONS: readonly ["agent_signin", "agent_enroll", "agent_rotate", "agent_recover", "agent_governance"];
9
+ export type AgentProofAction = (typeof AGENT_PROOF_ACTIONS)[number];
10
+ export declare const ACCOUNT_AUTH_METHODS: readonly ["identity", "agent_key"];
11
+ export type AccountAuthMethod = (typeof ACCOUNT_AUTH_METHODS)[number];
12
+ export declare const agentProofClaimsCheck: import("./check").Check<{
13
+ expiresAt: number;
14
+ accountId: string;
15
+ version: 1;
16
+ audience: "oxy-api/agent";
17
+ action: "agent_signin" | "agent_enroll" | "agent_rotate" | "agent_recover" | "agent_governance";
18
+ challenge: string;
19
+ actorId: string;
20
+ authMethodId: string | null;
21
+ publicKey: string;
22
+ payloadDigest: string;
23
+ }>;
24
+ export declare const agentChallengeRequestCheck: import("./check").Check<{
25
+ publicKey: string;
26
+ }>;
27
+ export declare const agentVerifyRequestCheck: import("./check").Check<{
28
+ signature: string;
29
+ challenge: string;
30
+ publicKey: string;
31
+ timestamp: number;
32
+ }>;
33
+ export declare const agentKeyOperationCheck: import("./check").Check<{
34
+ publicKey: string;
35
+ operation: "enroll";
36
+ label: string;
37
+ } | {
38
+ publicKey: string;
39
+ operation: "recover";
40
+ label: string;
41
+ } | {
42
+ publicKey: string;
43
+ operation: "rotate";
44
+ label: string;
45
+ retireCurrent?: boolean | undefined;
46
+ } | {
47
+ operation: "revoke";
48
+ methodId: string;
49
+ }>;
50
+ export declare const executeAgentKeyOperationCheck: import("./check").Check<{
51
+ operation: {
52
+ publicKey: string;
53
+ operation: "enroll";
54
+ label: string;
55
+ } | {
56
+ publicKey: string;
57
+ operation: "recover";
58
+ label: string;
59
+ } | {
60
+ publicKey: string;
61
+ operation: "rotate";
62
+ label: string;
63
+ retireCurrent?: boolean | undefined;
64
+ } | {
65
+ operation: "revoke";
66
+ methodId: string;
67
+ };
68
+ proof: {
69
+ challenge: string;
70
+ timestamp: number;
71
+ reauth?: {
72
+ password?: string | undefined;
73
+ emailCode?: {
74
+ code: string;
75
+ verificationId: string;
76
+ } | undefined;
77
+ totpCode?: string | undefined;
78
+ } | undefined;
79
+ keySignature?: string | undefined;
80
+ governorSignature?: string | undefined;
81
+ };
82
+ }>;
83
+ export declare const agentKeyOperationChallengeCheck: import("./check").Check<{
84
+ claims: {
85
+ expiresAt: number;
86
+ accountId: string;
87
+ version: 1;
88
+ audience: "oxy-api/agent";
89
+ action: "agent_signin" | "agent_enroll" | "agent_rotate" | "agent_recover" | "agent_governance";
90
+ challenge: string;
91
+ actorId: string;
92
+ authMethodId: string | null;
93
+ publicKey: string;
94
+ payloadDigest: string;
95
+ };
96
+ governorPublicKey: string | null;
97
+ }>;
98
+ export declare const agentKeyOperationResultCheck: import("./check").Check<{
99
+ methodId: string | null;
100
+ revokedMethodIds: string[];
101
+ }>;
102
+ export declare const agentKeyListResponseCheck: import("./check").Check<{
103
+ keys: {
104
+ id: string;
105
+ revokedAt: string | null;
106
+ publicKey: string;
107
+ label: string;
108
+ enrolledByUserId: string | null;
109
+ enrollmentMethod: "governor" | "rotation" | "recovery";
110
+ linkedAt: string;
111
+ lastUsedAt: string | null;
112
+ }[];
113
+ }>;
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Structural checks for contract values, without Zod.
3
+ *
4
+ * The Zod schemas in this package are the contract, and the API parses with
5
+ * them. A client only needs to know that a response has the shape its type
6
+ * promises, and Zod's object schemas pull Zod's whole runtime into every app
7
+ * that bundles the SDK (~120 KB before compression, evaluated at startup). The
8
+ * checks here give the client the same answers in plain TypeScript.
9
+ *
10
+ * Every check mirrors one Zod 3 schema in this package, and
11
+ * `__tests__/clientChecks.parity.test.ts` runs both over the same inputs and
12
+ * requires the same verdict, the same output and the same failing path. The
13
+ * rules follow Zod 3 exactly:
14
+ *
15
+ * string(...rules) a string; `trim`/`toLowerCase` rewrite it, the other
16
+ * rules test it, in the order given
17
+ * number(...rules) a number that is not NaN (Infinity passes, as in Zod)
18
+ * literal(v) / oneOf `===` one value / one of a fixed set of strings
19
+ * optional(c) `undefined` (or an absent key) passes; `null` does not
20
+ * nullable(c) `null` passes and is kept
21
+ * withDefault(c, v) `undefined` becomes `v`, which is then checked
22
+ * array(c, ...rules) the size rules first, then every element in order
23
+ * object(shape) unknown keys are DROPPED (Zod's default "strip")
24
+ * strictObject(shape) unknown keys FAIL (`.strict()`)
25
+ * looseObject(shape) unknown keys are KEPT (`.passthrough()`)
26
+ * refine(c, test) a further condition, run once `c` passes
27
+ * union / discriminatedUnion as Zod 3 reports them
28
+ *
29
+ * A failure carries the first issue Zod would report and whether Zod would have
30
+ * stopped there (`fatal`: the type was wrong) or kept checking (`fatal: false`:
31
+ * only a rule failed). Only `union` reads the difference, because Zod reports a
32
+ * union through its first "rule failed" option.
33
+ *
34
+ * This module, and everything under `src/client/`, must never import `zod`
35
+ * (`__tests__/clientEntryGraph.test.ts` walks the graph).
36
+ */
37
+ /** Where in the value a check failed. */
38
+ export type CheckPath = (string | number)[];
39
+ /** Zod 3's issue codes, for the ones these checks can report. */
40
+ export type CheckIssueCode = 'invalid_type' | 'invalid_literal' | 'invalid_enum_value' | 'invalid_string' | 'too_small' | 'too_big' | 'unrecognized_keys' | 'invalid_union' | 'invalid_union_discriminator' | 'custom';
41
+ /**
42
+ * The first problem found, in the order Zod reports its issues, with Zod's
43
+ * code and message. `expected`/`received` name TYPES (`'number'`, `'string'`)
44
+ * on an `invalid_type`, never values, so they are safe to log.
45
+ */
46
+ export interface CheckIssue {
47
+ path: CheckPath;
48
+ code: CheckIssueCode;
49
+ message: string;
50
+ expected?: string;
51
+ received?: string;
52
+ }
53
+ /** An issue before it knows where it happened. */
54
+ type Problem = Omit<CheckIssue, 'path'>;
55
+ export type CheckResult<T> = {
56
+ ok: true;
57
+ value: T;
58
+ } | {
59
+ ok: false;
60
+ issue: CheckIssue;
61
+ fatal: boolean;
62
+ };
63
+ /** Checks one value at `path`. */
64
+ export type Check<T> = (input: unknown, path: CheckPath) => CheckResult<T>;
65
+ /** The value type a check produces. */
66
+ export type CheckOutput<C> = C extends Check<infer T> ? T : never;
67
+ /** One step of a string check: rewrite the value, or test it. */
68
+ export type StringRule = {
69
+ rewrite: (value: string) => string;
70
+ } | {
71
+ test: (value: string) => boolean;
72
+ code: CheckIssueCode;
73
+ message: string;
74
+ };
75
+ export declare const trim: StringRule;
76
+ export declare const toLowerCase: StringRule;
77
+ export declare function minLength(min: number, message?: string): StringRule;
78
+ export declare function maxLength(max: number, message?: string): StringRule;
79
+ export declare function pattern(regex: RegExp, message?: string): StringRule;
80
+ export declare function startsWith(prefix: string): StringRule;
81
+ export declare const email: StringRule;
82
+ /** Zod 3's `.url()`: anything `new URL()` accepts. */
83
+ export declare const url: StringRule;
84
+ export declare const datetime: StringRule;
85
+ export declare function string(...rules: StringRule[]): Check<string>;
86
+ /** A test on a number; `undefined` when it passes, else Zod's issue. */
87
+ export type NumberRule = (value: number) => Problem | undefined;
88
+ /** Zod's `.int()` — reported, as Zod does, as an `invalid_type` that does not stop the parse. */
89
+ export declare const int: NumberRule;
90
+ export declare function atLeast(min: number): NumberRule;
91
+ export declare function atMost(max: number): NumberRule;
92
+ /** Zod's `.positive()`. */
93
+ export declare const positive: NumberRule;
94
+ /** Zod's `.nonnegative()` (and `.min(0)`). */
95
+ export declare const nonnegative: NumberRule;
96
+ /** Zod's `.safe()`: both bounds, low first. */
97
+ export declare const safe: NumberRule;
98
+ export declare function number(...rules: NumberRule[]): Check<number>;
99
+ export declare const boolean: Check<boolean>;
100
+ export declare function literal<const T extends string | number | boolean>(expected: T): Check<T>;
101
+ /** One of a fixed set of strings — Zod's `z.enum`. */
102
+ export declare function oneOf<const T extends readonly [string, ...string[]]>(values: T): Check<T[number]>;
103
+ export declare function optional<T>(inner: Check<T>): Check<T | undefined>;
104
+ export declare function nullable<T>(inner: Check<T>): Check<T | null>;
105
+ export declare function withDefault<T>(inner: Check<T>, fallback: T): Check<T>;
106
+ /** A further condition on a value `inner` accepted. */
107
+ export declare function refine<T>(inner: Check<T>, test: (value: T) => boolean, message: string): Check<T>;
108
+ /**
109
+ * Zod's `.superRefine()` for the one-issue case: `test` returns the first
110
+ * problem (its path relative to the value) or `undefined`.
111
+ */
112
+ export declare function refineAt<T>(inner: Check<T>, test: (value: T) => {
113
+ path: CheckPath;
114
+ message: string;
115
+ } | undefined): Check<T>;
116
+ /** Narrows a checked value to a branded contract type (Zod's `.brand()`). */
117
+ export declare function branded<T extends B, B>(inner: Check<B>): Check<T>;
118
+ export interface ArrayRule {
119
+ test: (length: number) => boolean;
120
+ code: CheckIssueCode;
121
+ message: string;
122
+ }
123
+ export declare function minItems(min: number): ArrayRule;
124
+ export declare function maxItems(max: number): ArrayRule;
125
+ /** Zod's `.length(n)`: `too_big` or `too_small`, by which side it missed. */
126
+ export declare function exactItems(count: number): ArrayRule[];
127
+ export declare function array<T>(inner: Check<T>, ...rules: (ArrayRule | ArrayRule[])[]): Check<T[]>;
128
+ /** One check per key. */
129
+ export type Shape = Record<string, Check<unknown>>;
130
+ type Flatten<T> = {
131
+ [K in keyof T]: T[K];
132
+ };
133
+ type OptionalKeys<S extends Shape> = {
134
+ [K in keyof S]: undefined extends CheckOutput<S[K]> ? K : never;
135
+ }[keyof S];
136
+ type RequiredKeys<S extends Shape> = Exclude<keyof S, OptionalKeys<S>>;
137
+ /** What Zod 3 infers for `z.object(shape)`: keys that admit `undefined` become optional. */
138
+ export type ShapeOutput<S extends Shape> = Flatten<{
139
+ [K in RequiredKeys<S>]: CheckOutput<S[K]>;
140
+ } & {
141
+ [K in OptionalKeys<S>]?: CheckOutput<S[K]>;
142
+ }>;
143
+ /** Unknown keys are dropped — Zod's `z.object(shape)`. */
144
+ export declare function object<S extends Shape>(shape: S): Check<ShapeOutput<S>>;
145
+ /** Unknown keys fail — Zod's `z.object(shape).strict()`. */
146
+ export declare function strictObject<S extends Shape>(shape: S): Check<ShapeOutput<S>>;
147
+ /** Unknown keys are kept as sent — Zod's `z.object(shape).passthrough()`. */
148
+ export declare function looseObject<S extends Shape>(shape: S): Check<Flatten<ShapeOutput<S> & {
149
+ [key: string]: unknown;
150
+ }>>;
151
+ /** Any object, every value kept — Zod's `z.record(z.unknown())`. */
152
+ export declare const unknownRecord: Check<Record<string, unknown>>;
153
+ /** The first option that passes; else Zod 3's report (the first option that only failed a rule). */
154
+ export declare function union<const C extends readonly Check<unknown>[]>(...options: C): Check<CheckOutput<C[number]>>;
155
+ /** Zod 3's `z.discriminatedUnion(key, options)`, with the options keyed by their tag. */
156
+ export declare function discriminatedUnion<K extends string, M extends Record<string, Check<unknown>>>(key: K, options: M): Check<CheckOutput<M[keyof M]>>;
157
+ /** `a.b[0].c` — for messages. */
158
+ export declare function formatCheckPath(path: CheckPath): string;
159
+ /**
160
+ * A value did not have the shape its contract requires. Thrown where a Zod
161
+ * schema's `.parse()` used to throw a `ZodError`; `issues` keeps that error's
162
+ * issue shape (`code`, `path`, `message`), holding the first issue Zod reports.
163
+ */
164
+ export declare class ContractCheckError extends Error {
165
+ readonly issues: CheckIssue[];
166
+ constructor(issue: CheckIssue, context?: string);
167
+ }
168
+ /** The checked value, or `null` — the twin of `safeParseContract`. */
169
+ export declare function checkContract<T>(check: Check<T>, input: unknown): T | null;
170
+ /** The checked value; throws {@link ContractCheckError} — the twin of a schema's `.parse()`. */
171
+ export declare function parseContract<T>(check: Check<T>, input: unknown, context?: string): T;
172
+ /** `true` when `A` and `B` are the same type (not merely assignable either way). */
173
+ export type Equal<A, B> = (<X>() => X extends A ? 1 : 2) extends <X>() => X extends B ? 1 : 2 ? true : false;
174
+ /**
175
+ * `exact<DeviceSessionState>()(check)` compiles only when `check` produces
176
+ * exactly `DeviceSessionState` — every key, every optional mark, every literal
177
+ * — so a contract type that changes without its check is a type error here.
178
+ */
179
+ export declare function exact<T>(): <C extends Check<unknown>>(check: C & (Equal<CheckOutput<C>, T> extends true ? unknown : {
180
+ mismatch: "the check does not produce the contract type";
181
+ check: CheckOutput<C>;
182
+ contract: T;
183
+ })) => Check<T>;
184
+ export {};
@@ -0,0 +1,6 @@
1
+ /**
2
+ * The first-party login result check, without Zod. Schemas: `../deviceBoot.ts`.
3
+ *
4
+ * Part of `@oxy.so/contracts/client`: never import `zod` here (see `./check.ts`).
5
+ */
6
+ export declare const loginResultCheck: import("./check").Check<import("..").LoginSessionResult>;