@oxy.so/contracts 4.13.0 → 4.15.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 (57) hide show
  1. package/dist/cjs/.tsbuildinfo +1 -1
  2. package/dist/cjs/accountGraph.js +23 -4
  3. package/dist/cjs/index.js +19 -15
  4. package/dist/cjs/organizations.js +210 -0
  5. package/dist/cjs/products/billing.js +1 -0
  6. package/dist/cjs/products/checkout.js +14 -1
  7. package/dist/cjs/products/plans.js +18 -2
  8. package/dist/cjs/safety.js +15 -0
  9. package/dist/cjs/userResponse.js +8 -1
  10. package/dist/esm/.tsbuildinfo +1 -1
  11. package/dist/esm/accountGraph.js +21 -2
  12. package/dist/esm/index.js +4 -2
  13. package/dist/esm/organizations.js +207 -0
  14. package/dist/esm/products/billing.js +1 -0
  15. package/dist/esm/products/checkout.js +13 -0
  16. package/dist/esm/products/plans.js +17 -1
  17. package/dist/esm/safety.js +12 -0
  18. package/dist/esm/userResponse.js +8 -1
  19. package/dist/types/.tsbuildinfo +1 -1
  20. package/dist/types/accountGraph.d.ts +50 -18
  21. package/dist/types/agency.d.ts +42 -42
  22. package/dist/types/deviceDirectory.d.ts +56 -56
  23. package/dist/types/email/messages.d.ts +56 -56
  24. package/dist/types/externalIdentity.d.ts +56 -23
  25. package/dist/types/index.d.ts +4 -2
  26. package/dist/types/inference/accountBilling.d.ts +36 -36
  27. package/dist/types/inference/catalogue.d.ts +12 -12
  28. package/dist/types/inference/decisions.d.ts +16 -16
  29. package/dist/types/inference/economics.d.ts +6 -6
  30. package/dist/types/inference/embeddings.d.ts +18 -18
  31. package/dist/types/inference/entitlement.d.ts +12 -12
  32. package/dist/types/inference/errors.d.ts +4 -4
  33. package/dist/types/inference/inbox.d.ts +17 -17
  34. package/dist/types/inference/priceVersion.d.ts +8 -8
  35. package/dist/types/inference/privateAutoExecution.d.ts +12 -12
  36. package/dist/types/inference/providerConnection.d.ts +24 -24
  37. package/dist/types/inference/realtime.d.ts +26 -26
  38. package/dist/types/inference/request.d.ts +26 -26
  39. package/dist/types/inference/routingPolicy.d.ts +4 -4
  40. package/dist/types/inference/scopedExecution.d.ts +8 -8
  41. package/dist/types/inference/streamEvents.d.ts +20 -20
  42. package/dist/types/inference/usage.d.ts +8 -8
  43. package/dist/types/keyRecovery.d.ts +4 -4
  44. package/dist/types/linkedAccounts.d.ts +16 -16
  45. package/dist/types/notifications.d.ts +4 -4
  46. package/dist/types/oauth.d.ts +40 -40
  47. package/dist/types/organizations.d.ts +1088 -0
  48. package/dist/types/products/access.d.ts +18 -18
  49. package/dist/types/products/billing.d.ts +32 -24
  50. package/dist/types/products/checkout.d.ts +36 -0
  51. package/dist/types/products/plans.d.ts +108 -11
  52. package/dist/types/recommendations.d.ts +2 -2
  53. package/dist/types/safety.d.ts +24 -0
  54. package/dist/types/sessionStatus.d.ts +6 -6
  55. package/dist/types/stickers.d.ts +32 -32
  56. package/dist/types/userResponse.d.ts +169 -33
  57. package/package.json +1 -1
@@ -8,6 +8,7 @@
8
8
  */
9
9
  import { z } from 'zod';
10
10
  import { avatarCharacterSchema } from './avatarCharacter.js';
11
+ import { ORGANIZATION_TYPES, ORGANIZATION_NAME_MAX_LENGTH, organizationNameSchema, } from './organizations.js';
11
12
  import { usernameSchema, usernameSchemaForAccountKind } from './username.js';
12
13
  /**
13
14
  * The union is spelled out above and the array proves coverage BOTH ways
@@ -369,11 +370,11 @@ export function kindAcceptsAccountCategories(kind) {
369
370
  * `composeDisplayName`, which already preferred an explicit value — only the
370
371
  * storage for one was missing).
371
372
  */
372
- const accountNameSchema = z
373
+ export const accountNameSchema = z
373
374
  .object({
374
375
  first: z.string().trim().max(100).optional(),
375
376
  last: z.string().trim().max(100).optional(),
376
- displayName: z.string().trim().max(100).optional(),
377
+ displayName: z.string().trim().max(ORGANIZATION_NAME_MAX_LENGTH).optional(),
377
378
  })
378
379
  .optional();
379
380
  /**
@@ -426,6 +427,7 @@ export const createAccountRequestSchema = z
426
427
  color: z.string().trim().max(32).optional(),
427
428
  /** Ordered, PRIMARY FIRST — see rule 2 above {@link ACCOUNT_CATEGORY_IDS}. */
428
429
  accountCategories: accountCategoriesSchema.optional(),
430
+ organizationType: z.enum(ORGANIZATION_TYPES).optional(),
429
431
  /**
430
432
  * Create the account already opted OUT of discovery.
431
433
  *
@@ -483,6 +485,23 @@ export const createAccountRequestSchema = z
483
485
  message: 'Only a bot account carries an avatar character',
484
486
  });
485
487
  }
488
+ const displayName = request.name?.displayName;
489
+ if (displayName) {
490
+ const parsedName = request.kind === 'organization'
491
+ ? organizationNameSchema.safeParse(displayName)
492
+ : z.string().max(100).safeParse(displayName);
493
+ if (!parsedName.success) {
494
+ for (const issue of parsedName.error.issues) {
495
+ ctx.addIssue({ ...issue, path: ['name', 'displayName', ...issue.path] });
496
+ }
497
+ }
498
+ }
499
+ if (request.organizationType !== undefined && request.kind !== 'organization')
500
+ ctx.addIssue({
501
+ code: z.ZodIssueCode.custom,
502
+ path: ['organizationType'],
503
+ message: 'Organization type requires an organization account',
504
+ });
486
505
  // The ONE place `kind` and `username` arrive in the same object, so it is the
487
506
  // only place a wire schema CAN apply the per-kind half of the policy: a bot's
488
507
  // handle must end in `bot`. Not a second rule — it asks
package/dist/esm/index.js CHANGED
@@ -9,7 +9,7 @@
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, isDelegatedActAsEligibleKind, isOperatorSwitchTargetKind, 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.js';
12
+ export { ACCOUNT_KINDS, accountKindSchema, CHILD_ACCOUNT_KINDS, childAccountKindSchema, isAccountKind, isDelegatedActAsEligibleKind, isOperatorSwitchTargetKind, ACCOUNT_CATEGORY_IDS, ACCOUNT_CATEGORY_KINDS, accountCategoriesSchema, accountCategoryIdSchema, isSelectableAccountCategoryId, kindAcceptsAccountCategories, MAX_ACCOUNT_CATEGORIES, newlyAddedRetiredCategories, RETIRED_ACCOUNT_CATEGORY_IDS, SELECTABLE_ACCOUNT_CATEGORY_IDS, createAccountRequestSchema, accountNameSchema, } from './accountGraph.js';
13
13
  export { AVATAR_EYE_SPACING, AVATAR_PICKABLE_COLORS, AVATAR_PICKABLE_SHAPES, avatarCharacterFor, avatarCharacterSchema, parseAvatarCharacter, } from './avatarCharacter.js';
14
14
  export { ACCOUNT_ACTOR_NATURES, ACCOUNT_SUBJECT_CONTRACT_VERSION, FINANCIAL_EFFECT_DIRECTIONS, KIND_INDEPENDENT_ACCOUNT_DIMENSIONS, accountActorChainFromSession, accountActorChainSchema, accountActorNatureSchema, accountKindActorNature, accountKindActsAsItself, attributeFinancialEffect, financialEffectAttributionSchema, } from './accountSubject.js';
15
15
  export { usernameSchema, usernameSchemaForAccountKind, isValidUsername, stripDisallowedUsernameCharacters, applyBotUsernameSuffix, USERNAME_MIN_LENGTH, USERNAME_MAX_LENGTH, USERNAME_INVALID_MESSAGE, BOT_USERNAME_INVALID_MESSAGE, RESERVED_USERNAME_MESSAGE, NUMERIC_USERNAME_MESSAGE, } from './username.js';
@@ -200,5 +200,7 @@ export { meteredGenerationSchema } from './inference/economics.js';
200
200
  export { canonicalCapabilityJson, inputSatisfiesCapabilityLimits, isLoopbackOrigin, } from './capabilityBindings.js';
201
201
  export * from './agentKeys.js';
202
202
  export { productSubscriptionSummarySchema, productSubscriptionsResponseSchema, subscriptionCreditGrantSchema, subscriptionCreditGrantsResponseSchema, cancelProductSubscriptionSchema, productSubscriptionCancellationResultSchema, } from './products/billing.js';
203
- export { personalPlanDisplayPriceSchema, personalPlanCatalogueSchema, } from './products/plans.js';
203
+ export { personalPlanDisplayPriceSchema, personalPlanCatalogueSchema, productPlanCatalogueSchema, } from './products/plans.js';
204
204
  export * from './products/checkout.js';
205
+ export * from './organizations.js';
206
+ export * from './safety.js';
@@ -0,0 +1,207 @@
1
+ import { z } from 'zod';
2
+ /** Real-world identity classification, independent of account topics and permissions. */
3
+ export const ORGANIZATION_TYPES = [
4
+ 'business',
5
+ 'nonprofit',
6
+ 'public_body',
7
+ 'community',
8
+ 'other',
9
+ ];
10
+ export const ORGANIZATION_STATUSES = ['active', 'inactive', 'merged', 'suppressed'];
11
+ export const ORGANIZATION_CLAIM_STATUSES = ['unclaimed', 'claimed'];
12
+ export const ORGANIZATION_ALIAS_KINDS = [
13
+ 'name_variant',
14
+ 'former_name',
15
+ 'localized_name',
16
+ 'marketing_name',
17
+ 'misspelling',
18
+ ];
19
+ export const ORGANIZATION_CLAIM_DECISIONS = ['pending', 'approved', 'rejected'];
20
+ const id = z.string().min(1).max(128);
21
+ const optionalText = (max) => z.string().trim().min(1).max(max).nullable().optional();
22
+ export const organizationAliasSchema = z
23
+ .object({
24
+ alias: z.string().trim().min(1).max(300),
25
+ kind: z.enum(ORGANIZATION_ALIAS_KINDS),
26
+ language: z.string().min(2).max(35).optional(),
27
+ })
28
+ .strict();
29
+ export const ORGANIZATION_NAME_MAX_LENGTH = 300;
30
+ export const organizationNameSchema = z
31
+ .string()
32
+ .trim()
33
+ .min(1)
34
+ .max(ORGANIZATION_NAME_MAX_LENGTH)
35
+ .refine((value) => !/[<>]/.test(value) &&
36
+ Array.from(value).every((character) => character.charCodeAt(0) >= 32 && character.charCodeAt(0) !== 127), 'Organization name must be plain text');
37
+ export const createOrganizationSchema = z
38
+ .object({
39
+ name: organizationNameSchema,
40
+ organizationType: z.enum(ORGANIZATION_TYPES),
41
+ legalName: optionalText(300),
42
+ websiteUrl: z
43
+ .string()
44
+ .url()
45
+ .max(2048)
46
+ .refine((value) => /^https?:\/\//.test(value), 'Use HTTP or HTTPS')
47
+ .nullable()
48
+ .optional(),
49
+ countryCode: z
50
+ .string()
51
+ .regex(/^[A-Z]{2}$/)
52
+ .nullable()
53
+ .optional(),
54
+ aliases: z.array(organizationAliasSchema).max(100).optional(),
55
+ })
56
+ .strict();
57
+ export const updateOrganizationSchema = createOrganizationSchema.partial();
58
+ export const organizationSchema = createOrganizationSchema
59
+ .extend({
60
+ accountId: id,
61
+ username: z.string().nullable(),
62
+ avatar: z.string().nullable(),
63
+ legalName: z.string().nullable(),
64
+ websiteUrl: z.string().nullable(),
65
+ countryCode: z.string().nullable(),
66
+ aliases: z.array(organizationAliasSchema),
67
+ verifiedDomains: z.array(z.string()),
68
+ claimStatus: z.enum(ORGANIZATION_CLAIM_STATUSES),
69
+ status: z.enum(ORGANIZATION_STATUSES),
70
+ mergedIntoAccountId: id.nullable(),
71
+ createdAt: z.string().datetime(),
72
+ updatedAt: z.string().datetime(),
73
+ })
74
+ .strict();
75
+ export const organizationSearchSchema = z
76
+ .object({
77
+ query: z.string().trim().max(200).default(''),
78
+ organizationType: z.enum(ORGANIZATION_TYPES).optional(),
79
+ limit: z.coerce.number().int().min(1).max(50).default(20),
80
+ cursor: z.string().min(1).max(2048).optional(),
81
+ })
82
+ .strict();
83
+ export const organizationListSchema = z
84
+ .object({ items: z.array(organizationSchema), nextCursor: z.string().nullable() })
85
+ .strict();
86
+ export const organizationBatchInputSchema = z.object({ ids: z.array(id).min(1).max(100) }).strict();
87
+ export const organizationBatchSchema = z
88
+ .object({
89
+ items: z.array(z.object({ requestedAccountId: id, organization: organizationSchema }).strict()),
90
+ missingIds: z.array(id),
91
+ })
92
+ .strict();
93
+ export const organizationClaimInputSchema = z
94
+ .object({
95
+ evidenceReference: z.string().trim().min(1).max(1000),
96
+ })
97
+ .strict();
98
+ export const organizationClaimSchema = z
99
+ .object({
100
+ id,
101
+ accountId: id,
102
+ claimantUserId: id,
103
+ status: z.enum(ORGANIZATION_CLAIM_DECISIONS),
104
+ createdAt: z.string().datetime(),
105
+ })
106
+ .strict();
107
+ export const organizationClaimDetailSchema = organizationClaimSchema
108
+ .extend({
109
+ evidenceReference: z.string(),
110
+ reviewEvidenceReference: z.string().nullable(),
111
+ reviewedAt: z.string().datetime().nullable(),
112
+ })
113
+ .strict();
114
+ export const organizationClaimListQuerySchema = z
115
+ .object({
116
+ status: z.enum(ORGANIZATION_CLAIM_DECISIONS).optional(),
117
+ limit: z.coerce.number().int().min(1).max(50).default(20),
118
+ cursor: z.string().min(1).max(2048).optional(),
119
+ })
120
+ .strict();
121
+ export const organizationClaimListSchema = z
122
+ .object({ items: z.array(organizationClaimDetailSchema), nextCursor: z.string().nullable() })
123
+ .strict();
124
+ export const organizationClaimReviewSchema = z
125
+ .object({
126
+ decision: z.enum(['approved', 'rejected']),
127
+ evidenceReference: z.string().trim().min(1).max(1000),
128
+ })
129
+ .strict();
130
+ export const organizationExternalInputSchema = z
131
+ .object({
132
+ namespace: z.string().regex(/^[a-z][a-z0-9_-]{0,63}$/),
133
+ externalId: z.string().min(1).max(256),
134
+ accountId: id.optional(),
135
+ organization: createOrganizationSchema,
136
+ evidenceReference: z.string().trim().min(1).max(1000),
137
+ avatarFileId: id.optional(),
138
+ })
139
+ .strict();
140
+ /** Automated ingestion can create neutral identities in its granted namespace only. */
141
+ export const organizationImportBatchSchema = z
142
+ .object({
143
+ namespace: organizationExternalInputSchema.shape.namespace,
144
+ items: z
145
+ .array(organizationExternalInputSchema.pick({
146
+ externalId: true,
147
+ organization: true,
148
+ evidenceReference: true,
149
+ avatarFileId: true,
150
+ }))
151
+ .min(1)
152
+ .max(100),
153
+ })
154
+ .strict()
155
+ .refine((input) => new Set(input.items.map((item) => item.externalId)).size === input.items.length, 'External IDs must be unique within the batch');
156
+ export const organizationImportBatchResultSchema = z
157
+ .object({
158
+ items: z.array(z.object({ externalId: z.string(), accountId: id, created: z.boolean() }).strict()),
159
+ })
160
+ .strict();
161
+ export const organizationExternalSchema = z
162
+ .object({ accountId: id, created: z.boolean() })
163
+ .strict();
164
+ export const organizationExternalResolutionSchema = z.object({ accountId: id }).strict();
165
+ export const organizationMergeSchema = z
166
+ .object({
167
+ targetAccountId: id,
168
+ evidenceReference: z.string().trim().min(1).max(1000),
169
+ })
170
+ .strict();
171
+ export const ORGANIZATION_ERROR_CODES = [
172
+ 'bad_request',
173
+ 'unauthorized',
174
+ 'forbidden',
175
+ 'not_found',
176
+ 'unknown_route',
177
+ 'conflict',
178
+ 'validation_failed',
179
+ 'rate_limited',
180
+ 'internal_error',
181
+ 'service_unavailable',
182
+ ];
183
+ export const organizationErrorSchema = z
184
+ .object({
185
+ error: z
186
+ .object({
187
+ code: z.enum(ORGANIZATION_ERROR_CODES),
188
+ message: z.string(),
189
+ details: z
190
+ .record(z.string(), z.union([z.string(), z.number(), z.boolean(), z.null()]))
191
+ .optional(),
192
+ })
193
+ .strict(),
194
+ })
195
+ .strict();
196
+ /** Staff curation corrects neutral facts or moderates visibility without claiming ownership. */
197
+ export const organizationCurationSchema = z
198
+ .object({
199
+ changes: updateOrganizationSchema.optional(),
200
+ status: z.enum(['active', 'inactive', 'suppressed']).optional(),
201
+ evidenceReference: z.string().trim().min(1).max(1000),
202
+ })
203
+ .strict()
204
+ .refine((input) => input.changes !== undefined || input.status !== undefined, 'At least one change is required');
205
+ export const organizationCurationResultSchema = z
206
+ .object({ accountId: id, status: z.enum(['active', 'inactive', 'suppressed']) })
207
+ .strict();
@@ -24,6 +24,7 @@ export const productSubscriptionSummarySchema = z
24
24
  period,
25
25
  cancelAtPeriodEnd: z.boolean(),
26
26
  canCancel: z.boolean(),
27
+ canRenew: z.boolean().optional(),
27
28
  offers: z.array(z
28
29
  .object({
29
30
  segmentId: id,
@@ -30,3 +30,16 @@ export const personalPlanCheckoutResultSchema = z.discriminatedUnion('state', [
30
30
  z.object({ state: z.literal('closed'), intentId: z.string().min(1).max(160) }).strict(),
31
31
  z.object({ state: z.literal('fulfilled'), intentId: z.string().min(1).max(160) }).strict(),
32
32
  ]);
33
+ /** Explicit individual product offer; still owned and paid through Oxy. */
34
+ export const productPlanCheckoutRequestSchema = personalPlanCheckoutRequestSchema
35
+ .extend({
36
+ productId: z.string().min(1).max(160),
37
+ })
38
+ .strict();
39
+ export const productSubscriptionRenewalRequestSchema = z
40
+ .object({
41
+ expectedSubjectAccountId: oxyAccountIdSchema,
42
+ sourceId: z.string().min(1).max(160),
43
+ idempotencyKey: personalPlanCheckoutRequestSchema.shape.idempotencyKey,
44
+ })
45
+ .strict();
@@ -16,7 +16,7 @@ export const personalPlanCatalogueSchema = z
16
16
  .object({
17
17
  schemaVersion: z.literal(1),
18
18
  state: z.enum(['unconfigured', 'configured']),
19
- purchase: z.literal('unavailable'),
19
+ purchase: z.enum(['unavailable', 'available']),
20
20
  plans: z.array(z
21
21
  .object({
22
22
  offerId: z.string().min(1).max(160),
@@ -33,3 +33,19 @@ export const personalPlanCatalogueSchema = z
33
33
  })
34
34
  .strict()
35
35
  .refine((value) => (value.state === 'unconfigured') === (value.plans.length === 0), 'Catalogue state must match published plans');
36
+ export const productPlanCatalogueSchema = z
37
+ .object({
38
+ schemaVersion: z.literal(1),
39
+ productId: z.string().min(1).max(160),
40
+ purchase: z.enum(['unavailable', 'available']),
41
+ plans: z.array(z
42
+ .object({
43
+ productId: z.string().min(1).max(160),
44
+ offerId: z.string().min(1).max(160),
45
+ offerVersion: z.number().int().positive().safe(),
46
+ displayName: z.string().min(1).max(100),
47
+ price: personalPlanDisplayPriceSchema.extend({ interval: z.enum(['month', 'year']) }),
48
+ })
49
+ .strict()),
50
+ })
51
+ .strict();
@@ -0,0 +1,12 @@
1
+ import { z } from 'zod';
2
+ /** The requester is authenticated by the bearer; applications cannot submit viewer IDs. */
3
+ export const profileAccessInputSchema = z
4
+ .object({ subjectAccountId: z.string().min(1).max(128) })
5
+ .strict();
6
+ export const profileAccessDecisionSchema = z
7
+ .object({
8
+ allowed: z.boolean(),
9
+ reason: z.enum(['public', 'owner', 'private', 'blocked', 'unavailable']),
10
+ policyVersion: z.literal('1'),
11
+ })
12
+ .strict();
@@ -241,6 +241,10 @@ 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(),
244
248
  themePreference: themePreferenceSchema.optional(),
245
249
  personalization: z
246
250
  .object({
@@ -301,7 +305,10 @@ export const userProfileUpdateSchema = z
301
305
  languages: z.array(z.string()).optional(),
302
306
  accountExpiresAfterInactivityDays: z.number().nullable().optional(),
303
307
  notificationPreferences: z.record(z.unknown()).optional(),
304
- userPreferences: z.record(z.unknown()).optional(),
308
+ userPreferences: z
309
+ .object({ displayCurrency: z.enum(['USD', 'EUR', 'FAIR']).optional() })
310
+ .catchall(z.unknown())
311
+ .optional(),
305
312
  privacySettings: z.record(z.unknown()).optional(),
306
313
  /**
307
314
  * Portable theme preference. Written through the same `PUT /users/me`