@oxy.so/contracts 4.17.0 → 4.21.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/accountAccess.js +72 -0
- package/dist/cjs/agency.js +112 -1
- package/dist/cjs/applicationRoles.js +211 -0
- package/dist/cjs/client/check.js +9 -0
- package/dist/cjs/client/index.js +22 -1
- package/dist/cjs/client/safety.js +183 -2
- package/dist/cjs/client/signIn.js +2 -0
- package/dist/cjs/index.js +13 -3
- package/dist/cjs/safety.js +430 -1
- package/dist/cjs/serviceToken.js +14 -0
- package/dist/esm/accountAccess.js +69 -0
- package/dist/esm/agency.js +111 -0
- package/dist/esm/applicationRoles.js +207 -0
- package/dist/esm/client/check.js +8 -0
- package/dist/esm/client/index.js +1 -1
- package/dist/esm/client/safety.js +183 -2
- package/dist/esm/client/signIn.js +2 -0
- package/dist/esm/index.js +4 -1
- package/dist/esm/safety.js +423 -0
- package/dist/esm/serviceToken.js +11 -0
- package/dist/types/accountAccess.d.ts +128 -0
- package/dist/types/accountEmail.d.ts +2 -2
- package/dist/types/agency.d.ts +327 -2
- package/dist/types/agentKeys.d.ts +6 -6
- package/dist/types/applicationRoles.d.ts +438 -0
- package/dist/types/client/agentKeys.d.ts +2 -2
- package/dist/types/client/check.d.ts +3 -0
- package/dist/types/client/deviceSession.d.ts +1 -1
- package/dist/types/client/index.d.ts +1 -1
- package/dist/types/client/safety.d.ts +204 -4
- package/dist/types/client/signIn.d.ts +1 -1
- package/dist/types/deviceSession.d.ts +4 -4
- package/dist/types/email/messages.d.ts +2 -2
- package/dist/types/externalIdentity.d.ts +4 -4
- package/dist/types/index.d.ts +5 -2
- package/dist/types/inference/accountBilling.d.ts +2 -2
- package/dist/types/inference/catalogue.d.ts +22 -22
- package/dist/types/inference/providerConnection.d.ts +4 -4
- package/dist/types/inference/realtime.d.ts +74 -74
- package/dist/types/inference/request.d.ts +60 -60
- package/dist/types/inference/usage.d.ts +4 -4
- package/dist/types/products/access.d.ts +4 -4
- package/dist/types/safety.d.ts +2374 -2
- package/dist/types/serviceToken.d.ts +11 -0
- package/dist/types/signIn.d.ts +5 -5
- package/dist/types/userResponse.d.ts +2 -2
- package/package.json +5 -20
- package/dist/cjs/.tsbuildinfo +0 -1
- package/dist/esm/.tsbuildinfo +0 -1
- package/dist/types/.tsbuildinfo +0 -1
package/dist/esm/safety.js
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { accountActorChainSchema } from './accountSubject.js';
|
|
3
|
+
// The Zod-free half of this contract lives in `./client/` (`@oxy.so/contracts/client`);
|
|
4
|
+
// its vocabularies are re-exported here so the root entry is unchanged.
|
|
5
|
+
import { PURCHASE_APPROVAL_STATUSES, SAFETY_POLICY_VERSION, SUPERVISED_ACTIONS, SUPERVISION_CONSENT_VERSION, SUPERVISION_INVITATION_STATUSES, SUPERVISION_STATUSES, } from './client/safety.js';
|
|
6
|
+
import { ORGANIZATION_TYPES } from './organizations.js';
|
|
7
|
+
import { reauthProofSchema } from './signIn.js';
|
|
8
|
+
import { userResponseSchema } from './userResponse.js';
|
|
9
|
+
export { PURCHASE_APPROVAL_STATUSES, SAFETY_POLICY_VERSION, SUPERVISED_ACTIONS, SUPERVISION_CONSENT_VERSION, SUPERVISION_INVITATION_STATUSES, SUPERVISION_STATUSES, };
|
|
2
10
|
/** The requester is authenticated by the bearer; applications cannot submit viewer IDs. */
|
|
3
11
|
export const profileAccessInputSchema = z
|
|
4
12
|
.object({ subjectAccountId: z.string().min(1).max(128) })
|
|
@@ -10,3 +18,418 @@ export const profileAccessDecisionSchema = z
|
|
|
10
18
|
policyVersion: z.literal('1'),
|
|
11
19
|
})
|
|
12
20
|
.strict();
|
|
21
|
+
export const SAFETY_DECISION_REASONS = [
|
|
22
|
+
'allowed',
|
|
23
|
+
'owner',
|
|
24
|
+
'public',
|
|
25
|
+
'private',
|
|
26
|
+
'blocked',
|
|
27
|
+
'unavailable',
|
|
28
|
+
'unsupported_consumer',
|
|
29
|
+
'contact_not_approved',
|
|
30
|
+
'mature_content',
|
|
31
|
+
'unrated_content',
|
|
32
|
+
'approval_required',
|
|
33
|
+
];
|
|
34
|
+
const accountId = z.string().min(1).max(128);
|
|
35
|
+
const resourceId = z.string().trim().min(1).max(256);
|
|
36
|
+
const uniqueIds = (max, min = 1) => z
|
|
37
|
+
.array(accountId)
|
|
38
|
+
.min(min)
|
|
39
|
+
.max(max)
|
|
40
|
+
.refine((ids) => new Set(ids).size === ids.length, 'Account IDs must be unique');
|
|
41
|
+
export const safetyDecisionSchema = z
|
|
42
|
+
.object({
|
|
43
|
+
allowed: z.boolean(),
|
|
44
|
+
reason: z.enum(SAFETY_DECISION_REASONS),
|
|
45
|
+
policyVersion: z.literal(SAFETY_POLICY_VERSION),
|
|
46
|
+
})
|
|
47
|
+
.strict();
|
|
48
|
+
export const profileAccessBatchInputSchema = z
|
|
49
|
+
.object({ subjectAccountIds: uniqueIds(100) })
|
|
50
|
+
.strict();
|
|
51
|
+
export const profileAccessBatchResponseSchema = z
|
|
52
|
+
.object({
|
|
53
|
+
items: z
|
|
54
|
+
.array(z
|
|
55
|
+
.object({
|
|
56
|
+
subjectAccountId: accountId,
|
|
57
|
+
decision: safetyDecisionSchema,
|
|
58
|
+
})
|
|
59
|
+
.strict())
|
|
60
|
+
.max(100),
|
|
61
|
+
})
|
|
62
|
+
.strict();
|
|
63
|
+
export const MESSAGE_ACCESS_MAX_RESOURCES = 100;
|
|
64
|
+
export const MESSAGE_ACCESS_MAX_PARTICIPANTS = 1024;
|
|
65
|
+
export const MESSAGE_ACCESS_MAX_SUPERVISED_PARTICIPANTS = 256;
|
|
66
|
+
export const MESSAGE_ACCESS_MAX_PARTICIPANT_SLOTS = 4096;
|
|
67
|
+
/** Leaves room for the original requester proof in a 512 KiB request. */
|
|
68
|
+
export const MESSAGE_ACCESS_MAX_INPUT_BYTES = 448 * 1024;
|
|
69
|
+
export const messageAccessInputSchema = z
|
|
70
|
+
.object({ participantAccountIds: uniqueIds(MESSAGE_ACCESS_MAX_PARTICIPANTS), resourceId })
|
|
71
|
+
.strict();
|
|
72
|
+
export const contactAccessInputSchema = z.object({ targetAccountIds: uniqueIds(1000) }).strict();
|
|
73
|
+
export const contactAccessResponseSchema = z
|
|
74
|
+
.object({
|
|
75
|
+
items: z
|
|
76
|
+
.array(z
|
|
77
|
+
.object({
|
|
78
|
+
targetAccountId: accountId,
|
|
79
|
+
decision: safetyDecisionSchema,
|
|
80
|
+
})
|
|
81
|
+
.strict())
|
|
82
|
+
.max(1000),
|
|
83
|
+
})
|
|
84
|
+
.strict();
|
|
85
|
+
export const CONTENT_CLASSIFICATIONS = ['general', 'mature', 'unrated'];
|
|
86
|
+
export const contentAccessInputSchema = z
|
|
87
|
+
.object({
|
|
88
|
+
resourceId,
|
|
89
|
+
classification: z.enum(CONTENT_CLASSIFICATIONS),
|
|
90
|
+
authorAccountId: accountId.optional(),
|
|
91
|
+
audience: z.enum(['public', 'private', 'followers']).optional(),
|
|
92
|
+
applicationAudienceAllowed: z.boolean().optional(),
|
|
93
|
+
applicationResourceGrant: z.boolean().optional(),
|
|
94
|
+
operation: z.enum(['read', 'manage_own']).optional(),
|
|
95
|
+
})
|
|
96
|
+
.strict()
|
|
97
|
+
.refine((item) => !item.audience ||
|
|
98
|
+
item.audience === 'public' ||
|
|
99
|
+
(!!item.authorAccountId && item.applicationAudienceAllowed !== undefined), 'Nonpublic content requires its authoritative author and application audience decision')
|
|
100
|
+
.refine((item) => item.operation !== 'manage_own' || !!item.authorAccountId, 'Own management requires its authoritative author');
|
|
101
|
+
export const publicationPolicySchema = z
|
|
102
|
+
.object({
|
|
103
|
+
publicationAllowed: z.boolean(),
|
|
104
|
+
requiredAudience: z.literal('private').nullable(),
|
|
105
|
+
collaborationAllowed: z.boolean(),
|
|
106
|
+
federationAllowed: z.boolean(),
|
|
107
|
+
policyVersion: z.literal(SAFETY_POLICY_VERSION),
|
|
108
|
+
})
|
|
109
|
+
.strict();
|
|
110
|
+
export const publicationPoliciesInputSchema = z
|
|
111
|
+
.object({
|
|
112
|
+
authorAccountIds: z
|
|
113
|
+
.array(accountId)
|
|
114
|
+
.min(1)
|
|
115
|
+
.max(100)
|
|
116
|
+
.refine((ids) => new Set(ids).size === ids.length, 'Author IDs must be unique'),
|
|
117
|
+
})
|
|
118
|
+
.strict();
|
|
119
|
+
export const publicationPoliciesResponseSchema = z
|
|
120
|
+
.object({
|
|
121
|
+
items: z
|
|
122
|
+
.array(z.object({ authorAccountId: accountId, policy: publicationPolicySchema }).strict())
|
|
123
|
+
.max(100),
|
|
124
|
+
})
|
|
125
|
+
.strict();
|
|
126
|
+
export const contentAccessBatchInputSchema = z
|
|
127
|
+
.object({
|
|
128
|
+
items: z
|
|
129
|
+
.array(contentAccessInputSchema)
|
|
130
|
+
.min(1)
|
|
131
|
+
.max(100)
|
|
132
|
+
.refine((items) => new Set(items.map((item) => item.resourceId)).size === items.length, 'Resource IDs must be unique'),
|
|
133
|
+
})
|
|
134
|
+
.strict();
|
|
135
|
+
export const contentAccessBatchResponseSchema = z
|
|
136
|
+
.object({
|
|
137
|
+
items: z
|
|
138
|
+
.array(z
|
|
139
|
+
.object({
|
|
140
|
+
resourceId,
|
|
141
|
+
decision: safetyDecisionSchema,
|
|
142
|
+
})
|
|
143
|
+
.strict())
|
|
144
|
+
.max(100),
|
|
145
|
+
})
|
|
146
|
+
.strict();
|
|
147
|
+
/** A reviewed background consumer may decide delivery, but never authenticate as the sender. */
|
|
148
|
+
export const deliveryAccessInputSchema = messageAccessInputSchema
|
|
149
|
+
.extend({ senderAccountId: accountId })
|
|
150
|
+
.strict();
|
|
151
|
+
/** Count repeated participants across resources too: this bounds both graph and pair evaluations. */
|
|
152
|
+
const messageBatch = (schema) => z
|
|
153
|
+
.object({ items: z.array(schema).min(1).max(MESSAGE_ACCESS_MAX_RESOURCES) })
|
|
154
|
+
.strict()
|
|
155
|
+
.refine((value) => new Set(value.items.map((item) => item.resourceId)).size === value.items.length, 'Resource IDs must be unique')
|
|
156
|
+
.refine((value) => value.items.reduce((total, item) => total + item.participantAccountIds.length, 0) <=
|
|
157
|
+
MESSAGE_ACCESS_MAX_PARTICIPANT_SLOTS, 'Participant budget exceeded')
|
|
158
|
+
.refine((value) => new TextEncoder().encode(JSON.stringify(value)).byteLength <=
|
|
159
|
+
MESSAGE_ACCESS_MAX_INPUT_BYTES, 'Message batch byte budget exceeded');
|
|
160
|
+
export const messageAccessBatchInputSchema = messageBatch(messageAccessInputSchema);
|
|
161
|
+
export const deliveryAccessBatchInputSchema = messageBatch(deliveryAccessInputSchema);
|
|
162
|
+
export const messageAccessBatchResponseSchema = contentAccessBatchResponseSchema;
|
|
163
|
+
/** Live socket-recipient proof; a request ID correlates the result and never identifies an account. */
|
|
164
|
+
export const messagingSessionsInputSchema = z
|
|
165
|
+
.object({
|
|
166
|
+
items: z
|
|
167
|
+
.array(z
|
|
168
|
+
.object({
|
|
169
|
+
requestId: resourceId,
|
|
170
|
+
accessToken: z.string().min(1).max(16384),
|
|
171
|
+
})
|
|
172
|
+
.strict())
|
|
173
|
+
.min(1)
|
|
174
|
+
.max(100),
|
|
175
|
+
})
|
|
176
|
+
.strict()
|
|
177
|
+
.refine((value) => new Set(value.items.map((item) => item.requestId)).size === value.items.length, 'Request IDs must be unique')
|
|
178
|
+
.refine((value) => new TextEncoder().encode(JSON.stringify(value)).byteLength <= MESSAGE_ACCESS_MAX_INPUT_BYTES, 'Session proof byte budget exceeded');
|
|
179
|
+
export const messagingSessionsResponseSchema = z
|
|
180
|
+
.object({
|
|
181
|
+
items: z
|
|
182
|
+
.array(z.discriminatedUnion('allowed', [
|
|
183
|
+
z.object({ requestId: resourceId, allowed: z.literal(true), accountId }).strict(),
|
|
184
|
+
z.object({ requestId: resourceId, allowed: z.literal(false) }).strict(),
|
|
185
|
+
]))
|
|
186
|
+
.max(100),
|
|
187
|
+
})
|
|
188
|
+
.strict();
|
|
189
|
+
export const safetyRequesterSchema = z.union([
|
|
190
|
+
z.object({ accessToken: z.string().min(1).max(16384).nullable() }).strict(),
|
|
191
|
+
z.object({ connectionToken: z.string().min(1).max(16384) }).strict(),
|
|
192
|
+
]);
|
|
193
|
+
export const supervisionSchema = z
|
|
194
|
+
.object({
|
|
195
|
+
childAccountId: accountId,
|
|
196
|
+
guardianAccountId: accountId.nullable(),
|
|
197
|
+
status: z.enum(SUPERVISION_STATUSES),
|
|
198
|
+
policyVersion: z.literal(SAFETY_POLICY_VERSION),
|
|
199
|
+
consentVersion: z.literal(SUPERVISION_CONSENT_VERSION),
|
|
200
|
+
createdAt: z.string().datetime(),
|
|
201
|
+
})
|
|
202
|
+
.strict();
|
|
203
|
+
export const supervisionInvitationSchema = z
|
|
204
|
+
.object({
|
|
205
|
+
id: accountId,
|
|
206
|
+
childAccountId: accountId,
|
|
207
|
+
guardianAccountId: accountId,
|
|
208
|
+
status: z.enum(SUPERVISION_INVITATION_STATUSES),
|
|
209
|
+
expiresAt: z.string().datetime(),
|
|
210
|
+
consentVersion: z.literal(SUPERVISION_CONSENT_VERSION),
|
|
211
|
+
createdAt: z.string().datetime(),
|
|
212
|
+
})
|
|
213
|
+
.strict();
|
|
214
|
+
export const supervisionContactSchema = z
|
|
215
|
+
.object({
|
|
216
|
+
childAccountId: accountId,
|
|
217
|
+
contactAccountId: accountId,
|
|
218
|
+
approvedAt: z.string().datetime(),
|
|
219
|
+
})
|
|
220
|
+
.strict();
|
|
221
|
+
export const supervisionStateSchema = z
|
|
222
|
+
.object({
|
|
223
|
+
self: supervisionSchema.nullable(),
|
|
224
|
+
children: z.array(supervisionSchema).max(100),
|
|
225
|
+
invitations: z.array(supervisionInvitationSchema).max(100),
|
|
226
|
+
})
|
|
227
|
+
.strict();
|
|
228
|
+
export const supervisionContactsResponseSchema = z
|
|
229
|
+
.object({ items: z.array(supervisionContactSchema).max(1000) })
|
|
230
|
+
.strict();
|
|
231
|
+
const fingerprint = z.string().regex(/^[a-f0-9]{64}$/);
|
|
232
|
+
const minorUnits = z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER);
|
|
233
|
+
export const purchaseApprovalLineSchema = z
|
|
234
|
+
.object({
|
|
235
|
+
itemReference: resourceId,
|
|
236
|
+
title: z.string().trim().min(1).max(300),
|
|
237
|
+
optionsText: z.string().trim().max(300),
|
|
238
|
+
merchantAccountId: accountId,
|
|
239
|
+
quantity: z.number().int().min(1).max(1000000),
|
|
240
|
+
unitAmountMinor: minorUnits,
|
|
241
|
+
lineAmountMinor: minorUnits,
|
|
242
|
+
})
|
|
243
|
+
.strict();
|
|
244
|
+
const purchaseEffectsObject = z
|
|
245
|
+
.object({
|
|
246
|
+
operationId: resourceId,
|
|
247
|
+
resourceId,
|
|
248
|
+
cartFingerprint: fingerprint,
|
|
249
|
+
summary: z.string().trim().min(1).max(300),
|
|
250
|
+
merchantAccountIds: z
|
|
251
|
+
.array(accountId)
|
|
252
|
+
.min(1)
|
|
253
|
+
.max(100)
|
|
254
|
+
.refine((ids) => new Set(ids).size === ids.length, 'Merchant accounts must be unique')
|
|
255
|
+
.transform((ids) => [...ids].sort()),
|
|
256
|
+
lineItems: z.array(purchaseApprovalLineSchema).min(1).max(200),
|
|
257
|
+
shippingMinor: minorUnits,
|
|
258
|
+
taxMinor: minorUnits,
|
|
259
|
+
discountMinor: minorUnits,
|
|
260
|
+
roundingAdjustmentMinor: z
|
|
261
|
+
.number()
|
|
262
|
+
.int()
|
|
263
|
+
.min(-Number.MAX_SAFE_INTEGER)
|
|
264
|
+
.max(Number.MAX_SAFE_INTEGER),
|
|
265
|
+
paymentFingerprint: fingerprint,
|
|
266
|
+
amountMinor: minorUnits,
|
|
267
|
+
currency: z.string().regex(/^[A-Z]{3}$/),
|
|
268
|
+
expiresAt: z.string().datetime(),
|
|
269
|
+
})
|
|
270
|
+
.strict();
|
|
271
|
+
function validatePurchaseEvidence(value, ctx) {
|
|
272
|
+
const merchants = new Set(value.merchantAccountIds);
|
|
273
|
+
const references = new Set();
|
|
274
|
+
for (const line of value.lineItems) {
|
|
275
|
+
const key = `${line.merchantAccountId}:${line.itemReference}`;
|
|
276
|
+
if (!merchants.has(line.merchantAccountId) || references.has(key))
|
|
277
|
+
ctx.addIssue({
|
|
278
|
+
code: z.ZodIssueCode.custom,
|
|
279
|
+
message: 'Purchase lines must name an included merchant and unique item reference',
|
|
280
|
+
});
|
|
281
|
+
references.add(key);
|
|
282
|
+
}
|
|
283
|
+
if (merchants.size !== new Set(value.lineItems.map((line) => line.merchantAccountId)).size)
|
|
284
|
+
ctx.addIssue({
|
|
285
|
+
code: z.ZodIssueCode.custom,
|
|
286
|
+
message: 'Every merchant must have an approval line',
|
|
287
|
+
});
|
|
288
|
+
const total = value.lineItems.reduce((sum, line) => sum + BigInt(line.lineAmountMinor), 0n) +
|
|
289
|
+
BigInt(value.shippingMinor) +
|
|
290
|
+
BigInt(value.taxMinor) -
|
|
291
|
+
BigInt(value.discountMinor) +
|
|
292
|
+
BigInt(value.roundingAdjustmentMinor);
|
|
293
|
+
if (total < 0n || total > BigInt(Number.MAX_SAFE_INTEGER) || total !== BigInt(value.amountMinor))
|
|
294
|
+
ctx.addIssue({
|
|
295
|
+
code: z.ZodIssueCode.custom,
|
|
296
|
+
message: 'Approval evidence must equal the exact payment total',
|
|
297
|
+
});
|
|
298
|
+
if (Math.abs(value.roundingAdjustmentMinor) >
|
|
299
|
+
value.lineItems.length + 3 * value.merchantAccountIds.length)
|
|
300
|
+
ctx.addIssue({
|
|
301
|
+
code: z.ZodIssueCode.custom,
|
|
302
|
+
message: 'Rounding adjustment exceeds the bounded conversion stages',
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
export const purchaseEffectsSchema = purchaseEffectsObject.superRefine(validatePurchaseEvidence);
|
|
306
|
+
const purchaseApprovalFields = {
|
|
307
|
+
id: accountId,
|
|
308
|
+
childAccountId: accountId,
|
|
309
|
+
applicationId: accountId,
|
|
310
|
+
status: z.enum(PURCHASE_APPROVAL_STATUSES),
|
|
311
|
+
createdAt: z.string().datetime(),
|
|
312
|
+
receiptReference: z.string().max(512).nullable(),
|
|
313
|
+
};
|
|
314
|
+
export const purchaseApprovalSchema = purchaseEffectsObject
|
|
315
|
+
.extend(purchaseApprovalFields)
|
|
316
|
+
.strict()
|
|
317
|
+
.superRefine(validatePurchaseEvidence);
|
|
318
|
+
export const purchaseApprovalSummarySchema = purchaseEffectsObject
|
|
319
|
+
.omit({ lineItems: true })
|
|
320
|
+
.extend(purchaseApprovalFields)
|
|
321
|
+
.strict();
|
|
322
|
+
export const purchaseApprovalListSchema = z
|
|
323
|
+
.object({
|
|
324
|
+
items: z.array(purchaseApprovalSummarySchema).max(100),
|
|
325
|
+
nextCursor: z.string().nullable(),
|
|
326
|
+
})
|
|
327
|
+
.strict();
|
|
328
|
+
export const reservePurchaseSchema = purchaseEffectsObject
|
|
329
|
+
.extend({ approvalId: accountId })
|
|
330
|
+
.strict()
|
|
331
|
+
.superRefine(validatePurchaseEvidence);
|
|
332
|
+
export const confirmPurchaseSchema = z
|
|
333
|
+
.object({
|
|
334
|
+
approvalId: accountId,
|
|
335
|
+
operationId: resourceId,
|
|
336
|
+
receiptReference: z.string().trim().min(1).max(512),
|
|
337
|
+
})
|
|
338
|
+
.strict();
|
|
339
|
+
export const cancelPurchaseSchema = confirmPurchaseSchema.omit({ receiptReference: true });
|
|
340
|
+
export const SAFETY_ERROR_CODES = [
|
|
341
|
+
'bad_request',
|
|
342
|
+
'validation_failed',
|
|
343
|
+
'unauthorized',
|
|
344
|
+
'forbidden',
|
|
345
|
+
'not_found',
|
|
346
|
+
'conflict',
|
|
347
|
+
'reauth_required',
|
|
348
|
+
'limit_reached',
|
|
349
|
+
'service_unavailable',
|
|
350
|
+
'rate_limited',
|
|
351
|
+
];
|
|
352
|
+
export const safetyErrorSchema = z
|
|
353
|
+
.object({ error: z.object({ code: z.enum(SAFETY_ERROR_CODES), message: z.string() }).strict() })
|
|
354
|
+
.strict();
|
|
355
|
+
export const supervisionInviteInputSchema = z
|
|
356
|
+
.object({
|
|
357
|
+
guardianAccountId: accountId,
|
|
358
|
+
consentVersion: z.literal(SUPERVISION_CONSENT_VERSION),
|
|
359
|
+
reauth: reauthProofSchema,
|
|
360
|
+
})
|
|
361
|
+
.strict();
|
|
362
|
+
export const supervisionAcceptInputSchema = z
|
|
363
|
+
.object({ consentVersion: z.literal(SUPERVISION_CONSENT_VERSION), reauth: reauthProofSchema })
|
|
364
|
+
.strict();
|
|
365
|
+
export const supervisionContactInputSchema = z
|
|
366
|
+
.object({ childAccountId: accountId, contactAccountId: accountId, reauth: reauthProofSchema })
|
|
367
|
+
.strict();
|
|
368
|
+
export const supervisionReviewInputSchema = z
|
|
369
|
+
.object({
|
|
370
|
+
childAccountId: accountId,
|
|
371
|
+
action: z.enum(['end', 'transfer']),
|
|
372
|
+
guardianAccountId: accountId.optional(),
|
|
373
|
+
evidenceReference: z.string().trim().min(1).max(2048),
|
|
374
|
+
reauth: reauthProofSchema,
|
|
375
|
+
})
|
|
376
|
+
.strict();
|
|
377
|
+
export const purchaseReviewInputSchema = z
|
|
378
|
+
.object({ decision: z.enum(['approved', 'rejected']), reauth: reauthProofSchema })
|
|
379
|
+
.strict();
|
|
380
|
+
export const safetySessionInputSchema = z
|
|
381
|
+
.object({
|
|
382
|
+
sessionId: accountId,
|
|
383
|
+
accessToken: z.string().min(1).max(16384),
|
|
384
|
+
action: z.enum(SUPERVISED_ACTIONS),
|
|
385
|
+
})
|
|
386
|
+
.strict();
|
|
387
|
+
export const safetySessionValidationSchema = z
|
|
388
|
+
.object({
|
|
389
|
+
valid: z.literal(true),
|
|
390
|
+
sessionId: accountId,
|
|
391
|
+
expiresAt: z.string().datetime(),
|
|
392
|
+
lastActivity: z.string().datetime(),
|
|
393
|
+
user: userResponseSchema,
|
|
394
|
+
actor: accountActorChainSchema,
|
|
395
|
+
})
|
|
396
|
+
.strict();
|
|
397
|
+
/** Minimal identity for the authenticated account's supervision management, never profile details. */
|
|
398
|
+
export const safetyPersonSchema = z
|
|
399
|
+
.object({ accountId, username: z.string().nullable(), displayName: z.string().nullable() })
|
|
400
|
+
.strict();
|
|
401
|
+
export const safetyPeopleInputSchema = z.union([
|
|
402
|
+
z.object({ query: z.string().trim().min(2).max(100) }).strict(),
|
|
403
|
+
z.object({ accountIds: uniqueIds(100) }).strict(),
|
|
404
|
+
]);
|
|
405
|
+
export const safetyPeopleResponseSchema = z
|
|
406
|
+
.object({ items: z.array(safetyPersonSchema).max(100) })
|
|
407
|
+
.strict();
|
|
408
|
+
/** Existing public employer identity only; never directory content or management authority. */
|
|
409
|
+
export const safetyOrganizationIdentitySchema = z
|
|
410
|
+
.object({
|
|
411
|
+
accountId,
|
|
412
|
+
username: z.string().nullable(),
|
|
413
|
+
name: z.string(),
|
|
414
|
+
organizationType: z.enum(ORGANIZATION_TYPES),
|
|
415
|
+
})
|
|
416
|
+
.strict();
|
|
417
|
+
export const safetyOrganizationsInputSchema = z.union([
|
|
418
|
+
z
|
|
419
|
+
.object({
|
|
420
|
+
query: z.string().trim().min(1).max(100),
|
|
421
|
+
limit: z.number().int().min(1).max(20).optional(),
|
|
422
|
+
})
|
|
423
|
+
.strict(),
|
|
424
|
+
z.object({ ids: uniqueIds(100) }).strict(),
|
|
425
|
+
]);
|
|
426
|
+
export const safetyOrganizationsResponseSchema = z
|
|
427
|
+
.object({
|
|
428
|
+
items: z
|
|
429
|
+
.array(z
|
|
430
|
+
.object({ requestedAccountId: accountId, organization: safetyOrganizationIdentitySchema })
|
|
431
|
+
.strict())
|
|
432
|
+
.max(100),
|
|
433
|
+
missingIds: z.array(accountId).max(100),
|
|
434
|
+
})
|
|
435
|
+
.strict();
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/** Omitted means the existing grant; an explicit set only narrows that authority. */
|
|
3
|
+
export const serviceTokenScopesSchema = z
|
|
4
|
+
.array(z.string().trim().min(1).max(128))
|
|
5
|
+
.min(1)
|
|
6
|
+
.max(100)
|
|
7
|
+
.refine((scopes) => new Set(scopes).size === scopes.length, 'Requested scopes must be unique')
|
|
8
|
+
.transform((scopes) => [...scopes].sort());
|
|
9
|
+
export const serviceTokenOptionsSchema = z
|
|
10
|
+
.object({ scopes: serviceTokenScopesSchema.optional() })
|
|
11
|
+
.strict();
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire contract for `GET /internal/accounts/:accountId/access/:userId`: Oxy
|
|
3
|
+
* answers a trusted first-party service's question "may this person act FOR
|
|
4
|
+
* that account, and with what?" with no session of that person in the request.
|
|
5
|
+
*
|
|
6
|
+
* It exists for the account Oxy never lets anybody act AS: a `channel`
|
|
7
|
+
* ({@link isDelegatedActAsEligibleKind} refuses it). An app publishes to a
|
|
8
|
+
* channel with ITS OWN credential, on behalf of a member Oxy vouches for here,
|
|
9
|
+
* so nobody holds a bearer that speaks as the channel. A long-running import
|
|
10
|
+
* (Oxy Move) has only a service token and `X-Oxy-User-Id`, which the
|
|
11
|
+
* user-facing `GET /accounts/:id/members` refuses; this is its answer.
|
|
12
|
+
*
|
|
13
|
+
* Needs a service token whose application is platform-trusted AND holds the
|
|
14
|
+
* privileged {@link ACCOUNTS_MEMBERSHIP_READ_SCOPE}. The answer is always 200:
|
|
15
|
+
* `access` is `null` for no active membership, an archived account, an unknown
|
|
16
|
+
* account and an unclaimed directory account alike. Callers must treat every
|
|
17
|
+
* other status as a refusal (fail closed), and must not cache the answer longer
|
|
18
|
+
* than the action it authorizes.
|
|
19
|
+
*
|
|
20
|
+
* Platform-agnostic — zod only.
|
|
21
|
+
*/
|
|
22
|
+
import { z } from 'zod';
|
|
23
|
+
/**
|
|
24
|
+
* The scope the endpoint requires.
|
|
25
|
+
*
|
|
26
|
+
* Privileged (staff-granted). Channel membership is sensitive because a channel
|
|
27
|
+
* is anonymous: its members are the people behind a voice that is published
|
|
28
|
+
* without their names, and "is this person a member of that channel" is
|
|
29
|
+
* exactly the fact the channel exists to withhold.
|
|
30
|
+
*/
|
|
31
|
+
export declare const ACCOUNTS_MEMBERSHIP_READ_SCOPE: "accounts:membership:read";
|
|
32
|
+
/**
|
|
33
|
+
* Where the access comes from.
|
|
34
|
+
*
|
|
35
|
+
* - `self` — the person IS the account (a personal account asked about itself).
|
|
36
|
+
* - `direct` — an active membership row on the account.
|
|
37
|
+
* - `inherited` — an active, cascading membership on an ancestor account.
|
|
38
|
+
*/
|
|
39
|
+
export declare const ACCOUNT_ACCESS_SOURCES: readonly ["self", "direct", "inherited"];
|
|
40
|
+
export type AccountAccessSource = (typeof ACCOUNT_ACCESS_SOURCES)[number];
|
|
41
|
+
export declare const accountAccessSourceSchema: z.ZodEnum<["self", "direct", "inherited"]>;
|
|
42
|
+
/**
|
|
43
|
+
* One person's EFFECTIVE access over one account.
|
|
44
|
+
*
|
|
45
|
+
* `role` and `permissions` are strings rather than closed enums on purpose: the
|
|
46
|
+
* role and permission vocabularies are the API's, they grow, and a consumer
|
|
47
|
+
* pinned to an older contracts release must keep reading new ones. Gate on
|
|
48
|
+
* `permissions` (the role's baseline adjusted by per-member grants and
|
|
49
|
+
* revokes), never on `role`.
|
|
50
|
+
*/
|
|
51
|
+
export declare const accountAccessGrantSchema: z.ZodObject<{
|
|
52
|
+
role: z.ZodString;
|
|
53
|
+
permissions: z.ZodArray<z.ZodString, "many">;
|
|
54
|
+
/** Only an active membership grants access, so this is the one value. */
|
|
55
|
+
status: z.ZodLiteral<"active">;
|
|
56
|
+
source: z.ZodEnum<["self", "direct", "inherited"]>;
|
|
57
|
+
}, "strip", z.ZodTypeAny, {
|
|
58
|
+
status: "active";
|
|
59
|
+
role: string;
|
|
60
|
+
permissions: string[];
|
|
61
|
+
source: "self" | "direct" | "inherited";
|
|
62
|
+
}, {
|
|
63
|
+
status: "active";
|
|
64
|
+
role: string;
|
|
65
|
+
permissions: string[];
|
|
66
|
+
source: "self" | "direct" | "inherited";
|
|
67
|
+
}>;
|
|
68
|
+
export type AccountAccessGrant = z.infer<typeof accountAccessGrantSchema>;
|
|
69
|
+
export declare const accountAccessVerdictSchema: z.ZodEffects<z.ZodObject<{
|
|
70
|
+
accountId: z.ZodString;
|
|
71
|
+
/** `null` when no such account exists. */
|
|
72
|
+
kind: z.ZodNullable<z.ZodEnum<["personal", "organization", "project", "bot", "channel"]>>;
|
|
73
|
+
/** `null` means: this person may not act for this account. */
|
|
74
|
+
access: z.ZodNullable<z.ZodObject<{
|
|
75
|
+
role: z.ZodString;
|
|
76
|
+
permissions: z.ZodArray<z.ZodString, "many">;
|
|
77
|
+
/** Only an active membership grants access, so this is the one value. */
|
|
78
|
+
status: z.ZodLiteral<"active">;
|
|
79
|
+
source: z.ZodEnum<["self", "direct", "inherited"]>;
|
|
80
|
+
}, "strip", z.ZodTypeAny, {
|
|
81
|
+
status: "active";
|
|
82
|
+
role: string;
|
|
83
|
+
permissions: string[];
|
|
84
|
+
source: "self" | "direct" | "inherited";
|
|
85
|
+
}, {
|
|
86
|
+
status: "active";
|
|
87
|
+
role: string;
|
|
88
|
+
permissions: string[];
|
|
89
|
+
source: "self" | "direct" | "inherited";
|
|
90
|
+
}>>;
|
|
91
|
+
}, "strip", z.ZodTypeAny, {
|
|
92
|
+
kind: "organization" | "personal" | "project" | "bot" | "channel" | null;
|
|
93
|
+
accountId: string;
|
|
94
|
+
access: {
|
|
95
|
+
status: "active";
|
|
96
|
+
role: string;
|
|
97
|
+
permissions: string[];
|
|
98
|
+
source: "self" | "direct" | "inherited";
|
|
99
|
+
} | null;
|
|
100
|
+
}, {
|
|
101
|
+
kind: "organization" | "personal" | "project" | "bot" | "channel" | null;
|
|
102
|
+
accountId: string;
|
|
103
|
+
access: {
|
|
104
|
+
status: "active";
|
|
105
|
+
role: string;
|
|
106
|
+
permissions: string[];
|
|
107
|
+
source: "self" | "direct" | "inherited";
|
|
108
|
+
} | null;
|
|
109
|
+
}>, {
|
|
110
|
+
kind: "organization" | "personal" | "project" | "bot" | "channel" | null;
|
|
111
|
+
accountId: string;
|
|
112
|
+
access: {
|
|
113
|
+
status: "active";
|
|
114
|
+
role: string;
|
|
115
|
+
permissions: string[];
|
|
116
|
+
source: "self" | "direct" | "inherited";
|
|
117
|
+
} | null;
|
|
118
|
+
}, {
|
|
119
|
+
kind: "organization" | "personal" | "project" | "bot" | "channel" | null;
|
|
120
|
+
accountId: string;
|
|
121
|
+
access: {
|
|
122
|
+
status: "active";
|
|
123
|
+
role: string;
|
|
124
|
+
permissions: string[];
|
|
125
|
+
source: "self" | "direct" | "inherited";
|
|
126
|
+
} | null;
|
|
127
|
+
}>;
|
|
128
|
+
export type AccountAccessVerdict = z.infer<typeof accountAccessVerdictSchema>;
|
|
@@ -24,11 +24,11 @@ export declare const emailVerificationStartRequestSchema: z.ZodObject<{
|
|
|
24
24
|
purpose: z.ZodLiteral<"signup">;
|
|
25
25
|
email: z.ZodString;
|
|
26
26
|
}, "strict", z.ZodTypeAny, {
|
|
27
|
-
purpose: "signup";
|
|
28
27
|
email: string;
|
|
29
|
-
}, {
|
|
30
28
|
purpose: "signup";
|
|
29
|
+
}, {
|
|
31
30
|
email: string;
|
|
31
|
+
purpose: "signup";
|
|
32
32
|
}>;
|
|
33
33
|
export type EmailVerificationStartRequest = z.infer<typeof emailVerificationStartRequestSchema>;
|
|
34
34
|
export interface EmailVerificationStartResponse {
|