@oxy.so/contracts 4.10.0 → 4.11.0-oxy-one.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/esm/index.js CHANGED
@@ -14,7 +14,7 @@ export { ACCOUNT_ACTOR_NATURES, ACCOUNT_SUBJECT_CONTRACT_VERSION, FINANCIAL_EFFE
14
14
  export { usernameSchema, usernameSchemaForAccountKind, isValidUsername, stripDisallowedUsernameCharacters, applyBotUsernameSuffix, USERNAME_MIN_LENGTH, USERNAME_MAX_LENGTH, USERNAME_INVALID_MESSAGE, BOT_USERNAME_INVALID_MESSAGE, RESERVED_USERNAME_MESSAGE, NUMERIC_USERNAME_MESSAGE, } from './username.js';
15
15
  export {
16
16
  // Schemas
17
- userNameSchema, userRelationshipSchema, themePreferenceSchema, dateOfBirthSchema, userResponseSchema, userProfileUpdateSchema, currentUserResponseSchema, deviceLinkedSessionSchema, deviceLinkedSessionsResponseSchema,
17
+ userNameSchema, userRelationshipSchema, themePreferenceSchema, USER_PROFILE_COLOR_PRESETS, dateOfBirthSchema, userResponseSchema, userProfileUpdateSchema, currentUserResponseSchema, deviceLinkedSessionSchema, deviceLinkedSessionsResponseSchema,
18
18
  // Helpers
19
19
  resolveUserId, safeParseContract, } from './userResponse.js';
20
20
  export {
@@ -192,8 +192,10 @@ export { SCOPED_EXECUTION_CONTRACT_VERSION, SCOPED_REQUEST_ENVELOPE_VERSION, sco
192
192
  export { scopedInferenceRequestSchema } from './inference/request.js';
193
193
  export { PRIVATE_AUTO_EXECUTION_CONTRACT_VERSION, PRIVATE_AUTO_REQUEST_ENVELOPE_VERSION, PRIVATE_AUTO_LIMITS, PRIVATE_AUTO_INSTRUCTIONS, PRIVATE_AUTO_QUESTION, privateAutoPrincipalSchema, privateAutoSourceApprovalSchema, privateAutoExecutionSchema, privateAutoInputSchema, privateAutoOperationId, } from './inference/privateAutoExecution.js';
194
194
  export { privateAutoInferenceRequestSchema } from './inference/request.js';
195
- export { productDefinitionSchema, subjectProductAccessQuerySchema, productBenefitSchema, productOfferSchema, productSubscriptionSourceSchema, productAccessGrantSchema, productOfferSegmentSchema, subjectProductAccessSchema, } from './products/access.js';
195
+ export { productDefinitionSchema, subjectProductAccessQuerySchema, productBenefitSchema, productOfferSchema, productSubscriptionSourceSchema, productAccessGrantSchema, subjectProductGrantSnapshotSchema, productOfferSegmentSchema, subjectProductAccessSchema, } from './products/access.js';
196
196
  export { meteredGenerationSchema } from "./inference/economics.js";
197
197
  export { canonicalCapabilityJson, inputSatisfiesCapabilityLimits, isLoopbackOrigin } from './capabilityBindings.js';
198
198
  export * from './agentKeys.js';
199
199
  export { productSubscriptionSummarySchema, productSubscriptionsResponseSchema, subscriptionCreditGrantSchema, subscriptionCreditGrantsResponseSchema, cancelProductSubscriptionSchema, productSubscriptionCancellationResultSchema } from './products/billing.js';
200
+ export { personalPlanDisplayPriceSchema, personalPlanCatalogueSchema } from './products/plans.js';
201
+ export * from './products/checkout.js';
@@ -55,3 +55,34 @@ export const subjectProductAccessSchema = z.object({
55
55
  reason: z.enum(['combination_mismatch', 'unit_mismatch', 'exclusive_overlap', 'unsafe_total']),
56
56
  grantIds: z.array(identifier) }).strict()),
57
57
  }).strict();
58
+ /** Active grant periods for metering adapters; no financial/provider identity. */
59
+ export const subjectProductGrantSnapshotSchema = z.object({
60
+ schemaVersion: z.literal(1), access: subjectProductAccessSchema, grants: z.array(productAccessGrantSchema),
61
+ }).strict().superRefine((value, ctx) => {
62
+ const active = new Set([...value.access.capabilities, ...value.access.quotas].flatMap(entry => entry.grantIds));
63
+ if (active.size !== value.grants.length || new Set(value.grants.map(g => g.id)).size !== value.grants.length
64
+ || value.grants.some(g => g.beneficiaryAccountId !== value.access.subjectAccountId
65
+ || g.benefit.productId !== value.access.productId || !active.has(g.id)
66
+ // A future revocation is still active at evaluation time, as in access composition.
67
+ || (g.revokedAt !== null && Date.parse(g.revokedAt) <= Date.parse(value.access.evaluatedAt))
68
+ || Date.parse(g.period.start) > Date.parse(value.access.evaluatedAt)
69
+ || Date.parse(g.period.end) <= Date.parse(value.access.evaluatedAt)))
70
+ ctx.addIssue({ code: 'custom', message: 'Active grant snapshot attribution differs' });
71
+ for (const quota of value.access.quotas) {
72
+ const benefits = quota.grantIds.map(id => value.grants.find(g => g.id === id)?.benefit);
73
+ if (benefits.some(b => !b || b.kind !== 'quota' || b.key !== quota.key || b.unit !== quota.unit || b.combination !== quota.combination)) {
74
+ ctx.addIssue({ code: 'custom', message: 'Grant quota terms differ' });
75
+ continue;
76
+ }
77
+ const amounts = benefits.map(b => b?.kind === 'quota' ? BigInt(b.included) : 0n);
78
+ const included = quota.combination === 'sum' ? amounts.reduce((sum, n) => sum + n, 0n) : amounts.reduce((maximum, n) => n > maximum ? n : maximum, 0n);
79
+ if (included !== BigInt(quota.included) || (quota.combination === 'exclusive' && benefits.length > 1))
80
+ ctx.addIssue({ code: 'custom', message: 'Grant quota composition differs' });
81
+ }
82
+ for (const capability of value.access.capabilities)
83
+ if (capability.grantIds.some(id => {
84
+ const benefit = value.grants.find(g => g.id === id)?.benefit;
85
+ return benefit?.kind !== 'capability' || benefit.key !== capability.key;
86
+ }))
87
+ ctx.addIssue({ code: 'custom', message: 'Grant capability terms differ' });
88
+ });
@@ -21,7 +21,7 @@ export const subscriptionCreditGrantSchema = z.object({ id, invoiceId: id,
21
21
  promotionId: id.nullable(), createdAt: z.string().datetime(),
22
22
  }).strict().refine(value => BigInt(value.consumed) + BigInt(value.clawed) + BigInt(value.remaining) === BigInt(value.granted), 'Grant conservation differs');
23
23
  export const subscriptionCreditGrantsResponseSchema = z.object({ grants: z.array(subscriptionCreditGrantSchema) }).strict();
24
- export const cancelProductSubscriptionSchema = z.object({ sourceId: id, expectedSubjectAccountId: oxyAccountIdSchema.optional() }).strict();
24
+ export const cancelProductSubscriptionSchema = z.object({ sourceId: id, actionId: z.string().min(8).max(160).regex(/^[a-zA-Z0-9_-]+$/).optional(), expectedSubjectAccountId: oxyAccountIdSchema.optional() }).strict();
25
25
  /** Remote acceptance is distinct from completed local reconciliation. */
26
26
  export const productSubscriptionCancellationResultSchema = z.union([
27
27
  z.object({ sourceId: id, cancelAtPeriodEnd: z.literal(true) }).strict(),
@@ -0,0 +1,14 @@
1
+ import { z } from 'zod';
2
+ import { oxyAccountIdSchema } from '../inference/identifiers.js';
3
+ export const personalPlanCheckoutRequestSchema = z.object({
4
+ expectedSubjectAccountId: oxyAccountIdSchema,
5
+ offerId: z.string().min(1).max(160), offerVersion: z.number().int().positive().safe(),
6
+ idempotencyKey: z.string().min(8).max(160).regex(/^[a-zA-Z0-9_-]+$/),
7
+ }).strict();
8
+ /** No grant or subscription is created by checkout completion in the browser. */
9
+ export const personalPlanCheckoutResultSchema = z.discriminatedUnion('state', [
10
+ z.object({ state: z.literal('unconfigured'), reason: z.enum(['provider_unconfigured', 'offer_unconfigured', 'price_unconfigured']) }).strict(),
11
+ z.object({ state: z.literal('pending'), intentId: z.string().min(1).max(160), checkoutUrl: z.string().url().startsWith('https://') }).strict(),
12
+ z.object({ state: z.literal('closed'), intentId: z.string().min(1).max(160) }).strict(),
13
+ z.object({ state: z.literal('fulfilled'), intentId: z.string().min(1).max(160) }).strict(),
14
+ ]);
@@ -0,0 +1,20 @@
1
+ import { z } from 'zod';
2
+ import { productBenefitSchema } from './access.js';
3
+ /** Approved display terms never identify or activate a billing-provider price. */
4
+ export const personalPlanDisplayPriceSchema = z.object({ currency: z.string().regex(/^[A-Z]{3}$/),
5
+ amountMinorUnits: z.number().int().positive().safe(), interval: z.literal('month'), trial: z.literal('none'), taxTreatment: z.literal('inclusive'), merchantTotal: z.literal('final') }).strict();
6
+ /** Public discovery is separate from customer access. No provider or owner IDs. */
7
+ export const personalPlanCatalogueSchema = z.object({
8
+ schemaVersion: z.literal(1),
9
+ state: z.enum(['unconfigured', 'configured']),
10
+ purchase: z.literal('unavailable'),
11
+ plans: z.array(z.object({
12
+ offerId: z.string().min(1).max(160),
13
+ offerVersion: z.number().int().positive().safe(),
14
+ displayName: z.string().min(1).max(100),
15
+ audience: z.literal('personal'),
16
+ kind: z.literal('oxy_one'),
17
+ price: personalPlanDisplayPriceSchema.optional(),
18
+ benefits: z.array(z.object({ displayName: z.string().min(1).max(100), benefit: productBenefitSchema }).strict()),
19
+ }).strict()),
20
+ }).strict().refine(value => (value.state === 'unconfigured') === (value.plans.length === 0), 'Catalogue state must match published plans');
@@ -1,3 +1,5 @@
1
+ /** Canonical profile/theme preset identities accepted by Oxy writes. */
2
+ export const USER_PROFILE_COLOR_PRESETS = ['teal', 'blue', 'green', 'amber', 'red', 'purple', 'pink', 'sky', 'orange', 'mint', 'mono', 'oxy'];
1
3
  /**
2
4
  * Canonical API user-response contracts.
3
5
  *
@@ -220,6 +222,7 @@ export const userResponseSchema = z
220
222
  * `GET /session/user/:sessionId`) and absent until the user sets it.
221
223
  */
222
224
  themePreference: themePreferenceSchema.optional(),
225
+ personalization: z.object({ mentionMono: z.object({ allowed: z.boolean(), expiresAt: z.string().datetime().nullable() }).strict() }).strict().optional(),
223
226
  })
224
227
  .passthrough();
225
228
  export const userProfileUpdateSchema = z