@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
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Application roles — the wire contract for permissions an APPLICATION declares
|
|
3
|
+
* about its own users, and for the grants that give them to Oxy users.
|
|
4
|
+
*
|
|
5
|
+
* Oxy decides who holds an app's operator powers (who may run Mercaria's
|
|
6
|
+
* payments desk, moderate GoWay, administer Homiio), so no app keeps an
|
|
7
|
+
* allow-list of Oxy user ids in its environment. The app declares a closed
|
|
8
|
+
* vocabulary of keys, its owners grant them to people, and the app's backend
|
|
9
|
+
* asks Oxy which of them the human behind a request holds
|
|
10
|
+
* (`GET /applications/:appId/roles/me`, read through `@oxy.so/core/server`).
|
|
11
|
+
*
|
|
12
|
+
* ## Why an application key can never collide with an Oxy permission
|
|
13
|
+
*
|
|
14
|
+
* Every permission Oxy itself checks (`app:update`, `apps:create`,
|
|
15
|
+
* `credentials:rotate`, every scope) is spelled with a COLON. An application key
|
|
16
|
+
* is dot-separated lowercase segments and cannot contain one, so the two
|
|
17
|
+
* vocabularies are disjoint by syntax, not by convention. They are also stored
|
|
18
|
+
* apart (scoped to one application id) and no Oxy gate ever reads an
|
|
19
|
+
* application key. A key means something only to the application that declared
|
|
20
|
+
* it.
|
|
21
|
+
*
|
|
22
|
+
* The pattern is exported as a SOURCE string because the API renders the same
|
|
23
|
+
* text into a Postgres CHECK; JavaScript's `RegExp` and Postgres' ARE agree on
|
|
24
|
+
* everything it uses (anchors, classes, a capturing group, a bounded repeat).
|
|
25
|
+
*
|
|
26
|
+
* Platform-agnostic — zod only, no react/react-native/expo.
|
|
27
|
+
*/
|
|
28
|
+
import { z } from 'zod';
|
|
29
|
+
/**
|
|
30
|
+
* Two to four dot-separated segments, each a lowercase letter followed by
|
|
31
|
+
* lowercase letters, digits or underscores: `payments.operate`,
|
|
32
|
+
* `catalog.review.publish`. At least two segments so a key always names an
|
|
33
|
+
* area and an action; never a colon (see the header).
|
|
34
|
+
*/
|
|
35
|
+
export const APPLICATION_PERMISSION_KEY_PATTERN_SOURCE = '^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*){1,3}$';
|
|
36
|
+
export const APPLICATION_PERMISSION_KEY_PATTERN = new RegExp(APPLICATION_PERMISSION_KEY_PATTERN_SOURCE);
|
|
37
|
+
export const APPLICATION_PERMISSION_KEY_MAX_LENGTH = 64;
|
|
38
|
+
export const APPLICATION_PERMISSION_DESCRIPTION_MAX_LENGTH = 280;
|
|
39
|
+
/** How many live keys one application may declare. Operator powers are few. */
|
|
40
|
+
export const APPLICATION_PERMISSIONS_MAX_DECLARED = 64;
|
|
41
|
+
export const APPLICATION_ROLE_REASON_MAX_LENGTH = 500;
|
|
42
|
+
export const APPLICATION_ROLE_GRANTS_PAGE_DEFAULT = 50;
|
|
43
|
+
export const APPLICATION_ROLE_GRANTS_PAGE_MAX = 200;
|
|
44
|
+
/**
|
|
45
|
+
* The `error` codes the application-roles routes answer beyond the generic
|
|
46
|
+
* ones (`BAD_REQUEST`, `UNAUTHORIZED`, `FORBIDDEN`, `NOT_FOUND`). Renaming one
|
|
47
|
+
* is a breaking change.
|
|
48
|
+
*/
|
|
49
|
+
export const APPLICATION_ROLE_ERROR_CODES = {
|
|
50
|
+
/** 403: a grant naming yourself on an application you do not own outright. */
|
|
51
|
+
selfGrantForbidden: 'SELF_GRANT_FORBIDDEN',
|
|
52
|
+
/** 422: the key is not a live declared permission of this application. */
|
|
53
|
+
unknownPermission: 'UNKNOWN_PERMISSION',
|
|
54
|
+
/** 422: the grantee is not a person (an organization, project, bot or channel). */
|
|
55
|
+
granteeNotAPerson: 'GRANTEE_NOT_A_PERSON',
|
|
56
|
+
/** 409: the grantee already holds the key; `details.grantId` names the live grant. */
|
|
57
|
+
alreadyGranted: 'ALREADY_GRANTED',
|
|
58
|
+
/** 409: the grant was already revoked. */
|
|
59
|
+
alreadyRevoked: 'ALREADY_REVOKED',
|
|
60
|
+
/** 403: the bearer's session belongs to a DIFFERENT application. */
|
|
61
|
+
sessionApplicationMismatch: 'SESSION_APPLICATION_MISMATCH',
|
|
62
|
+
};
|
|
63
|
+
/** Whether `value` is a well-formed application permission key. */
|
|
64
|
+
export function isApplicationPermissionKey(value) {
|
|
65
|
+
return (typeof value === 'string' &&
|
|
66
|
+
value.length <= APPLICATION_PERMISSION_KEY_MAX_LENGTH &&
|
|
67
|
+
APPLICATION_PERMISSION_KEY_PATTERN.test(value));
|
|
68
|
+
}
|
|
69
|
+
export const applicationPermissionKeySchema = z
|
|
70
|
+
.string()
|
|
71
|
+
.max(APPLICATION_PERMISSION_KEY_MAX_LENGTH)
|
|
72
|
+
.regex(APPLICATION_PERMISSION_KEY_PATTERN, 'A permission key is 2-4 dot-separated lowercase segments, e.g. payments.operate');
|
|
73
|
+
/** Plain text: no control characters other than a newline or a tab. */
|
|
74
|
+
function plainText(max) {
|
|
75
|
+
return z
|
|
76
|
+
.string()
|
|
77
|
+
.trim()
|
|
78
|
+
.min(1)
|
|
79
|
+
.max(max)
|
|
80
|
+
.refine((value) => Array.from(value).every((character) => {
|
|
81
|
+
const code = character.charCodeAt(0);
|
|
82
|
+
return (code >= 32 && code !== 127) || character === '\n' || character === '\t';
|
|
83
|
+
}), 'Must be plain text');
|
|
84
|
+
}
|
|
85
|
+
const id = z.string().min(1).max(128);
|
|
86
|
+
const isoTimestamp = z.string().min(1);
|
|
87
|
+
const reasonSchema = plainText(APPLICATION_ROLE_REASON_MAX_LENGTH);
|
|
88
|
+
/** One key as the application's owners declare it. */
|
|
89
|
+
export const applicationPermissionDeclarationSchema = z
|
|
90
|
+
.object({
|
|
91
|
+
key: applicationPermissionKeySchema,
|
|
92
|
+
description: plainText(APPLICATION_PERMISSION_DESCRIPTION_MAX_LENGTH),
|
|
93
|
+
})
|
|
94
|
+
.strict();
|
|
95
|
+
/**
|
|
96
|
+
* `PUT /applications/:appId/roles/permissions` — the WHOLE vocabulary.
|
|
97
|
+
*
|
|
98
|
+
* Declarative: a key present here and not live is added, a live key absent
|
|
99
|
+
* here is retired (and every grant of it revoked), a live key present here
|
|
100
|
+
* keeps its identity and takes the new description. Sending the same body twice
|
|
101
|
+
* changes nothing.
|
|
102
|
+
*/
|
|
103
|
+
export const declareApplicationPermissionsRequestSchema = z
|
|
104
|
+
.object({
|
|
105
|
+
permissions: z
|
|
106
|
+
.array(applicationPermissionDeclarationSchema)
|
|
107
|
+
.max(APPLICATION_PERMISSIONS_MAX_DECLARED),
|
|
108
|
+
})
|
|
109
|
+
.strict()
|
|
110
|
+
.superRefine((value, ctx) => {
|
|
111
|
+
const seen = new Set();
|
|
112
|
+
value.permissions.forEach((permission, index) => {
|
|
113
|
+
if (seen.has(permission.key)) {
|
|
114
|
+
ctx.addIssue({
|
|
115
|
+
code: z.ZodIssueCode.custom,
|
|
116
|
+
path: ['permissions', index, 'key'],
|
|
117
|
+
message: `Duplicate permission key ${permission.key}`,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
seen.add(permission.key);
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
/** A declared key. Retired keys are history: they confer nothing. */
|
|
124
|
+
export const applicationPermissionSchema = z.object({
|
|
125
|
+
key: applicationPermissionKeySchema,
|
|
126
|
+
description: z.string(),
|
|
127
|
+
declaredAt: isoTimestamp,
|
|
128
|
+
declaredByUserId: id.nullable(),
|
|
129
|
+
retiredAt: isoTimestamp.nullable(),
|
|
130
|
+
retiredByUserId: id.nullable(),
|
|
131
|
+
});
|
|
132
|
+
export const applicationPermissionListSchema = z.object({
|
|
133
|
+
items: z.array(applicationPermissionSchema),
|
|
134
|
+
});
|
|
135
|
+
export const declareApplicationPermissionsResponseSchema = applicationPermissionListSchema.extend({
|
|
136
|
+
/** Keys that became live with this declaration. */
|
|
137
|
+
added: z.array(applicationPermissionKeySchema),
|
|
138
|
+
/** Keys this declaration retired. */
|
|
139
|
+
retired: z.array(applicationPermissionKeySchema),
|
|
140
|
+
/** Live keys whose description changed. */
|
|
141
|
+
described: z.array(applicationPermissionKeySchema),
|
|
142
|
+
/** Live grants revoked because their key was retired. */
|
|
143
|
+
revokedGrants: z.number().int().nonnegative(),
|
|
144
|
+
});
|
|
145
|
+
/** One grant of one key to one Oxy user. Revocation is a stamp, never a delete. */
|
|
146
|
+
export const applicationRoleGrantSchema = z.object({
|
|
147
|
+
id,
|
|
148
|
+
applicationId: id,
|
|
149
|
+
permission: applicationPermissionKeySchema,
|
|
150
|
+
userId: id,
|
|
151
|
+
/** The grantee's handle, for display. */
|
|
152
|
+
username: z.string().nullable(),
|
|
153
|
+
/** The HUMAN who granted it; null once that account was erased. */
|
|
154
|
+
grantedByUserId: id.nullable(),
|
|
155
|
+
grantedAt: isoTimestamp,
|
|
156
|
+
grantReason: z.string().nullable(),
|
|
157
|
+
revokedAt: isoTimestamp.nullable(),
|
|
158
|
+
revokedByUserId: id.nullable(),
|
|
159
|
+
revokeReason: z.string().nullable(),
|
|
160
|
+
});
|
|
161
|
+
export const applicationRoleGrantListSchema = z.object({
|
|
162
|
+
items: z.array(applicationRoleGrantSchema),
|
|
163
|
+
nextCursor: z.string().nullable(),
|
|
164
|
+
});
|
|
165
|
+
/** `POST /applications/:appId/roles/grants` — name the grantee by id OR handle. */
|
|
166
|
+
export const createApplicationRoleGrantRequestSchema = z
|
|
167
|
+
.object({
|
|
168
|
+
userId: id.optional(),
|
|
169
|
+
username: z.string().trim().min(1).max(64).optional(),
|
|
170
|
+
permission: applicationPermissionKeySchema,
|
|
171
|
+
reason: reasonSchema.optional(),
|
|
172
|
+
})
|
|
173
|
+
.strict()
|
|
174
|
+
.refine((value) => (value.userId === undefined) !== (value.username === undefined), {
|
|
175
|
+
message: 'Name the grantee with exactly one of userId or username',
|
|
176
|
+
path: ['userId'],
|
|
177
|
+
});
|
|
178
|
+
/** `POST /applications/:appId/roles/grants/:grantId/revoke`. */
|
|
179
|
+
export const revokeApplicationRoleGrantRequestSchema = z
|
|
180
|
+
.object({
|
|
181
|
+
reason: reasonSchema.optional(),
|
|
182
|
+
})
|
|
183
|
+
.strict();
|
|
184
|
+
/** `GET /applications/:appId/roles/grants` query. */
|
|
185
|
+
export const listApplicationRoleGrantsQuerySchema = z
|
|
186
|
+
.object({
|
|
187
|
+
permission: applicationPermissionKeySchema.optional(),
|
|
188
|
+
userId: id.optional(),
|
|
189
|
+
includeRevoked: z
|
|
190
|
+
.enum(['true', 'false'])
|
|
191
|
+
.transform((value) => value === 'true')
|
|
192
|
+
.optional(),
|
|
193
|
+
limit: z.coerce.number().int().min(1).max(APPLICATION_ROLE_GRANTS_PAGE_MAX).optional(),
|
|
194
|
+
cursor: z.string().min(1).max(512).optional(),
|
|
195
|
+
})
|
|
196
|
+
.strict();
|
|
197
|
+
/**
|
|
198
|
+
* `GET /applications/:appId/roles/me` — the keys the HUMAN behind the bearer
|
|
199
|
+
* holds for this application, in no particular order. `userId` is that human
|
|
200
|
+
* (the operator), which is NOT the account the session speaks as when a person
|
|
201
|
+
* is acting as an organization.
|
|
202
|
+
*/
|
|
203
|
+
export const applicationRolesMeSchema = z.object({
|
|
204
|
+
applicationId: id,
|
|
205
|
+
userId: id,
|
|
206
|
+
permissions: z.array(applicationPermissionKeySchema),
|
|
207
|
+
});
|
package/dist/esm/client/check.js
CHANGED
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
* strictObject(shape) unknown keys FAIL (`.strict()`)
|
|
25
25
|
* looseObject(shape) unknown keys are KEPT (`.passthrough()`)
|
|
26
26
|
* refine(c, test) a further condition, run once `c` passes
|
|
27
|
+
* transform(c, f) `f` rewrites the value once `c` passes
|
|
27
28
|
* union / discriminatedUnion as Zod 3 reports them
|
|
28
29
|
*
|
|
29
30
|
* A failure carries the first issue Zod would report and whether Zod would have
|
|
@@ -229,6 +230,13 @@ export function refineAt(inner, test) {
|
|
|
229
230
|
: checked;
|
|
230
231
|
};
|
|
231
232
|
}
|
|
233
|
+
/** Zod's `.transform()`: rewrites a value `inner` accepted. */
|
|
234
|
+
export function transform(inner, rewrite) {
|
|
235
|
+
return (input, path) => {
|
|
236
|
+
const checked = inner(input, path);
|
|
237
|
+
return checked.ok ? ok(rewrite(checked.value)) : checked;
|
|
238
|
+
};
|
|
239
|
+
}
|
|
232
240
|
/** Narrows a checked value to a branded contract type (Zod's `.brand()`). */
|
|
233
241
|
export function branded(inner) {
|
|
234
242
|
return inner;
|
package/dist/esm/client/index.js
CHANGED
|
@@ -30,7 +30,7 @@ export { ORGANIZATION_ALIAS_KINDS, ORGANIZATION_CLAIM_DECISIONS, ORGANIZATION_CL
|
|
|
30
30
|
export { cancelProductSubscriptionCheck, personalPlanCatalogueCheck, personalPlanCheckoutRequestCheck, personalPlanCheckoutResultCheck, productSubscriptionCancellationResultCheck, productSubscriptionsResponseCheck, subjectProductAccessCheck, subjectProductAccessQueryCheck, subscriptionCreditGrantsResponseCheck, } from './products.js';
|
|
31
31
|
export { recommendationRequestCheck } from './recommendations.js';
|
|
32
32
|
export { isFullReputationBalance } from './reputation.js';
|
|
33
|
-
export { profileAccessDecisionCheck, profileAccessInputCheck } from './safety.js';
|
|
33
|
+
export { PURCHASE_APPROVAL_STATUSES, SAFETY_POLICY_VERSION, SUPERVISED_ACTIONS, SUPERVISION_CONSENT_VERSION, SUPERVISION_INVITATION_STATUSES, SUPERVISION_STATUSES, profileAccessDecisionCheck, profileAccessInputCheck, purchaseApprovalCheck, purchaseApprovalListCheck, purchaseReviewInputCheck, safetyOrganizationsInputCheck, safetyOrganizationsResponseCheck, safetyPeopleInputCheck, safetyPeopleResponseCheck, supervisionAcceptInputCheck, supervisionContactInputCheck, supervisionContactsResponseCheck, supervisionInvitationCheck, supervisionInviteInputCheck, supervisionReviewInputCheck, supervisionStateCheck, } from './safety.js';
|
|
34
34
|
export { publicApplicationCheck } from './sessionStatus.js';
|
|
35
35
|
export { EMAIL_ACCOUNTS_MAX, EMAIL_SIGNIN_CHOICE_TTL_MS, EMAIL_SIGNIN_LINK_TTL_MS, EMAIL_SIGNIN_LONG_CODE_ALPHABET, EMAIL_SIGNIN_LONG_CODE_LENGTH, PASSWORD_MAX_LENGTH, PASSWORD_MIN_LENGTH, REAUTH_ACTIONS, SIGNIN_SECOND_FACTOR_MAX_ATTEMPTS, SIGNIN_SECOND_FACTOR_TTL_MS, SIGN_IN_ERROR_CODES, TOTP_BACKUP_CODE_COUNT, TOTP_DIGITS, TOTP_PERIOD_SECONDS, emailSignInChooseAccountCheck, emailSignInLinkResponseCheck, emailSignInPendingCheck, emailSignInStartResponseCheck, isEmailSignInChooseAccount, isSecondFactorRequired, normalizeEmailSignInCode, reauthProofCheck, secondFactorRequiredCheck, signInMethodsCheck, totpBackupCodesResponseCheck, totpEnrollResponseCheck, } from './signIn.js';
|
|
36
36
|
export { BOT_USERNAME_INVALID_MESSAGE, BOT_USERNAME_SUFFIX, NUMERIC_USERNAME_MESSAGE, RESERVED_USERNAMES, RESERVED_USERNAME_MESSAGE, USERNAME_INVALID_MESSAGE, USERNAME_MAX_LENGTH, USERNAME_MIN_LENGTH, USERNAME_PATTERN_SOURCE, applyBotUsernameSuffix, botUsernameCheck, stripDisallowedUsernameCharacters, usernameCheck, usernameCheckForAccountKind, } from './username.js';
|
|
@@ -1,12 +1,193 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Safety and supervision checks, without Zod. Schemas: `../safety.ts`.
|
|
3
|
+
*
|
|
4
|
+
* Only what a browser or device sends and reads is here: the profile-access
|
|
5
|
+
* read, supervision management and the guardian's purchase review. The service
|
|
6
|
+
* decision lanes are server-only (`@oxy.so/core/server`) and parse with the
|
|
7
|
+
* Zod schemas directly.
|
|
3
8
|
*
|
|
4
9
|
* Part of `@oxy.so/contracts/client`: never import `zod` here (see `./check.ts`).
|
|
5
10
|
*/
|
|
6
|
-
import { boolean, exact, literal, maxLength, minLength, oneOf, strictObject, string, } from './check.js';
|
|
11
|
+
import { array, atLeast, atMost, boolean, datetime, exact, int, literal, maxItems, maxLength, minItems, minLength, nonnegative, nullable, number, oneOf, optional, pattern, refine, refineAt, strictObject, string, transform, trim, union, } from './check.js';
|
|
12
|
+
import { ORGANIZATION_TYPES } from './organizations.js';
|
|
13
|
+
import { reauthProofCheck } from './signIn.js';
|
|
14
|
+
/** Supervision is a personal-account safety policy, never a new login/account kind. */
|
|
15
|
+
export const SUPERVISED_ACTIONS = ['profile', 'messaging', 'content', 'purchases'];
|
|
16
|
+
export const SAFETY_POLICY_VERSION = '2';
|
|
17
|
+
export const SUPERVISION_CONSENT_VERSION = '1';
|
|
18
|
+
export const SUPERVISION_STATUSES = ['active', 'orphaned', 'ended'];
|
|
19
|
+
export const SUPERVISION_INVITATION_STATUSES = ['pending', 'accepted', 'cancelled'];
|
|
20
|
+
export const PURCHASE_APPROVAL_STATUSES = [
|
|
21
|
+
'pending',
|
|
22
|
+
'approved',
|
|
23
|
+
'rejected',
|
|
24
|
+
'reserved',
|
|
25
|
+
'confirmed',
|
|
26
|
+
'cancelled',
|
|
27
|
+
];
|
|
7
28
|
export const profileAccessInputCheck = exact()(strictObject({ subjectAccountId: string(minLength(1), maxLength(128)) }));
|
|
8
29
|
export const profileAccessDecisionCheck = exact()(strictObject({
|
|
9
30
|
allowed: boolean,
|
|
10
31
|
reason: oneOf(['public', 'owner', 'private', 'blocked', 'unavailable']),
|
|
11
32
|
policyVersion: literal('1'),
|
|
12
33
|
}));
|
|
34
|
+
const accountId = string(minLength(1), maxLength(128));
|
|
35
|
+
const resourceId = string(trim, minLength(1), maxLength(256));
|
|
36
|
+
const uniqueIds = (max) => refine(array(accountId, minItems(1), maxItems(max)), (ids) => new Set(ids).size === ids.length, 'Account IDs must be unique');
|
|
37
|
+
/* -------------------------------------------------------------------------- */
|
|
38
|
+
/* Supervision management */
|
|
39
|
+
/* -------------------------------------------------------------------------- */
|
|
40
|
+
const supervisionCheck = exact()(strictObject({
|
|
41
|
+
childAccountId: accountId,
|
|
42
|
+
guardianAccountId: nullable(accountId),
|
|
43
|
+
status: oneOf(SUPERVISION_STATUSES),
|
|
44
|
+
policyVersion: literal(SAFETY_POLICY_VERSION),
|
|
45
|
+
consentVersion: literal(SUPERVISION_CONSENT_VERSION),
|
|
46
|
+
createdAt: string(datetime),
|
|
47
|
+
}));
|
|
48
|
+
export const supervisionInvitationCheck = exact()(strictObject({
|
|
49
|
+
id: accountId,
|
|
50
|
+
childAccountId: accountId,
|
|
51
|
+
guardianAccountId: accountId,
|
|
52
|
+
status: oneOf(SUPERVISION_INVITATION_STATUSES),
|
|
53
|
+
expiresAt: string(datetime),
|
|
54
|
+
consentVersion: literal(SUPERVISION_CONSENT_VERSION),
|
|
55
|
+
createdAt: string(datetime),
|
|
56
|
+
}));
|
|
57
|
+
export const supervisionStateCheck = exact()(strictObject({
|
|
58
|
+
self: nullable(supervisionCheck),
|
|
59
|
+
children: array(supervisionCheck, maxItems(100)),
|
|
60
|
+
invitations: array(supervisionInvitationCheck, maxItems(100)),
|
|
61
|
+
}));
|
|
62
|
+
export const supervisionContactsResponseCheck = exact()(strictObject({
|
|
63
|
+
items: array(strictObject({
|
|
64
|
+
childAccountId: accountId,
|
|
65
|
+
contactAccountId: accountId,
|
|
66
|
+
approvedAt: string(datetime),
|
|
67
|
+
}), maxItems(1000)),
|
|
68
|
+
}));
|
|
69
|
+
export const supervisionInviteInputCheck = exact()(strictObject({
|
|
70
|
+
guardianAccountId: accountId,
|
|
71
|
+
consentVersion: literal(SUPERVISION_CONSENT_VERSION),
|
|
72
|
+
reauth: reauthProofCheck,
|
|
73
|
+
}));
|
|
74
|
+
export const supervisionAcceptInputCheck = exact()(strictObject({ consentVersion: literal(SUPERVISION_CONSENT_VERSION), reauth: reauthProofCheck }));
|
|
75
|
+
export const supervisionContactInputCheck = exact()(strictObject({
|
|
76
|
+
childAccountId: accountId,
|
|
77
|
+
contactAccountId: accountId,
|
|
78
|
+
reauth: reauthProofCheck,
|
|
79
|
+
}));
|
|
80
|
+
export const supervisionReviewInputCheck = exact()(strictObject({
|
|
81
|
+
childAccountId: accountId,
|
|
82
|
+
action: oneOf(['end', 'transfer']),
|
|
83
|
+
guardianAccountId: optional(accountId),
|
|
84
|
+
evidenceReference: string(trim, minLength(1), maxLength(2048)),
|
|
85
|
+
reauth: reauthProofCheck,
|
|
86
|
+
}));
|
|
87
|
+
/* -------------------------------------------------------------------------- */
|
|
88
|
+
/* Minimal identities for the management screens */
|
|
89
|
+
/* -------------------------------------------------------------------------- */
|
|
90
|
+
const safetyPersonCheck = exact()(strictObject({ accountId, username: nullable(string()), displayName: nullable(string()) }));
|
|
91
|
+
export const safetyPeopleInputCheck = exact()(union(strictObject({ query: string(trim, minLength(2), maxLength(100)) }), strictObject({ accountIds: uniqueIds(100) })));
|
|
92
|
+
export const safetyPeopleResponseCheck = exact()(strictObject({ items: array(safetyPersonCheck, maxItems(100)) }));
|
|
93
|
+
export const safetyOrganizationsInputCheck = exact()(union(strictObject({
|
|
94
|
+
query: string(trim, minLength(1), maxLength(100)),
|
|
95
|
+
limit: optional(number(int, atLeast(1), atMost(20))),
|
|
96
|
+
}), strictObject({ ids: uniqueIds(100) })));
|
|
97
|
+
export const safetyOrganizationsResponseCheck = exact()(strictObject({
|
|
98
|
+
items: array(strictObject({
|
|
99
|
+
requestedAccountId: accountId,
|
|
100
|
+
organization: strictObject({
|
|
101
|
+
accountId,
|
|
102
|
+
username: nullable(string()),
|
|
103
|
+
name: string(),
|
|
104
|
+
organizationType: oneOf(ORGANIZATION_TYPES),
|
|
105
|
+
}),
|
|
106
|
+
}), maxItems(100)),
|
|
107
|
+
missingIds: array(accountId, maxItems(100)),
|
|
108
|
+
}));
|
|
109
|
+
/* -------------------------------------------------------------------------- */
|
|
110
|
+
/* Purchase approvals */
|
|
111
|
+
/* -------------------------------------------------------------------------- */
|
|
112
|
+
const fingerprint = string(pattern(/^[a-f0-9]{64}$/));
|
|
113
|
+
const minorUnits = number(int, nonnegative, atMost(Number.MAX_SAFE_INTEGER));
|
|
114
|
+
const purchaseApprovalLineCheck = exact()(strictObject({
|
|
115
|
+
itemReference: resourceId,
|
|
116
|
+
title: string(trim, minLength(1), maxLength(300)),
|
|
117
|
+
optionsText: string(trim, maxLength(300)),
|
|
118
|
+
merchantAccountId: accountId,
|
|
119
|
+
quantity: number(int, atLeast(1), atMost(1000000)),
|
|
120
|
+
unitAmountMinor: minorUnits,
|
|
121
|
+
lineAmountMinor: minorUnits,
|
|
122
|
+
}));
|
|
123
|
+
/** The effect fields every approval shape shares, in the schema's key order. */
|
|
124
|
+
const purchaseEffectFields = {
|
|
125
|
+
operationId: resourceId,
|
|
126
|
+
resourceId,
|
|
127
|
+
cartFingerprint: fingerprint,
|
|
128
|
+
summary: string(trim, minLength(1), maxLength(300)),
|
|
129
|
+
merchantAccountIds: transform(refine(array(accountId, minItems(1), maxItems(100)), (ids) => new Set(ids).size === ids.length, 'Merchant accounts must be unique'), (ids) => [...ids].sort()),
|
|
130
|
+
};
|
|
131
|
+
const purchaseAmountFields = {
|
|
132
|
+
shippingMinor: minorUnits,
|
|
133
|
+
taxMinor: minorUnits,
|
|
134
|
+
discountMinor: minorUnits,
|
|
135
|
+
roundingAdjustmentMinor: number(int, atLeast(-Number.MAX_SAFE_INTEGER), atMost(Number.MAX_SAFE_INTEGER)),
|
|
136
|
+
paymentFingerprint: fingerprint,
|
|
137
|
+
amountMinor: minorUnits,
|
|
138
|
+
currency: string(pattern(/^[A-Z]{3}$/)),
|
|
139
|
+
expiresAt: string(datetime),
|
|
140
|
+
};
|
|
141
|
+
const purchaseApprovalFields = {
|
|
142
|
+
id: accountId,
|
|
143
|
+
childAccountId: accountId,
|
|
144
|
+
applicationId: accountId,
|
|
145
|
+
status: oneOf(PURCHASE_APPROVAL_STATUSES),
|
|
146
|
+
createdAt: string(datetime),
|
|
147
|
+
receiptReference: nullable(string(maxLength(512))),
|
|
148
|
+
};
|
|
149
|
+
/** The first problem `validatePurchaseEvidence` in `../safety.ts` reports, in its order. */
|
|
150
|
+
function purchaseEvidenceProblem(value) {
|
|
151
|
+
const merchants = new Set(value.merchantAccountIds);
|
|
152
|
+
const references = new Set();
|
|
153
|
+
for (const line of value.lineItems) {
|
|
154
|
+
const key = `${line.merchantAccountId}:${line.itemReference}`;
|
|
155
|
+
if (!merchants.has(line.merchantAccountId) || references.has(key)) {
|
|
156
|
+
return {
|
|
157
|
+
path: [],
|
|
158
|
+
message: 'Purchase lines must name an included merchant and unique item reference',
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
references.add(key);
|
|
162
|
+
}
|
|
163
|
+
if (merchants.size !== new Set(value.lineItems.map((line) => line.merchantAccountId)).size) {
|
|
164
|
+
return { path: [], message: 'Every merchant must have an approval line' };
|
|
165
|
+
}
|
|
166
|
+
const total = value.lineItems.reduce((sum, line) => sum + BigInt(line.lineAmountMinor), 0n) +
|
|
167
|
+
BigInt(value.shippingMinor) +
|
|
168
|
+
BigInt(value.taxMinor) -
|
|
169
|
+
BigInt(value.discountMinor) +
|
|
170
|
+
BigInt(value.roundingAdjustmentMinor);
|
|
171
|
+
if (total < 0n ||
|
|
172
|
+
total > BigInt(Number.MAX_SAFE_INTEGER) ||
|
|
173
|
+
total !== BigInt(value.amountMinor)) {
|
|
174
|
+
return { path: [], message: 'Approval evidence must equal the exact payment total' };
|
|
175
|
+
}
|
|
176
|
+
if (Math.abs(value.roundingAdjustmentMinor) >
|
|
177
|
+
value.lineItems.length + 3 * value.merchantAccountIds.length) {
|
|
178
|
+
return { path: [], message: 'Rounding adjustment exceeds the bounded conversion stages' };
|
|
179
|
+
}
|
|
180
|
+
return undefined;
|
|
181
|
+
}
|
|
182
|
+
export const purchaseApprovalCheck = exact()(refineAt(strictObject({
|
|
183
|
+
...purchaseEffectFields,
|
|
184
|
+
lineItems: array(purchaseApprovalLineCheck, minItems(1), maxItems(200)),
|
|
185
|
+
...purchaseAmountFields,
|
|
186
|
+
...purchaseApprovalFields,
|
|
187
|
+
}), purchaseEvidenceProblem));
|
|
188
|
+
const purchaseApprovalSummaryCheck = exact()(strictObject({ ...purchaseEffectFields, ...purchaseAmountFields, ...purchaseApprovalFields }));
|
|
189
|
+
export const purchaseApprovalListCheck = exact()(strictObject({
|
|
190
|
+
items: array(purchaseApprovalSummaryCheck, maxItems(100)),
|
|
191
|
+
nextCursor: nullable(string()),
|
|
192
|
+
}));
|
|
193
|
+
export const purchaseReviewInputCheck = exact()(strictObject({ decision: oneOf(['approved', 'rejected']), reauth: reauthProofCheck }));
|
package/dist/esm/index.js
CHANGED
|
@@ -180,13 +180,14 @@ PRODUCT_PLAN_STATUSES, productPlanStatusSchema, LIVE_PRODUCT_PLAN_STATUSES, plan
|
|
|
180
180
|
export {
|
|
181
181
|
// Economic treatment (I09): derived by the server, never sent by a caller.
|
|
182
182
|
INFERENCE_ECONOMIC_TREATMENTS, inferenceEconomicTreatmentSchema, PROVIDER_COST_SOURCES, providerCostSourceSchema, costCenterUsageSchema, } from './inference/economics.js';
|
|
183
|
-
export { AUTONOMY_LEVELS, CAPABILITY_PACKAGES, autonomyLevelSchema, capabilityPackageSchema, actorRefSchema, executionActorRefSchema, foregroundExecutionAuthorizationInputSchema, resourceRefSchema, toolGrantOverrideSchema, grantLimitSchema, capabilityCatalogBindingSchema, executionAuthorizationRefSchema, capabilityCoordinatorSchema, capabilityTicketRequestSchema, delegationGrantSchema, automationTriggerSchema, automationActorSelectionSchema, automationDataFlowSchema, automationDefinitionSchema, capabilityTicketClaimsSchema, invocationPrincipalSchema, policyDecisionSchema, auditResultSchema, auditEventSchema, catalogToolSchema, catalogEventSchema, appCapabilityCatalogSchema, catalogRegistrationSchema, normalizedAppEventSchema, } from './agency.js';
|
|
183
|
+
export { AUTONOMY_LEVELS, CAPABILITY_PACKAGES, autonomyLevelSchema, capabilityPackageSchema, actorRefSchema, executionActorRefSchema, foregroundExecutionAuthorizationInputSchema, resourceRefSchema, toolGrantOverrideSchema, grantLimitSchema, capabilityCatalogBindingSchema, executionAuthorizationRefSchema, capabilityCoordinatorSchema, capabilityTicketRequestSchema, delegationGrantSchema, AGENT_REQUESTER_CEILING_AUTONOMY, agentRequesterCeilingWriteSchema, agentRequesterCeilingSchema, automationTriggerSchema, automationActorSelectionSchema, automationDataFlowSchema, automationDefinitionSchema, capabilityTicketClaimsSchema, invocationPrincipalSchema, policyDecisionSchema, auditResultSchema, auditEventSchema, catalogToolSchema, catalogEventSchema, catalogFeatureSchema, CATALOG_INTERNAL_TRANSPORTS, appCapabilityCatalogSchema, catalogRegistrationSchema, normalizedAppEventSchema, } from './agency.js';
|
|
184
184
|
export { catalogInvocationPathParameters, catalogInvocationsOverlap, catalogInvocationTemplatesEquivalent, findOverlappingCatalogInvocations, matchCatalogInvocation, resolveCatalogInvocation, } from './capabilityInvocation.js';
|
|
185
185
|
export { emailContextAddressSchema, emailContextMailboxSchema, emailContextMessageSchema, emailAgentContextSchema, } from './emailAgentContext.js';
|
|
186
186
|
export { inboxComposeRequestSchema, inboxDailyBriefRequestSchema, inboxDailyBriefResponseSchema, INBOX_DAILY_BRIEF_SECTIONS, inboxNaturalSearchRequestSchema, inboxMessageInferenceParamsSchema, inboxInferenceTextResponseSchema, inboxNaturalSearchResponseSchema, inboxSmartRepliesResponseSchema, inboxThreadSummaryResponseSchema, inboxInferenceStreamEventSchema, } from './inference/inbox.js';
|
|
187
187
|
export * from './externalIdentity.js';
|
|
188
188
|
export * from './linkedAccounts.js';
|
|
189
189
|
export * from './federationInstanceFetch.js';
|
|
190
|
+
export * from './accountAccess.js';
|
|
190
191
|
export * from './notifications.js';
|
|
191
192
|
export * from './email/messages.js';
|
|
192
193
|
export * from './stickers.js';
|
|
@@ -204,3 +205,5 @@ export { personalPlanDisplayPriceSchema, personalPlanCatalogueSchema, } from './
|
|
|
204
205
|
export * from './products/checkout.js';
|
|
205
206
|
export * from './organizations.js';
|
|
206
207
|
export * from './safety.js';
|
|
208
|
+
export { serviceTokenScopesSchema, serviceTokenOptionsSchema, } from './serviceToken.js';
|
|
209
|
+
export * from './applicationRoles.js';
|