@oxy.so/contracts 4.11.0-oxy-one.0 → 4.12.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/.tsbuildinfo +1 -1
- package/dist/cjs/accountGraph.js +5 -3
- package/dist/cjs/agency.js +178 -96
- package/dist/cjs/agentKeys.js +80 -26
- package/dist/cjs/capabilityBindings.js +2 -2
- package/dist/cjs/capabilityInvocation.js +3 -1
- package/dist/cjs/commonsSignIn.js +2 -2
- package/dist/cjs/deviceSession.js +5 -1
- package/dist/cjs/email/messages.js +70 -4
- package/dist/cjs/emailAgentContext.js +16 -8
- package/dist/cjs/externalIdentity.js +30 -12
- package/dist/cjs/identity.js +14 -6
- package/dist/cjs/identityLink.js +7 -2
- package/dist/cjs/identityProof.js +2 -1
- package/dist/cjs/index.js +12 -8
- package/dist/cjs/inference/catalogue.js +2 -12
- package/dist/cjs/inference/decisions.js +102 -83
- package/dist/cjs/inference/economics.js +15 -5
- package/dist/cjs/inference/embeddings.js +44 -6
- package/dist/cjs/inference/identifiers.js +14 -1
- package/dist/cjs/inference/inbox.js +33 -2
- package/dist/cjs/inference/providerConnection.js +21 -6
- package/dist/cjs/inference/realtime.js +114 -107
- package/dist/cjs/inference/routingPolicy.js +17 -0
- package/dist/cjs/inference/scopedExecution.js +12 -12
- package/dist/cjs/inference/usage.js +10 -9
- package/dist/cjs/inference/version.js +1 -1
- package/dist/cjs/notifications.js +25 -5
- package/dist/cjs/oauth.js +30 -14
- package/dist/cjs/oxyRecordTypes.js +2 -2
- package/dist/cjs/products/access.js +146 -57
- package/dist/cjs/products/billing.js +71 -17
- package/dist/cjs/products/checkout.js +24 -6
- package/dist/cjs/products/plans.js +22 -7
- package/dist/cjs/recommendations.js +4 -6
- package/dist/cjs/reputation.js +3 -6
- package/dist/cjs/sessionStatus.js +1 -6
- package/dist/cjs/signIn.js +17 -4
- package/dist/cjs/transparency.js +3 -1
- package/dist/cjs/updates.js +2 -4
- package/dist/cjs/userResponse.js +27 -7
- package/dist/cjs/username.js +3 -1
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/accountGraph.js +5 -3
- package/dist/esm/agency.js +178 -96
- package/dist/esm/agentKeys.js +80 -26
- package/dist/esm/capabilityBindings.js +2 -2
- package/dist/esm/capabilityInvocation.js +3 -1
- package/dist/esm/commonsSignIn.js +2 -2
- package/dist/esm/deviceSession.js +5 -1
- package/dist/esm/email/messages.js +69 -3
- package/dist/esm/emailAgentContext.js +16 -8
- package/dist/esm/externalIdentity.js +30 -12
- package/dist/esm/identity.js +14 -6
- package/dist/esm/identityLink.js +7 -2
- package/dist/esm/identityProof.js +2 -1
- package/dist/esm/index.js +10 -8
- package/dist/esm/inference/aliaModelRelease.js +1 -1
- package/dist/esm/inference/catalogue.js +3 -13
- package/dist/esm/inference/decisions.js +108 -89
- package/dist/esm/inference/economics.js +16 -6
- package/dist/esm/inference/embeddings.js +44 -6
- package/dist/esm/inference/identifiers.js +13 -0
- package/dist/esm/inference/inbox.js +32 -1
- package/dist/esm/inference/providerConnection.js +21 -6
- package/dist/esm/inference/realtime.js +123 -116
- package/dist/esm/inference/routingPolicy.js +18 -1
- package/dist/esm/inference/scopedExecution.js +15 -15
- package/dist/esm/inference/usage.js +11 -10
- package/dist/esm/inference/version.js +1 -1
- package/dist/esm/notifications.js +25 -5
- package/dist/esm/oauth.js +30 -14
- package/dist/esm/oxyRecordTypes.js +2 -2
- package/dist/esm/products/access.js +146 -57
- package/dist/esm/products/billing.js +71 -17
- package/dist/esm/products/checkout.js +24 -6
- package/dist/esm/products/plans.js +22 -7
- package/dist/esm/recommendations.js +4 -6
- package/dist/esm/reputation.js +3 -6
- package/dist/esm/sessionStatus.js +1 -6
- package/dist/esm/signIn.js +17 -4
- package/dist/esm/transparency.js +3 -1
- package/dist/esm/updates.js +2 -4
- package/dist/esm/userResponse.js +27 -7
- package/dist/esm/username.js +3 -1
- package/dist/types/.tsbuildinfo +1 -1
- package/dist/types/accountGraph.d.ts +1 -1
- package/dist/types/accountSubject.d.ts +4 -4
- package/dist/types/commonsSignIn.d.ts +2 -2
- package/dist/types/email/messages.d.ts +208 -2
- package/dist/types/identity.d.ts +1 -1
- package/dist/types/index.d.ts +10 -10
- package/dist/types/inference/accountBilling.d.ts +2 -2
- package/dist/types/inference/decisions.d.ts +21 -1
- package/dist/types/inference/identifiers.d.ts +14 -0
- package/dist/types/inference/inbox.d.ts +129 -5
- package/dist/types/inference/realtime.d.ts +19 -1
- package/dist/types/inference/request.d.ts +54 -0
- package/dist/types/inference/routingPolicy.d.ts +10 -0
- package/dist/types/inference/scopedExecution.d.ts +1 -1
- package/dist/types/inference/usage.d.ts +12 -0
- package/dist/types/inference/version.d.ts +1 -1
- package/dist/types/moderationReputation.d.ts +1 -1
- package/dist/types/oxyRecordTypes.d.ts +2 -2
- package/dist/types/products/access.d.ts +102 -102
- package/dist/types/products/checkout.d.ts +3 -3
- package/dist/types/products/plans.d.ts +40 -40
- package/dist/types/reputation.d.ts +4 -4
- package/dist/types/updates.d.ts +1 -1
- package/dist/types/userResponse.d.ts +22 -23
- package/package.json +1 -2
|
@@ -6,7 +6,7 @@ const zod_1 = require("zod");
|
|
|
6
6
|
const identifiers_1 = require("./identifiers");
|
|
7
7
|
const money_1 = require("./money");
|
|
8
8
|
/** Explicit extension negotiation; never replaces the legacy 3.5 handshake. */
|
|
9
|
-
exports.SCOPED_EXECUTION_CONTRACT_VERSION =
|
|
9
|
+
exports.SCOPED_EXECUTION_CONTRACT_VERSION = '3.6.0';
|
|
10
10
|
/** Scoped only; normal envelope v2 and metadata 3.5 remain unchanged. */
|
|
11
11
|
exports.SCOPED_REQUEST_ENVELOPE_VERSION = 3;
|
|
12
12
|
const identity = zod_1.z.string().min(1).max(256);
|
|
@@ -14,10 +14,10 @@ const sha256 = zod_1.z.string().regex(/^[0-9a-f]{64}$/);
|
|
|
14
14
|
const maxCost = money_1.exactDecimalSchema.refine((value) => {
|
|
15
15
|
if (!money_1.exactDecimalSchema.safeParse(value).success)
|
|
16
16
|
return false;
|
|
17
|
-
const [whole, fraction =
|
|
18
|
-
const units = BigInt(whole) * 1000000000000n + BigInt(fraction.padEnd(12,
|
|
17
|
+
const [whole, fraction = ''] = value.split('.');
|
|
18
|
+
const units = BigInt(whole) * 1000000000000n + BigInt(fraction.padEnd(12, '0'));
|
|
19
19
|
return units > 0n && units <= 10000000000n;
|
|
20
|
-
},
|
|
20
|
+
}, 'scoped cost must be positive and at most 0.01 USD');
|
|
21
21
|
/** Restriction only: none of these identities grants catalogue eligibility. */
|
|
22
22
|
exports.scopedExecutionAudienceSchema = zod_1.z
|
|
23
23
|
.object({
|
|
@@ -42,7 +42,7 @@ exports.scopedExecutionAudienceSchema = zod_1.z
|
|
|
42
42
|
deploymentId: identifiers_1.deploymentIdSchema,
|
|
43
43
|
provider: identifiers_1.inferenceProviderSlugSchema,
|
|
44
44
|
keyId: identity,
|
|
45
|
-
modelReference: identifiers_1.modelReferenceSchema.refine((value) => value.includes(
|
|
45
|
+
modelReference: identifiers_1.modelReferenceSchema.refine((value) => value.includes('@'), 'must pin a revision'),
|
|
46
46
|
upstreamModelId: identity,
|
|
47
47
|
priceVersionId: identity,
|
|
48
48
|
providerRateCardVersionId: identity,
|
|
@@ -63,25 +63,25 @@ exports.scopedExecutionSchema = exports.scopedExecutionAudienceSchema
|
|
|
63
63
|
* reparsed/defaulted decision. Reject non-JSON values rather than dropping them.
|
|
64
64
|
*/
|
|
65
65
|
function canonicalScopedExecutionJson(value) {
|
|
66
|
-
if (value === null || typeof value ===
|
|
66
|
+
if (value === null || typeof value === 'string' || typeof value === 'boolean')
|
|
67
67
|
return JSON.stringify(value);
|
|
68
|
-
if (typeof value ===
|
|
68
|
+
if (typeof value === 'number' && Number.isFinite(value))
|
|
69
69
|
return JSON.stringify(value);
|
|
70
70
|
if (Array.isArray(value)) {
|
|
71
71
|
const entries = Array.from(value, (entry, index) => {
|
|
72
72
|
if (!(index in value))
|
|
73
|
-
throw new Error(
|
|
73
|
+
throw new Error('Scoped execution requires dense JSON arrays.');
|
|
74
74
|
return canonicalScopedExecutionJson(entry);
|
|
75
75
|
});
|
|
76
|
-
return `[${entries.join(
|
|
76
|
+
return `[${entries.join(',')}]`;
|
|
77
77
|
}
|
|
78
|
-
if (typeof value ===
|
|
78
|
+
if (typeof value === 'object' &&
|
|
79
79
|
value !== null &&
|
|
80
80
|
Object.getPrototypeOf(value) === Object.prototype) {
|
|
81
81
|
const entries = Object.keys(value)
|
|
82
82
|
.sort()
|
|
83
83
|
.map((key) => `${JSON.stringify(key)}:${canonicalScopedExecutionJson(value[key])}`);
|
|
84
|
-
return `{${entries.join(
|
|
84
|
+
return `{${entries.join(',')}}`;
|
|
85
85
|
}
|
|
86
|
-
throw new Error(
|
|
86
|
+
throw new Error('Scoped execution requires JSON wire values.');
|
|
87
87
|
}
|
|
@@ -65,12 +65,7 @@ exports.usageReservationRequestSchema = zod_1.z.object({
|
|
|
65
65
|
expiresInSeconds: zod_1.z.number().int().positive().max(86400),
|
|
66
66
|
});
|
|
67
67
|
/** Lifecycle of a hold. Terminal states are `settled`, `released`, `expired`. */
|
|
68
|
-
exports.usageReservationStatusSchema = zod_1.z.enum([
|
|
69
|
-
'held',
|
|
70
|
-
'settled',
|
|
71
|
-
'released',
|
|
72
|
-
'expired',
|
|
73
|
-
]);
|
|
68
|
+
exports.usageReservationStatusSchema = zod_1.z.enum(['held', 'settled', 'released', 'expired']);
|
|
74
69
|
/**
|
|
75
70
|
* A hold placed against an account's balance.
|
|
76
71
|
*
|
|
@@ -178,6 +173,14 @@ exports.normalizedUsageReportSchema = zod_1.z
|
|
|
178
173
|
deploymentId: identifiers_1.deploymentIdSchema,
|
|
179
174
|
/** How many allowed route switches occurred while serving this request. */
|
|
180
175
|
routeSwitches: zod_1.z.number().int().nonnegative().max(100),
|
|
176
|
+
/**
|
|
177
|
+
* The funding tier of the platform key that served the final attempt, as
|
|
178
|
+
* the data plane states it (ADR 0038). Absent when the key's economics
|
|
179
|
+
* were never stated, when a customer credential served, or when nothing
|
|
180
|
+
* was served. Oxy reads it to account for what the request cost the
|
|
181
|
+
* platform; it is never a key identity and never reaches a customer.
|
|
182
|
+
*/
|
|
183
|
+
fundingTier: identifiers_1.inferenceFundingTierSchema.optional(),
|
|
181
184
|
startedAt: identifiers_1.inferenceTimestampSchema,
|
|
182
185
|
completedAt: identifiers_1.inferenceTimestampSchema,
|
|
183
186
|
timeToFirstTokenMs: zod_1.z.number().int().nonnegative().safe().optional(),
|
|
@@ -270,9 +273,7 @@ exports.usageReceiptSchema = zod_1.z
|
|
|
270
273
|
* ledger accounts and only the second one is visible on an invoice.
|
|
271
274
|
*/
|
|
272
275
|
exports.usageRefundSubjectSchema = zod_1.z.discriminatedUnion('kind', [
|
|
273
|
-
zod_1.z
|
|
274
|
-
.object({ kind: zod_1.z.literal('reservation'), reservationId: zod_1.z.string().min(1).max(128) })
|
|
275
|
-
.strict(),
|
|
276
|
+
zod_1.z.object({ kind: zod_1.z.literal('reservation'), reservationId: zod_1.z.string().min(1).max(128) }).strict(),
|
|
276
277
|
zod_1.z.object({ kind: zod_1.z.literal('receipt'), receiptId: zod_1.z.string().min(1).max(128) }).strict(),
|
|
277
278
|
]);
|
|
278
279
|
/** Why money was given back or a hold was released. */
|
|
@@ -102,4 +102,4 @@ exports.INFERENCE_CONTRACT_VERSION = void 0;
|
|
|
102
102
|
* change to, say, the catalogue reject every in-flight inference request; the
|
|
103
103
|
* per-shape `schemaVersion` is what a message is validated against.
|
|
104
104
|
*/
|
|
105
|
-
exports.INFERENCE_CONTRACT_VERSION = '3.
|
|
105
|
+
exports.INFERENCE_CONTRACT_VERSION = '3.8.0';
|
|
@@ -64,18 +64,38 @@ exports.createOxyNotificationRequestSchema = zod_1.z
|
|
|
64
64
|
.superRefine((value, context) => {
|
|
65
65
|
if (value.type === 'system') {
|
|
66
66
|
if (value.actorId !== value.recipientId)
|
|
67
|
-
context.addIssue({
|
|
67
|
+
context.addIssue({
|
|
68
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
69
|
+
path: ['actorId'],
|
|
70
|
+
message: "a system notification is from the recipient's own account",
|
|
71
|
+
});
|
|
68
72
|
if (!value.title)
|
|
69
|
-
context.addIssue({
|
|
73
|
+
context.addIssue({
|
|
74
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
75
|
+
path: ['title'],
|
|
76
|
+
message: 'title is required for a system notification',
|
|
77
|
+
});
|
|
70
78
|
if (!value.message)
|
|
71
|
-
context.addIssue({
|
|
79
|
+
context.addIssue({
|
|
80
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
81
|
+
path: ['message'],
|
|
82
|
+
message: 'message is required for a system notification',
|
|
83
|
+
});
|
|
72
84
|
}
|
|
73
85
|
else {
|
|
74
86
|
if (value.url !== undefined) {
|
|
75
|
-
context.addIssue({
|
|
87
|
+
context.addIssue({
|
|
88
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
89
|
+
path: ['url'],
|
|
90
|
+
message: 'url is only stored for a system notification',
|
|
91
|
+
});
|
|
76
92
|
}
|
|
77
93
|
if (value.entityType === 'app') {
|
|
78
|
-
context.addIssue({
|
|
94
|
+
context.addIssue({
|
|
95
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
96
|
+
path: ['entityType'],
|
|
97
|
+
message: "entityType 'app' is only valid for a system notification",
|
|
98
|
+
});
|
|
79
99
|
}
|
|
80
100
|
}
|
|
81
101
|
});
|
package/dist/cjs/oauth.js
CHANGED
|
@@ -71,45 +71,61 @@ exports.oauthAuthorizeCodeResponseSchema = zod_1.z.object({
|
|
|
71
71
|
* Reuses the ordinary public application projection and adds only the public
|
|
72
72
|
* DCR client id needed to bind the consent surface to the request.
|
|
73
73
|
*/
|
|
74
|
-
exports.mcpOAuthClientApplicationSchema = sessionStatus_1.publicApplicationSchema
|
|
74
|
+
exports.mcpOAuthClientApplicationSchema = sessionStatus_1.publicApplicationSchema
|
|
75
|
+
.extend({
|
|
75
76
|
clientId: zod_1.z.string().min(1),
|
|
76
|
-
})
|
|
77
|
+
})
|
|
78
|
+
.strict();
|
|
77
79
|
/**
|
|
78
80
|
* An effectful MCP action the requested capability set can actually invoke.
|
|
79
81
|
* Every field is picked from the canonical catalog tool schema so consent can
|
|
80
82
|
* never maintain a second tool description or effect classification.
|
|
81
83
|
*/
|
|
82
|
-
exports.mcpOAuthWriteActionSchema = agency_1.catalogToolSchema
|
|
84
|
+
exports.mcpOAuthWriteActionSchema = agency_1.catalogToolSchema
|
|
85
|
+
.innerType()
|
|
86
|
+
.pick({
|
|
83
87
|
name: true,
|
|
84
88
|
version: true,
|
|
85
89
|
description: true,
|
|
86
90
|
requiredCapabilities: true,
|
|
87
91
|
effect: true,
|
|
88
|
-
})
|
|
92
|
+
})
|
|
93
|
+
.strict()
|
|
94
|
+
.refine((action) => action.effect !== 'read', {
|
|
89
95
|
message: 'MCP consent write actions must be effectful',
|
|
90
96
|
path: ['effect'],
|
|
91
97
|
});
|
|
92
98
|
/** Exact, server-resolved context rendered before an external MCP grant. */
|
|
93
|
-
exports.mcpOAuthConsentContextSchema = zod_1.z
|
|
99
|
+
exports.mcpOAuthConsentContextSchema = zod_1.z
|
|
100
|
+
.object({
|
|
94
101
|
client: exports.mcpOAuthClientApplicationSchema,
|
|
95
|
-
account: zod_1.z
|
|
102
|
+
account: zod_1.z
|
|
103
|
+
.object({
|
|
96
104
|
id: zod_1.z.string().min(1),
|
|
97
105
|
displayName: zod_1.z.string().min(1).optional(),
|
|
98
106
|
handle: zod_1.z.string().min(1).optional(),
|
|
99
107
|
avatar: zod_1.z.string().min(1).optional(),
|
|
100
|
-
})
|
|
101
|
-
|
|
108
|
+
})
|
|
109
|
+
.strict(),
|
|
110
|
+
resource: zod_1.z
|
|
111
|
+
.object({
|
|
102
112
|
appId: zod_1.z.string().min(1),
|
|
103
113
|
uri: zod_1.z.string().url(),
|
|
104
114
|
application: sessionStatus_1.publicApplicationSchema,
|
|
105
|
-
})
|
|
115
|
+
})
|
|
116
|
+
.strict(),
|
|
106
117
|
capabilities: zod_1.z.array(zod_1.z.string().min(1)).min(1),
|
|
107
118
|
writeActions: zod_1.z.array(exports.mcpOAuthWriteActionSchema),
|
|
108
|
-
})
|
|
109
|
-
|
|
119
|
+
})
|
|
120
|
+
.strict();
|
|
121
|
+
exports.mcpOAuthClientInfoResponseSchema = zod_1.z
|
|
122
|
+
.object({
|
|
110
123
|
application: exports.mcpOAuthClientApplicationSchema,
|
|
111
|
-
})
|
|
112
|
-
|
|
124
|
+
})
|
|
125
|
+
.strict();
|
|
126
|
+
exports.mcpOAuthConsentResponseSchema = zod_1.z
|
|
127
|
+
.object({
|
|
113
128
|
consentRequired: zod_1.z.boolean(),
|
|
114
129
|
context: exports.mcpOAuthConsentContextSchema,
|
|
115
|
-
})
|
|
130
|
+
})
|
|
131
|
+
.strict();
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
* is rejected as `invalid_envelope`.
|
|
9
9
|
*
|
|
10
10
|
* `oxySignedRecordTypeSchema` is that runtime gate (the API's `verifyEnvelope`
|
|
11
|
-
* re-narrows with it; the
|
|
12
|
-
*
|
|
11
|
+
* re-narrows with it; the Postgres CHECK on `signed_records.type` is derived
|
|
12
|
+
* from `.options`);
|
|
13
13
|
* `OxySignedRecordType` is the matching compile-time union the SDK
|
|
14
14
|
* identity/civic mixins type against.
|
|
15
15
|
*
|
|
@@ -5,86 +5,175 @@ const zod_1 = require("zod");
|
|
|
5
5
|
const identifiers_1 = require("../inference/identifiers");
|
|
6
6
|
const identifier = zod_1.z.string().min(1).max(160);
|
|
7
7
|
const count = zod_1.z.number().int().nonnegative().safe();
|
|
8
|
-
const period = zod_1.z
|
|
9
|
-
.
|
|
8
|
+
const period = zod_1.z
|
|
9
|
+
.object({ start: zod_1.z.string().datetime(), end: zod_1.z.string().datetime() })
|
|
10
|
+
.strict()
|
|
11
|
+
.refine((value) => Date.parse(value.end) > Date.parse(value.start), 'period end must follow start');
|
|
10
12
|
/** Product ownership and audience are registered together; branding grants no trust. */
|
|
11
|
-
exports.productDefinitionSchema = zod_1.z
|
|
12
|
-
|
|
13
|
+
exports.productDefinitionSchema = zod_1.z
|
|
14
|
+
.object({
|
|
15
|
+
schemaVersion: zod_1.z.literal(1),
|
|
16
|
+
id: identifier,
|
|
17
|
+
ownerAccountId: identifiers_1.oxyAccountIdSchema,
|
|
13
18
|
applicationId: identifiers_1.oxyApplicationIdSchema,
|
|
14
|
-
})
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
19
|
+
})
|
|
20
|
+
.strict();
|
|
21
|
+
exports.subjectProductAccessQuerySchema = zod_1.z
|
|
22
|
+
.object({
|
|
23
|
+
schemaVersion: zod_1.z.literal(1),
|
|
24
|
+
subjectAccountId: identifiers_1.oxyAccountIdSchema,
|
|
25
|
+
productId: identifier,
|
|
26
|
+
})
|
|
27
|
+
.strict();
|
|
18
28
|
/** Every quota declares its combination rule; there is no commercial default. */
|
|
19
29
|
exports.productBenefitSchema = zod_1.z.discriminatedUnion('kind', [
|
|
20
30
|
zod_1.z.object({ kind: zod_1.z.literal('capability'), productId: identifier, key: identifier }).strict(),
|
|
21
|
-
zod_1.z
|
|
22
|
-
|
|
31
|
+
zod_1.z
|
|
32
|
+
.object({
|
|
33
|
+
kind: zod_1.z.literal('quota'),
|
|
34
|
+
productId: identifier,
|
|
35
|
+
key: identifier,
|
|
36
|
+
unit: identifier,
|
|
37
|
+
included: count,
|
|
38
|
+
combination: zod_1.z.enum(['maximum', 'sum', 'exclusive']),
|
|
39
|
+
})
|
|
40
|
+
.strict(),
|
|
23
41
|
]);
|
|
24
42
|
/** A version names a frozen offer. An empty bundle grants nothing. */
|
|
25
|
-
exports.productOfferSchema = zod_1.z
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
43
|
+
exports.productOfferSchema = zod_1.z
|
|
44
|
+
.object({
|
|
45
|
+
schemaVersion: zod_1.z.literal(1),
|
|
46
|
+
id: identifier,
|
|
47
|
+
version: zod_1.z.number().int().positive().safe(),
|
|
48
|
+
kind: zod_1.z.enum(['individual', 'bundle']),
|
|
49
|
+
benefits: zod_1.z.array(exports.productBenefitSchema),
|
|
50
|
+
})
|
|
51
|
+
.strict()
|
|
52
|
+
.refine((value) => value.kind === 'bundle' ||
|
|
53
|
+
new Set(value.benefits.map((benefit) => benefit.productId)).size <= 1, 'individual offers cannot cover multiple products');
|
|
54
|
+
exports.productSubscriptionSourceSchema = zod_1.z
|
|
55
|
+
.object({
|
|
56
|
+
schemaVersion: zod_1.z.literal(1),
|
|
57
|
+
id: identifier,
|
|
58
|
+
beneficiaryAccountId: identifiers_1.oxyAccountIdSchema,
|
|
59
|
+
payerAccountId: identifiers_1.oxyAccountIdSchema,
|
|
60
|
+
provider: zod_1.z.enum(['stripe', 'peable']),
|
|
61
|
+
providerSubscriptionId: identifier,
|
|
62
|
+
status: zod_1.z.enum([
|
|
63
|
+
'active',
|
|
64
|
+
'trialing',
|
|
65
|
+
'past_due',
|
|
66
|
+
'unpaid',
|
|
67
|
+
'canceled',
|
|
68
|
+
'paused',
|
|
69
|
+
'incomplete',
|
|
70
|
+
'incomplete_expired',
|
|
71
|
+
]),
|
|
72
|
+
period,
|
|
73
|
+
cancelAtPeriodEnd: zod_1.z.boolean(),
|
|
74
|
+
})
|
|
75
|
+
.strict();
|
|
36
76
|
/** A frozen paid-period/offer segment; upgrades append, never rewrite it. */
|
|
37
|
-
exports.productOfferSegmentSchema = zod_1.z
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
77
|
+
exports.productOfferSegmentSchema = zod_1.z
|
|
78
|
+
.object({
|
|
79
|
+
schemaVersion: zod_1.z.literal(1),
|
|
80
|
+
id: identifier,
|
|
81
|
+
subscriptionId: identifier,
|
|
82
|
+
beneficiaryAccountId: identifiers_1.oxyAccountIdSchema,
|
|
83
|
+
offerId: identifier,
|
|
84
|
+
offerVersion: zod_1.z.number().int().positive().safe(),
|
|
85
|
+
origin: zod_1.z.enum(['individual', 'bundle']),
|
|
86
|
+
period,
|
|
87
|
+
})
|
|
88
|
+
.strict();
|
|
42
89
|
/** Provenance survives cancellation: deactivate a source, never delete history. */
|
|
43
|
-
exports.productAccessGrantSchema = zod_1.z
|
|
44
|
-
|
|
45
|
-
|
|
90
|
+
exports.productAccessGrantSchema = zod_1.z
|
|
91
|
+
.object({
|
|
92
|
+
schemaVersion: zod_1.z.literal(1),
|
|
93
|
+
id: identifier,
|
|
94
|
+
sourceSegmentId: identifier,
|
|
95
|
+
beneficiaryAccountId: identifiers_1.oxyAccountIdSchema,
|
|
96
|
+
offerId: identifier,
|
|
46
97
|
offerVersion: zod_1.z.number().int().positive().safe(),
|
|
47
|
-
origin: zod_1.z.enum(['individual', 'bundle']),
|
|
48
|
-
|
|
49
|
-
|
|
98
|
+
origin: zod_1.z.enum(['individual', 'bundle']),
|
|
99
|
+
benefit: exports.productBenefitSchema,
|
|
100
|
+
period,
|
|
101
|
+
revokedAt: zod_1.z.string().datetime().nullable(),
|
|
102
|
+
})
|
|
103
|
+
.strict();
|
|
50
104
|
/** Access answers contain no payer, provider reference, price or account balance. */
|
|
51
|
-
exports.subjectProductAccessSchema = zod_1.z
|
|
52
|
-
|
|
105
|
+
exports.subjectProductAccessSchema = zod_1.z
|
|
106
|
+
.object({
|
|
107
|
+
schemaVersion: zod_1.z.literal(1),
|
|
108
|
+
subjectAccountId: identifiers_1.oxyAccountIdSchema,
|
|
109
|
+
productId: identifier,
|
|
53
110
|
evaluatedAt: zod_1.z.string().datetime(),
|
|
54
111
|
capabilities: zod_1.z.array(zod_1.z.object({ key: identifier, grantIds: zod_1.z.array(identifier) }).strict()),
|
|
55
|
-
quotas: zod_1.z.array(zod_1.z
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
112
|
+
quotas: zod_1.z.array(zod_1.z
|
|
113
|
+
.object({
|
|
114
|
+
key: identifier,
|
|
115
|
+
unit: identifier,
|
|
116
|
+
included: count,
|
|
117
|
+
combination: zod_1.z.enum(['maximum', 'sum', 'exclusive']),
|
|
118
|
+
grantIds: zod_1.z.array(identifier),
|
|
119
|
+
})
|
|
120
|
+
.strict()),
|
|
121
|
+
conflicts: zod_1.z.array(zod_1.z
|
|
122
|
+
.object({
|
|
123
|
+
key: identifier,
|
|
124
|
+
reason: zod_1.z.enum([
|
|
125
|
+
'combination_mismatch',
|
|
126
|
+
'unit_mismatch',
|
|
127
|
+
'exclusive_overlap',
|
|
128
|
+
'unsafe_total',
|
|
129
|
+
]),
|
|
130
|
+
grantIds: zod_1.z.array(identifier),
|
|
131
|
+
})
|
|
132
|
+
.strict()),
|
|
133
|
+
})
|
|
134
|
+
.strict();
|
|
61
135
|
/** Active grant periods for metering adapters; no financial/provider identity. */
|
|
62
|
-
exports.subjectProductGrantSnapshotSchema = zod_1.z
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
136
|
+
exports.subjectProductGrantSnapshotSchema = zod_1.z
|
|
137
|
+
.object({
|
|
138
|
+
schemaVersion: zod_1.z.literal(1),
|
|
139
|
+
access: exports.subjectProductAccessSchema,
|
|
140
|
+
grants: zod_1.z.array(exports.productAccessGrantSchema),
|
|
141
|
+
})
|
|
142
|
+
.strict()
|
|
143
|
+
.superRefine((value, ctx) => {
|
|
144
|
+
const active = new Set([...value.access.capabilities, ...value.access.quotas].flatMap((entry) => entry.grantIds));
|
|
145
|
+
if (active.size !== value.grants.length ||
|
|
146
|
+
new Set(value.grants.map((g) => g.id)).size !== value.grants.length ||
|
|
147
|
+
value.grants.some((g) => g.beneficiaryAccountId !== value.access.subjectAccountId ||
|
|
148
|
+
g.benefit.productId !== value.access.productId ||
|
|
149
|
+
!active.has(g.id) ||
|
|
69
150
|
// A future revocation is still active at evaluation time, as in access composition.
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
151
|
+
(g.revokedAt !== null &&
|
|
152
|
+
Date.parse(g.revokedAt) <= Date.parse(value.access.evaluatedAt)) ||
|
|
153
|
+
Date.parse(g.period.start) > Date.parse(value.access.evaluatedAt) ||
|
|
154
|
+
Date.parse(g.period.end) <= Date.parse(value.access.evaluatedAt)))
|
|
73
155
|
ctx.addIssue({ code: 'custom', message: 'Active grant snapshot attribution differs' });
|
|
74
156
|
for (const quota of value.access.quotas) {
|
|
75
|
-
const benefits = quota.grantIds.map(id => value.grants.find(g => g.id === id)?.benefit);
|
|
76
|
-
if (benefits.some(b => !b ||
|
|
157
|
+
const benefits = quota.grantIds.map((id) => value.grants.find((g) => g.id === id)?.benefit);
|
|
158
|
+
if (benefits.some((b) => !b ||
|
|
159
|
+
b.kind !== 'quota' ||
|
|
160
|
+
b.key !== quota.key ||
|
|
161
|
+
b.unit !== quota.unit ||
|
|
162
|
+
b.combination !== quota.combination)) {
|
|
77
163
|
ctx.addIssue({ code: 'custom', message: 'Grant quota terms differ' });
|
|
78
164
|
continue;
|
|
79
165
|
}
|
|
80
|
-
const amounts = benefits.map(b => b?.kind === 'quota' ? BigInt(b.included) : 0n);
|
|
81
|
-
const included = quota.combination === 'sum'
|
|
82
|
-
|
|
166
|
+
const amounts = benefits.map((b) => (b?.kind === 'quota' ? BigInt(b.included) : 0n));
|
|
167
|
+
const included = quota.combination === 'sum'
|
|
168
|
+
? amounts.reduce((sum, n) => sum + n, 0n)
|
|
169
|
+
: amounts.reduce((maximum, n) => (n > maximum ? n : maximum), 0n);
|
|
170
|
+
if (included !== BigInt(quota.included) ||
|
|
171
|
+
(quota.combination === 'exclusive' && benefits.length > 1))
|
|
83
172
|
ctx.addIssue({ code: 'custom', message: 'Grant quota composition differs' });
|
|
84
173
|
}
|
|
85
174
|
for (const capability of value.access.capabilities)
|
|
86
|
-
if (capability.grantIds.some(id => {
|
|
87
|
-
const benefit = value.grants.find(g => g.id === id)?.benefit;
|
|
175
|
+
if (capability.grantIds.some((id) => {
|
|
176
|
+
const benefit = value.grants.find((g) => g.id === id)?.benefit;
|
|
88
177
|
return benefit?.kind !== 'capability' || benefit.key !== capability.key;
|
|
89
178
|
}))
|
|
90
179
|
ctx.addIssue({ code: 'custom', message: 'Grant capability terms differ' });
|
|
@@ -6,25 +6,79 @@ const identifiers_1 = require("../inference/identifiers");
|
|
|
6
6
|
const id = zod_1.z.string().min(1).max(160);
|
|
7
7
|
const name = zod_1.z.string().min(1).max(100);
|
|
8
8
|
const count = zod_1.z.number().int().nonnegative().safe();
|
|
9
|
-
const period = zod_1.z
|
|
10
|
-
.
|
|
9
|
+
const period = zod_1.z
|
|
10
|
+
.object({ start: zod_1.z.string().datetime(), end: zod_1.z.string().datetime() })
|
|
11
|
+
.strict()
|
|
12
|
+
.refine((value) => Date.parse(value.end) > Date.parse(value.start), 'Period end must follow start');
|
|
11
13
|
/** Self-service provenance; no payer/provider identifiers or balances in access metadata. */
|
|
12
|
-
exports.productSubscriptionSummarySchema = zod_1.z
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
exports.productSubscriptionSummarySchema = zod_1.z
|
|
15
|
+
.object({
|
|
16
|
+
sourceId: id,
|
|
17
|
+
status: zod_1.z.enum([
|
|
18
|
+
'active',
|
|
19
|
+
'trialing',
|
|
20
|
+
'past_due',
|
|
21
|
+
'unpaid',
|
|
22
|
+
'canceled',
|
|
23
|
+
'paused',
|
|
24
|
+
'incomplete',
|
|
25
|
+
'incomplete_expired',
|
|
26
|
+
]),
|
|
27
|
+
period,
|
|
28
|
+
cancelAtPeriodEnd: zod_1.z.boolean(),
|
|
29
|
+
canCancel: zod_1.z.boolean(),
|
|
30
|
+
offers: zod_1.z.array(zod_1.z
|
|
31
|
+
.object({
|
|
32
|
+
segmentId: id,
|
|
33
|
+
offerId: id,
|
|
34
|
+
offerVersion: zod_1.z.number().int().positive().safe(),
|
|
35
|
+
displayName: name,
|
|
36
|
+
origin: zod_1.z.enum(['individual', 'bundle']),
|
|
37
|
+
period,
|
|
38
|
+
current: zod_1.z.boolean(),
|
|
17
39
|
products: zod_1.z.array(zod_1.z.object({ id, displayName: name }).strict()),
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
40
|
+
})
|
|
41
|
+
.strict()),
|
|
42
|
+
})
|
|
43
|
+
.strict();
|
|
44
|
+
exports.productSubscriptionsResponseSchema = zod_1.z
|
|
45
|
+
.object({ subscriptions: zod_1.z.array(exports.productSubscriptionSummarySchema) })
|
|
46
|
+
.strict();
|
|
47
|
+
exports.subscriptionCreditGrantSchema = zod_1.z
|
|
48
|
+
.object({
|
|
49
|
+
id,
|
|
50
|
+
invoiceId: id,
|
|
51
|
+
origin: zod_1.z.enum([
|
|
52
|
+
'subscription_payment',
|
|
53
|
+
'subscription_proration',
|
|
54
|
+
'subscription_promotional_grant',
|
|
55
|
+
]),
|
|
56
|
+
period,
|
|
57
|
+
granted: count,
|
|
58
|
+
consumed: count,
|
|
59
|
+
clawed: count,
|
|
60
|
+
remaining: count,
|
|
61
|
+
promotionId: id.nullable(),
|
|
62
|
+
createdAt: zod_1.z.string().datetime(),
|
|
63
|
+
})
|
|
64
|
+
.strict()
|
|
65
|
+
.refine((value) => BigInt(value.consumed) + BigInt(value.clawed) + BigInt(value.remaining) ===
|
|
66
|
+
BigInt(value.granted), 'Grant conservation differs');
|
|
67
|
+
exports.subscriptionCreditGrantsResponseSchema = zod_1.z
|
|
68
|
+
.object({ grants: zod_1.z.array(exports.subscriptionCreditGrantSchema) })
|
|
69
|
+
.strict();
|
|
70
|
+
exports.cancelProductSubscriptionSchema = zod_1.z
|
|
71
|
+
.object({
|
|
72
|
+
sourceId: id,
|
|
73
|
+
actionId: zod_1.z
|
|
74
|
+
.string()
|
|
75
|
+
.min(8)
|
|
76
|
+
.max(160)
|
|
77
|
+
.regex(/^[a-zA-Z0-9_-]+$/)
|
|
78
|
+
.optional(),
|
|
79
|
+
expectedSubjectAccountId: identifiers_1.oxyAccountIdSchema.optional(),
|
|
80
|
+
})
|
|
81
|
+
.strict();
|
|
28
82
|
/** Remote acceptance is distinct from completed local reconciliation. */
|
|
29
83
|
exports.productSubscriptionCancellationResultSchema = zod_1.z.union([
|
|
30
84
|
zod_1.z.object({ sourceId: id, cancelAtPeriodEnd: zod_1.z.literal(true) }).strict(),
|
|
@@ -3,15 +3,33 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.personalPlanCheckoutResultSchema = exports.personalPlanCheckoutRequestSchema = void 0;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
const identifiers_1 = require("../inference/identifiers");
|
|
6
|
-
exports.personalPlanCheckoutRequestSchema = zod_1.z
|
|
6
|
+
exports.personalPlanCheckoutRequestSchema = zod_1.z
|
|
7
|
+
.object({
|
|
7
8
|
expectedSubjectAccountId: identifiers_1.oxyAccountIdSchema,
|
|
8
|
-
offerId: zod_1.z.string().min(1).max(160),
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
offerId: zod_1.z.string().min(1).max(160),
|
|
10
|
+
offerVersion: zod_1.z.number().int().positive().safe(),
|
|
11
|
+
idempotencyKey: zod_1.z
|
|
12
|
+
.string()
|
|
13
|
+
.min(8)
|
|
14
|
+
.max(160)
|
|
15
|
+
.regex(/^[a-zA-Z0-9_-]+$/),
|
|
16
|
+
})
|
|
17
|
+
.strict();
|
|
11
18
|
/** No grant or subscription is created by checkout completion in the browser. */
|
|
12
19
|
exports.personalPlanCheckoutResultSchema = zod_1.z.discriminatedUnion('state', [
|
|
13
|
-
zod_1.z
|
|
14
|
-
|
|
20
|
+
zod_1.z
|
|
21
|
+
.object({
|
|
22
|
+
state: zod_1.z.literal('unconfigured'),
|
|
23
|
+
reason: zod_1.z.enum(['provider_unconfigured', 'offer_unconfigured', 'price_unconfigured']),
|
|
24
|
+
})
|
|
25
|
+
.strict(),
|
|
26
|
+
zod_1.z
|
|
27
|
+
.object({
|
|
28
|
+
state: zod_1.z.literal('pending'),
|
|
29
|
+
intentId: zod_1.z.string().min(1).max(160),
|
|
30
|
+
checkoutUrl: zod_1.z.string().url().startsWith('https://').optional(),
|
|
31
|
+
})
|
|
32
|
+
.strict(),
|
|
15
33
|
zod_1.z.object({ state: zod_1.z.literal('closed'), intentId: zod_1.z.string().min(1).max(160) }).strict(),
|
|
16
34
|
zod_1.z.object({ state: zod_1.z.literal('fulfilled'), intentId: zod_1.z.string().min(1).max(160) }).strict(),
|
|
17
35
|
]);
|