@oxy.so/contracts 4.17.0 → 4.22.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 (61) hide show
  1. package/dist/cjs/accountAccess.js +72 -0
  2. package/dist/cjs/agency.js +112 -1
  3. package/dist/cjs/applicationRoles.js +211 -0
  4. package/dist/cjs/client/check.js +9 -0
  5. package/dist/cjs/client/contentClaims.js +139 -0
  6. package/dist/cjs/client/index.js +37 -1
  7. package/dist/cjs/client/safety.js +183 -2
  8. package/dist/cjs/client/signIn.js +2 -0
  9. package/dist/cjs/contentClaims.js +246 -0
  10. package/dist/cjs/index.js +14 -3
  11. package/dist/cjs/safety.js +430 -1
  12. package/dist/cjs/serviceToken.js +14 -0
  13. package/dist/esm/accountAccess.js +69 -0
  14. package/dist/esm/agency.js +111 -0
  15. package/dist/esm/applicationRoles.js +207 -0
  16. package/dist/esm/client/check.js +8 -0
  17. package/dist/esm/client/contentClaims.js +134 -0
  18. package/dist/esm/client/index.js +2 -1
  19. package/dist/esm/client/safety.js +183 -2
  20. package/dist/esm/client/signIn.js +2 -0
  21. package/dist/esm/contentClaims.js +229 -0
  22. package/dist/esm/index.js +5 -1
  23. package/dist/esm/safety.js +423 -0
  24. package/dist/esm/serviceToken.js +11 -0
  25. package/dist/types/accountAccess.d.ts +128 -0
  26. package/dist/types/accountEmail.d.ts +2 -2
  27. package/dist/types/agency.d.ts +327 -2
  28. package/dist/types/agentKeys.d.ts +6 -6
  29. package/dist/types/applicationRoles.d.ts +438 -0
  30. package/dist/types/client/agentKeys.d.ts +2 -2
  31. package/dist/types/client/check.d.ts +3 -0
  32. package/dist/types/client/contentClaims.d.ts +106 -0
  33. package/dist/types/client/deviceSession.d.ts +1 -1
  34. package/dist/types/client/index.d.ts +2 -1
  35. package/dist/types/client/safety.d.ts +204 -4
  36. package/dist/types/client/signIn.d.ts +1 -1
  37. package/dist/types/contentClaims.d.ts +383 -0
  38. package/dist/types/deviceSession.d.ts +4 -4
  39. package/dist/types/email/messages.d.ts +4 -4
  40. package/dist/types/externalIdentity.d.ts +16 -16
  41. package/dist/types/index.d.ts +6 -2
  42. package/dist/types/inference/accountBilling.d.ts +2 -2
  43. package/dist/types/inference/aliaModelRelease.d.ts +8 -8
  44. package/dist/types/inference/catalogue.d.ts +26 -26
  45. package/dist/types/inference/inbox.d.ts +4 -4
  46. package/dist/types/inference/modelDocumentation.d.ts +16 -16
  47. package/dist/types/inference/providerConnection.d.ts +4 -4
  48. package/dist/types/inference/realtime.d.ts +74 -74
  49. package/dist/types/inference/request.d.ts +60 -60
  50. package/dist/types/inference/usage.d.ts +4 -4
  51. package/dist/types/products/access.d.ts +4 -4
  52. package/dist/types/safety.d.ts +2374 -2
  53. package/dist/types/serviceToken.d.ts +11 -0
  54. package/dist/types/sessionStatus.d.ts +4 -4
  55. package/dist/types/signIn.d.ts +5 -5
  56. package/dist/types/updates.d.ts +6 -6
  57. package/dist/types/userResponse.d.ts +8 -8
  58. package/package.json +5 -20
  59. package/dist/cjs/.tsbuildinfo +0 -1
  60. package/dist/esm/.tsbuildinfo +0 -1
  61. package/dist/types/.tsbuildinfo +0 -1
@@ -1,7 +1,21 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.profileAccessDecisionSchema = exports.profileAccessInputSchema = void 0;
3
+ exports.supervisionInviteInputSchema = exports.safetyErrorSchema = exports.SAFETY_ERROR_CODES = exports.cancelPurchaseSchema = exports.confirmPurchaseSchema = exports.reservePurchaseSchema = exports.purchaseApprovalListSchema = exports.purchaseApprovalSummarySchema = exports.purchaseApprovalSchema = exports.purchaseEffectsSchema = exports.purchaseApprovalLineSchema = exports.supervisionContactsResponseSchema = exports.supervisionStateSchema = exports.supervisionContactSchema = exports.supervisionInvitationSchema = exports.supervisionSchema = exports.safetyRequesterSchema = exports.messagingSessionsResponseSchema = exports.messagingSessionsInputSchema = exports.messageAccessBatchResponseSchema = exports.deliveryAccessBatchInputSchema = exports.messageAccessBatchInputSchema = exports.deliveryAccessInputSchema = exports.contentAccessBatchResponseSchema = exports.contentAccessBatchInputSchema = exports.publicationPoliciesResponseSchema = exports.publicationPoliciesInputSchema = exports.publicationPolicySchema = exports.contentAccessInputSchema = exports.CONTENT_CLASSIFICATIONS = exports.contactAccessResponseSchema = exports.contactAccessInputSchema = exports.messageAccessInputSchema = exports.MESSAGE_ACCESS_MAX_INPUT_BYTES = exports.MESSAGE_ACCESS_MAX_PARTICIPANT_SLOTS = exports.MESSAGE_ACCESS_MAX_SUPERVISED_PARTICIPANTS = exports.MESSAGE_ACCESS_MAX_PARTICIPANTS = exports.MESSAGE_ACCESS_MAX_RESOURCES = exports.profileAccessBatchResponseSchema = exports.profileAccessBatchInputSchema = exports.safetyDecisionSchema = exports.SAFETY_DECISION_REASONS = exports.profileAccessDecisionSchema = exports.profileAccessInputSchema = exports.SUPERVISION_STATUSES = exports.SUPERVISION_INVITATION_STATUSES = exports.SUPERVISION_CONSENT_VERSION = exports.SUPERVISED_ACTIONS = exports.SAFETY_POLICY_VERSION = exports.PURCHASE_APPROVAL_STATUSES = void 0;
4
+ exports.safetyOrganizationsResponseSchema = exports.safetyOrganizationsInputSchema = exports.safetyOrganizationIdentitySchema = exports.safetyPeopleResponseSchema = exports.safetyPeopleInputSchema = exports.safetyPersonSchema = exports.safetySessionValidationSchema = exports.safetySessionInputSchema = exports.purchaseReviewInputSchema = exports.supervisionReviewInputSchema = exports.supervisionContactInputSchema = exports.supervisionAcceptInputSchema = void 0;
4
5
  const zod_1 = require("zod");
6
+ const accountSubject_1 = require("./accountSubject");
7
+ // The Zod-free half of this contract lives in `./client/` (`@oxy.so/contracts/client`);
8
+ // its vocabularies are re-exported here so the root entry is unchanged.
9
+ const safety_1 = require("./client/safety");
10
+ Object.defineProperty(exports, "PURCHASE_APPROVAL_STATUSES", { enumerable: true, get: function () { return safety_1.PURCHASE_APPROVAL_STATUSES; } });
11
+ Object.defineProperty(exports, "SAFETY_POLICY_VERSION", { enumerable: true, get: function () { return safety_1.SAFETY_POLICY_VERSION; } });
12
+ Object.defineProperty(exports, "SUPERVISED_ACTIONS", { enumerable: true, get: function () { return safety_1.SUPERVISED_ACTIONS; } });
13
+ Object.defineProperty(exports, "SUPERVISION_CONSENT_VERSION", { enumerable: true, get: function () { return safety_1.SUPERVISION_CONSENT_VERSION; } });
14
+ Object.defineProperty(exports, "SUPERVISION_INVITATION_STATUSES", { enumerable: true, get: function () { return safety_1.SUPERVISION_INVITATION_STATUSES; } });
15
+ Object.defineProperty(exports, "SUPERVISION_STATUSES", { enumerable: true, get: function () { return safety_1.SUPERVISION_STATUSES; } });
16
+ const organizations_1 = require("./organizations");
17
+ const signIn_1 = require("./signIn");
18
+ const userResponse_1 = require("./userResponse");
5
19
  /** The requester is authenticated by the bearer; applications cannot submit viewer IDs. */
6
20
  exports.profileAccessInputSchema = zod_1.z
7
21
  .object({ subjectAccountId: zod_1.z.string().min(1).max(128) })
@@ -13,3 +27,418 @@ exports.profileAccessDecisionSchema = zod_1.z
13
27
  policyVersion: zod_1.z.literal('1'),
14
28
  })
15
29
  .strict();
30
+ exports.SAFETY_DECISION_REASONS = [
31
+ 'allowed',
32
+ 'owner',
33
+ 'public',
34
+ 'private',
35
+ 'blocked',
36
+ 'unavailable',
37
+ 'unsupported_consumer',
38
+ 'contact_not_approved',
39
+ 'mature_content',
40
+ 'unrated_content',
41
+ 'approval_required',
42
+ ];
43
+ const accountId = zod_1.z.string().min(1).max(128);
44
+ const resourceId = zod_1.z.string().trim().min(1).max(256);
45
+ const uniqueIds = (max, min = 1) => zod_1.z
46
+ .array(accountId)
47
+ .min(min)
48
+ .max(max)
49
+ .refine((ids) => new Set(ids).size === ids.length, 'Account IDs must be unique');
50
+ exports.safetyDecisionSchema = zod_1.z
51
+ .object({
52
+ allowed: zod_1.z.boolean(),
53
+ reason: zod_1.z.enum(exports.SAFETY_DECISION_REASONS),
54
+ policyVersion: zod_1.z.literal(safety_1.SAFETY_POLICY_VERSION),
55
+ })
56
+ .strict();
57
+ exports.profileAccessBatchInputSchema = zod_1.z
58
+ .object({ subjectAccountIds: uniqueIds(100) })
59
+ .strict();
60
+ exports.profileAccessBatchResponseSchema = zod_1.z
61
+ .object({
62
+ items: zod_1.z
63
+ .array(zod_1.z
64
+ .object({
65
+ subjectAccountId: accountId,
66
+ decision: exports.safetyDecisionSchema,
67
+ })
68
+ .strict())
69
+ .max(100),
70
+ })
71
+ .strict();
72
+ exports.MESSAGE_ACCESS_MAX_RESOURCES = 100;
73
+ exports.MESSAGE_ACCESS_MAX_PARTICIPANTS = 1024;
74
+ exports.MESSAGE_ACCESS_MAX_SUPERVISED_PARTICIPANTS = 256;
75
+ exports.MESSAGE_ACCESS_MAX_PARTICIPANT_SLOTS = 4096;
76
+ /** Leaves room for the original requester proof in a 512 KiB request. */
77
+ exports.MESSAGE_ACCESS_MAX_INPUT_BYTES = 448 * 1024;
78
+ exports.messageAccessInputSchema = zod_1.z
79
+ .object({ participantAccountIds: uniqueIds(exports.MESSAGE_ACCESS_MAX_PARTICIPANTS), resourceId })
80
+ .strict();
81
+ exports.contactAccessInputSchema = zod_1.z.object({ targetAccountIds: uniqueIds(1000) }).strict();
82
+ exports.contactAccessResponseSchema = zod_1.z
83
+ .object({
84
+ items: zod_1.z
85
+ .array(zod_1.z
86
+ .object({
87
+ targetAccountId: accountId,
88
+ decision: exports.safetyDecisionSchema,
89
+ })
90
+ .strict())
91
+ .max(1000),
92
+ })
93
+ .strict();
94
+ exports.CONTENT_CLASSIFICATIONS = ['general', 'mature', 'unrated'];
95
+ exports.contentAccessInputSchema = zod_1.z
96
+ .object({
97
+ resourceId,
98
+ classification: zod_1.z.enum(exports.CONTENT_CLASSIFICATIONS),
99
+ authorAccountId: accountId.optional(),
100
+ audience: zod_1.z.enum(['public', 'private', 'followers']).optional(),
101
+ applicationAudienceAllowed: zod_1.z.boolean().optional(),
102
+ applicationResourceGrant: zod_1.z.boolean().optional(),
103
+ operation: zod_1.z.enum(['read', 'manage_own']).optional(),
104
+ })
105
+ .strict()
106
+ .refine((item) => !item.audience ||
107
+ item.audience === 'public' ||
108
+ (!!item.authorAccountId && item.applicationAudienceAllowed !== undefined), 'Nonpublic content requires its authoritative author and application audience decision')
109
+ .refine((item) => item.operation !== 'manage_own' || !!item.authorAccountId, 'Own management requires its authoritative author');
110
+ exports.publicationPolicySchema = zod_1.z
111
+ .object({
112
+ publicationAllowed: zod_1.z.boolean(),
113
+ requiredAudience: zod_1.z.literal('private').nullable(),
114
+ collaborationAllowed: zod_1.z.boolean(),
115
+ federationAllowed: zod_1.z.boolean(),
116
+ policyVersion: zod_1.z.literal(safety_1.SAFETY_POLICY_VERSION),
117
+ })
118
+ .strict();
119
+ exports.publicationPoliciesInputSchema = zod_1.z
120
+ .object({
121
+ authorAccountIds: zod_1.z
122
+ .array(accountId)
123
+ .min(1)
124
+ .max(100)
125
+ .refine((ids) => new Set(ids).size === ids.length, 'Author IDs must be unique'),
126
+ })
127
+ .strict();
128
+ exports.publicationPoliciesResponseSchema = zod_1.z
129
+ .object({
130
+ items: zod_1.z
131
+ .array(zod_1.z.object({ authorAccountId: accountId, policy: exports.publicationPolicySchema }).strict())
132
+ .max(100),
133
+ })
134
+ .strict();
135
+ exports.contentAccessBatchInputSchema = zod_1.z
136
+ .object({
137
+ items: zod_1.z
138
+ .array(exports.contentAccessInputSchema)
139
+ .min(1)
140
+ .max(100)
141
+ .refine((items) => new Set(items.map((item) => item.resourceId)).size === items.length, 'Resource IDs must be unique'),
142
+ })
143
+ .strict();
144
+ exports.contentAccessBatchResponseSchema = zod_1.z
145
+ .object({
146
+ items: zod_1.z
147
+ .array(zod_1.z
148
+ .object({
149
+ resourceId,
150
+ decision: exports.safetyDecisionSchema,
151
+ })
152
+ .strict())
153
+ .max(100),
154
+ })
155
+ .strict();
156
+ /** A reviewed background consumer may decide delivery, but never authenticate as the sender. */
157
+ exports.deliveryAccessInputSchema = exports.messageAccessInputSchema
158
+ .extend({ senderAccountId: accountId })
159
+ .strict();
160
+ /** Count repeated participants across resources too: this bounds both graph and pair evaluations. */
161
+ const messageBatch = (schema) => zod_1.z
162
+ .object({ items: zod_1.z.array(schema).min(1).max(exports.MESSAGE_ACCESS_MAX_RESOURCES) })
163
+ .strict()
164
+ .refine((value) => new Set(value.items.map((item) => item.resourceId)).size === value.items.length, 'Resource IDs must be unique')
165
+ .refine((value) => value.items.reduce((total, item) => total + item.participantAccountIds.length, 0) <=
166
+ exports.MESSAGE_ACCESS_MAX_PARTICIPANT_SLOTS, 'Participant budget exceeded')
167
+ .refine((value) => new TextEncoder().encode(JSON.stringify(value)).byteLength <=
168
+ exports.MESSAGE_ACCESS_MAX_INPUT_BYTES, 'Message batch byte budget exceeded');
169
+ exports.messageAccessBatchInputSchema = messageBatch(exports.messageAccessInputSchema);
170
+ exports.deliveryAccessBatchInputSchema = messageBatch(exports.deliveryAccessInputSchema);
171
+ exports.messageAccessBatchResponseSchema = exports.contentAccessBatchResponseSchema;
172
+ /** Live socket-recipient proof; a request ID correlates the result and never identifies an account. */
173
+ exports.messagingSessionsInputSchema = zod_1.z
174
+ .object({
175
+ items: zod_1.z
176
+ .array(zod_1.z
177
+ .object({
178
+ requestId: resourceId,
179
+ accessToken: zod_1.z.string().min(1).max(16384),
180
+ })
181
+ .strict())
182
+ .min(1)
183
+ .max(100),
184
+ })
185
+ .strict()
186
+ .refine((value) => new Set(value.items.map((item) => item.requestId)).size === value.items.length, 'Request IDs must be unique')
187
+ .refine((value) => new TextEncoder().encode(JSON.stringify(value)).byteLength <= exports.MESSAGE_ACCESS_MAX_INPUT_BYTES, 'Session proof byte budget exceeded');
188
+ exports.messagingSessionsResponseSchema = zod_1.z
189
+ .object({
190
+ items: zod_1.z
191
+ .array(zod_1.z.discriminatedUnion('allowed', [
192
+ zod_1.z.object({ requestId: resourceId, allowed: zod_1.z.literal(true), accountId }).strict(),
193
+ zod_1.z.object({ requestId: resourceId, allowed: zod_1.z.literal(false) }).strict(),
194
+ ]))
195
+ .max(100),
196
+ })
197
+ .strict();
198
+ exports.safetyRequesterSchema = zod_1.z.union([
199
+ zod_1.z.object({ accessToken: zod_1.z.string().min(1).max(16384).nullable() }).strict(),
200
+ zod_1.z.object({ connectionToken: zod_1.z.string().min(1).max(16384) }).strict(),
201
+ ]);
202
+ exports.supervisionSchema = zod_1.z
203
+ .object({
204
+ childAccountId: accountId,
205
+ guardianAccountId: accountId.nullable(),
206
+ status: zod_1.z.enum(safety_1.SUPERVISION_STATUSES),
207
+ policyVersion: zod_1.z.literal(safety_1.SAFETY_POLICY_VERSION),
208
+ consentVersion: zod_1.z.literal(safety_1.SUPERVISION_CONSENT_VERSION),
209
+ createdAt: zod_1.z.string().datetime(),
210
+ })
211
+ .strict();
212
+ exports.supervisionInvitationSchema = zod_1.z
213
+ .object({
214
+ id: accountId,
215
+ childAccountId: accountId,
216
+ guardianAccountId: accountId,
217
+ status: zod_1.z.enum(safety_1.SUPERVISION_INVITATION_STATUSES),
218
+ expiresAt: zod_1.z.string().datetime(),
219
+ consentVersion: zod_1.z.literal(safety_1.SUPERVISION_CONSENT_VERSION),
220
+ createdAt: zod_1.z.string().datetime(),
221
+ })
222
+ .strict();
223
+ exports.supervisionContactSchema = zod_1.z
224
+ .object({
225
+ childAccountId: accountId,
226
+ contactAccountId: accountId,
227
+ approvedAt: zod_1.z.string().datetime(),
228
+ })
229
+ .strict();
230
+ exports.supervisionStateSchema = zod_1.z
231
+ .object({
232
+ self: exports.supervisionSchema.nullable(),
233
+ children: zod_1.z.array(exports.supervisionSchema).max(100),
234
+ invitations: zod_1.z.array(exports.supervisionInvitationSchema).max(100),
235
+ })
236
+ .strict();
237
+ exports.supervisionContactsResponseSchema = zod_1.z
238
+ .object({ items: zod_1.z.array(exports.supervisionContactSchema).max(1000) })
239
+ .strict();
240
+ const fingerprint = zod_1.z.string().regex(/^[a-f0-9]{64}$/);
241
+ const minorUnits = zod_1.z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER);
242
+ exports.purchaseApprovalLineSchema = zod_1.z
243
+ .object({
244
+ itemReference: resourceId,
245
+ title: zod_1.z.string().trim().min(1).max(300),
246
+ optionsText: zod_1.z.string().trim().max(300),
247
+ merchantAccountId: accountId,
248
+ quantity: zod_1.z.number().int().min(1).max(1000000),
249
+ unitAmountMinor: minorUnits,
250
+ lineAmountMinor: minorUnits,
251
+ })
252
+ .strict();
253
+ const purchaseEffectsObject = zod_1.z
254
+ .object({
255
+ operationId: resourceId,
256
+ resourceId,
257
+ cartFingerprint: fingerprint,
258
+ summary: zod_1.z.string().trim().min(1).max(300),
259
+ merchantAccountIds: zod_1.z
260
+ .array(accountId)
261
+ .min(1)
262
+ .max(100)
263
+ .refine((ids) => new Set(ids).size === ids.length, 'Merchant accounts must be unique')
264
+ .transform((ids) => [...ids].sort()),
265
+ lineItems: zod_1.z.array(exports.purchaseApprovalLineSchema).min(1).max(200),
266
+ shippingMinor: minorUnits,
267
+ taxMinor: minorUnits,
268
+ discountMinor: minorUnits,
269
+ roundingAdjustmentMinor: zod_1.z
270
+ .number()
271
+ .int()
272
+ .min(-Number.MAX_SAFE_INTEGER)
273
+ .max(Number.MAX_SAFE_INTEGER),
274
+ paymentFingerprint: fingerprint,
275
+ amountMinor: minorUnits,
276
+ currency: zod_1.z.string().regex(/^[A-Z]{3}$/),
277
+ expiresAt: zod_1.z.string().datetime(),
278
+ })
279
+ .strict();
280
+ function validatePurchaseEvidence(value, ctx) {
281
+ const merchants = new Set(value.merchantAccountIds);
282
+ const references = new Set();
283
+ for (const line of value.lineItems) {
284
+ const key = `${line.merchantAccountId}:${line.itemReference}`;
285
+ if (!merchants.has(line.merchantAccountId) || references.has(key))
286
+ ctx.addIssue({
287
+ code: zod_1.z.ZodIssueCode.custom,
288
+ message: 'Purchase lines must name an included merchant and unique item reference',
289
+ });
290
+ references.add(key);
291
+ }
292
+ if (merchants.size !== new Set(value.lineItems.map((line) => line.merchantAccountId)).size)
293
+ ctx.addIssue({
294
+ code: zod_1.z.ZodIssueCode.custom,
295
+ message: 'Every merchant must have an approval line',
296
+ });
297
+ const total = value.lineItems.reduce((sum, line) => sum + BigInt(line.lineAmountMinor), 0n) +
298
+ BigInt(value.shippingMinor) +
299
+ BigInt(value.taxMinor) -
300
+ BigInt(value.discountMinor) +
301
+ BigInt(value.roundingAdjustmentMinor);
302
+ if (total < 0n || total > BigInt(Number.MAX_SAFE_INTEGER) || total !== BigInt(value.amountMinor))
303
+ ctx.addIssue({
304
+ code: zod_1.z.ZodIssueCode.custom,
305
+ message: 'Approval evidence must equal the exact payment total',
306
+ });
307
+ if (Math.abs(value.roundingAdjustmentMinor) >
308
+ value.lineItems.length + 3 * value.merchantAccountIds.length)
309
+ ctx.addIssue({
310
+ code: zod_1.z.ZodIssueCode.custom,
311
+ message: 'Rounding adjustment exceeds the bounded conversion stages',
312
+ });
313
+ }
314
+ exports.purchaseEffectsSchema = purchaseEffectsObject.superRefine(validatePurchaseEvidence);
315
+ const purchaseApprovalFields = {
316
+ id: accountId,
317
+ childAccountId: accountId,
318
+ applicationId: accountId,
319
+ status: zod_1.z.enum(safety_1.PURCHASE_APPROVAL_STATUSES),
320
+ createdAt: zod_1.z.string().datetime(),
321
+ receiptReference: zod_1.z.string().max(512).nullable(),
322
+ };
323
+ exports.purchaseApprovalSchema = purchaseEffectsObject
324
+ .extend(purchaseApprovalFields)
325
+ .strict()
326
+ .superRefine(validatePurchaseEvidence);
327
+ exports.purchaseApprovalSummarySchema = purchaseEffectsObject
328
+ .omit({ lineItems: true })
329
+ .extend(purchaseApprovalFields)
330
+ .strict();
331
+ exports.purchaseApprovalListSchema = zod_1.z
332
+ .object({
333
+ items: zod_1.z.array(exports.purchaseApprovalSummarySchema).max(100),
334
+ nextCursor: zod_1.z.string().nullable(),
335
+ })
336
+ .strict();
337
+ exports.reservePurchaseSchema = purchaseEffectsObject
338
+ .extend({ approvalId: accountId })
339
+ .strict()
340
+ .superRefine(validatePurchaseEvidence);
341
+ exports.confirmPurchaseSchema = zod_1.z
342
+ .object({
343
+ approvalId: accountId,
344
+ operationId: resourceId,
345
+ receiptReference: zod_1.z.string().trim().min(1).max(512),
346
+ })
347
+ .strict();
348
+ exports.cancelPurchaseSchema = exports.confirmPurchaseSchema.omit({ receiptReference: true });
349
+ exports.SAFETY_ERROR_CODES = [
350
+ 'bad_request',
351
+ 'validation_failed',
352
+ 'unauthorized',
353
+ 'forbidden',
354
+ 'not_found',
355
+ 'conflict',
356
+ 'reauth_required',
357
+ 'limit_reached',
358
+ 'service_unavailable',
359
+ 'rate_limited',
360
+ ];
361
+ exports.safetyErrorSchema = zod_1.z
362
+ .object({ error: zod_1.z.object({ code: zod_1.z.enum(exports.SAFETY_ERROR_CODES), message: zod_1.z.string() }).strict() })
363
+ .strict();
364
+ exports.supervisionInviteInputSchema = zod_1.z
365
+ .object({
366
+ guardianAccountId: accountId,
367
+ consentVersion: zod_1.z.literal(safety_1.SUPERVISION_CONSENT_VERSION),
368
+ reauth: signIn_1.reauthProofSchema,
369
+ })
370
+ .strict();
371
+ exports.supervisionAcceptInputSchema = zod_1.z
372
+ .object({ consentVersion: zod_1.z.literal(safety_1.SUPERVISION_CONSENT_VERSION), reauth: signIn_1.reauthProofSchema })
373
+ .strict();
374
+ exports.supervisionContactInputSchema = zod_1.z
375
+ .object({ childAccountId: accountId, contactAccountId: accountId, reauth: signIn_1.reauthProofSchema })
376
+ .strict();
377
+ exports.supervisionReviewInputSchema = zod_1.z
378
+ .object({
379
+ childAccountId: accountId,
380
+ action: zod_1.z.enum(['end', 'transfer']),
381
+ guardianAccountId: accountId.optional(),
382
+ evidenceReference: zod_1.z.string().trim().min(1).max(2048),
383
+ reauth: signIn_1.reauthProofSchema,
384
+ })
385
+ .strict();
386
+ exports.purchaseReviewInputSchema = zod_1.z
387
+ .object({ decision: zod_1.z.enum(['approved', 'rejected']), reauth: signIn_1.reauthProofSchema })
388
+ .strict();
389
+ exports.safetySessionInputSchema = zod_1.z
390
+ .object({
391
+ sessionId: accountId,
392
+ accessToken: zod_1.z.string().min(1).max(16384),
393
+ action: zod_1.z.enum(safety_1.SUPERVISED_ACTIONS),
394
+ })
395
+ .strict();
396
+ exports.safetySessionValidationSchema = zod_1.z
397
+ .object({
398
+ valid: zod_1.z.literal(true),
399
+ sessionId: accountId,
400
+ expiresAt: zod_1.z.string().datetime(),
401
+ lastActivity: zod_1.z.string().datetime(),
402
+ user: userResponse_1.userResponseSchema,
403
+ actor: accountSubject_1.accountActorChainSchema,
404
+ })
405
+ .strict();
406
+ /** Minimal identity for the authenticated account's supervision management, never profile details. */
407
+ exports.safetyPersonSchema = zod_1.z
408
+ .object({ accountId, username: zod_1.z.string().nullable(), displayName: zod_1.z.string().nullable() })
409
+ .strict();
410
+ exports.safetyPeopleInputSchema = zod_1.z.union([
411
+ zod_1.z.object({ query: zod_1.z.string().trim().min(2).max(100) }).strict(),
412
+ zod_1.z.object({ accountIds: uniqueIds(100) }).strict(),
413
+ ]);
414
+ exports.safetyPeopleResponseSchema = zod_1.z
415
+ .object({ items: zod_1.z.array(exports.safetyPersonSchema).max(100) })
416
+ .strict();
417
+ /** Existing public employer identity only; never directory content or management authority. */
418
+ exports.safetyOrganizationIdentitySchema = zod_1.z
419
+ .object({
420
+ accountId,
421
+ username: zod_1.z.string().nullable(),
422
+ name: zod_1.z.string(),
423
+ organizationType: zod_1.z.enum(organizations_1.ORGANIZATION_TYPES),
424
+ })
425
+ .strict();
426
+ exports.safetyOrganizationsInputSchema = zod_1.z.union([
427
+ zod_1.z
428
+ .object({
429
+ query: zod_1.z.string().trim().min(1).max(100),
430
+ limit: zod_1.z.number().int().min(1).max(20).optional(),
431
+ })
432
+ .strict(),
433
+ zod_1.z.object({ ids: uniqueIds(100) }).strict(),
434
+ ]);
435
+ exports.safetyOrganizationsResponseSchema = zod_1.z
436
+ .object({
437
+ items: zod_1.z
438
+ .array(zod_1.z
439
+ .object({ requestedAccountId: accountId, organization: exports.safetyOrganizationIdentitySchema })
440
+ .strict())
441
+ .max(100),
442
+ missingIds: zod_1.z.array(accountId).max(100),
443
+ })
444
+ .strict();
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.serviceTokenOptionsSchema = exports.serviceTokenScopesSchema = void 0;
4
+ const zod_1 = require("zod");
5
+ /** Omitted means the existing grant; an explicit set only narrows that authority. */
6
+ exports.serviceTokenScopesSchema = zod_1.z
7
+ .array(zod_1.z.string().trim().min(1).max(128))
8
+ .min(1)
9
+ .max(100)
10
+ .refine((scopes) => new Set(scopes).size === scopes.length, 'Requested scopes must be unique')
11
+ .transform((scopes) => [...scopes].sort());
12
+ exports.serviceTokenOptionsSchema = zod_1.z
13
+ .object({ scopes: exports.serviceTokenScopesSchema.optional() })
14
+ .strict();
@@ -0,0 +1,69 @@
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
+ import { accountKindSchema } from './accountGraph.js';
24
+ /**
25
+ * The scope the endpoint requires.
26
+ *
27
+ * Privileged (staff-granted). Channel membership is sensitive because a channel
28
+ * is anonymous: its members are the people behind a voice that is published
29
+ * without their names, and "is this person a member of that channel" is
30
+ * exactly the fact the channel exists to withhold.
31
+ */
32
+ export const ACCOUNTS_MEMBERSHIP_READ_SCOPE = 'accounts:membership:read';
33
+ /**
34
+ * Where the access comes from.
35
+ *
36
+ * - `self` — the person IS the account (a personal account asked about itself).
37
+ * - `direct` — an active membership row on the account.
38
+ * - `inherited` — an active, cascading membership on an ancestor account.
39
+ */
40
+ export const ACCOUNT_ACCESS_SOURCES = ['self', 'direct', 'inherited'];
41
+ export const accountAccessSourceSchema = z.enum(ACCOUNT_ACCESS_SOURCES);
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 const accountAccessGrantSchema = z.object({
52
+ role: z.string().min(1),
53
+ permissions: z.array(z.string().min(1)),
54
+ /** Only an active membership grants access, so this is the one value. */
55
+ status: z.literal('active'),
56
+ source: accountAccessSourceSchema,
57
+ });
58
+ export const accountAccessVerdictSchema = z
59
+ .object({
60
+ accountId: z.string().min(1),
61
+ /** `null` when no such account exists. */
62
+ kind: accountKindSchema.nullable(),
63
+ /** `null` means: this person may not act for this account. */
64
+ access: accountAccessGrantSchema.nullable(),
65
+ })
66
+ .refine((verdict) => verdict.access === null || verdict.kind !== null, {
67
+ message: 'An account that does not exist grants no access',
68
+ path: ['access'],
69
+ });
@@ -140,6 +140,35 @@ export const delegationGrantSchema = z
140
140
  updatedAt: z.string().datetime(),
141
141
  })
142
142
  .strict();
143
+ /**
144
+ * The two levels an owner publishes for whoever uses their agent (ADR 0042):
145
+ * "Ver" and "Ver y actuar". A ceiling never says `draft` or `execute_on_request`:
146
+ * an agent is either allowed to act on its own or not at all, and nothing ever
147
+ * asks the person for approval.
148
+ */
149
+ export const AGENT_REQUESTER_CEILING_AUTONOMY = ['read_only', 'autonomous'];
150
+ /** What an agent may do in one app for whoever uses it; written by an operator of the bot. */
151
+ export const agentRequesterCeilingWriteSchema = z
152
+ .object({
153
+ capabilityPackages: z.array(capabilityPackageSchema),
154
+ capabilities: z.array(identifierSchema).default([]),
155
+ toolOverrides: z.array(toolGrantOverrideSchema).default([]),
156
+ limits: z.array(grantLimitSchema).default([]),
157
+ maximumAutonomy: z.enum(AGENT_REQUESTER_CEILING_AUTONOMY),
158
+ })
159
+ .strict();
160
+ export const agentRequesterCeilingSchema = agentRequesterCeilingWriteSchema
161
+ .extend({
162
+ id: identifierSchema,
163
+ agentAccountId: identifierSchema,
164
+ appId: identifierSchema,
165
+ catalog: capabilityCatalogBindingSchema,
166
+ version: z.number().int().positive(),
167
+ revokedAt: z.string().datetime().nullable(),
168
+ createdAt: z.string().datetime(),
169
+ updatedAt: z.string().datetime(),
170
+ })
171
+ .strict();
143
172
  export const automationTriggerSchema = z.discriminatedUnion('type', [
144
173
  z.object({ type: z.literal('manual') }).strict(),
145
174
  z
@@ -201,6 +230,8 @@ export const capabilityTicketClaimsSchema = z
201
230
  /** Signed only for callers that explicitly requested a pinned catalogue. */
202
231
  catalog: capabilityCatalogBindingSchema.optional(),
203
232
  grantId: identifierSchema.optional(),
233
+ /** The owner's published ceiling that bounds an agent acting for a non-owner (ADR 0042). */
234
+ ceilingId: identifierSchema.optional(),
204
235
  requesterAccountId: identifierSchema,
205
236
  ownerAccountId: identifierSchema,
206
237
  actor: executionActorRefSchema,
@@ -239,6 +270,24 @@ export const capabilityTicketClaimsSchema = z
239
270
  message: 'requester actors require their exact principal and direct read-only authority without standing grants',
240
271
  });
241
272
  }
273
+ if (claims.ceilingId !== undefined) {
274
+ if (claims.grantId !== undefined) {
275
+ context.addIssue({
276
+ code: z.ZodIssueCode.custom,
277
+ path: ['ceilingId'],
278
+ message: 'a ticket is bounded by either a grant or a ceiling, never both',
279
+ });
280
+ }
281
+ if (claims.actor.type !== 'agent' ||
282
+ claims.ownerAccountId !== claims.requesterAccountId ||
283
+ claims.resource.resourceId !== claims.resource.effectiveAccountId) {
284
+ context.addIssue({
285
+ code: z.ZodIssueCode.custom,
286
+ path: ['ceilingId'],
287
+ message: "a ceiling bounds an agent acting on the requester's own authority at an account root",
288
+ });
289
+ }
290
+ }
242
291
  if (claims.exp <= claims.iat) {
243
292
  context.addIssue({
244
293
  code: z.ZodIssueCode.custom,
@@ -300,6 +349,7 @@ export const policyDecisionSchema = z
300
349
  reason: identifierSchema,
301
350
  effectiveAutonomy: autonomyLevelSchema.optional(),
302
351
  grantId: identifierSchema.optional(),
352
+ ceilingId: identifierSchema.optional(),
303
353
  })
304
354
  .strict();
305
355
  export const auditResultSchema = z
@@ -509,6 +559,24 @@ export const catalogEventSchema = z
509
559
  resourceTypes: z.array(identifierSchema).min(1),
510
560
  })
511
561
  .strict();
562
+ /**
563
+ * A feature an agent may gate on (Alia ADR 0020 §6): the app answers whether the
564
+ * person may use it (`checkTool`) and, when using it costs something, spends it
565
+ * (`consumeTool`). Both are internal tools of the same catalogue.
566
+ */
567
+ export const catalogFeatureSchema = z
568
+ .object({
569
+ key: z
570
+ .string()
571
+ .regex(/^[a-z][a-z0-9_-]*(?:\.[a-z][a-z0-9_-]*)*$/, 'feature keys are dot-separated slugs')
572
+ .max(128),
573
+ description: nonEmptyStringSchema,
574
+ checkTool: identifierSchema,
575
+ consumeTool: identifierSchema.optional(),
576
+ })
577
+ .strict();
578
+ /** How a coordinator reaches the catalogue's internal tools. */
579
+ export const CATALOG_INTERNAL_TRANSPORTS = ['http', 'mcp'];
512
580
  export const appCapabilityCatalogSchema = z
513
581
  .object({
514
582
  schemaVersion: z.literal('1'),
@@ -564,11 +632,54 @@ export const appCapabilityCatalogSchema = z
564
632
  })
565
633
  .strict()
566
634
  .optional(),
635
+ /**
636
+ * `mcp`: internal tools are served at `<internalBaseUrl>/_oxy/mcp`. Absent or
637
+ * `http`: each tool's `invocation` path on `internalBaseUrl`.
638
+ */
639
+ internalTransport: z.enum(CATALOG_INTERNAL_TRANSPORTS).optional(),
640
+ features: z.array(catalogFeatureSchema).optional(),
567
641
  tools: z.array(catalogToolSchema),
568
642
  events: z.array(catalogEventSchema),
569
643
  })
570
644
  .strict()
571
645
  .superRefine((catalog, context) => {
646
+ const toolsByName = new Map(catalog.tools.map((tool) => [tool.name, tool]));
647
+ const featureKeys = new Set();
648
+ for (const [index, feature] of (catalog.features ?? []).entries()) {
649
+ if (featureKeys.has(feature.key)) {
650
+ context.addIssue({
651
+ code: z.ZodIssueCode.custom,
652
+ message: `Duplicate feature key: ${feature.key}`,
653
+ path: ['features', index, 'key'],
654
+ });
655
+ }
656
+ featureKeys.add(feature.key);
657
+ const check = toolsByName.get(feature.checkTool);
658
+ if (!check ||
659
+ check.effect !== 'read' ||
660
+ check.exposure.length !== 1 ||
661
+ check.exposure[0] !== 'internal') {
662
+ context.addIssue({
663
+ code: z.ZodIssueCode.custom,
664
+ message: 'checkTool must name an internal-only read tool of this catalogue',
665
+ path: ['features', index, 'checkTool'],
666
+ });
667
+ }
668
+ if (feature.consumeTool !== undefined) {
669
+ const consume = toolsByName.get(feature.consumeTool);
670
+ if (!consume ||
671
+ consume.effect === 'read' ||
672
+ consume.idempotency !== 'required' ||
673
+ consume.exposure.length !== 1 ||
674
+ consume.exposure[0] !== 'internal') {
675
+ context.addIssue({
676
+ code: z.ZodIssueCode.custom,
677
+ message: 'consumeTool must name an internal-only effectful tool that requires idempotency keys',
678
+ path: ['features', index, 'consumeTool'],
679
+ });
680
+ }
681
+ }
682
+ }
572
683
  const names = new Set();
573
684
  for (const [index, tool] of catalog.tools.entries()) {
574
685
  if (names.has(tool.name)) {