@oxy.so/contracts 4.12.0 → 4.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/accountGraph.js +38 -4
- package/dist/cjs/avatarCharacter.js +120 -0
- package/dist/cjs/index.js +25 -14
- package/dist/cjs/organizations.js +210 -0
- package/dist/cjs/recommendations.js +3 -0
- package/dist/cjs/safety.js +15 -0
- package/dist/cjs/userResponse.js +7 -0
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/accountGraph.js +36 -2
- package/dist/esm/avatarCharacter.js +115 -0
- package/dist/esm/index.js +4 -1
- package/dist/esm/organizations.js +207 -0
- package/dist/esm/recommendations.js +3 -0
- package/dist/esm/safety.js +12 -0
- package/dist/esm/userResponse.js +7 -0
- package/dist/types/.tsbuildinfo +1 -1
- package/dist/types/accountGraph.d.ts +57 -14
- package/dist/types/accountSubject.d.ts +4 -4
- package/dist/types/avatarCharacter.d.ts +57 -0
- package/dist/types/deviceDirectory.d.ts +246 -246
- package/dist/types/externalIdentity.d.ts +62 -55
- package/dist/types/index.d.ts +5 -1
- package/dist/types/organizations.d.ts +1088 -0
- package/dist/types/recommendations.d.ts +40 -28
- package/dist/types/safety.d.ts +24 -0
- package/dist/types/userResponse.d.ts +200 -102
- package/package.json +1 -1
package/dist/esm/accountGraph.js
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
* {@link ACCOUNT_CATEGORY_IDS} for the four rules that govern it.
|
|
8
8
|
*/
|
|
9
9
|
import { z } from 'zod';
|
|
10
|
+
import { avatarCharacterSchema } from './avatarCharacter.js';
|
|
11
|
+
import { ORGANIZATION_TYPES, ORGANIZATION_NAME_MAX_LENGTH, organizationNameSchema, } from './organizations.js';
|
|
10
12
|
import { usernameSchema, usernameSchemaForAccountKind } from './username.js';
|
|
11
13
|
/**
|
|
12
14
|
* The union is spelled out above and the array proves coverage BOTH ways
|
|
@@ -368,11 +370,11 @@ export function kindAcceptsAccountCategories(kind) {
|
|
|
368
370
|
* `composeDisplayName`, which already preferred an explicit value — only the
|
|
369
371
|
* storage for one was missing).
|
|
370
372
|
*/
|
|
371
|
-
const accountNameSchema = z
|
|
373
|
+
export const accountNameSchema = z
|
|
372
374
|
.object({
|
|
373
375
|
first: z.string().trim().max(100).optional(),
|
|
374
376
|
last: z.string().trim().max(100).optional(),
|
|
375
|
-
displayName: z.string().trim().max(
|
|
377
|
+
displayName: z.string().trim().max(ORGANIZATION_NAME_MAX_LENGTH).optional(),
|
|
376
378
|
})
|
|
377
379
|
.optional();
|
|
378
380
|
/**
|
|
@@ -425,6 +427,7 @@ export const createAccountRequestSchema = z
|
|
|
425
427
|
color: z.string().trim().max(32).optional(),
|
|
426
428
|
/** Ordered, PRIMARY FIRST — see rule 2 above {@link ACCOUNT_CATEGORY_IDS}. */
|
|
427
429
|
accountCategories: accountCategoriesSchema.optional(),
|
|
430
|
+
organizationType: z.enum(ORGANIZATION_TYPES).optional(),
|
|
428
431
|
/**
|
|
429
432
|
* Create the account already opted OUT of discovery.
|
|
430
433
|
*
|
|
@@ -466,8 +469,39 @@ export const createAccountRequestSchema = z
|
|
|
466
469
|
* remedy must not either.
|
|
467
470
|
*/
|
|
468
471
|
isPrivateAccount: z.boolean().optional(),
|
|
472
|
+
/**
|
|
473
|
+
* The 3D avatar character of a `bot` — and ONLY of a bot (the refinement
|
|
474
|
+
* below). Optional on the wire: a bot created without one is given a look
|
|
475
|
+
* seeded from its handle (`avatarCharacterFor`), so every bot account has a
|
|
476
|
+
* character from birth and the owner customizes it afterwards.
|
|
477
|
+
*/
|
|
478
|
+
character: avatarCharacterSchema.optional(),
|
|
469
479
|
})
|
|
470
480
|
.superRefine((request, ctx) => {
|
|
481
|
+
if (request.character !== undefined && request.kind !== 'bot') {
|
|
482
|
+
ctx.addIssue({
|
|
483
|
+
code: z.ZodIssueCode.custom,
|
|
484
|
+
path: ['character'],
|
|
485
|
+
message: 'Only a bot account carries an avatar character',
|
|
486
|
+
});
|
|
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
|
+
});
|
|
471
505
|
// The ONE place `kind` and `username` arrive in the same object, so it is the
|
|
472
506
|
// only place a wire schema CAN apply the per-kind half of the policy: a bot's
|
|
473
507
|
// handle must end in `bot`. Not a second rule — it asks
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The 3D avatar character a `bot` account carries.
|
|
3
|
+
*
|
|
4
|
+
* ONE definition for the wire shape, its validator and the generator that picks
|
|
5
|
+
* a look for a new bot, shared by the Oxy API (which stores and serves it) and
|
|
6
|
+
* every client. It mirrors Bloom's flat `AvatarCharacter`
|
|
7
|
+
* (`@oxy.so/bloom/agent-avatar`).
|
|
8
|
+
*
|
|
9
|
+
* ## The vocabulary is Bloom's and is NOT enforced here
|
|
10
|
+
*
|
|
11
|
+
* Bloom is a React Native package this one cannot depend on, so the ids a
|
|
12
|
+
* character is made of are restated below as a curated SUBSET, only to PICK a
|
|
13
|
+
* look for a new bot ({@link avatarCharacterFor}). A STORED character is never
|
|
14
|
+
* checked against them: validating against a stale copy of somebody else's
|
|
15
|
+
* catalogue is how a working look starts being refused. What the schema checks
|
|
16
|
+
* is the SHAPE of what a client writes: only the keys a character has, each an
|
|
17
|
+
* id-like string, a `#rrggbb` paint, a spacing in range. The client resolves
|
|
18
|
+
* the ids and falls back on a default look for one it cannot draw.
|
|
19
|
+
*/
|
|
20
|
+
import { z } from 'zod';
|
|
21
|
+
const ID = /^[a-z][a-z0-9_]{0,39}$/;
|
|
22
|
+
const HEX = /^#[0-9a-fA-F]{6}$/;
|
|
23
|
+
/** Bounds of {@link AvatarCharacter.eyeSpacing}. */
|
|
24
|
+
export const AVATAR_EYE_SPACING = { min: 0.5, max: 1.5 };
|
|
25
|
+
const idSchema = z.string().regex(ID);
|
|
26
|
+
/**
|
|
27
|
+
* A character a client sends. `.strict()` so a misspelled field is a refusal
|
|
28
|
+
* now rather than a look that never takes effect. A character with nothing in
|
|
29
|
+
* it draws nothing: it needs a preset, or a shape and a paint.
|
|
30
|
+
*/
|
|
31
|
+
export const avatarCharacterSchema = z
|
|
32
|
+
.object({
|
|
33
|
+
preset: idSchema.optional(),
|
|
34
|
+
shape: idSchema.optional(),
|
|
35
|
+
eyes: idSchema.optional(),
|
|
36
|
+
eyewear: idSchema.optional(),
|
|
37
|
+
accessory: idSchema.optional(),
|
|
38
|
+
color: idSchema.optional(),
|
|
39
|
+
bodyColor: z
|
|
40
|
+
.string()
|
|
41
|
+
.regex(HEX)
|
|
42
|
+
.transform((hex) => hex.toLowerCase())
|
|
43
|
+
.optional(),
|
|
44
|
+
eyeSpacing: z
|
|
45
|
+
.number()
|
|
46
|
+
.finite()
|
|
47
|
+
.min(AVATAR_EYE_SPACING.min)
|
|
48
|
+
.max(AVATAR_EYE_SPACING.max)
|
|
49
|
+
.optional(),
|
|
50
|
+
})
|
|
51
|
+
.strict()
|
|
52
|
+
.refine((c) => c.preset !== undefined ||
|
|
53
|
+
(c.shape !== undefined && (c.color !== undefined || c.bodyColor !== undefined)), { message: 'A character needs a preset, or a shape and a color' });
|
|
54
|
+
/** The validated character, or `null` for anything that is not one. */
|
|
55
|
+
export function parseAvatarCharacter(value) {
|
|
56
|
+
const parsed = avatarCharacterSchema.safeParse(value);
|
|
57
|
+
return parsed.success ? parsed.data : null;
|
|
58
|
+
}
|
|
59
|
+
/** The parts a new bot's look is picked from: the plain, friendly shapes, in the editor's order. */
|
|
60
|
+
export const AVATAR_PICKABLE_SHAPES = [
|
|
61
|
+
'rounded_triangle',
|
|
62
|
+
'capsule',
|
|
63
|
+
'rounded_head_two_ears',
|
|
64
|
+
'six_lobed_flower',
|
|
65
|
+
'heart',
|
|
66
|
+
'four_lobed_butterfly',
|
|
67
|
+
'circle_two_ears',
|
|
68
|
+
'twelve_scalloped_rosette',
|
|
69
|
+
'rounded_cube',
|
|
70
|
+
'rounded_diamond',
|
|
71
|
+
'slender',
|
|
72
|
+
'pocket',
|
|
73
|
+
'petal',
|
|
74
|
+
'star',
|
|
75
|
+
'cloud',
|
|
76
|
+
'shield',
|
|
77
|
+
'pebble',
|
|
78
|
+
'squircle',
|
|
79
|
+
];
|
|
80
|
+
/** Bloom's named paints. */
|
|
81
|
+
export const AVATAR_PICKABLE_COLORS = [
|
|
82
|
+
'pink',
|
|
83
|
+
'orchid',
|
|
84
|
+
'violet',
|
|
85
|
+
'blue',
|
|
86
|
+
'cyan',
|
|
87
|
+
'teal',
|
|
88
|
+
'lime',
|
|
89
|
+
'yellow',
|
|
90
|
+
'coral',
|
|
91
|
+
];
|
|
92
|
+
/** A small, stable hash: the same seed always picks the same look. */
|
|
93
|
+
function hash(seed) {
|
|
94
|
+
let h = 2166136261;
|
|
95
|
+
for (let i = 0; i < seed.length; i++) {
|
|
96
|
+
h ^= seed.charCodeAt(i);
|
|
97
|
+
h = Math.imul(h, 16777619);
|
|
98
|
+
}
|
|
99
|
+
return h >>> 0;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* A look for a new bot, picked from its seed (its handle): a shape and a paint,
|
|
103
|
+
* plain oval eyes, nothing on its head. Stable — the same seed is the same look
|
|
104
|
+
* — and the owner changes it afterwards.
|
|
105
|
+
*/
|
|
106
|
+
export function avatarCharacterFor(seed) {
|
|
107
|
+
const h = hash(seed);
|
|
108
|
+
return {
|
|
109
|
+
shape: AVATAR_PICKABLE_SHAPES[h % AVATAR_PICKABLE_SHAPES.length],
|
|
110
|
+
eyes: 'oval',
|
|
111
|
+
eyewear: 'none',
|
|
112
|
+
accessory: 'none',
|
|
113
|
+
color: AVATAR_PICKABLE_COLORS[Math.floor(h / AVATAR_PICKABLE_SHAPES.length) % AVATAR_PICKABLE_COLORS.length],
|
|
114
|
+
};
|
|
115
|
+
}
|
package/dist/esm/index.js
CHANGED
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
* Platform-agnostic — zod is the only runtime dependency. No react/react-native/
|
|
10
10
|
* expo, no `require()` in the ESM build.
|
|
11
11
|
*/
|
|
12
|
-
export { ACCOUNT_KINDS, accountKindSchema, CHILD_ACCOUNT_KINDS, childAccountKindSchema, isAccountKind, 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
|
+
export { AVATAR_EYE_SPACING, AVATAR_PICKABLE_COLORS, AVATAR_PICKABLE_SHAPES, avatarCharacterFor, avatarCharacterSchema, parseAvatarCharacter, } from './avatarCharacter.js';
|
|
13
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';
|
|
14
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';
|
|
15
16
|
export {
|
|
@@ -201,3 +202,5 @@ export * from './agentKeys.js';
|
|
|
201
202
|
export { productSubscriptionSummarySchema, productSubscriptionsResponseSchema, subscriptionCreditGrantSchema, subscriptionCreditGrantsResponseSchema, cancelProductSubscriptionSchema, productSubscriptionCancellationResultSchema, } from './products/billing.js';
|
|
202
203
|
export { personalPlanDisplayPriceSchema, personalPlanCatalogueSchema, } from './products/plans.js';
|
|
203
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();
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* / expo, ESM-safe).
|
|
12
12
|
*/
|
|
13
13
|
import { z } from 'zod';
|
|
14
|
+
import { avatarCharacterSchema } from './avatarCharacter.js';
|
|
14
15
|
import { userNameSchema } from './userResponse.js';
|
|
15
16
|
/** User-type filters a caller may exclude from the recommendation surface. */
|
|
16
17
|
export const recommendationExcludeTypeSchema = z.enum(['federated', 'agent', 'automated']);
|
|
@@ -77,6 +78,8 @@ export const recommendationItemSchema = z
|
|
|
77
78
|
username: z.string().optional(),
|
|
78
79
|
name: userNameSchema,
|
|
79
80
|
avatar: z.string().nullable().optional(),
|
|
81
|
+
/** A bot's 3D avatar character; absent for every other kind. */
|
|
82
|
+
character: avatarCharacterSchema.optional(),
|
|
80
83
|
/** The account's accent colour, as on every profile; absent when unset. */
|
|
81
84
|
color: z.string().optional(),
|
|
82
85
|
description: z.string().nullable().optional(),
|
|
@@ -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();
|
package/dist/esm/userResponse.js
CHANGED
|
@@ -46,6 +46,7 @@ export const USER_PROFILE_COLOR_PRESETS = [
|
|
|
46
46
|
import { z } from 'zod';
|
|
47
47
|
import { verifiedDomainSchema } from './identity.js';
|
|
48
48
|
import { accountCategoriesSchema, accountKindSchema } from './accountGraph.js';
|
|
49
|
+
import { avatarCharacterSchema } from './avatarCharacter.js';
|
|
49
50
|
export const userNameSchema = z
|
|
50
51
|
.object({
|
|
51
52
|
first: z.string().optional(),
|
|
@@ -222,6 +223,12 @@ export const userResponseSchema = z
|
|
|
222
223
|
* `user.accountCategories ?? []`.
|
|
223
224
|
*/
|
|
224
225
|
accountCategories: accountCategoriesSchema.optional(),
|
|
226
|
+
/**
|
|
227
|
+
* The 3D avatar character of a `kind: 'bot'` account — what Bloom's
|
|
228
|
+
* `Avatar` draws instead of a picture. Present ONLY on a bot's payload,
|
|
229
|
+
* never on a person's or an organization's, so those DTOs do not grow.
|
|
230
|
+
*/
|
|
231
|
+
character: avatarCharacterSchema.optional(),
|
|
225
232
|
/**
|
|
226
233
|
* The authenticated viewer's relationship to this profile. Present ONLY
|
|
227
234
|
* on single-profile fetches (`GET /profiles/username/:username`,
|