@oxy.so/contracts 4.23.0 → 4.25.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/agency.js +33 -1
- package/dist/cjs/appAssertions.js +201 -0
- package/dist/cjs/client/appAssertions.js +80 -0
- package/dist/cjs/client/index.js +27 -1
- package/dist/cjs/index.js +10 -3
- package/dist/cjs/products/one.js +142 -0
- package/dist/esm/agency.js +32 -0
- package/dist/esm/appAssertions.js +191 -0
- package/dist/esm/client/appAssertions.js +77 -0
- package/dist/esm/client/index.js +2 -0
- package/dist/esm/index.js +3 -1
- package/dist/esm/products/one.js +137 -0
- package/dist/types/agency.d.ts +64 -0
- package/dist/types/appAssertions.d.ts +335 -0
- package/dist/types/client/appAssertions.d.ts +60 -0
- package/dist/types/client/index.d.ts +2 -0
- package/dist/types/index.d.ts +4 -2
- package/dist/types/inference/aliaModelRelease.d.ts +8 -8
- package/dist/types/inference/modelDocumentation.d.ts +8 -8
- package/dist/types/products/one.d.ts +250 -0
- package/dist/types/updates.d.ts +6 -6
- package/package.json +1 -1
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* App assertions (ADR 0045): how an Oxy app proves which app it is.
|
|
3
|
+
*
|
|
4
|
+
* ## The registry
|
|
5
|
+
*
|
|
6
|
+
* Each application may declare how it is recognised, written only by Oxy staff
|
|
7
|
+
* through the application administration lane
|
|
8
|
+
* (`PUT /applications/:appId/recognition`): its exact `https://` web origins,
|
|
9
|
+
* its Android package and signing certificates, and its iOS team and bundle.
|
|
10
|
+
* A platform it does not declare can never assert it.
|
|
11
|
+
*
|
|
12
|
+
* ## The exchange
|
|
13
|
+
*
|
|
14
|
+
* With the person's own bearer, the app asks `POST /apps/assertions` for an
|
|
15
|
+
* `OXY-APP+JWT` naming the application, and proves itself by platform: on the
|
|
16
|
+
* web the browser's `Origin`; on Android a Play Integrity token whose request
|
|
17
|
+
* hash is a challenge from `POST /apps/assertions/challenge`; on iOS an App
|
|
18
|
+
* Attest assertion over such a challenge, made with a key registered through
|
|
19
|
+
* `POST /apps/attest-keys`. The assertion lives five minutes and names the
|
|
20
|
+
* person (`sub`) and the session (`sid`) it was issued to.
|
|
21
|
+
*
|
|
22
|
+
* The Zod-free half (vocabularies, header name, response checks) is
|
|
23
|
+
* `./client/appAssertions.ts`.
|
|
24
|
+
*/
|
|
25
|
+
import { z } from 'zod';
|
|
26
|
+
import { APP_ASSERTION_CHALLENGE_PURPOSES, APP_ASSERTION_ERROR_CODES, APP_ASSERTION_PLATFORMS, OXY_APP_ASSERTION_AUDIENCE, OXY_APP_ASSERTION_HEADER, OXY_APP_ASSERTION_TTL_SECONDS, OXY_APP_ASSERTION_TYPE, } from './client/appAssertions.js';
|
|
27
|
+
export { APP_ASSERTION_CHALLENGE_PURPOSES, APP_ASSERTION_ERROR_CODES, APP_ASSERTION_PLATFORMS, OXY_APP_ASSERTION_AUDIENCE, OXY_APP_ASSERTION_HEADER, OXY_APP_ASSERTION_TTL_SECONDS, OXY_APP_ASSERTION_TYPE, };
|
|
28
|
+
const applicationIdSchema = z.string().trim().min(1).max(255);
|
|
29
|
+
const base64Url32Schema = z.string().regex(/^[A-Za-z0-9_-]{43}$/);
|
|
30
|
+
const base64Schema = (max) => z
|
|
31
|
+
.string()
|
|
32
|
+
.min(4)
|
|
33
|
+
.max(max)
|
|
34
|
+
.regex(/^[A-Za-z0-9+/]+={0,2}$/);
|
|
35
|
+
export const appAssertionPlatformSchema = z.enum(APP_ASSERTION_PLATFORMS);
|
|
36
|
+
export const appAssertionErrorCodeSchema = z.enum(APP_ASSERTION_ERROR_CODES);
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
// Registry
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
/** True for an exact origin: `https:`, no path, query, fragment or credentials, in canonical form. */
|
|
41
|
+
export function isExactHttpsOrigin(value) {
|
|
42
|
+
try {
|
|
43
|
+
const url = new URL(value);
|
|
44
|
+
return url.protocol === 'https:' && url.origin === value;
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/** An exact `https://` origin, in the form a browser sends in `Origin` (`https://mention.earth`). */
|
|
51
|
+
export const applicationWebOriginSchema = z
|
|
52
|
+
.string()
|
|
53
|
+
.max(255)
|
|
54
|
+
.refine(isExactHttpsOrigin, 'Must be an exact https origin, as a browser sends it');
|
|
55
|
+
/** A Java-style Android application id, at least two segments. */
|
|
56
|
+
export const androidPackageNameSchema = z
|
|
57
|
+
.string()
|
|
58
|
+
.max(255)
|
|
59
|
+
.regex(/^[A-Za-z][A-Za-z0-9_]*(?:\.[A-Za-z][A-Za-z0-9_]*)+$/, 'Must be an Android package name');
|
|
60
|
+
/** A signing certificate's SHA-256, 64 lowercase hex characters (keytool's digest without colons). */
|
|
61
|
+
export const signingCertSha256Schema = z
|
|
62
|
+
.string()
|
|
63
|
+
.regex(/^[0-9a-f]{64}$/, 'Must be 64 lowercase hex characters');
|
|
64
|
+
/** An Apple Developer team id. */
|
|
65
|
+
export const appleTeamIdSchema = z.string().regex(/^[A-Z0-9]{10}$/, 'Must be an Apple team id');
|
|
66
|
+
/** An Apple bundle id. */
|
|
67
|
+
export const appleBundleIdSchema = z
|
|
68
|
+
.string()
|
|
69
|
+
.max(255)
|
|
70
|
+
.regex(/^[A-Za-z0-9-]+(?:\.[A-Za-z0-9-]+)+$/, 'Must be an Apple bundle id');
|
|
71
|
+
const unique = (values) => new Set(values).size === values.length;
|
|
72
|
+
export const applicationAndroidRecognitionSchema = z
|
|
73
|
+
.object({
|
|
74
|
+
packageName: androidPackageNameSchema,
|
|
75
|
+
signingCertSha256: z
|
|
76
|
+
.array(signingCertSha256Schema)
|
|
77
|
+
.min(1)
|
|
78
|
+
.max(10)
|
|
79
|
+
.refine(unique, 'Certificates must be unique'),
|
|
80
|
+
})
|
|
81
|
+
.strict();
|
|
82
|
+
export const applicationIosRecognitionSchema = z
|
|
83
|
+
.object({ teamId: appleTeamIdSchema, bundleId: appleBundleIdSchema })
|
|
84
|
+
.strict();
|
|
85
|
+
/**
|
|
86
|
+
* What Oxy staff write for an application: the whole declaration, replaced at
|
|
87
|
+
* once. `null` and `[]` declare nothing for that platform.
|
|
88
|
+
*/
|
|
89
|
+
export const applicationRecognitionWriteSchema = z
|
|
90
|
+
.object({
|
|
91
|
+
webOrigins: z
|
|
92
|
+
.array(applicationWebOriginSchema)
|
|
93
|
+
.max(20)
|
|
94
|
+
.refine(unique, 'Origins must be unique'),
|
|
95
|
+
android: applicationAndroidRecognitionSchema.nullable(),
|
|
96
|
+
ios: applicationIosRecognitionSchema.nullable(),
|
|
97
|
+
})
|
|
98
|
+
.strict();
|
|
99
|
+
/** An application's recognition as the registry holds it; `updatedAt` is `null` when none was written. */
|
|
100
|
+
export const applicationRecognitionSchema = applicationRecognitionWriteSchema
|
|
101
|
+
.extend({
|
|
102
|
+
applicationId: applicationIdSchema,
|
|
103
|
+
updatedAt: z.string().datetime().nullable(),
|
|
104
|
+
})
|
|
105
|
+
.strict();
|
|
106
|
+
// ---------------------------------------------------------------------------
|
|
107
|
+
// The exchange
|
|
108
|
+
// ---------------------------------------------------------------------------
|
|
109
|
+
/** `POST /apps/assertions/challenge`: a single-use challenge for a device proof. */
|
|
110
|
+
export const appAssertionChallengeRequestSchema = z.discriminatedUnion('platform', [
|
|
111
|
+
z.object({ applicationId: applicationIdSchema, platform: z.literal('android') }).strict(),
|
|
112
|
+
z
|
|
113
|
+
.object({
|
|
114
|
+
applicationId: applicationIdSchema,
|
|
115
|
+
platform: z.literal('ios'),
|
|
116
|
+
purpose: z.enum(APP_ASSERTION_CHALLENGE_PURPOSES),
|
|
117
|
+
})
|
|
118
|
+
.strict(),
|
|
119
|
+
]);
|
|
120
|
+
/**
|
|
121
|
+
* The challenge, and `requestHash`: what the device signs or hands to Play
|
|
122
|
+
* Integrity, binding the challenge to this application, platform, purpose and
|
|
123
|
+
* session. `cloudProjectNumber` is the Google Cloud project Play Integrity
|
|
124
|
+
* tokens are requested for (Android only).
|
|
125
|
+
*/
|
|
126
|
+
export const appAssertionChallengeResponseSchema = z
|
|
127
|
+
.object({
|
|
128
|
+
challenge: base64Url32Schema,
|
|
129
|
+
requestHash: base64Url32Schema,
|
|
130
|
+
expiresAt: z.string().datetime(),
|
|
131
|
+
cloudProjectNumber: z
|
|
132
|
+
.string()
|
|
133
|
+
.regex(/^[0-9]{1,20}$/)
|
|
134
|
+
.optional(),
|
|
135
|
+
})
|
|
136
|
+
.strict();
|
|
137
|
+
/** An App Attest key id: the standard base64 of the SHA-256 of the key. */
|
|
138
|
+
export const appAttestKeyIdSchema = z.string().regex(/^[A-Za-z0-9+/]{43}=$/);
|
|
139
|
+
/** `POST /apps/attest-keys`: register an App Attest key, attested over a `attest_key` challenge. */
|
|
140
|
+
export const appAttestKeyRequestSchema = z
|
|
141
|
+
.object({
|
|
142
|
+
applicationId: applicationIdSchema,
|
|
143
|
+
keyId: appAttestKeyIdSchema,
|
|
144
|
+
challenge: base64Url32Schema,
|
|
145
|
+
attestation: base64Schema(32768),
|
|
146
|
+
})
|
|
147
|
+
.strict();
|
|
148
|
+
export const appAttestKeyResponseSchema = z.object({ keyId: appAttestKeyIdSchema }).strict();
|
|
149
|
+
/**
|
|
150
|
+
* `POST /apps/assertions`. The body names the application and the platform;
|
|
151
|
+
* the proof is the platform's: none on the web (the browser's `Origin` is), a
|
|
152
|
+
* Play Integrity token on Android, an App Attest assertion on iOS, each over a
|
|
153
|
+
* challenge minted for `assertion`.
|
|
154
|
+
*/
|
|
155
|
+
export const appAssertionRequestSchema = z.discriminatedUnion('platform', [
|
|
156
|
+
z.object({ applicationId: applicationIdSchema, platform: z.literal('web') }).strict(),
|
|
157
|
+
z
|
|
158
|
+
.object({
|
|
159
|
+
applicationId: applicationIdSchema,
|
|
160
|
+
platform: z.literal('android'),
|
|
161
|
+
proof: z
|
|
162
|
+
.object({
|
|
163
|
+
challenge: base64Url32Schema,
|
|
164
|
+
integrityToken: z.string().min(1).max(16384),
|
|
165
|
+
})
|
|
166
|
+
.strict(),
|
|
167
|
+
})
|
|
168
|
+
.strict(),
|
|
169
|
+
z
|
|
170
|
+
.object({
|
|
171
|
+
applicationId: applicationIdSchema,
|
|
172
|
+
platform: z.literal('ios'),
|
|
173
|
+
proof: z
|
|
174
|
+
.object({
|
|
175
|
+
challenge: base64Url32Schema,
|
|
176
|
+
keyId: appAttestKeyIdSchema,
|
|
177
|
+
assertion: base64Schema(4096),
|
|
178
|
+
})
|
|
179
|
+
.strict(),
|
|
180
|
+
})
|
|
181
|
+
.strict(),
|
|
182
|
+
]);
|
|
183
|
+
/** The assertion, and what it says. Send it as {@link OXY_APP_ASSERTION_HEADER}. */
|
|
184
|
+
export const appAssertionResponseSchema = z
|
|
185
|
+
.object({
|
|
186
|
+
assertion: z.string().regex(/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/),
|
|
187
|
+
applicationId: z.string().regex(/^\S{1,255}$/),
|
|
188
|
+
platform: appAssertionPlatformSchema,
|
|
189
|
+
expiresAt: z.string().datetime(),
|
|
190
|
+
})
|
|
191
|
+
.strict();
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* App assertions (ADR 0045), without Zod. Schemas: `../appAssertions.ts`.
|
|
3
|
+
*
|
|
4
|
+
* An Oxy app proves which app it is by trading platform evidence (the browser's
|
|
5
|
+
* `Origin`, a Play Integrity verdict, an App Attest assertion) for a short-lived
|
|
6
|
+
* `OXY-APP+JWT` signed by Oxy. A service that needs to know the app reads it
|
|
7
|
+
* from {@link OXY_APP_ASSERTION_HEADER} and verifies it against Oxy's JWKS
|
|
8
|
+
* (`verifyAppAssertion` in `@oxy.so/core/server`).
|
|
9
|
+
*
|
|
10
|
+
* Part of `@oxy.so/contracts/client`: never import `zod` here (see `./check.ts`).
|
|
11
|
+
*/
|
|
12
|
+
import { datetime, exact, oneOf, optional, pattern, strictObject, string } from './check.js';
|
|
13
|
+
/** How an app proves itself: the browser's origin, Play Integrity, or App Attest. */
|
|
14
|
+
export const APP_ASSERTION_PLATFORMS = ['web', 'android', 'ios'];
|
|
15
|
+
/**
|
|
16
|
+
* What a device challenge is spent on: an assertion, or (iOS only) registering
|
|
17
|
+
* an App Attest key. A challenge minted for one is refused for the other.
|
|
18
|
+
*/
|
|
19
|
+
export const APP_ASSERTION_CHALLENGE_PURPOSES = ['assertion', 'attest_key'];
|
|
20
|
+
/** The JOSE `typ` of an app assertion. No other Oxy token carries it. */
|
|
21
|
+
export const OXY_APP_ASSERTION_TYPE = 'OXY-APP+JWT';
|
|
22
|
+
/** The `aud` of every app assertion. */
|
|
23
|
+
export const OXY_APP_ASSERTION_AUDIENCE = 'oxy-apps';
|
|
24
|
+
/** The request header an app (or an SDK acting for it) sends the assertion in. */
|
|
25
|
+
export const OXY_APP_ASSERTION_HEADER = 'X-Oxy-App-Assertion';
|
|
26
|
+
/** Oxy signs an app assertion for exactly this long. */
|
|
27
|
+
export const OXY_APP_ASSERTION_TTL_SECONDS = 300;
|
|
28
|
+
/**
|
|
29
|
+
* Why Oxy refused an app assertion, a challenge or an App Attest key. The API
|
|
30
|
+
* answers `{ error: <code>, message }`.
|
|
31
|
+
*
|
|
32
|
+
* - `application_unavailable`: no active application has that id.
|
|
33
|
+
* - `session_other_application`: the bearer's session belongs to another application.
|
|
34
|
+
* - `platform_not_registered`: the application declares no recognition for that platform.
|
|
35
|
+
* - `origin_not_registered`: the request's `Origin` is not one of the application's web origins.
|
|
36
|
+
* - `challenge_invalid`: the challenge is unknown, used, expired, or minted for something else.
|
|
37
|
+
* - `integrity_refused`: the Play Integrity verdict does not name this app, a registered
|
|
38
|
+
* certificate, a Play-recognised install and this challenge.
|
|
39
|
+
* - `integrity_unconfigured` / `integrity_unavailable`: Oxy cannot ask Google (503).
|
|
40
|
+
* - `attest_key_unknown`: no App Attest key with that id is registered for the app; attest a new one.
|
|
41
|
+
* - `attest_key_exists`: that App Attest key is already registered.
|
|
42
|
+
* - `attestation_invalid`: the App Attest attestation does not verify.
|
|
43
|
+
* - `assertion_invalid`: the App Attest assertion does not verify, or its counter did not advance.
|
|
44
|
+
* - `signing_unavailable`: Oxy cannot sign (503).
|
|
45
|
+
*/
|
|
46
|
+
export const APP_ASSERTION_ERROR_CODES = [
|
|
47
|
+
'application_unavailable',
|
|
48
|
+
'session_other_application',
|
|
49
|
+
'platform_not_registered',
|
|
50
|
+
'origin_not_registered',
|
|
51
|
+
'challenge_invalid',
|
|
52
|
+
'integrity_refused',
|
|
53
|
+
'integrity_unconfigured',
|
|
54
|
+
'integrity_unavailable',
|
|
55
|
+
'attest_key_unknown',
|
|
56
|
+
'attest_key_exists',
|
|
57
|
+
'attestation_invalid',
|
|
58
|
+
'assertion_invalid',
|
|
59
|
+
'signing_unavailable',
|
|
60
|
+
];
|
|
61
|
+
/** 32 random bytes, base64url: a challenge, or the SHA-256 it is bound into. */
|
|
62
|
+
const BASE64URL_32 = /^[A-Za-z0-9_-]{43}$/;
|
|
63
|
+
/** An App Attest key id: the standard base64 of a SHA-256. */
|
|
64
|
+
const APP_ATTEST_KEY_ID = /^[A-Za-z0-9+/]{43}=$/;
|
|
65
|
+
export const appAssertionChallengeResponseCheck = exact()(strictObject({
|
|
66
|
+
challenge: string(pattern(BASE64URL_32)),
|
|
67
|
+
requestHash: string(pattern(BASE64URL_32)),
|
|
68
|
+
expiresAt: string(datetime),
|
|
69
|
+
cloudProjectNumber: optional(string(pattern(/^[0-9]{1,20}$/))),
|
|
70
|
+
}));
|
|
71
|
+
export const appAttestKeyResponseCheck = exact()(strictObject({ keyId: string(pattern(APP_ATTEST_KEY_ID)) }));
|
|
72
|
+
export const appAssertionResponseCheck = exact()(strictObject({
|
|
73
|
+
assertion: string(pattern(/^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$/)),
|
|
74
|
+
applicationId: string(pattern(/^\S{1,255}$/)),
|
|
75
|
+
platform: oneOf(APP_ASSERTION_PLATFORMS),
|
|
76
|
+
expiresAt: string(datetime),
|
|
77
|
+
}));
|
package/dist/esm/client/index.js
CHANGED
|
@@ -36,3 +36,5 @@ export { EMAIL_ACCOUNTS_MAX, EMAIL_SIGNIN_CHOICE_TTL_MS, EMAIL_SIGNIN_LINK_TTL_M
|
|
|
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';
|
|
37
37
|
export { userNameCheck } from './userResponse.js';
|
|
38
38
|
export { CLAIMANT_RELATIONSHIPS, CLOSED_CONTENT_CLAIM_STATES, CONTENT_CLAIM_COUNTER_NOTICE_LIMITS, CONTENT_CLAIM_ERROR_CODES, CONTENT_CLAIM_KINDS, CONTENT_CLAIM_LIMITS, CONTENT_CLAIM_REFERENCE_PATTERN, CONTENT_CLAIM_STATES, COUNTER_NOTICE_STATEMENT_VERSION, COUNTER_NOTICE_STATEMENTS, ERASURE_REQUEST_DEADLINE_DAYS, OPEN_CONTENT_CLAIM_STATES, isErasureRequest, isRightsClaim, } from './contentClaims.js';
|
|
39
|
+
export { APP_ASSERTION_CHALLENGE_PURPOSES, APP_ASSERTION_ERROR_CODES, APP_ASSERTION_PLATFORMS, OXY_APP_ASSERTION_AUDIENCE, OXY_APP_ASSERTION_HEADER, OXY_APP_ASSERTION_TTL_SECONDS, OXY_APP_ASSERTION_TYPE, appAssertionChallengeResponseCheck, appAssertionResponseCheck, appAttestKeyResponseCheck, } from './appAssertions.js';
|
|
40
|
+
export * from '../products/one.js';
|
package/dist/esm/index.js
CHANGED
|
@@ -180,7 +180,7 @@ 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, 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';
|
|
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, APPLICATION_AGENT_AVAILABILITIES, applicationAgentAvailabilitySchema, applicationAgentWriteSchema, applicationAgentSchema, agentAvailabilitySchema, 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';
|
|
@@ -208,3 +208,5 @@ export * from './safety.js';
|
|
|
208
208
|
export { serviceTokenScopesSchema, serviceTokenOptionsSchema, } from './serviceToken.js';
|
|
209
209
|
export * from './applicationRoles.js';
|
|
210
210
|
export * from './contentClaims.js';
|
|
211
|
+
export * from './appAssertions.js';
|
|
212
|
+
export * from './products/one.js';
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
export const OXY_ONE_ANNUAL_DISCOUNT = 20;
|
|
2
|
+
export const OXY_ONE_FAMILY_MEMBERS = 6;
|
|
3
|
+
export const OXY_ONE_AUDIENCE_THEMES = {
|
|
4
|
+
personal: 'one-plans-theme',
|
|
5
|
+
creator: 'one-creator-theme',
|
|
6
|
+
business: 'one-professional-theme',
|
|
7
|
+
};
|
|
8
|
+
/** Approved prices and credits; proposed storage capacities for the bundle design.
|
|
9
|
+
* USD minor units; credits renew monthly even on annual plans. Free 2 GB and Go 20 GB follow
|
|
10
|
+
* the new product direction; existing backend quotas are not changed here. */
|
|
11
|
+
export const OXY_ONE_PERSONAL_PLANS = {
|
|
12
|
+
Free: { monthlyPrice: 0, monthlyCredits: 0, creditDiscount: 0, storageGB: 2 },
|
|
13
|
+
Go: { monthlyPrice: 1500, monthlyCredits: 4000, creditDiscount: 5, storageGB: 20 },
|
|
14
|
+
Pro: { monthlyPrice: 2999, monthlyCredits: 10000, creditDiscount: 10, storageGB: 100 },
|
|
15
|
+
Max: { monthlyPrice: 9900, monthlyCredits: 50000, creditDiscount: 15, storageGB: 500 },
|
|
16
|
+
Ultra: { monthlyPrice: 40000, monthlyCredits: 200000, creditDiscount: 20, storageGB: 2000 },
|
|
17
|
+
};
|
|
18
|
+
/** A family quota belongs to the whole group, never multiplied by member count. */
|
|
19
|
+
export const OXY_ONE_FAMILY_PLANS = {
|
|
20
|
+
Go: { monthlyPrice: 2500, monthlyCredits: 8000, creditDiscount: 5, storageGB: 40 },
|
|
21
|
+
Pro: { monthlyPrice: 4900, monthlyCredits: 20000, creditDiscount: 10, storageGB: 200 },
|
|
22
|
+
Max: { monthlyPrice: 16900, monthlyCredits: 100000, creditDiscount: 15, storageGB: 1000 },
|
|
23
|
+
Ultra: { monthlyPrice: 59900, monthlyCredits: 300000, creditDiscount: 20, storageGB: 4000 },
|
|
24
|
+
};
|
|
25
|
+
export const OXY_ONE_BUSINESS_PLANS = {
|
|
26
|
+
Go: {
|
|
27
|
+
monthlyPrice: 3900,
|
|
28
|
+
monthlySeatPrice: 900,
|
|
29
|
+
monthlyCredits: 8000,
|
|
30
|
+
creditsPerSeat: 2000,
|
|
31
|
+
creditDiscount: 15,
|
|
32
|
+
storageGB: 20,
|
|
33
|
+
storagePerSeatGB: 5,
|
|
34
|
+
},
|
|
35
|
+
Pro: {
|
|
36
|
+
monthlyPrice: 9999,
|
|
37
|
+
monthlySeatPrice: 1900,
|
|
38
|
+
monthlyCredits: 25000,
|
|
39
|
+
creditsPerSeat: 5000,
|
|
40
|
+
creditDiscount: 25,
|
|
41
|
+
storageGB: 100,
|
|
42
|
+
storagePerSeatGB: 10,
|
|
43
|
+
},
|
|
44
|
+
Max: {
|
|
45
|
+
monthlyPrice: 19900,
|
|
46
|
+
monthlySeatPrice: 2900,
|
|
47
|
+
monthlyCredits: 60000,
|
|
48
|
+
creditsPerSeat: 8000,
|
|
49
|
+
creditDiscount: 30,
|
|
50
|
+
storageGB: 500,
|
|
51
|
+
storagePerSeatGB: 25,
|
|
52
|
+
},
|
|
53
|
+
Ultra: {
|
|
54
|
+
monthlyPrice: 59900,
|
|
55
|
+
monthlySeatPrice: 4900,
|
|
56
|
+
monthlyCredits: 200000,
|
|
57
|
+
creditsPerSeat: 15000,
|
|
58
|
+
creditDiscount: 35,
|
|
59
|
+
storageGB: 2000,
|
|
60
|
+
storagePerSeatGB: 50,
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
/** Verification, basic app access and model access are not subscription gates. */
|
|
64
|
+
export const OXY_ONE_CREATOR_PLANS = {
|
|
65
|
+
Go: { monthlyPrice: 2900, monthlyCredits: 10000, creditDiscount: 10, storageGB: 20 },
|
|
66
|
+
Pro: { monthlyPrice: 6900, monthlyCredits: 25000, creditDiscount: 15, storageGB: 100 },
|
|
67
|
+
Max: { monthlyPrice: 14900, monthlyCredits: 60000, creditDiscount: 20, storageGB: 500 },
|
|
68
|
+
Ultra: { monthlyPrice: 49900, monthlyCredits: 250000, creditDiscount: 25, storageGB: 2000 },
|
|
69
|
+
};
|
|
70
|
+
export function getOnePlans(audience, mode = 'individual') {
|
|
71
|
+
const plans = audience === 'business'
|
|
72
|
+
? OXY_ONE_BUSINESS_PLANS
|
|
73
|
+
: audience === 'creator'
|
|
74
|
+
? OXY_ONE_CREATOR_PLANS
|
|
75
|
+
: mode === 'family'
|
|
76
|
+
? OXY_ONE_FAMILY_PLANS
|
|
77
|
+
: OXY_ONE_PERSONAL_PLANS;
|
|
78
|
+
return Object.entries(plans).map(([name, plan]) => ({ name, ...plan }));
|
|
79
|
+
}
|
|
80
|
+
/** Each product owns its tier names; an Oxy One level selects an app subscription.
|
|
81
|
+
* Bundle inclusion is a proposal and does not activate product entitlements. */
|
|
82
|
+
export const OXY_ONE_APP_SUBSCRIPTIONS = {
|
|
83
|
+
alia: { name: 'Alia', tiers: { Free: null, Go: 'Go', Pro: 'Pro', Max: 'Max', Ultra: 'Ultra' } },
|
|
84
|
+
// Product-owned names; these bundle mappings remain a proposal.
|
|
85
|
+
mention: {
|
|
86
|
+
name: 'Mention',
|
|
87
|
+
tiers: { Free: null, Go: 'Plus', Pro: 'Plus', Max: 'Plus', Ultra: 'Plus' },
|
|
88
|
+
},
|
|
89
|
+
mercaria: {
|
|
90
|
+
name: 'Mercaria',
|
|
91
|
+
tiers: { Free: null, Go: 'Go', Pro: 'Plus', Max: 'Plus', Ultra: 'Ultra' },
|
|
92
|
+
creatorTiers: { Free: null, Go: 'Creator', Pro: 'Creator', Max: 'Creator', Ultra: 'Creator' },
|
|
93
|
+
},
|
|
94
|
+
noted: { name: 'Noted', tiers: { Free: null, Go: '+', Pro: '+', Max: '+', Ultra: '+' } },
|
|
95
|
+
clarity: {
|
|
96
|
+
name: 'Clarity',
|
|
97
|
+
tiers: { Free: null, Go: null, Pro: 'Plus', Max: 'Plus', Ultra: 'Plus' },
|
|
98
|
+
},
|
|
99
|
+
schedio: {
|
|
100
|
+
name: 'Schedio',
|
|
101
|
+
tiers: { Free: null, Go: null, Pro: 'Plus', Max: 'Plus', Ultra: 'Plus' },
|
|
102
|
+
},
|
|
103
|
+
inbox: {
|
|
104
|
+
name: 'Inbox',
|
|
105
|
+
tiers: { Free: null, Go: null, Pro: 'Plus', Max: 'Plus', Ultra: 'Plus' },
|
|
106
|
+
},
|
|
107
|
+
homiio: {
|
|
108
|
+
name: 'Homiio',
|
|
109
|
+
tiers: { Free: null, Go: 'Plus', Pro: 'Plus', Max: 'Plus', Ultra: 'Plus' },
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
/** Annual rounding follows the billable base and per-seat line items. */
|
|
113
|
+
export function onePlanQuote(plan, period, seats) {
|
|
114
|
+
const annual = (value) => Math.round(value * 12 * (1 - OXY_ONE_ANNUAL_DISCOUNT / 100));
|
|
115
|
+
const baseAnnual = annual(plan.monthlyPrice);
|
|
116
|
+
const seatAnnual = plan.monthlySeatPrice === undefined ? undefined : annual(plan.monthlySeatPrice);
|
|
117
|
+
const known = plan.monthlySeatPrice === undefined || seats !== undefined;
|
|
118
|
+
const totalAnnual = known ? baseAnnual + (seatAnnual ?? 0) * (seats ?? 0) : undefined;
|
|
119
|
+
return {
|
|
120
|
+
baseMonthly: period === 'annual' ? Math.round(baseAnnual / 12) : plan.monthlyPrice,
|
|
121
|
+
seatMonthly: seatAnnual === undefined
|
|
122
|
+
? undefined
|
|
123
|
+
: period === 'annual'
|
|
124
|
+
? Math.round(seatAnnual / 12)
|
|
125
|
+
: plan.monthlySeatPrice,
|
|
126
|
+
totalMonthly: totalAnnual === undefined
|
|
127
|
+
? undefined
|
|
128
|
+
: period === 'annual'
|
|
129
|
+
? Math.round(totalAnnual / 12)
|
|
130
|
+
: plan.monthlyPrice + (plan.monthlySeatPrice ?? 0) * (seats ?? 0),
|
|
131
|
+
totalAnnual,
|
|
132
|
+
storageGB: known ? plan.storageGB + (plan.storagePerSeatGB ?? 0) * (seats ?? 0) : undefined,
|
|
133
|
+
monthlyCredits: known
|
|
134
|
+
? plan.monthlyCredits + (plan.creditsPerSeat ?? 0) * (seats ?? 0)
|
|
135
|
+
: undefined,
|
|
136
|
+
};
|
|
137
|
+
}
|
package/dist/types/agency.d.ts
CHANGED
|
@@ -533,6 +533,66 @@ export declare const agentRequesterCeilingSchema: z.ZodObject<{
|
|
|
533
533
|
key: string;
|
|
534
534
|
}[] | undefined;
|
|
535
535
|
}>;
|
|
536
|
+
/**
|
|
537
|
+
* Where an application's own agent opens (ADR 0044): `anywhere`, or only in
|
|
538
|
+
* sessions that belong to that application (`own_application`). An agent with
|
|
539
|
+
* no application row is available anywhere.
|
|
540
|
+
*/
|
|
541
|
+
export declare const APPLICATION_AGENT_AVAILABILITIES: readonly ["anywhere", "own_application"];
|
|
542
|
+
export declare const applicationAgentAvailabilitySchema: z.ZodEnum<["anywhere", "own_application"]>;
|
|
543
|
+
/** What Oxy staff write for one of an application's agents. */
|
|
544
|
+
export declare const applicationAgentWriteSchema: z.ZodObject<{
|
|
545
|
+
availability: z.ZodEnum<["anywhere", "own_application"]>;
|
|
546
|
+
}, "strict", z.ZodTypeAny, {
|
|
547
|
+
availability: "anywhere" | "own_application";
|
|
548
|
+
}, {
|
|
549
|
+
availability: "anywhere" | "own_application";
|
|
550
|
+
}>;
|
|
551
|
+
/** One row of the application registry's agents: an agent is one application's. */
|
|
552
|
+
export declare const applicationAgentSchema: z.ZodObject<{
|
|
553
|
+
availability: z.ZodEnum<["anywhere", "own_application"]>;
|
|
554
|
+
} & {
|
|
555
|
+
applicationId: z.ZodString;
|
|
556
|
+
agentAccountId: z.ZodString;
|
|
557
|
+
createdByUserId: z.ZodNullable<z.ZodString>;
|
|
558
|
+
createdAt: z.ZodString;
|
|
559
|
+
updatedAt: z.ZodString;
|
|
560
|
+
}, "strict", z.ZodTypeAny, {
|
|
561
|
+
createdAt: string;
|
|
562
|
+
updatedAt: string;
|
|
563
|
+
applicationId: string;
|
|
564
|
+
agentAccountId: string;
|
|
565
|
+
availability: "anywhere" | "own_application";
|
|
566
|
+
createdByUserId: string | null;
|
|
567
|
+
}, {
|
|
568
|
+
createdAt: string;
|
|
569
|
+
updatedAt: string;
|
|
570
|
+
applicationId: string;
|
|
571
|
+
agentAccountId: string;
|
|
572
|
+
availability: "anywhere" | "own_application";
|
|
573
|
+
createdByUserId: string | null;
|
|
574
|
+
}>;
|
|
575
|
+
/**
|
|
576
|
+
* `GET /capabilities/agent-availability/:agentAccountId`: the sessions an agent
|
|
577
|
+
* is reachable from. `anywhere: false` lists the applications whose sessions
|
|
578
|
+
* (the session validation answer's `applicationId`) may reach it.
|
|
579
|
+
*/
|
|
580
|
+
export declare const agentAvailabilitySchema: z.ZodDiscriminatedUnion<"anywhere", [z.ZodObject<{
|
|
581
|
+
anywhere: z.ZodLiteral<true>;
|
|
582
|
+
}, "strict", z.ZodTypeAny, {
|
|
583
|
+
anywhere: true;
|
|
584
|
+
}, {
|
|
585
|
+
anywhere: true;
|
|
586
|
+
}>, z.ZodObject<{
|
|
587
|
+
anywhere: z.ZodLiteral<false>;
|
|
588
|
+
applicationIds: z.ZodArray<z.ZodString, "many">;
|
|
589
|
+
}, "strict", z.ZodTypeAny, {
|
|
590
|
+
anywhere: false;
|
|
591
|
+
applicationIds: string[];
|
|
592
|
+
}, {
|
|
593
|
+
anywhere: false;
|
|
594
|
+
applicationIds: string[];
|
|
595
|
+
}>]>;
|
|
536
596
|
export declare const automationTriggerSchema: z.ZodDiscriminatedUnion<"type", [z.ZodObject<{
|
|
537
597
|
type: z.ZodLiteral<"manual">;
|
|
538
598
|
}, "strict", z.ZodTypeAny, {
|
|
@@ -3286,5 +3346,9 @@ export type CatalogInternalTransport = (typeof CATALOG_INTERNAL_TRANSPORTS)[numb
|
|
|
3286
3346
|
export type AgentRequesterCeilingWrite = z.infer<typeof agentRequesterCeilingWriteSchema>;
|
|
3287
3347
|
export type AgentRequesterCeiling = z.infer<typeof agentRequesterCeilingSchema>;
|
|
3288
3348
|
export type AgentRequesterCeilingAutonomy = (typeof AGENT_REQUESTER_CEILING_AUTONOMY)[number];
|
|
3349
|
+
export type ApplicationAgentAvailability = (typeof APPLICATION_AGENT_AVAILABILITIES)[number];
|
|
3350
|
+
export type ApplicationAgentWrite = z.infer<typeof applicationAgentWriteSchema>;
|
|
3351
|
+
export type ApplicationAgent = z.infer<typeof applicationAgentSchema>;
|
|
3352
|
+
export type AgentAvailability = z.infer<typeof agentAvailabilitySchema>;
|
|
3289
3353
|
export type CatalogRegistration = z.infer<typeof catalogRegistrationSchema>;
|
|
3290
3354
|
export type NormalizedAppEvent = z.infer<typeof normalizedAppEventSchema>;
|