@oxy.so/contracts 1.0.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/LICENSE +202 -0
- package/NOTICE +16 -0
- package/dist/cjs/.tsbuildinfo +1 -0
- package/dist/cjs/accountGraph.js +489 -0
- package/dist/cjs/agency.js +439 -0
- package/dist/cjs/browserHub.js +215 -0
- package/dist/cjs/civic.js +163 -0
- package/dist/cjs/commonsSignIn.js +59 -0
- package/dist/cjs/deviceBoot.js +50 -0
- package/dist/cjs/deviceDirectory.js +189 -0
- package/dist/cjs/devicePairing.js +138 -0
- package/dist/cjs/deviceSession.js +164 -0
- package/dist/cjs/emailAgentContext.js +32 -0
- package/dist/cjs/followGraph.js +28 -0
- package/dist/cjs/identity.js +258 -0
- package/dist/cjs/inboxPush.js +24 -0
- package/dist/cjs/index.js +618 -0
- package/dist/cjs/inference/accountBilling.js +334 -0
- package/dist/cjs/inference/aliaModelRelease.js +262 -0
- package/dist/cjs/inference/attribution.js +106 -0
- package/dist/cjs/inference/catalogue.js +487 -0
- package/dist/cjs/inference/entitlement.js +217 -0
- package/dist/cjs/inference/errors.js +309 -0
- package/dist/cjs/inference/identifiers.js +224 -0
- package/dist/cjs/inference/inbox.js +105 -0
- package/dist/cjs/inference/modelDocumentation.js +433 -0
- package/dist/cjs/inference/money.js +188 -0
- package/dist/cjs/inference/priceVersion.js +110 -0
- package/dist/cjs/inference/providerConnection.js +455 -0
- package/dist/cjs/inference/request.js +477 -0
- package/dist/cjs/inference/routingPolicy.js +318 -0
- package/dist/cjs/inference/streamEvents.js +258 -0
- package/dist/cjs/inference/usage.js +329 -0
- package/dist/cjs/inference/version.js +105 -0
- package/dist/cjs/keyRecovery.js +91 -0
- package/dist/cjs/keyRotation.js +75 -0
- package/dist/cjs/links.js +68 -0
- package/dist/cjs/moderationReputation.js +298 -0
- package/dist/cjs/oauth.js +66 -0
- package/dist/cjs/oxyRecordTypes.js +71 -0
- package/dist/cjs/protocol.js +53 -0
- package/dist/cjs/recommendations.js +168 -0
- package/dist/cjs/reputation.js +297 -0
- package/dist/cjs/sessionStatus.js +121 -0
- package/dist/cjs/transparency.js +89 -0
- package/dist/cjs/updates.js +252 -0
- package/dist/cjs/userInvalidation.js +89 -0
- package/dist/cjs/userResponse.js +245 -0
- package/dist/cjs/username.js +290 -0
- package/dist/cjs/webauthn.js +71 -0
- package/dist/esm/.tsbuildinfo +1 -0
- package/dist/esm/accountGraph.js +480 -0
- package/dist/esm/agency.js +436 -0
- package/dist/esm/browserHub.js +212 -0
- package/dist/esm/civic.js +160 -0
- package/dist/esm/commonsSignIn.js +56 -0
- package/dist/esm/deviceBoot.js +47 -0
- package/dist/esm/deviceDirectory.js +186 -0
- package/dist/esm/devicePairing.js +135 -0
- package/dist/esm/deviceSession.js +161 -0
- package/dist/esm/emailAgentContext.js +29 -0
- package/dist/esm/followGraph.js +27 -0
- package/dist/esm/identity.js +255 -0
- package/dist/esm/inboxPush.js +21 -0
- package/dist/esm/index.js +172 -0
- package/dist/esm/inference/accountBilling.js +331 -0
- package/dist/esm/inference/aliaModelRelease.js +259 -0
- package/dist/esm/inference/attribution.js +103 -0
- package/dist/esm/inference/catalogue.js +484 -0
- package/dist/esm/inference/entitlement.js +214 -0
- package/dist/esm/inference/errors.js +306 -0
- package/dist/esm/inference/identifiers.js +221 -0
- package/dist/esm/inference/inbox.js +102 -0
- package/dist/esm/inference/modelDocumentation.js +430 -0
- package/dist/esm/inference/money.js +185 -0
- package/dist/esm/inference/priceVersion.js +107 -0
- package/dist/esm/inference/providerConnection.js +452 -0
- package/dist/esm/inference/request.js +474 -0
- package/dist/esm/inference/routingPolicy.js +315 -0
- package/dist/esm/inference/streamEvents.js +255 -0
- package/dist/esm/inference/usage.js +326 -0
- package/dist/esm/inference/version.js +102 -0
- package/dist/esm/keyRecovery.js +88 -0
- package/dist/esm/keyRotation.js +72 -0
- package/dist/esm/links.js +65 -0
- package/dist/esm/moderationReputation.js +295 -0
- package/dist/esm/oauth.js +63 -0
- package/dist/esm/oxyRecordTypes.js +68 -0
- package/dist/esm/protocol.js +50 -0
- package/dist/esm/recommendations.js +165 -0
- package/dist/esm/reputation.js +293 -0
- package/dist/esm/sessionStatus.js +118 -0
- package/dist/esm/transparency.js +86 -0
- package/dist/esm/updates.js +249 -0
- package/dist/esm/userInvalidation.js +85 -0
- package/dist/esm/userResponse.js +240 -0
- package/dist/esm/username.js +283 -0
- package/dist/esm/webauthn.js +68 -0
- package/dist/types/.tsbuildinfo +1 -0
- package/dist/types/accountGraph.d.ts +378 -0
- package/dist/types/agency.d.ts +2162 -0
- package/dist/types/browserHub.d.ts +856 -0
- package/dist/types/civic.d.ts +338 -0
- package/dist/types/commonsSignIn.d.ts +58 -0
- package/dist/types/deviceBoot.d.ts +74 -0
- package/dist/types/deviceDirectory.d.ts +1317 -0
- package/dist/types/devicePairing.d.ts +130 -0
- package/dist/types/deviceSession.d.ts +411 -0
- package/dist/types/emailAgentContext.d.ts +248 -0
- package/dist/types/followGraph.d.ts +150 -0
- package/dist/types/identity.d.ts +402 -0
- package/dist/types/inboxPush.d.ts +30 -0
- package/dist/types/index.d.ts +100 -0
- package/dist/types/inference/accountBilling.d.ts +738 -0
- package/dist/types/inference/aliaModelRelease.d.ts +609 -0
- package/dist/types/inference/attribution.d.ts +176 -0
- package/dist/types/inference/catalogue.d.ts +1618 -0
- package/dist/types/inference/entitlement.d.ts +519 -0
- package/dist/types/inference/errors.d.ts +242 -0
- package/dist/types/inference/identifiers.d.ts +182 -0
- package/dist/types/inference/inbox.d.ts +374 -0
- package/dist/types/inference/modelDocumentation.d.ts +1603 -0
- package/dist/types/inference/money.d.ts +185 -0
- package/dist/types/inference/priceVersion.d.ts +182 -0
- package/dist/types/inference/providerConnection.d.ts +968 -0
- package/dist/types/inference/request.d.ts +2800 -0
- package/dist/types/inference/routingPolicy.d.ts +616 -0
- package/dist/types/inference/streamEvents.d.ts +950 -0
- package/dist/types/inference/usage.d.ts +1164 -0
- package/dist/types/inference/version.d.ts +102 -0
- package/dist/types/keyRecovery.d.ts +138 -0
- package/dist/types/keyRotation.d.ts +103 -0
- package/dist/types/links.d.ts +96 -0
- package/dist/types/moderationReputation.d.ts +487 -0
- package/dist/types/oauth.d.ts +86 -0
- package/dist/types/oxyRecordTypes.d.ts +62 -0
- package/dist/types/protocol.d.ts +86 -0
- package/dist/types/recommendations.d.ts +542 -0
- package/dist/types/reputation.d.ts +457 -0
- package/dist/types/sessionStatus.d.ts +231 -0
- package/dist/types/transparency.d.ts +392 -0
- package/dist/types/updates.d.ts +545 -0
- package/dist/types/userInvalidation.d.ts +94 -0
- package/dist/types/userResponse.d.ts +1706 -0
- package/dist/types/username.d.ts +265 -0
- package/dist/types/webauthn.d.ts +77 -0
- package/package.json +87 -0
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.normalizedAppEventSchema = exports.catalogRegistrationSchema = exports.appCapabilityCatalogSchema = exports.catalogEventSchema = exports.catalogToolSchema = exports.auditEventSchema = exports.auditResultSchema = exports.policyDecisionSchema = exports.capabilityTicketClaimsSchema = exports.automationDefinitionSchema = exports.automationDataFlowSchema = exports.automationActorSelectionSchema = exports.automationTriggerSchema = exports.delegationGrantSchema = exports.capabilityCoordinatorSchema = exports.executionAuthorizationRefSchema = exports.grantLimitSchema = exports.toolGrantOverrideSchema = exports.resourceRefSchema = exports.actorRefSchema = exports.capabilityPackageSchema = exports.CAPABILITY_PACKAGES = exports.autonomyLevelSchema = exports.AUTONOMY_LEVELS = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const nonEmptyStringSchema = zod_1.z.string().trim().min(1);
|
|
6
|
+
const identifierSchema = zod_1.z.string().trim().min(1).max(255);
|
|
7
|
+
const limitKeySchema = zod_1.z.string().regex(/^[A-Za-z][A-Za-z0-9_]*(?:\.[A-Za-z][A-Za-z0-9_]*)*$/, 'limit keys must be dot-separated input property names').max(255);
|
|
8
|
+
const auditCodeSchema = zod_1.z.string().regex(/^[A-Za-z0-9_.:-]{1,128}$/);
|
|
9
|
+
const sha256HexSchema = zod_1.z.string().regex(/^[a-f0-9]{64}$/);
|
|
10
|
+
const invocationPathSchema = zod_1.z.string().regex(/^\/(?!\/)[^\\?#]*$/, 'invocation paths must be absolute app-local paths without backslashes, query or fragment');
|
|
11
|
+
/** Autonomy is ordered from least to most permissive. */
|
|
12
|
+
exports.AUTONOMY_LEVELS = [
|
|
13
|
+
'read_only',
|
|
14
|
+
'draft',
|
|
15
|
+
'execute_on_request',
|
|
16
|
+
'autonomous',
|
|
17
|
+
];
|
|
18
|
+
exports.autonomyLevelSchema = zod_1.z.enum(exports.AUTONOMY_LEVELS);
|
|
19
|
+
exports.CAPABILITY_PACKAGES = [
|
|
20
|
+
'read',
|
|
21
|
+
'create',
|
|
22
|
+
'publish',
|
|
23
|
+
'communicate',
|
|
24
|
+
'administer',
|
|
25
|
+
'finance',
|
|
26
|
+
'security',
|
|
27
|
+
'delegate',
|
|
28
|
+
];
|
|
29
|
+
exports.capabilityPackageSchema = zod_1.z.enum(exports.CAPABILITY_PACKAGES);
|
|
30
|
+
exports.actorRefSchema = zod_1.z.discriminatedUnion('type', [
|
|
31
|
+
zod_1.z.object({
|
|
32
|
+
type: zod_1.z.literal('alia'),
|
|
33
|
+
ownerAccountId: identifierSchema,
|
|
34
|
+
}).strict(),
|
|
35
|
+
zod_1.z.object({
|
|
36
|
+
type: zod_1.z.literal('agent'),
|
|
37
|
+
accountId: identifierSchema,
|
|
38
|
+
}).strict(),
|
|
39
|
+
]);
|
|
40
|
+
exports.resourceRefSchema = zod_1.z.object({
|
|
41
|
+
appId: identifierSchema,
|
|
42
|
+
effectiveAccountId: identifierSchema,
|
|
43
|
+
resourceType: identifierSchema,
|
|
44
|
+
resourceId: identifierSchema,
|
|
45
|
+
}).strict();
|
|
46
|
+
exports.toolGrantOverrideSchema = zod_1.z.object({
|
|
47
|
+
tool: identifierSchema,
|
|
48
|
+
decision: zod_1.z.enum(['allow', 'deny']),
|
|
49
|
+
}).strict();
|
|
50
|
+
exports.grantLimitSchema = zod_1.z.object({
|
|
51
|
+
tool: identifierSchema,
|
|
52
|
+
key: limitKeySchema,
|
|
53
|
+
// Persisted limits are deliberately closed scalar bounds. Strings and
|
|
54
|
+
// arrays are tool arguments in disguise (recipient lists, prompts, search
|
|
55
|
+
// queries) and ADR 0016 forbids persisting those in Oxy.
|
|
56
|
+
value: zod_1.z.union([zod_1.z.number().finite(), zod_1.z.boolean()]),
|
|
57
|
+
}).strict();
|
|
58
|
+
exports.executionAuthorizationRefSchema = zod_1.z.discriminatedUnion('kind', [
|
|
59
|
+
zod_1.z.object({
|
|
60
|
+
kind: zod_1.z.literal('direct_request'),
|
|
61
|
+
id: identifierSchema,
|
|
62
|
+
}).strict(),
|
|
63
|
+
zod_1.z.object({
|
|
64
|
+
kind: zod_1.z.literal('automation'),
|
|
65
|
+
id: identifierSchema,
|
|
66
|
+
automationId: identifierSchema,
|
|
67
|
+
}).strict(),
|
|
68
|
+
]);
|
|
69
|
+
exports.capabilityCoordinatorSchema = zod_1.z.object({
|
|
70
|
+
applicationId: identifierSchema,
|
|
71
|
+
credentialId: identifierSchema,
|
|
72
|
+
}).strict();
|
|
73
|
+
exports.delegationGrantSchema = zod_1.z.object({
|
|
74
|
+
id: identifierSchema,
|
|
75
|
+
ownerAccountId: identifierSchema,
|
|
76
|
+
actor: exports.actorRefSchema,
|
|
77
|
+
resource: exports.resourceRefSchema,
|
|
78
|
+
capabilityPackages: zod_1.z.array(exports.capabilityPackageSchema),
|
|
79
|
+
capabilities: zod_1.z.array(identifierSchema),
|
|
80
|
+
toolOverrides: zod_1.z.array(exports.toolGrantOverrideSchema).default([]),
|
|
81
|
+
limits: zod_1.z.array(exports.grantLimitSchema).default([]),
|
|
82
|
+
maximumAutonomy: exports.autonomyLevelSchema,
|
|
83
|
+
canRedelegate: zod_1.z.boolean().default(false),
|
|
84
|
+
expiresAt: zod_1.z.string().datetime().nullable(),
|
|
85
|
+
revokedAt: zod_1.z.string().datetime().nullable().default(null),
|
|
86
|
+
createdAt: zod_1.z.string().datetime(),
|
|
87
|
+
updatedAt: zod_1.z.string().datetime(),
|
|
88
|
+
}).strict();
|
|
89
|
+
exports.automationTriggerSchema = zod_1.z.discriminatedUnion('type', [
|
|
90
|
+
zod_1.z.object({ type: zod_1.z.literal('manual') }).strict(),
|
|
91
|
+
zod_1.z.object({
|
|
92
|
+
type: zod_1.z.literal('event'),
|
|
93
|
+
appId: identifierSchema,
|
|
94
|
+
eventType: identifierSchema,
|
|
95
|
+
resource: exports.resourceRefSchema.optional(),
|
|
96
|
+
}).strict(),
|
|
97
|
+
zod_1.z.object({
|
|
98
|
+
type: zod_1.z.literal('schedule'),
|
|
99
|
+
cron: nonEmptyStringSchema,
|
|
100
|
+
timezone: nonEmptyStringSchema,
|
|
101
|
+
}).strict(),
|
|
102
|
+
]);
|
|
103
|
+
exports.automationActorSelectionSchema = zod_1.z.discriminatedUnion('mode', [
|
|
104
|
+
zod_1.z.object({ mode: zod_1.z.literal('fixed'), actor: exports.actorRefSchema }).strict(),
|
|
105
|
+
zod_1.z.object({ mode: zod_1.z.literal('automatic') }).strict(),
|
|
106
|
+
]);
|
|
107
|
+
exports.automationDataFlowSchema = zod_1.z.object({
|
|
108
|
+
sources: zod_1.z.array(exports.resourceRefSchema),
|
|
109
|
+
destinations: zod_1.z.array(exports.resourceRefSchema),
|
|
110
|
+
}).strict();
|
|
111
|
+
exports.automationDefinitionSchema = zod_1.z.object({
|
|
112
|
+
id: identifierSchema,
|
|
113
|
+
ownerAccountId: identifierSchema,
|
|
114
|
+
objective: nonEmptyStringSchema,
|
|
115
|
+
trigger: exports.automationTriggerSchema,
|
|
116
|
+
actorSelection: exports.automationActorSelectionSchema,
|
|
117
|
+
inputs: zod_1.z.record(zod_1.z.unknown()),
|
|
118
|
+
resources: zod_1.z.array(exports.resourceRefSchema),
|
|
119
|
+
dataFlow: exports.automationDataFlowSchema,
|
|
120
|
+
maximumAutonomy: exports.autonomyLevelSchema,
|
|
121
|
+
limits: zod_1.z.array(exports.grantLimitSchema).default([]),
|
|
122
|
+
enabled: zod_1.z.boolean(),
|
|
123
|
+
createdAt: zod_1.z.string().datetime(),
|
|
124
|
+
updatedAt: zod_1.z.string().datetime(),
|
|
125
|
+
}).strict();
|
|
126
|
+
exports.capabilityTicketClaimsSchema = zod_1.z.object({
|
|
127
|
+
iss: nonEmptyStringSchema,
|
|
128
|
+
aud: identifierSchema,
|
|
129
|
+
sub: identifierSchema,
|
|
130
|
+
jti: identifierSchema,
|
|
131
|
+
iat: zod_1.z.number().int().nonnegative(),
|
|
132
|
+
exp: zod_1.z.number().int().positive(),
|
|
133
|
+
runId: identifierSchema,
|
|
134
|
+
stepId: identifierSchema.optional(),
|
|
135
|
+
automationId: identifierSchema.optional(),
|
|
136
|
+
executionAuthorization: exports.executionAuthorizationRefSchema,
|
|
137
|
+
coordinator: exports.capabilityCoordinatorSchema,
|
|
138
|
+
grantId: identifierSchema.optional(),
|
|
139
|
+
requesterAccountId: identifierSchema,
|
|
140
|
+
ownerAccountId: identifierSchema,
|
|
141
|
+
actor: exports.actorRefSchema,
|
|
142
|
+
resource: exports.resourceRefSchema,
|
|
143
|
+
tool: identifierSchema,
|
|
144
|
+
capabilities: zod_1.z.array(identifierSchema).min(1),
|
|
145
|
+
limits: zod_1.z.array(exports.grantLimitSchema).default([]),
|
|
146
|
+
autonomy: exports.autonomyLevelSchema,
|
|
147
|
+
}).strict().superRefine((claims, context) => {
|
|
148
|
+
const expectedSubject = claims.actor.type === 'agent'
|
|
149
|
+
? claims.actor.accountId
|
|
150
|
+
: `alia:${claims.actor.ownerAccountId}`;
|
|
151
|
+
if (claims.sub !== expectedSubject) {
|
|
152
|
+
context.addIssue({
|
|
153
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
154
|
+
message: 'sub must identify the exact executing actor',
|
|
155
|
+
path: ['sub'],
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
if (claims.actor.type === 'alia' && claims.actor.ownerAccountId !== claims.ownerAccountId) {
|
|
159
|
+
context.addIssue({
|
|
160
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
161
|
+
message: 'Alia actor owner must match ownerAccountId',
|
|
162
|
+
path: ['actor', 'ownerAccountId'],
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
if (claims.exp <= claims.iat) {
|
|
166
|
+
context.addIssue({
|
|
167
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
168
|
+
message: 'exp must be later than iat',
|
|
169
|
+
path: ['exp'],
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
if (claims.executionAuthorization.kind === 'automation') {
|
|
173
|
+
if (claims.automationId !== claims.executionAuthorization.automationId) {
|
|
174
|
+
context.addIssue({
|
|
175
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
176
|
+
message: 'automationId must match the execution authorization',
|
|
177
|
+
path: ['automationId'],
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
else if (claims.automationId !== undefined || claims.autonomy === 'autonomous') {
|
|
182
|
+
context.addIssue({
|
|
183
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
184
|
+
message: 'direct requests cannot carry automation identity or autonomous authority',
|
|
185
|
+
path: ['executionAuthorization'],
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
for (const [index, limit] of claims.limits.entries()) {
|
|
189
|
+
if (limit.tool !== claims.tool) {
|
|
190
|
+
context.addIssue({
|
|
191
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
192
|
+
message: 'ticket limits must be scoped to the ticket tool',
|
|
193
|
+
path: ['limits', index, 'tool'],
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
exports.policyDecisionSchema = zod_1.z.object({
|
|
199
|
+
allowed: zod_1.z.boolean(),
|
|
200
|
+
reason: identifierSchema,
|
|
201
|
+
effectiveAutonomy: exports.autonomyLevelSchema.optional(),
|
|
202
|
+
grantId: identifierSchema.optional(),
|
|
203
|
+
}).strict();
|
|
204
|
+
exports.auditResultSchema = zod_1.z.object({
|
|
205
|
+
status: zod_1.z.enum(['planned', 'allowed', 'denied', 'succeeded', 'failed', 'rolled_back']),
|
|
206
|
+
code: auditCodeSchema.optional(),
|
|
207
|
+
}).strict();
|
|
208
|
+
exports.auditEventSchema = zod_1.z.object({
|
|
209
|
+
eventId: identifierSchema,
|
|
210
|
+
occurredAt: zod_1.z.string().datetime(),
|
|
211
|
+
requesterAccountId: identifierSchema,
|
|
212
|
+
coordinator: exports.capabilityCoordinatorSchema,
|
|
213
|
+
executor: exports.actorRefSchema,
|
|
214
|
+
effectiveAccountId: identifierSchema,
|
|
215
|
+
resource: exports.resourceRefSchema,
|
|
216
|
+
appId: identifierSchema,
|
|
217
|
+
tool: identifierSchema,
|
|
218
|
+
capabilities: zod_1.z.array(identifierSchema),
|
|
219
|
+
policyDecision: exports.policyDecisionSchema,
|
|
220
|
+
result: exports.auditResultSchema,
|
|
221
|
+
rollback: zod_1.z.object({
|
|
222
|
+
supported: zod_1.z.boolean(),
|
|
223
|
+
attempted: zod_1.z.boolean(),
|
|
224
|
+
succeeded: zod_1.z.boolean().optional(),
|
|
225
|
+
}).strict(),
|
|
226
|
+
correlation: zod_1.z.object({
|
|
227
|
+
runId: identifierSchema,
|
|
228
|
+
stepId: identifierSchema.optional(),
|
|
229
|
+
automationId: identifierSchema.optional(),
|
|
230
|
+
idempotencyKeyHash: sha256HexSchema.optional(),
|
|
231
|
+
capabilityTicketId: identifierSchema.optional(),
|
|
232
|
+
}).strict(),
|
|
233
|
+
}).strict();
|
|
234
|
+
exports.catalogToolSchema = zod_1.z.object({
|
|
235
|
+
name: identifierSchema,
|
|
236
|
+
version: identifierSchema,
|
|
237
|
+
description: nonEmptyStringSchema,
|
|
238
|
+
inputSchema: zod_1.z.record(zod_1.z.unknown()),
|
|
239
|
+
outputSchema: zod_1.z.record(zod_1.z.unknown()).optional(),
|
|
240
|
+
capabilityPackage: exports.capabilityPackageSchema,
|
|
241
|
+
requiredCapabilities: zod_1.z.array(identifierSchema).min(1),
|
|
242
|
+
resourceTypes: zod_1.z.array(identifierSchema).min(1),
|
|
243
|
+
effect: zod_1.z.enum(['read', 'write', 'external', 'financial', 'security']),
|
|
244
|
+
idempotency: zod_1.z.enum(['none', 'supported', 'required']),
|
|
245
|
+
rollback: zod_1.z.enum(['none', 'manual', 'supported']),
|
|
246
|
+
exposure: zod_1.z.array(zod_1.z.enum(['internal', 'mcp'])).min(1),
|
|
247
|
+
limitKeys: zod_1.z.array(zod_1.z.object({
|
|
248
|
+
key: limitKeySchema,
|
|
249
|
+
kind: zod_1.z.enum(['maximum_number', 'exact_boolean']),
|
|
250
|
+
}).strict()).default([]),
|
|
251
|
+
invocation: zod_1.z.object({
|
|
252
|
+
method: zod_1.z.enum(['GET', 'POST', 'PATCH', 'PUT', 'DELETE']),
|
|
253
|
+
path: invocationPathSchema,
|
|
254
|
+
}).strict(),
|
|
255
|
+
}).strict().superRefine((tool, context) => {
|
|
256
|
+
const requireUnique = (values, path) => {
|
|
257
|
+
if (new Set(values).size !== values.length) {
|
|
258
|
+
context.addIssue({
|
|
259
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
260
|
+
message: `${path} must not contain duplicates`,
|
|
261
|
+
path: [path],
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
requireUnique(tool.requiredCapabilities, 'requiredCapabilities');
|
|
266
|
+
requireUnique(tool.resourceTypes, 'resourceTypes');
|
|
267
|
+
requireUnique(tool.exposure, 'exposure');
|
|
268
|
+
requireUnique(tool.limitKeys.map((limit) => limit.key), 'limitKeys');
|
|
269
|
+
const inputSchemaAt = (key) => {
|
|
270
|
+
let schema = tool.inputSchema;
|
|
271
|
+
for (const segment of key.split('.')) {
|
|
272
|
+
if (typeof schema !== 'object' || schema === null || Array.isArray(schema))
|
|
273
|
+
return null;
|
|
274
|
+
const properties = schema.properties;
|
|
275
|
+
if (typeof properties !== 'object' || properties === null || Array.isArray(properties))
|
|
276
|
+
return null;
|
|
277
|
+
schema = properties[segment];
|
|
278
|
+
}
|
|
279
|
+
return typeof schema === 'object' && schema !== null && !Array.isArray(schema)
|
|
280
|
+
? schema
|
|
281
|
+
: null;
|
|
282
|
+
};
|
|
283
|
+
for (const [index, limit] of tool.limitKeys.entries()) {
|
|
284
|
+
const input = inputSchemaAt(limit.key);
|
|
285
|
+
const inputType = input?.type;
|
|
286
|
+
const compatible = limit.kind === 'maximum_number'
|
|
287
|
+
? inputType === 'number' || inputType === 'integer'
|
|
288
|
+
: inputType === 'boolean';
|
|
289
|
+
if (!compatible) {
|
|
290
|
+
context.addIssue({
|
|
291
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
292
|
+
message: `${limit.kind} must name a compatible input property`,
|
|
293
|
+
path: ['limitKeys', index, 'key'],
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
if (tool.inputSchema.type !== 'object') {
|
|
298
|
+
context.addIssue({
|
|
299
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
300
|
+
message: 'MCP-compatible tool input schemas must have object roots',
|
|
301
|
+
path: ['inputSchema', 'type'],
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
if (tool.outputSchema && tool.outputSchema.type !== 'object') {
|
|
305
|
+
context.addIssue({
|
|
306
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
307
|
+
message: 'Tool output schemas must have object roots',
|
|
308
|
+
path: ['outputSchema', 'type'],
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
if (tool.effect !== 'read' && tool.idempotency === 'none') {
|
|
312
|
+
context.addIssue({
|
|
313
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
314
|
+
message: 'Effectful tools must declare idempotency support',
|
|
315
|
+
path: ['idempotency'],
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
if (tool.effect === 'financial' && tool.capabilityPackage !== 'finance') {
|
|
319
|
+
context.addIssue({
|
|
320
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
321
|
+
message: 'Financial effects require the finance capability package',
|
|
322
|
+
path: ['capabilityPackage'],
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
if (tool.effect === 'security' && tool.capabilityPackage !== 'security') {
|
|
326
|
+
context.addIssue({
|
|
327
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
328
|
+
message: 'Security effects require the security capability package',
|
|
329
|
+
path: ['capabilityPackage'],
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
if ((tool.effect === 'financial' || tool.effect === 'security') && tool.idempotency !== 'required') {
|
|
333
|
+
context.addIssue({
|
|
334
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
335
|
+
message: 'Financial and security effects require idempotency keys',
|
|
336
|
+
path: ['idempotency'],
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
if (tool.effect !== 'read' && tool.invocation.method === 'GET') {
|
|
340
|
+
context.addIssue({
|
|
341
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
342
|
+
message: 'Effectful tools cannot use GET invocations',
|
|
343
|
+
path: ['invocation', 'method'],
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
exports.catalogEventSchema = zod_1.z.object({
|
|
348
|
+
type: identifierSchema,
|
|
349
|
+
version: identifierSchema,
|
|
350
|
+
description: nonEmptyStringSchema,
|
|
351
|
+
dataSchema: zod_1.z.record(zod_1.z.unknown()),
|
|
352
|
+
resourceTypes: zod_1.z.array(identifierSchema).min(1),
|
|
353
|
+
}).strict();
|
|
354
|
+
exports.appCapabilityCatalogSchema = zod_1.z.object({
|
|
355
|
+
schemaVersion: zod_1.z.literal('1'),
|
|
356
|
+
appId: identifierSchema,
|
|
357
|
+
version: identifierSchema,
|
|
358
|
+
audience: identifierSchema,
|
|
359
|
+
/** HTTPS origin that serves the catalog's internal invocation paths. */
|
|
360
|
+
internalBaseUrl: zod_1.z.string().url().superRefine((value, context) => {
|
|
361
|
+
const url = new URL(value);
|
|
362
|
+
const localDevelopment = url.hostname === 'localhost' || url.hostname === '127.0.0.1';
|
|
363
|
+
if (url.protocol !== 'https:' && !(localDevelopment && url.protocol === 'http:')) {
|
|
364
|
+
context.addIssue({
|
|
365
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
366
|
+
message: 'internalBaseUrl must use HTTPS outside local development',
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
if (url.pathname !== '/' || url.search !== '' || url.hash !== '') {
|
|
370
|
+
context.addIssue({
|
|
371
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
372
|
+
message: 'internalBaseUrl must be an origin without path, query or fragment',
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
}),
|
|
376
|
+
/** Account-scoped resource used for native Alia bindings without app-specific code. */
|
|
377
|
+
accountResourceType: identifierSchema,
|
|
378
|
+
/** Canonical protected-resource URI when this catalog is also exposed as an external MCP server. */
|
|
379
|
+
externalMcp: zod_1.z.object({
|
|
380
|
+
resource: zod_1.z.string().url().superRefine((value, context) => {
|
|
381
|
+
const url = new URL(value);
|
|
382
|
+
const localDevelopment = url.hostname === 'localhost'
|
|
383
|
+
|| url.hostname === '127.0.0.1'
|
|
384
|
+
|| url.hostname === '[::1]';
|
|
385
|
+
if (url.protocol !== 'https:' && !(localDevelopment && url.protocol === 'http:')) {
|
|
386
|
+
context.addIssue({
|
|
387
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
388
|
+
message: 'externalMcp.resource must use HTTPS outside local development',
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
if (url.username || url.password || url.search || url.hash) {
|
|
392
|
+
context.addIssue({
|
|
393
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
394
|
+
message: 'externalMcp.resource cannot contain credentials, query or fragment',
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
}),
|
|
398
|
+
}).strict().optional(),
|
|
399
|
+
tools: zod_1.z.array(exports.catalogToolSchema),
|
|
400
|
+
events: zod_1.z.array(exports.catalogEventSchema),
|
|
401
|
+
}).strict().superRefine((catalog, context) => {
|
|
402
|
+
const names = new Set();
|
|
403
|
+
for (const [index, tool] of catalog.tools.entries()) {
|
|
404
|
+
if (names.has(tool.name)) {
|
|
405
|
+
context.addIssue({
|
|
406
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
407
|
+
message: `Duplicate tool name: ${tool.name}`,
|
|
408
|
+
path: ['tools', index, 'name'],
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
names.add(tool.name);
|
|
412
|
+
}
|
|
413
|
+
const eventTypes = new Set();
|
|
414
|
+
for (const [index, event] of catalog.events.entries()) {
|
|
415
|
+
if (eventTypes.has(event.type)) {
|
|
416
|
+
context.addIssue({
|
|
417
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
418
|
+
message: `Duplicate event type: ${event.type}`,
|
|
419
|
+
path: ['events', index, 'type'],
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
eventTypes.add(event.type);
|
|
423
|
+
}
|
|
424
|
+
});
|
|
425
|
+
exports.catalogRegistrationSchema = zod_1.z.object({
|
|
426
|
+
catalog: exports.appCapabilityCatalogSchema,
|
|
427
|
+
digest: zod_1.z.string().regex(/^[a-f0-9]{64}$/),
|
|
428
|
+
signature: nonEmptyStringSchema,
|
|
429
|
+
deployedAt: zod_1.z.string().datetime(),
|
|
430
|
+
}).strict();
|
|
431
|
+
exports.normalizedAppEventSchema = zod_1.z.object({
|
|
432
|
+
eventId: identifierSchema,
|
|
433
|
+
appId: identifierSchema,
|
|
434
|
+
accountId: identifierSchema,
|
|
435
|
+
resource: exports.resourceRefSchema,
|
|
436
|
+
type: identifierSchema,
|
|
437
|
+
occurredAt: zod_1.z.string().datetime(),
|
|
438
|
+
data: zod_1.z.record(zod_1.z.unknown()),
|
|
439
|
+
}).strict();
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.hubAuthorizeResultSchema = exports.hubAuthorizeRequestSchema = exports.hubActivateRequestSchema = exports.hubClaimRequestSchema = exports.hubSessionSchema = exports.browserHubRevokeResponseSchema = exports.browserHubErrorSchema = exports.browserHubResolveResponseSchema = exports.browserHubHandleResponseSchema = exports.browserHubHandleRequestSchema = exports.browserHubHandleSchema = exports.BROWSER_HUB_HANDLE_TTL_MS = exports.BROWSER_HUB_COOKIE_ATTRIBUTES = exports.BROWSER_HUB_COOKIE_NAME = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const deviceDirectory_1 = require("./deviceDirectory");
|
|
6
|
+
/**
|
|
7
|
+
* The browser DeviceSession hub at `auth.oxy.so` (issue #937, Phase 5, ADR 0003).
|
|
8
|
+
*
|
|
9
|
+
* Two wire surfaces live in this file and they are deliberately different
|
|
10
|
+
* shapes, because they answer to different callers:
|
|
11
|
+
*
|
|
12
|
+
* - The `browserHub*` schemas below the first divider are the API's
|
|
13
|
+
* (`api.oxy.so/session/browser-hub/*`), spoken ONLY by the IdP's own
|
|
14
|
+
* server/edge layer. They carry the raw handle and a bearer, so nothing that
|
|
15
|
+
* speaks them may run in a browser.
|
|
16
|
+
* - The `hub*` schemas below the second divider are the EDGE's
|
|
17
|
+
* (`auth.oxy.so/hub/*`), spoken by the IdP SPA. They carry neither: the
|
|
18
|
+
* handle stays in an `HttpOnly` cookie the script cannot read, and the
|
|
19
|
+
* device-wide bearer stays at the edge.
|
|
20
|
+
*
|
|
21
|
+
* That split is the whole point of the phase. A single schema covering both
|
|
22
|
+
* would let a refactor move a credential across the boundary without any type
|
|
23
|
+
* changing shape.
|
|
24
|
+
*
|
|
25
|
+
* ## What is NOT reopened here
|
|
26
|
+
*
|
|
27
|
+
* Relying-party origins remain zero-cookie: they keep `{deviceId,
|
|
28
|
+
* deviceSecret}` + `POST /session/device/token` and set no cookie of any kind.
|
|
29
|
+
* `auth.oxy.so` alone holds a handle, first-party only. There is no
|
|
30
|
+
* refresh-token family and no bootstrap hop.
|
|
31
|
+
*/
|
|
32
|
+
/* -------------------------------------------------------------------------- */
|
|
33
|
+
/* The cookie */
|
|
34
|
+
/* -------------------------------------------------------------------------- */
|
|
35
|
+
/**
|
|
36
|
+
* The one cookie name, `__Host-` prefixed.
|
|
37
|
+
*
|
|
38
|
+
* The prefix is not decoration: a browser refuses to store a `__Host-` cookie
|
|
39
|
+
* that carries a `Domain` attribute or a `Path` other than `/`, or that arrives
|
|
40
|
+
* without `Secure`. So the name itself is what makes "bound to `auth.oxy.so`
|
|
41
|
+
* alone, readable by no other `oxy.so` host" enforced by the client rather than
|
|
42
|
+
* merely intended by the server — including against a compromised sibling
|
|
43
|
+
* subdomain, which is the specific attack `Domain=.oxy.so` would have opened.
|
|
44
|
+
*/
|
|
45
|
+
exports.BROWSER_HUB_COOKIE_NAME = '__Host-oxy-device';
|
|
46
|
+
/**
|
|
47
|
+
* The exact attribute set the edge sets, in the order it writes them.
|
|
48
|
+
*
|
|
49
|
+
* Held as data rather than as a template string so a test can assert the set
|
|
50
|
+
* rather than a rendered line, and so removing one attribute is a diff to a
|
|
51
|
+
* named constant instead of an edit inside a string literal.
|
|
52
|
+
*
|
|
53
|
+
* `Max-Age` is deliberately NOT in this list — see
|
|
54
|
+
* {@link BROWSER_HUB_HANDLE_TTL_MS}, which the edge appends. Everything here is
|
|
55
|
+
* a SECURITY attribute and none of them is ever conditional.
|
|
56
|
+
*/
|
|
57
|
+
exports.BROWSER_HUB_COOKIE_ATTRIBUTES = ['Secure', 'HttpOnly', 'SameSite=Lax', 'Path=/'];
|
|
58
|
+
/**
|
|
59
|
+
* How long a hub handle lives, server-side and in the cookie alike.
|
|
60
|
+
*
|
|
61
|
+
* Thirty days. The cookie's `Max-Age` is derived from this same constant so the
|
|
62
|
+
* two cannot disagree: a cookie outliving its credential produces a browser that
|
|
63
|
+
* believes it is signed in and is refused on every call, and a credential
|
|
64
|
+
* outliving its cookie leaves an un-addressable row alive on the server.
|
|
65
|
+
*
|
|
66
|
+
* A hub handle is NOT a session cookie (one with no `Max-Age`, discarded when
|
|
67
|
+
* the browser closes). It cannot be: the thing it identifies is the browser
|
|
68
|
+
* PROFILE's device session, and a device session that evaporates when the user
|
|
69
|
+
* quits their browser would send them back to a QR scan every morning — the
|
|
70
|
+
* exact failure ADR 0003 exists to remove.
|
|
71
|
+
*/
|
|
72
|
+
exports.BROWSER_HUB_HANDLE_TTL_MS = 30 * 24 * 60 * 60 * 1000;
|
|
73
|
+
/* -------------------------------------------------------------------------- */
|
|
74
|
+
/* api.oxy.so/session/browser-hub/* — spoken by the edge, never a browser */
|
|
75
|
+
/* -------------------------------------------------------------------------- */
|
|
76
|
+
/**
|
|
77
|
+
* The raw handle, as it travels between the edge and the API.
|
|
78
|
+
*
|
|
79
|
+
* An opaque base64url random value and NOTHING else — no token, no user id, no
|
|
80
|
+
* device id, no account id, no serialized state. The server stores only
|
|
81
|
+
* `sha256(handle)`, so a dump of the column cannot address a browser.
|
|
82
|
+
*
|
|
83
|
+
* The minimum length is a floor against an empty or truncated value reaching a
|
|
84
|
+
* hash comparison, not a statement about the entropy: that is fixed by the
|
|
85
|
+
* issuer (`BROWSER_HUB_HANDLE_BYTES` in the API), and a handle is the only
|
|
86
|
+
* credential in this flow, so it is 256 bits.
|
|
87
|
+
*/
|
|
88
|
+
exports.browserHubHandleSchema = zod_1.z.string().min(32);
|
|
89
|
+
/** Request body of every handle-presenting API endpoint. */
|
|
90
|
+
exports.browserHubHandleRequestSchema = zod_1.z.object({
|
|
91
|
+
handle: exports.browserHubHandleSchema,
|
|
92
|
+
});
|
|
93
|
+
/**
|
|
94
|
+
* Response of `POST /session/browser-hub/establish` and `.../rotate`.
|
|
95
|
+
*
|
|
96
|
+
* The raw handle is returned exactly ONCE, to the edge, which puts it straight
|
|
97
|
+
* into the cookie and keeps no copy. It is never logged, never re-readable, and
|
|
98
|
+
* never reaches the browser's script context.
|
|
99
|
+
*/
|
|
100
|
+
exports.browserHubHandleResponseSchema = zod_1.z.object({
|
|
101
|
+
handle: exports.browserHubHandleSchema,
|
|
102
|
+
expiresAt: zod_1.z.string(),
|
|
103
|
+
});
|
|
104
|
+
/**
|
|
105
|
+
* Response of `POST /session/browser-hub/resolve` — the browser's device
|
|
106
|
+
* session, resolved from the handle alone.
|
|
107
|
+
*
|
|
108
|
+
* Carries a bearer because the edge needs one to run the authorize lane on the
|
|
109
|
+
* browser's behalf. It is the ordinary short-lived access token of the device's
|
|
110
|
+
* active context, and it stops at the edge.
|
|
111
|
+
*/
|
|
112
|
+
exports.browserHubResolveResponseSchema = zod_1.z.object({
|
|
113
|
+
accessToken: zod_1.z.string().min(1),
|
|
114
|
+
expiresAt: zod_1.z.string(),
|
|
115
|
+
directory: deviceDirectory_1.deviceDirectorySchema,
|
|
116
|
+
});
|
|
117
|
+
/**
|
|
118
|
+
* Why a handle did not resolve. A CLOSED set, and deliberately coarse.
|
|
119
|
+
*
|
|
120
|
+
* - `invalid_handle` — unknown, expired, or revoked. One code for all
|
|
121
|
+
* three: distinguishing them would tell a caller
|
|
122
|
+
* holding a guessed value whether it ever existed.
|
|
123
|
+
* - `no_active_session` — the handle is good and the device has nothing live
|
|
124
|
+
* to mint for. The credential is NOT revoked; the
|
|
125
|
+
* browser re-authenticates and keeps its cookie.
|
|
126
|
+
*/
|
|
127
|
+
exports.browserHubErrorSchema = zod_1.z.enum(['invalid_handle', 'no_active_session']);
|
|
128
|
+
/** Response of `POST /session/browser-hub/revoke`. Idempotent by construction. */
|
|
129
|
+
exports.browserHubRevokeResponseSchema = zod_1.z.object({
|
|
130
|
+
revoked: zod_1.z.boolean(),
|
|
131
|
+
});
|
|
132
|
+
/* -------------------------------------------------------------------------- */
|
|
133
|
+
/* auth.oxy.so/hub/* — spoken by the IdP SPA */
|
|
134
|
+
/* -------------------------------------------------------------------------- */
|
|
135
|
+
/**
|
|
136
|
+
* What the SPA is allowed to know about the hub session.
|
|
137
|
+
*
|
|
138
|
+
* `signed_out` covers "no cookie", "cookie present but the handle no longer
|
|
139
|
+
* resolves" and "resolved, but the device has nothing live" — from the script's
|
|
140
|
+
* side those are one state, and collapsing them here is what stops a UI from
|
|
141
|
+
* branching on a distinction it must not act on.
|
|
142
|
+
*
|
|
143
|
+
* `active` carries the DIRECTORY and no credential. A switcher renders from it;
|
|
144
|
+
* nothing in it can be spent against the API. The bearer that produced it never
|
|
145
|
+
* left the edge.
|
|
146
|
+
*/
|
|
147
|
+
exports.hubSessionSchema = zod_1.z.discriminatedUnion('status', [
|
|
148
|
+
zod_1.z.object({ status: zod_1.z.literal('signed_out') }),
|
|
149
|
+
zod_1.z.object({ status: zod_1.z.literal('active'), directory: deviceDirectory_1.deviceDirectorySchema }),
|
|
150
|
+
]);
|
|
151
|
+
/** Request body of `POST /hub/claim` — the Commons approval lane's handoff. */
|
|
152
|
+
exports.hubClaimRequestSchema = zod_1.z.object({
|
|
153
|
+
/**
|
|
154
|
+
* The secret `sessionToken` of an approved `AuthSession`, held only by the
|
|
155
|
+
* page that created it. The edge spends it server-side: the access token and
|
|
156
|
+
* device secret the claim yields are consumed to establish the hub and are
|
|
157
|
+
* then discarded, so neither is ever returned to the script.
|
|
158
|
+
*/
|
|
159
|
+
sessionToken: zod_1.z.string().min(1),
|
|
160
|
+
});
|
|
161
|
+
/** Request body of `POST /hub/activate` — pick the globally active context. */
|
|
162
|
+
exports.hubActivateRequestSchema = zod_1.z.object({
|
|
163
|
+
contextId: zod_1.z.string().min(1),
|
|
164
|
+
});
|
|
165
|
+
/**
|
|
166
|
+
* Request body of `POST /hub/authorize` — a later official origin joining.
|
|
167
|
+
*
|
|
168
|
+
* There is no `prompt` field, and that is not an omission. `'none'` is absent
|
|
169
|
+
* from `buildOAuthAuthorizeUrl`'s union in `@oxy.so/core` precisely so a silent
|
|
170
|
+
* loop cannot be rebuilt in one line, and this endpoint would be the second
|
|
171
|
+
* place to rebuild it. A caller that needs a login or consent prompt gets one
|
|
172
|
+
* by not passing `approve`.
|
|
173
|
+
*/
|
|
174
|
+
exports.hubAuthorizeRequestSchema = zod_1.z.object({
|
|
175
|
+
clientId: zod_1.z.string().min(1),
|
|
176
|
+
redirectUri: zod_1.z.string().url(),
|
|
177
|
+
state: zod_1.z.string().optional(),
|
|
178
|
+
codeChallenge: zod_1.z.string().min(1),
|
|
179
|
+
/** S256 only. `plain` is refused before the request leaves the edge. */
|
|
180
|
+
codeChallengeMethod: zod_1.z.literal('S256'),
|
|
181
|
+
scope: zod_1.z.string().optional(),
|
|
182
|
+
/**
|
|
183
|
+
* The user's explicit answer on the consent screen.
|
|
184
|
+
*
|
|
185
|
+
* Absent or `false` means "tell me whether consent is needed"; the edge then
|
|
186
|
+
* returns `consent_required` and mints nothing. Only `true` may mint, and only
|
|
187
|
+
* the consent screen's own button sends it — which is why the decision of
|
|
188
|
+
* WHETHER consent is required is re-read from the server on both passes rather
|
|
189
|
+
* than remembered from the first.
|
|
190
|
+
*/
|
|
191
|
+
approve: zod_1.z.boolean().optional(),
|
|
192
|
+
});
|
|
193
|
+
/**
|
|
194
|
+
* Result of `POST /hub/authorize`.
|
|
195
|
+
*
|
|
196
|
+
* `signed_out` is the honest answer for a browser with no hub session: the SPA
|
|
197
|
+
* runs the ordinary Commons-first authentication and tries again. It is never a
|
|
198
|
+
* redirect the edge performs on the browser's behalf — no automatic chain
|
|
199
|
+
* across Oxy origins, and nothing here can be hidden inside an iframe.
|
|
200
|
+
*/
|
|
201
|
+
exports.hubAuthorizeResultSchema = zod_1.z.discriminatedUnion('status', [
|
|
202
|
+
zod_1.z.object({ status: zod_1.z.literal('signed_out') }),
|
|
203
|
+
zod_1.z.object({
|
|
204
|
+
status: zod_1.z.literal('consent_required'),
|
|
205
|
+
reason: zod_1.z.enum(['new', 'scope_changed']),
|
|
206
|
+
userConsentScopes: zod_1.z.array(zod_1.z.string()).optional(),
|
|
207
|
+
}),
|
|
208
|
+
zod_1.z.object({
|
|
209
|
+
status: zod_1.z.literal('code'),
|
|
210
|
+
code: zod_1.z.string().min(1),
|
|
211
|
+
state: zod_1.z.string().nullable(),
|
|
212
|
+
redirectUri: zod_1.z.string(),
|
|
213
|
+
expiresIn: zod_1.z.number().int().positive(),
|
|
214
|
+
}),
|
|
215
|
+
]);
|