@oxy.so/contracts 4.16.0 → 4.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/dist/cjs/accountAccess.js +72 -0
  2. package/dist/cjs/accountEmail.js +12 -34
  3. package/dist/cjs/accountGraph.js +22 -320
  4. package/dist/cjs/agency.js +112 -1
  5. package/dist/cjs/agentKeys.js +11 -13
  6. package/dist/cjs/applicationRoles.js +211 -0
  7. package/dist/cjs/client/accountEmail.js +48 -0
  8. package/dist/cjs/client/accountGraph.js +323 -0
  9. package/dist/cjs/client/agentKeys.js +77 -0
  10. package/dist/cjs/client/check.js +475 -0
  11. package/dist/cjs/client/deviceBoot.js +22 -0
  12. package/dist/cjs/client/deviceDirectory.js +51 -0
  13. package/dist/cjs/client/deviceSession.js +63 -0
  14. package/dist/cjs/client/externalIdentity.js +19 -0
  15. package/dist/cjs/client/identity.js +45 -0
  16. package/dist/cjs/client/identityLink.js +55 -0
  17. package/dist/cjs/client/identityProof.js +109 -0
  18. package/dist/cjs/client/index.js +211 -0
  19. package/dist/cjs/client/organizations.js +114 -0
  20. package/dist/cjs/client/products.js +153 -0
  21. package/dist/cjs/client/recommendations.js +33 -0
  22. package/dist/cjs/client/reputation.js +41 -0
  23. package/dist/cjs/client/safety.js +196 -0
  24. package/dist/cjs/client/sessionStatus.js +23 -0
  25. package/dist/cjs/client/signIn.js +159 -0
  26. package/dist/cjs/client/userResponse.js +15 -0
  27. package/dist/cjs/client/username.js +173 -0
  28. package/dist/cjs/deviceSession.js +3 -16
  29. package/dist/cjs/identityLink.js +13 -34
  30. package/dist/cjs/identityProof.js +18 -106
  31. package/dist/cjs/index.js +13 -3
  32. package/dist/cjs/organizations.js +21 -41
  33. package/dist/cjs/reputation.js +3 -34
  34. package/dist/cjs/safety.js +430 -1
  35. package/dist/cjs/serviceToken.js +14 -0
  36. package/dist/cjs/signIn.js +33 -111
  37. package/dist/cjs/username.js +23 -158
  38. package/dist/esm/accountAccess.js +69 -0
  39. package/dist/esm/accountEmail.js +4 -32
  40. package/dist/esm/accountGraph.js +4 -309
  41. package/dist/esm/agency.js +111 -0
  42. package/dist/esm/agentKeys.js +4 -10
  43. package/dist/esm/applicationRoles.js +207 -0
  44. package/dist/esm/client/accountEmail.js +45 -0
  45. package/dist/esm/client/accountGraph.js +314 -0
  46. package/dist/esm/client/agentKeys.js +74 -0
  47. package/dist/esm/client/check.js +436 -0
  48. package/dist/esm/client/deviceBoot.js +19 -0
  49. package/dist/esm/client/deviceDirectory.js +48 -0
  50. package/dist/esm/client/deviceSession.js +60 -0
  51. package/dist/esm/client/externalIdentity.js +16 -0
  52. package/dist/esm/client/identity.js +42 -0
  53. package/dist/esm/client/identityLink.js +50 -0
  54. package/dist/esm/client/identityProof.js +104 -0
  55. package/dist/esm/client/index.js +37 -0
  56. package/dist/esm/client/organizations.js +111 -0
  57. package/dist/esm/client/products.js +150 -0
  58. package/dist/esm/client/recommendations.js +30 -0
  59. package/dist/esm/client/reputation.js +37 -0
  60. package/dist/esm/client/safety.js +193 -0
  61. package/dist/esm/client/sessionStatus.js +20 -0
  62. package/dist/esm/client/signIn.js +153 -0
  63. package/dist/esm/client/userResponse.js +12 -0
  64. package/dist/esm/client/username.js +167 -0
  65. package/dist/esm/deviceSession.js +1 -15
  66. package/dist/esm/identityLink.js +4 -27
  67. package/dist/esm/identityProof.js +4 -99
  68. package/dist/esm/index.js +4 -1
  69. package/dist/esm/organizations.js +4 -31
  70. package/dist/esm/reputation.js +1 -32
  71. package/dist/esm/safety.js +423 -0
  72. package/dist/esm/serviceToken.js +11 -0
  73. package/dist/esm/signIn.js +4 -96
  74. package/dist/esm/username.js +4 -148
  75. package/dist/types/accountAccess.d.ts +128 -0
  76. package/dist/types/accountEmail.d.ts +4 -36
  77. package/dist/types/accountGraph.d.ts +12 -208
  78. package/dist/types/agency.d.ts +351 -26
  79. package/dist/types/agentKeys.d.ts +14 -12
  80. package/dist/types/applicationRoles.d.ts +438 -0
  81. package/dist/types/client/accountEmail.d.ts +44 -0
  82. package/dist/types/client/accountGraph.d.ts +203 -0
  83. package/dist/types/client/agentKeys.d.ts +113 -0
  84. package/dist/types/client/check.d.ts +187 -0
  85. package/dist/types/client/deviceBoot.d.ts +6 -0
  86. package/dist/types/client/deviceDirectory.d.ts +134 -0
  87. package/dist/types/client/deviceSession.d.ts +91 -0
  88. package/dist/types/client/externalIdentity.d.ts +14 -0
  89. package/dist/types/client/identity.d.ts +8 -0
  90. package/dist/types/client/identityLink.d.ts +21 -0
  91. package/dist/types/client/identityProof.d.ts +73 -0
  92. package/dist/types/client/index.d.ts +37 -0
  93. package/dist/types/client/organizations.d.ts +167 -0
  94. package/dist/types/client/products.d.ts +145 -0
  95. package/dist/types/client/recommendations.d.ts +27 -0
  96. package/dist/types/client/reputation.d.ts +28 -0
  97. package/dist/types/client/safety.d.ts +213 -0
  98. package/dist/types/client/sessionStatus.d.ts +19 -0
  99. package/dist/types/client/signIn.d.ts +107 -0
  100. package/dist/types/client/userResponse.d.ts +7 -0
  101. package/dist/types/client/username.d.ts +126 -0
  102. package/dist/types/deviceDirectory.d.ts +28 -28
  103. package/dist/types/deviceSession.d.ts +5 -16
  104. package/dist/types/email/messages.d.ts +2 -2
  105. package/dist/types/externalIdentity.d.ts +15 -15
  106. package/dist/types/identityLink.d.ts +3 -11
  107. package/dist/types/identityProof.d.ts +2 -65
  108. package/dist/types/index.d.ts +5 -2
  109. package/dist/types/inference/accountBilling.d.ts +2 -2
  110. package/dist/types/inference/catalogue.d.ts +22 -22
  111. package/dist/types/inference/decisions.d.ts +10 -10
  112. package/dist/types/inference/embeddings.d.ts +16 -16
  113. package/dist/types/inference/errors.d.ts +8 -8
  114. package/dist/types/inference/inbox.d.ts +8 -8
  115. package/dist/types/inference/privateAutoExecution.d.ts +6 -6
  116. package/dist/types/inference/providerConnection.d.ts +4 -4
  117. package/dist/types/inference/realtime.d.ts +92 -92
  118. package/dist/types/inference/request.d.ts +48 -48
  119. package/dist/types/inference/streamEvents.d.ts +16 -16
  120. package/dist/types/inference/usage.d.ts +4 -4
  121. package/dist/types/oauth.d.ts +2 -2
  122. package/dist/types/organizations.d.ts +8 -10
  123. package/dist/types/products/access.d.ts +4 -4
  124. package/dist/types/products/billing.d.ts +3 -0
  125. package/dist/types/reputation.d.ts +1 -11
  126. package/dist/types/safety.d.ts +2374 -2
  127. package/dist/types/serviceToken.d.ts +11 -0
  128. package/dist/types/sessionStatus.d.ts +2 -2
  129. package/dist/types/signIn.d.ts +11 -94
  130. package/dist/types/userResponse.d.ts +22 -22
  131. package/dist/types/username.d.ts +1 -96
  132. package/package.json +24 -20
  133. package/dist/cjs/.tsbuildinfo +0 -1
  134. package/dist/esm/.tsbuildinfo +0 -1
  135. package/dist/types/.tsbuildinfo +0 -1
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
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.invocationPrincipalSchema = exports.capabilityTicketClaimsSchema = exports.automationDefinitionSchema = exports.automationDataFlowSchema = exports.automationActorSelectionSchema = exports.automationTriggerSchema = exports.delegationGrantSchema = exports.capabilityTicketRequestSchema = exports.capabilityCoordinatorSchema = exports.executionAuthorizationRefSchema = exports.capabilityCatalogBindingSchema = exports.grantLimitSchema = exports.toolGrantOverrideSchema = exports.resourceRefSchema = exports.foregroundExecutionAuthorizationInputSchema = exports.executionActorRefSchema = exports.actorRefSchema = exports.capabilityPackageSchema = exports.CAPABILITY_PACKAGES = exports.autonomyLevelSchema = exports.AUTONOMY_LEVELS = void 0;
3
+ exports.normalizedAppEventSchema = exports.catalogRegistrationSchema = exports.appCapabilityCatalogSchema = exports.CATALOG_INTERNAL_TRANSPORTS = exports.catalogFeatureSchema = exports.catalogEventSchema = exports.catalogToolSchema = exports.auditEventSchema = exports.auditResultSchema = exports.policyDecisionSchema = exports.invocationPrincipalSchema = exports.capabilityTicketClaimsSchema = exports.automationDefinitionSchema = exports.automationDataFlowSchema = exports.automationActorSelectionSchema = exports.automationTriggerSchema = exports.agentRequesterCeilingSchema = exports.agentRequesterCeilingWriteSchema = exports.AGENT_REQUESTER_CEILING_AUTONOMY = exports.delegationGrantSchema = exports.capabilityTicketRequestSchema = exports.capabilityCoordinatorSchema = exports.executionAuthorizationRefSchema = exports.capabilityCatalogBindingSchema = exports.grantLimitSchema = exports.toolGrantOverrideSchema = exports.resourceRefSchema = exports.foregroundExecutionAuthorizationInputSchema = exports.executionActorRefSchema = exports.actorRefSchema = exports.capabilityPackageSchema = exports.CAPABILITY_PACKAGES = exports.autonomyLevelSchema = exports.AUTONOMY_LEVELS = void 0;
4
4
  const zod_1 = require("zod");
5
5
  const capabilityInvocation_1 = require("./capabilityInvocation");
6
6
  const nonEmptyStringSchema = zod_1.z.string().trim().min(1);
@@ -143,6 +143,35 @@ exports.delegationGrantSchema = zod_1.z
143
143
  updatedAt: zod_1.z.string().datetime(),
144
144
  })
145
145
  .strict();
146
+ /**
147
+ * The two levels an owner publishes for whoever uses their agent (ADR 0042):
148
+ * "Ver" and "Ver y actuar". A ceiling never says `draft` or `execute_on_request`:
149
+ * an agent is either allowed to act on its own or not at all, and nothing ever
150
+ * asks the person for approval.
151
+ */
152
+ exports.AGENT_REQUESTER_CEILING_AUTONOMY = ['read_only', 'autonomous'];
153
+ /** What an agent may do in one app for whoever uses it; written by an operator of the bot. */
154
+ exports.agentRequesterCeilingWriteSchema = zod_1.z
155
+ .object({
156
+ capabilityPackages: zod_1.z.array(exports.capabilityPackageSchema),
157
+ capabilities: zod_1.z.array(identifierSchema).default([]),
158
+ toolOverrides: zod_1.z.array(exports.toolGrantOverrideSchema).default([]),
159
+ limits: zod_1.z.array(exports.grantLimitSchema).default([]),
160
+ maximumAutonomy: zod_1.z.enum(exports.AGENT_REQUESTER_CEILING_AUTONOMY),
161
+ })
162
+ .strict();
163
+ exports.agentRequesterCeilingSchema = exports.agentRequesterCeilingWriteSchema
164
+ .extend({
165
+ id: identifierSchema,
166
+ agentAccountId: identifierSchema,
167
+ appId: identifierSchema,
168
+ catalog: exports.capabilityCatalogBindingSchema,
169
+ version: zod_1.z.number().int().positive(),
170
+ revokedAt: zod_1.z.string().datetime().nullable(),
171
+ createdAt: zod_1.z.string().datetime(),
172
+ updatedAt: zod_1.z.string().datetime(),
173
+ })
174
+ .strict();
146
175
  exports.automationTriggerSchema = zod_1.z.discriminatedUnion('type', [
147
176
  zod_1.z.object({ type: zod_1.z.literal('manual') }).strict(),
148
177
  zod_1.z
@@ -204,6 +233,8 @@ exports.capabilityTicketClaimsSchema = zod_1.z
204
233
  /** Signed only for callers that explicitly requested a pinned catalogue. */
205
234
  catalog: exports.capabilityCatalogBindingSchema.optional(),
206
235
  grantId: identifierSchema.optional(),
236
+ /** The owner's published ceiling that bounds an agent acting for a non-owner (ADR 0042). */
237
+ ceilingId: identifierSchema.optional(),
207
238
  requesterAccountId: identifierSchema,
208
239
  ownerAccountId: identifierSchema,
209
240
  actor: exports.executionActorRefSchema,
@@ -242,6 +273,24 @@ exports.capabilityTicketClaimsSchema = zod_1.z
242
273
  message: 'requester actors require their exact principal and direct read-only authority without standing grants',
243
274
  });
244
275
  }
276
+ if (claims.ceilingId !== undefined) {
277
+ if (claims.grantId !== undefined) {
278
+ context.addIssue({
279
+ code: zod_1.z.ZodIssueCode.custom,
280
+ path: ['ceilingId'],
281
+ message: 'a ticket is bounded by either a grant or a ceiling, never both',
282
+ });
283
+ }
284
+ if (claims.actor.type !== 'agent' ||
285
+ claims.ownerAccountId !== claims.requesterAccountId ||
286
+ claims.resource.resourceId !== claims.resource.effectiveAccountId) {
287
+ context.addIssue({
288
+ code: zod_1.z.ZodIssueCode.custom,
289
+ path: ['ceilingId'],
290
+ message: "a ceiling bounds an agent acting on the requester's own authority at an account root",
291
+ });
292
+ }
293
+ }
245
294
  if (claims.exp <= claims.iat) {
246
295
  context.addIssue({
247
296
  code: zod_1.z.ZodIssueCode.custom,
@@ -303,6 +352,7 @@ exports.policyDecisionSchema = zod_1.z
303
352
  reason: identifierSchema,
304
353
  effectiveAutonomy: exports.autonomyLevelSchema.optional(),
305
354
  grantId: identifierSchema.optional(),
355
+ ceilingId: identifierSchema.optional(),
306
356
  })
307
357
  .strict();
308
358
  exports.auditResultSchema = zod_1.z
@@ -512,6 +562,24 @@ exports.catalogEventSchema = zod_1.z
512
562
  resourceTypes: zod_1.z.array(identifierSchema).min(1),
513
563
  })
514
564
  .strict();
565
+ /**
566
+ * A feature an agent may gate on (Alia ADR 0020 §6): the app answers whether the
567
+ * person may use it (`checkTool`) and, when using it costs something, spends it
568
+ * (`consumeTool`). Both are internal tools of the same catalogue.
569
+ */
570
+ exports.catalogFeatureSchema = zod_1.z
571
+ .object({
572
+ key: zod_1.z
573
+ .string()
574
+ .regex(/^[a-z][a-z0-9_-]*(?:\.[a-z][a-z0-9_-]*)*$/, 'feature keys are dot-separated slugs')
575
+ .max(128),
576
+ description: nonEmptyStringSchema,
577
+ checkTool: identifierSchema,
578
+ consumeTool: identifierSchema.optional(),
579
+ })
580
+ .strict();
581
+ /** How a coordinator reaches the catalogue's internal tools. */
582
+ exports.CATALOG_INTERNAL_TRANSPORTS = ['http', 'mcp'];
515
583
  exports.appCapabilityCatalogSchema = zod_1.z
516
584
  .object({
517
585
  schemaVersion: zod_1.z.literal('1'),
@@ -567,11 +635,54 @@ exports.appCapabilityCatalogSchema = zod_1.z
567
635
  })
568
636
  .strict()
569
637
  .optional(),
638
+ /**
639
+ * `mcp`: internal tools are served at `<internalBaseUrl>/_oxy/mcp`. Absent or
640
+ * `http`: each tool's `invocation` path on `internalBaseUrl`.
641
+ */
642
+ internalTransport: zod_1.z.enum(exports.CATALOG_INTERNAL_TRANSPORTS).optional(),
643
+ features: zod_1.z.array(exports.catalogFeatureSchema).optional(),
570
644
  tools: zod_1.z.array(exports.catalogToolSchema),
571
645
  events: zod_1.z.array(exports.catalogEventSchema),
572
646
  })
573
647
  .strict()
574
648
  .superRefine((catalog, context) => {
649
+ const toolsByName = new Map(catalog.tools.map((tool) => [tool.name, tool]));
650
+ const featureKeys = new Set();
651
+ for (const [index, feature] of (catalog.features ?? []).entries()) {
652
+ if (featureKeys.has(feature.key)) {
653
+ context.addIssue({
654
+ code: zod_1.z.ZodIssueCode.custom,
655
+ message: `Duplicate feature key: ${feature.key}`,
656
+ path: ['features', index, 'key'],
657
+ });
658
+ }
659
+ featureKeys.add(feature.key);
660
+ const check = toolsByName.get(feature.checkTool);
661
+ if (!check ||
662
+ check.effect !== 'read' ||
663
+ check.exposure.length !== 1 ||
664
+ check.exposure[0] !== 'internal') {
665
+ context.addIssue({
666
+ code: zod_1.z.ZodIssueCode.custom,
667
+ message: 'checkTool must name an internal-only read tool of this catalogue',
668
+ path: ['features', index, 'checkTool'],
669
+ });
670
+ }
671
+ if (feature.consumeTool !== undefined) {
672
+ const consume = toolsByName.get(feature.consumeTool);
673
+ if (!consume ||
674
+ consume.effect === 'read' ||
675
+ consume.idempotency !== 'required' ||
676
+ consume.exposure.length !== 1 ||
677
+ consume.exposure[0] !== 'internal') {
678
+ context.addIssue({
679
+ code: zod_1.z.ZodIssueCode.custom,
680
+ message: 'consumeTool must name an internal-only effectful tool that requires idempotency keys',
681
+ path: ['features', index, 'consumeTool'],
682
+ });
683
+ }
684
+ }
685
+ }
575
686
  const names = new Set();
576
687
  for (const [index, tool] of catalog.tools.entries()) {
577
688
  if (names.has(tool.name)) {
@@ -1,25 +1,24 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.agentKeyListResponseSchema = exports.ACCOUNT_AUTH_METHODS = exports.agentKeyOperationResultSchema = exports.agentKeyOperationChallengeSchema = exports.executeAgentKeyOperationSchema = exports.agentKeyOperationProofSchema = exports.agentKeyOperationSchema = exports.agentVerifyRequestSchema = exports.agentChallengeRequestSchema = exports.agentSignatureSchema = exports.agentProofClaimsSchema = exports.AGENT_PROOF_ACTIONS = exports.AGENT_PROOF_TTL_MS = exports.AGENT_PROOF_AUDIENCE = void 0;
3
+ exports.agentKeyListResponseSchema = exports.agentKeyOperationResultSchema = exports.agentKeyOperationChallengeSchema = exports.executeAgentKeyOperationSchema = exports.agentKeyOperationProofSchema = exports.agentKeyOperationSchema = exports.agentVerifyRequestSchema = exports.agentChallengeRequestSchema = exports.agentSignatureSchema = exports.agentProofClaimsSchema = exports.ACCOUNT_AUTH_METHODS = exports.AGENT_PROOF_ACTIONS = exports.AGENT_PROOF_TTL_MS = exports.AGENT_PROOF_AUDIENCE = void 0;
4
4
  exports.buildAgentProofMessage = buildAgentProofMessage;
5
5
  /** Autonomous runtime proof. No private key crosses this contract. */
6
6
  const zod_1 = require("zod");
7
7
  const signIn_1 = require("./signIn");
8
8
  const identityProof_1 = require("./identityProof");
9
- exports.AGENT_PROOF_AUDIENCE = 'oxy-api/agent';
10
- exports.AGENT_PROOF_TTL_MS = 60000;
11
- exports.AGENT_PROOF_ACTIONS = [
12
- 'agent_signin',
13
- 'agent_enroll',
14
- 'agent_rotate',
15
- 'agent_recover',
16
- 'agent_governance',
17
- ];
9
+ // The Zod-free half of this contract lives in `./client/` (`@oxy.so/contracts/client`);
10
+ // it is re-exported here so the root entry is unchanged.
11
+ const agentKeys_1 = require("./client/agentKeys");
12
+ var agentKeys_2 = require("./client/agentKeys");
13
+ Object.defineProperty(exports, "AGENT_PROOF_AUDIENCE", { enumerable: true, get: function () { return agentKeys_2.AGENT_PROOF_AUDIENCE; } });
14
+ Object.defineProperty(exports, "AGENT_PROOF_TTL_MS", { enumerable: true, get: function () { return agentKeys_2.AGENT_PROOF_TTL_MS; } });
15
+ Object.defineProperty(exports, "AGENT_PROOF_ACTIONS", { enumerable: true, get: function () { return agentKeys_2.AGENT_PROOF_ACTIONS; } });
16
+ Object.defineProperty(exports, "ACCOUNT_AUTH_METHODS", { enumerable: true, get: function () { return agentKeys_2.ACCOUNT_AUTH_METHODS; } });
18
17
  exports.agentProofClaimsSchema = zod_1.z
19
18
  .object({
20
19
  version: zod_1.z.literal(1),
21
- audience: zod_1.z.literal(exports.AGENT_PROOF_AUDIENCE),
22
- action: zod_1.z.enum(exports.AGENT_PROOF_ACTIONS),
20
+ audience: zod_1.z.literal(agentKeys_1.AGENT_PROOF_AUDIENCE),
21
+ action: zod_1.z.enum(agentKeys_1.AGENT_PROOF_ACTIONS),
23
22
  accountId: zod_1.z.string().min(1),
24
23
  actorId: zod_1.z.string().min(1),
25
24
  authMethodId: zod_1.z.string().nullable(),
@@ -101,7 +100,6 @@ exports.agentKeyOperationResultSchema = zod_1.z
101
100
  revokedMethodIds: zod_1.z.array(zod_1.z.string()),
102
101
  })
103
102
  .strict();
104
- exports.ACCOUNT_AUTH_METHODS = ['identity', 'agent_key'];
105
103
  /** Public credential inventory. Never includes a proof, bearer or private key. */
106
104
  exports.agentKeyListResponseSchema = zod_1.z
107
105
  .object({
@@ -0,0 +1,211 @@
1
+ "use strict";
2
+ /**
3
+ * Application roles — the wire contract for permissions an APPLICATION declares
4
+ * about its own users, and for the grants that give them to Oxy users.
5
+ *
6
+ * Oxy decides who holds an app's operator powers (who may run Mercaria's
7
+ * payments desk, moderate GoWay, administer Homiio), so no app keeps an
8
+ * allow-list of Oxy user ids in its environment. The app declares a closed
9
+ * vocabulary of keys, its owners grant them to people, and the app's backend
10
+ * asks Oxy which of them the human behind a request holds
11
+ * (`GET /applications/:appId/roles/me`, read through `@oxy.so/core/server`).
12
+ *
13
+ * ## Why an application key can never collide with an Oxy permission
14
+ *
15
+ * Every permission Oxy itself checks (`app:update`, `apps:create`,
16
+ * `credentials:rotate`, every scope) is spelled with a COLON. An application key
17
+ * is dot-separated lowercase segments and cannot contain one, so the two
18
+ * vocabularies are disjoint by syntax, not by convention. They are also stored
19
+ * apart (scoped to one application id) and no Oxy gate ever reads an
20
+ * application key. A key means something only to the application that declared
21
+ * it.
22
+ *
23
+ * The pattern is exported as a SOURCE string because the API renders the same
24
+ * text into a Postgres CHECK; JavaScript's `RegExp` and Postgres' ARE agree on
25
+ * everything it uses (anchors, classes, a capturing group, a bounded repeat).
26
+ *
27
+ * Platform-agnostic — zod only, no react/react-native/expo.
28
+ */
29
+ Object.defineProperty(exports, "__esModule", { value: true });
30
+ exports.applicationRolesMeSchema = exports.listApplicationRoleGrantsQuerySchema = exports.revokeApplicationRoleGrantRequestSchema = exports.createApplicationRoleGrantRequestSchema = exports.applicationRoleGrantListSchema = exports.applicationRoleGrantSchema = exports.declareApplicationPermissionsResponseSchema = exports.applicationPermissionListSchema = exports.applicationPermissionSchema = exports.declareApplicationPermissionsRequestSchema = exports.applicationPermissionDeclarationSchema = exports.applicationPermissionKeySchema = exports.APPLICATION_ROLE_ERROR_CODES = exports.APPLICATION_ROLE_GRANTS_PAGE_MAX = exports.APPLICATION_ROLE_GRANTS_PAGE_DEFAULT = exports.APPLICATION_ROLE_REASON_MAX_LENGTH = exports.APPLICATION_PERMISSIONS_MAX_DECLARED = exports.APPLICATION_PERMISSION_DESCRIPTION_MAX_LENGTH = exports.APPLICATION_PERMISSION_KEY_MAX_LENGTH = exports.APPLICATION_PERMISSION_KEY_PATTERN = exports.APPLICATION_PERMISSION_KEY_PATTERN_SOURCE = void 0;
31
+ exports.isApplicationPermissionKey = isApplicationPermissionKey;
32
+ const zod_1 = require("zod");
33
+ /**
34
+ * Two to four dot-separated segments, each a lowercase letter followed by
35
+ * lowercase letters, digits or underscores: `payments.operate`,
36
+ * `catalog.review.publish`. At least two segments so a key always names an
37
+ * area and an action; never a colon (see the header).
38
+ */
39
+ exports.APPLICATION_PERMISSION_KEY_PATTERN_SOURCE = '^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*){1,3}$';
40
+ exports.APPLICATION_PERMISSION_KEY_PATTERN = new RegExp(exports.APPLICATION_PERMISSION_KEY_PATTERN_SOURCE);
41
+ exports.APPLICATION_PERMISSION_KEY_MAX_LENGTH = 64;
42
+ exports.APPLICATION_PERMISSION_DESCRIPTION_MAX_LENGTH = 280;
43
+ /** How many live keys one application may declare. Operator powers are few. */
44
+ exports.APPLICATION_PERMISSIONS_MAX_DECLARED = 64;
45
+ exports.APPLICATION_ROLE_REASON_MAX_LENGTH = 500;
46
+ exports.APPLICATION_ROLE_GRANTS_PAGE_DEFAULT = 50;
47
+ exports.APPLICATION_ROLE_GRANTS_PAGE_MAX = 200;
48
+ /**
49
+ * The `error` codes the application-roles routes answer beyond the generic
50
+ * ones (`BAD_REQUEST`, `UNAUTHORIZED`, `FORBIDDEN`, `NOT_FOUND`). Renaming one
51
+ * is a breaking change.
52
+ */
53
+ exports.APPLICATION_ROLE_ERROR_CODES = {
54
+ /** 403: a grant naming yourself on an application you do not own outright. */
55
+ selfGrantForbidden: 'SELF_GRANT_FORBIDDEN',
56
+ /** 422: the key is not a live declared permission of this application. */
57
+ unknownPermission: 'UNKNOWN_PERMISSION',
58
+ /** 422: the grantee is not a person (an organization, project, bot or channel). */
59
+ granteeNotAPerson: 'GRANTEE_NOT_A_PERSON',
60
+ /** 409: the grantee already holds the key; `details.grantId` names the live grant. */
61
+ alreadyGranted: 'ALREADY_GRANTED',
62
+ /** 409: the grant was already revoked. */
63
+ alreadyRevoked: 'ALREADY_REVOKED',
64
+ /** 403: the bearer's session belongs to a DIFFERENT application. */
65
+ sessionApplicationMismatch: 'SESSION_APPLICATION_MISMATCH',
66
+ };
67
+ /** Whether `value` is a well-formed application permission key. */
68
+ function isApplicationPermissionKey(value) {
69
+ return (typeof value === 'string' &&
70
+ value.length <= exports.APPLICATION_PERMISSION_KEY_MAX_LENGTH &&
71
+ exports.APPLICATION_PERMISSION_KEY_PATTERN.test(value));
72
+ }
73
+ exports.applicationPermissionKeySchema = zod_1.z
74
+ .string()
75
+ .max(exports.APPLICATION_PERMISSION_KEY_MAX_LENGTH)
76
+ .regex(exports.APPLICATION_PERMISSION_KEY_PATTERN, 'A permission key is 2-4 dot-separated lowercase segments, e.g. payments.operate');
77
+ /** Plain text: no control characters other than a newline or a tab. */
78
+ function plainText(max) {
79
+ return zod_1.z
80
+ .string()
81
+ .trim()
82
+ .min(1)
83
+ .max(max)
84
+ .refine((value) => Array.from(value).every((character) => {
85
+ const code = character.charCodeAt(0);
86
+ return (code >= 32 && code !== 127) || character === '\n' || character === '\t';
87
+ }), 'Must be plain text');
88
+ }
89
+ const id = zod_1.z.string().min(1).max(128);
90
+ const isoTimestamp = zod_1.z.string().min(1);
91
+ const reasonSchema = plainText(exports.APPLICATION_ROLE_REASON_MAX_LENGTH);
92
+ /** One key as the application's owners declare it. */
93
+ exports.applicationPermissionDeclarationSchema = zod_1.z
94
+ .object({
95
+ key: exports.applicationPermissionKeySchema,
96
+ description: plainText(exports.APPLICATION_PERMISSION_DESCRIPTION_MAX_LENGTH),
97
+ })
98
+ .strict();
99
+ /**
100
+ * `PUT /applications/:appId/roles/permissions` — the WHOLE vocabulary.
101
+ *
102
+ * Declarative: a key present here and not live is added, a live key absent
103
+ * here is retired (and every grant of it revoked), a live key present here
104
+ * keeps its identity and takes the new description. Sending the same body twice
105
+ * changes nothing.
106
+ */
107
+ exports.declareApplicationPermissionsRequestSchema = zod_1.z
108
+ .object({
109
+ permissions: zod_1.z
110
+ .array(exports.applicationPermissionDeclarationSchema)
111
+ .max(exports.APPLICATION_PERMISSIONS_MAX_DECLARED),
112
+ })
113
+ .strict()
114
+ .superRefine((value, ctx) => {
115
+ const seen = new Set();
116
+ value.permissions.forEach((permission, index) => {
117
+ if (seen.has(permission.key)) {
118
+ ctx.addIssue({
119
+ code: zod_1.z.ZodIssueCode.custom,
120
+ path: ['permissions', index, 'key'],
121
+ message: `Duplicate permission key ${permission.key}`,
122
+ });
123
+ }
124
+ seen.add(permission.key);
125
+ });
126
+ });
127
+ /** A declared key. Retired keys are history: they confer nothing. */
128
+ exports.applicationPermissionSchema = zod_1.z.object({
129
+ key: exports.applicationPermissionKeySchema,
130
+ description: zod_1.z.string(),
131
+ declaredAt: isoTimestamp,
132
+ declaredByUserId: id.nullable(),
133
+ retiredAt: isoTimestamp.nullable(),
134
+ retiredByUserId: id.nullable(),
135
+ });
136
+ exports.applicationPermissionListSchema = zod_1.z.object({
137
+ items: zod_1.z.array(exports.applicationPermissionSchema),
138
+ });
139
+ exports.declareApplicationPermissionsResponseSchema = exports.applicationPermissionListSchema.extend({
140
+ /** Keys that became live with this declaration. */
141
+ added: zod_1.z.array(exports.applicationPermissionKeySchema),
142
+ /** Keys this declaration retired. */
143
+ retired: zod_1.z.array(exports.applicationPermissionKeySchema),
144
+ /** Live keys whose description changed. */
145
+ described: zod_1.z.array(exports.applicationPermissionKeySchema),
146
+ /** Live grants revoked because their key was retired. */
147
+ revokedGrants: zod_1.z.number().int().nonnegative(),
148
+ });
149
+ /** One grant of one key to one Oxy user. Revocation is a stamp, never a delete. */
150
+ exports.applicationRoleGrantSchema = zod_1.z.object({
151
+ id,
152
+ applicationId: id,
153
+ permission: exports.applicationPermissionKeySchema,
154
+ userId: id,
155
+ /** The grantee's handle, for display. */
156
+ username: zod_1.z.string().nullable(),
157
+ /** The HUMAN who granted it; null once that account was erased. */
158
+ grantedByUserId: id.nullable(),
159
+ grantedAt: isoTimestamp,
160
+ grantReason: zod_1.z.string().nullable(),
161
+ revokedAt: isoTimestamp.nullable(),
162
+ revokedByUserId: id.nullable(),
163
+ revokeReason: zod_1.z.string().nullable(),
164
+ });
165
+ exports.applicationRoleGrantListSchema = zod_1.z.object({
166
+ items: zod_1.z.array(exports.applicationRoleGrantSchema),
167
+ nextCursor: zod_1.z.string().nullable(),
168
+ });
169
+ /** `POST /applications/:appId/roles/grants` — name the grantee by id OR handle. */
170
+ exports.createApplicationRoleGrantRequestSchema = zod_1.z
171
+ .object({
172
+ userId: id.optional(),
173
+ username: zod_1.z.string().trim().min(1).max(64).optional(),
174
+ permission: exports.applicationPermissionKeySchema,
175
+ reason: reasonSchema.optional(),
176
+ })
177
+ .strict()
178
+ .refine((value) => (value.userId === undefined) !== (value.username === undefined), {
179
+ message: 'Name the grantee with exactly one of userId or username',
180
+ path: ['userId'],
181
+ });
182
+ /** `POST /applications/:appId/roles/grants/:grantId/revoke`. */
183
+ exports.revokeApplicationRoleGrantRequestSchema = zod_1.z
184
+ .object({
185
+ reason: reasonSchema.optional(),
186
+ })
187
+ .strict();
188
+ /** `GET /applications/:appId/roles/grants` query. */
189
+ exports.listApplicationRoleGrantsQuerySchema = zod_1.z
190
+ .object({
191
+ permission: exports.applicationPermissionKeySchema.optional(),
192
+ userId: id.optional(),
193
+ includeRevoked: zod_1.z
194
+ .enum(['true', 'false'])
195
+ .transform((value) => value === 'true')
196
+ .optional(),
197
+ limit: zod_1.z.coerce.number().int().min(1).max(exports.APPLICATION_ROLE_GRANTS_PAGE_MAX).optional(),
198
+ cursor: zod_1.z.string().min(1).max(512).optional(),
199
+ })
200
+ .strict();
201
+ /**
202
+ * `GET /applications/:appId/roles/me` — the keys the HUMAN behind the bearer
203
+ * holds for this application, in no particular order. `userId` is that human
204
+ * (the operator), which is NOT the account the session speaks as when a person
205
+ * is acting as an organization.
206
+ */
207
+ exports.applicationRolesMeSchema = zod_1.z.object({
208
+ applicationId: id,
209
+ userId: id,
210
+ permissions: zod_1.z.array(exports.applicationPermissionKeySchema),
211
+ });
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ /**
3
+ * Account-email constants and response checks, without Zod. Schemas: `../accountEmail.ts`.
4
+ *
5
+ * Part of `@oxy.so/contracts/client`: never import `zod` here (see `./check.ts`).
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.emailVerificationConfirmResponseCheck = exports.emailVerificationStartResponseCheck = exports.emailTicketCheck = exports.emailAddressCheck = exports.EMAIL_VERIFICATION_ERROR_CODES = exports.EMAIL_TICKET_TTL_MS = exports.EMAIL_CODE_MAX_ATTEMPTS = exports.EMAIL_CODE_TTL_MS = exports.EMAIL_CODE_LENGTH = exports.EMAIL_VERIFICATION_PURPOSES = void 0;
9
+ const check_1 = require("./check");
10
+ /**
11
+ * - `signup`: above.
12
+ * - `signin`: the code (and link) of an email sign-in (`POST /auth/signin/email/start`).
13
+ * - `reauth`: a signed-in person proving it is them before a sensitive step
14
+ * (`POST /users/me/reauth/email`): a password, an authenticator, deleting the
15
+ * account, linking Commons.
16
+ */
17
+ exports.EMAIL_VERIFICATION_PURPOSES = ['signup', 'signin', 'reauth'];
18
+ /** Digits in a code. */
19
+ exports.EMAIL_CODE_LENGTH = 6;
20
+ /** How long a code can be confirmed. */
21
+ exports.EMAIL_CODE_TTL_MS = 10 * 60 * 1000;
22
+ /** Wrong codes before a verification is spent and a new code is needed. */
23
+ exports.EMAIL_CODE_MAX_ATTEMPTS = 5;
24
+ /** How long a confirmed code's ticket can be spent. */
25
+ exports.EMAIL_TICKET_TTL_MS = 15 * 60 * 1000;
26
+ /**
27
+ * Stable error codes (`error.code` in the API error body). Clients map these
28
+ * through their localization, never the English message.
29
+ */
30
+ exports.EMAIL_VERIFICATION_ERROR_CODES = {
31
+ /** The code is wrong, or its verification expired or was spent. */
32
+ codeInvalid: 'EMAIL_CODE_INVALID',
33
+ /** Too many wrong codes: request a new one. */
34
+ tooManyAttempts: 'EMAIL_CODE_TOO_MANY_ATTEMPTS',
35
+ /** The ticket is unknown, expired, spent, or for another email or purpose. */
36
+ ticketInvalid: 'EMAIL_TICKET_INVALID',
37
+ /** A sign-up without a confirmed email. */
38
+ ticketRequired: 'EMAIL_TICKET_REQUIRED',
39
+ /** This server cannot send mail. */
40
+ unavailable: 'EMAIL_UNAVAILABLE',
41
+ };
42
+ /* -------------------------------------------------------------------------- */
43
+ /* Checks */
44
+ /* -------------------------------------------------------------------------- */
45
+ exports.emailAddressCheck = (0, check_1.string)(check_1.trim, check_1.toLowerCase, (0, check_1.minLength)(3), (0, check_1.maxLength)(254), check_1.email);
46
+ exports.emailTicketCheck = (0, check_1.string)(check_1.trim, (0, check_1.pattern)(/^[A-Za-z0-9_-]{43}$/, 'ticket must be 32 bytes of base64url'));
47
+ exports.emailVerificationStartResponseCheck = (0, check_1.exact)()((0, check_1.object)({ verificationId: (0, check_1.string)((0, check_1.minLength)(1), (0, check_1.maxLength)(64)), expiresAt: (0, check_1.number)(check_1.int, check_1.positive) }));
48
+ exports.emailVerificationConfirmResponseCheck = (0, check_1.exact)()((0, check_1.object)({ ticket: exports.emailTicketCheck, expiresAt: (0, check_1.number)(check_1.int, check_1.positive) }));