@hartl-services/medusa-contracts 1.6.0 → 1.8.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/README.md CHANGED
@@ -77,7 +77,12 @@ The order assistant (`order-assistant`) is not a JSON REST route: `paths` holds
77
77
  the MCP endpoint (`/mcp`), `schemas` the input and output schemas of its four
78
78
  tools, the tool names and the order metadata keys the assistant writes, and
79
79
  `types` their inferred types. A storefront never calls it; the consumer is an
80
- MCP client (an AI chatbot) and the base's own tests.
80
+ MCP client (an AI chatbot) and the base's own tests. Since 1.7.0 the same
81
+ subpaths also hold the assistant's OAuth sign-in: `paths.oauth` (discovery,
82
+ registration, authorization, token), `paths.admin` and `paths.adminPages`
83
+ (consent page and connected chatbots in the Admin), the request and response
84
+ schemas of those endpoints, `ORDER_ASSISTANT_FEATURES` and
85
+ `ORDER_ASSISTANT_OAUTH` (scope and lifetimes).
81
86
 
82
87
  File Gateway responses are binary and have no JSON response DTO. Public paths
83
88
  come from `paths/files`. Private gateway URLs are opaque, signed server results
@@ -15,6 +15,7 @@ export declare const EmailKindSchema: z.ZodEnum<{
15
15
  "affiliate.application_submitted.admin": "affiliate.application_submitted.admin";
16
16
  "user.invite": "user.invite";
17
17
  "system.credential_expiry.admin": "system.credential_expiry.admin";
18
+ "order.picked_up": "order.picked_up";
18
19
  }>;
19
20
  export declare const EmailMessageStatusSchema: z.ZodEnum<{
20
21
  unknown: "unknown";
@@ -61,7 +62,7 @@ export declare const EMAIL_ATTACHMENT_MAX_PDF_BYTES: number;
61
62
  * Customer mails an Admin can attach library documents (terms, legal notices,
62
63
  * flyers) to. Account, Shop and affiliate mails never carry them.
63
64
  */
64
- export declare const EMAIL_ATTACHABLE_KINDS: readonly ["order.received", "order.shipped", "order.canceled", "order.return_requested", "order.return_received", "order.refunded"];
65
+ export declare const EMAIL_ATTACHABLE_KINDS: readonly ["order.received", "order.shipped", "order.picked_up", "order.canceled", "order.return_requested", "order.return_received", "order.refunded"];
65
66
  export declare const EmailAttachableKindSchema: z.ZodEnum<{
66
67
  "order.received": "order.received";
67
68
  "order.shipped": "order.shipped";
@@ -69,6 +70,7 @@ export declare const EmailAttachableKindSchema: z.ZodEnum<{
69
70
  "order.return_requested": "order.return_requested";
70
71
  "order.return_received": "order.return_received";
71
72
  "order.refunded": "order.refunded";
73
+ "order.picked_up": "order.picked_up";
72
74
  }>;
73
75
  export declare const ListAdminEmailMessagesQuerySchema: z.ZodObject<{
74
76
  kind: z.ZodOptional<z.ZodEnum<{
@@ -87,6 +89,7 @@ export declare const ListAdminEmailMessagesQuerySchema: z.ZodObject<{
87
89
  "affiliate.application_submitted.admin": "affiliate.application_submitted.admin";
88
90
  "user.invite": "user.invite";
89
91
  "system.credential_expiry.admin": "system.credential_expiry.admin";
92
+ "order.picked_up": "order.picked_up";
90
93
  }>>;
91
94
  status: z.ZodOptional<z.ZodEnum<{
92
95
  unknown: "unknown";
@@ -117,7 +120,8 @@ export declare const CreateAdminEmailAttachmentDocumentSchema: z.ZodObject<{
117
120
  "order.return_requested": "order.return_requested";
118
121
  "order.return_received": "order.return_received";
119
122
  "order.refunded": "order.refunded";
120
- }>>, z.ZodTransform<("order.received" | "order.shipped" | "order.canceled" | "order.return_requested" | "order.return_received" | "order.refunded")[], ("order.received" | "order.shipped" | "order.canceled" | "order.return_requested" | "order.return_received" | "order.refunded")[]>>;
123
+ "order.picked_up": "order.picked_up";
124
+ }>>, z.ZodTransform<("order.received" | "order.shipped" | "order.canceled" | "order.return_requested" | "order.return_received" | "order.refunded" | "order.picked_up")[], ("order.received" | "order.shipped" | "order.canceled" | "order.return_requested" | "order.return_received" | "order.refunded" | "order.picked_up")[]>>;
121
125
  }, z.core.$strict>;
122
126
  export declare const UpdateAdminEmailAttachmentDocumentSchema: z.ZodObject<{
123
127
  name: z.ZodString;
@@ -128,7 +132,8 @@ export declare const UpdateAdminEmailAttachmentDocumentSchema: z.ZodObject<{
128
132
  "order.return_requested": "order.return_requested";
129
133
  "order.return_received": "order.return_received";
130
134
  "order.refunded": "order.refunded";
131
- }>>, z.ZodTransform<("order.received" | "order.shipped" | "order.canceled" | "order.return_requested" | "order.return_received" | "order.refunded")[], ("order.received" | "order.shipped" | "order.canceled" | "order.return_requested" | "order.return_received" | "order.refunded")[]>>>;
135
+ "order.picked_up": "order.picked_up";
136
+ }>>, z.ZodTransform<("order.received" | "order.shipped" | "order.canceled" | "order.return_requested" | "order.return_received" | "order.refunded" | "order.picked_up")[], ("order.received" | "order.shipped" | "order.canceled" | "order.return_requested" | "order.return_received" | "order.refunded" | "order.picked_up")[]>>>;
132
137
  }, z.core.$strict>;
133
138
  export declare const CreateAdminEmailAttachmentVersionSchema: z.ZodObject<{
134
139
  request_id: z.ZodString;
@@ -154,6 +159,7 @@ export declare const AdminEmailMessageSchema: z.ZodObject<{
154
159
  "affiliate.application_submitted.admin": "affiliate.application_submitted.admin";
155
160
  "user.invite": "user.invite";
156
161
  "system.credential_expiry.admin": "system.credential_expiry.admin";
162
+ "order.picked_up": "order.picked_up";
157
163
  }>;
158
164
  status: z.ZodEnum<{
159
165
  unknown: "unknown";
@@ -258,6 +264,7 @@ export declare const AdminEmailAttachmentDocumentSchema: z.ZodObject<{
258
264
  "order.return_requested": "order.return_requested";
259
265
  "order.return_received": "order.return_received";
260
266
  "order.refunded": "order.refunded";
267
+ "order.picked_up": "order.picked_up";
261
268
  }>>;
262
269
  versions: z.ZodArray<z.ZodObject<{
263
270
  id: z.ZodString;
@@ -289,6 +296,7 @@ export declare const ListAdminEmailMessagesResponseSchema: z.ZodObject<{
289
296
  "affiliate.application_submitted.admin": "affiliate.application_submitted.admin";
290
297
  "user.invite": "user.invite";
291
298
  "system.credential_expiry.admin": "system.credential_expiry.admin";
299
+ "order.picked_up": "order.picked_up";
292
300
  }>;
293
301
  status: z.ZodEnum<{
294
302
  unknown: "unknown";
@@ -360,6 +368,7 @@ export declare const GetAdminEmailMessageResponseSchema: z.ZodObject<{
360
368
  "affiliate.application_submitted.admin": "affiliate.application_submitted.admin";
361
369
  "user.invite": "user.invite";
362
370
  "system.credential_expiry.admin": "system.credential_expiry.admin";
371
+ "order.picked_up": "order.picked_up";
363
372
  }>;
364
373
  status: z.ZodEnum<{
365
374
  unknown: "unknown";
@@ -466,6 +475,7 @@ export declare const ResendAdminEmailMessageResponseSchema: z.ZodObject<{
466
475
  "affiliate.application_submitted.admin": "affiliate.application_submitted.admin";
467
476
  "user.invite": "user.invite";
468
477
  "system.credential_expiry.admin": "system.credential_expiry.admin";
478
+ "order.picked_up": "order.picked_up";
469
479
  }>;
470
480
  status: z.ZodEnum<{
471
481
  unknown: "unknown";
@@ -526,6 +536,7 @@ export declare const ListAdminEmailAttachmentDocumentsResponseSchema: z.ZodObjec
526
536
  "order.return_requested": "order.return_requested";
527
537
  "order.return_received": "order.return_received";
528
538
  "order.refunded": "order.refunded";
539
+ "order.picked_up": "order.picked_up";
529
540
  }>>;
530
541
  versions: z.ZodArray<z.ZodObject<{
531
542
  id: z.ZodString;
@@ -551,6 +562,7 @@ export declare const AdminEmailAttachmentDocumentResponseSchema: z.ZodObject<{
551
562
  "order.return_requested": "order.return_requested";
552
563
  "order.return_received": "order.return_received";
553
564
  "order.refunded": "order.refunded";
565
+ "order.picked_up": "order.picked_up";
554
566
  }>>;
555
567
  versions: z.ZodArray<z.ZodObject<{
556
568
  id: z.ZodString;
@@ -590,7 +602,7 @@ export declare const AdminDraftOrderConfirmationResponseSchema: z.ZodObject<{
590
602
  * Mails whose content an Admin edits as a block template. Every other kind
591
603
  * keeps its code template.
592
604
  */
593
- export declare const EMAIL_EDITABLE_KINDS: readonly ["order.received", "order.received.admin", "order.shipped", "order.canceled", "order.return_requested", "order.return_received", "order.refunded", "auth.password_reset", "auth.admin_password_reset", "auth.verification", "auth.login_code", "user.invite", "affiliate.consignment_report_due", "affiliate.application_submitted.admin"];
605
+ export declare const EMAIL_EDITABLE_KINDS: readonly ["order.received", "order.received.admin", "order.shipped", "order.picked_up", "order.canceled", "order.return_requested", "order.return_received", "order.refunded", "auth.password_reset", "auth.admin_password_reset", "auth.verification", "auth.login_code", "user.invite", "affiliate.consignment_report_due", "affiliate.application_submitted.admin"];
594
606
  export declare const EmailEditableKindSchema: z.ZodEnum<{
595
607
  "order.received": "order.received";
596
608
  "order.received.admin": "order.received.admin";
@@ -606,6 +618,7 @@ export declare const EmailEditableKindSchema: z.ZodEnum<{
606
618
  "affiliate.consignment_report_due": "affiliate.consignment_report_due";
607
619
  "affiliate.application_submitted.admin": "affiliate.application_submitted.admin";
608
620
  "user.invite": "user.invite";
621
+ "order.picked_up": "order.picked_up";
609
622
  }>;
610
623
  /** Server-rendered blocks with the mail's real data. */
611
624
  export declare const EmailTemplateDynamicBlockSchema: z.ZodEnum<{
@@ -658,6 +671,12 @@ export declare const EMAIL_TEMPLATE_CATALOG: {
658
671
  readonly placeholders: readonly ["shop_name", "order_number", "customer_name"];
659
672
  readonly required_blocks: readonly [];
660
673
  };
674
+ readonly "order.picked_up": {
675
+ readonly blocks: readonly ["details", "item_list"];
676
+ readonly conditions: readonly ["invoice_attached"];
677
+ readonly placeholders: readonly ["shop_name", "order_number", "customer_name"];
678
+ readonly required_blocks: readonly [];
679
+ };
661
680
  readonly "order.canceled": {
662
681
  readonly blocks: readonly ["details", "order_summary"];
663
682
  readonly conditions: readonly ["cancellation_attached"];
@@ -1798,6 +1817,7 @@ export declare const AdminEmailTemplateSummarySchema: z.ZodObject<{
1798
1817
  "affiliate.consignment_report_due": "affiliate.consignment_report_due";
1799
1818
  "affiliate.application_submitted.admin": "affiliate.application_submitted.admin";
1800
1819
  "user.invite": "user.invite";
1820
+ "order.picked_up": "order.picked_up";
1801
1821
  }>;
1802
1822
  customized: z.ZodBoolean;
1803
1823
  code_override: z.ZodBoolean;
@@ -1820,6 +1840,7 @@ export declare const ListAdminEmailTemplatesResponseSchema: z.ZodObject<{
1820
1840
  "affiliate.consignment_report_due": "affiliate.consignment_report_due";
1821
1841
  "affiliate.application_submitted.admin": "affiliate.application_submitted.admin";
1822
1842
  "user.invite": "user.invite";
1843
+ "order.picked_up": "order.picked_up";
1823
1844
  }>;
1824
1845
  customized: z.ZodBoolean;
1825
1846
  code_override: z.ZodBoolean;
@@ -1843,6 +1864,7 @@ export declare const AdminEmailTemplateResponseSchema: z.ZodObject<{
1843
1864
  "affiliate.consignment_report_due": "affiliate.consignment_report_due";
1844
1865
  "affiliate.application_submitted.admin": "affiliate.application_submitted.admin";
1845
1866
  "user.invite": "user.invite";
1867
+ "order.picked_up": "order.picked_up";
1846
1868
  }>;
1847
1869
  customized: z.ZodBoolean;
1848
1870
  code_override: z.ZodBoolean;
@@ -2400,6 +2422,7 @@ export declare const SetAdminEmailAttachmentMailKindSchema: z.ZodObject<{
2400
2422
  "order.return_requested": "order.return_requested";
2401
2423
  "order.return_received": "order.return_received";
2402
2424
  "order.refunded": "order.refunded";
2425
+ "order.picked_up": "order.picked_up";
2403
2426
  }>;
2404
2427
  attached: z.ZodBoolean;
2405
2428
  }, z.core.$strict>;
@@ -19,6 +19,7 @@ exports.EmailKindSchema = zod_1.z.enum([
19
19
  "affiliate.application_submitted.admin",
20
20
  "user.invite",
21
21
  "system.credential_expiry.admin",
22
+ "order.picked_up",
22
23
  ]);
23
24
  exports.EmailMessageStatusSchema = zod_1.z.enum([
24
25
  "pending",
@@ -73,6 +74,7 @@ const NullableWireDateSchema = primitives_1.WireDateSchema.nullable();
73
74
  exports.EMAIL_ATTACHABLE_KINDS = [
74
75
  "order.received",
75
76
  "order.shipped",
77
+ "order.picked_up",
76
78
  "order.canceled",
77
79
  "order.return_requested",
78
80
  "order.return_received",
@@ -257,6 +259,7 @@ exports.EMAIL_EDITABLE_KINDS = [
257
259
  "order.received",
258
260
  "order.received.admin",
259
261
  "order.shipped",
262
+ "order.picked_up",
260
263
  "order.canceled",
261
264
  "order.return_requested",
262
265
  "order.return_received",
@@ -326,6 +329,12 @@ exports.EMAIL_TEMPLATE_CATALOG = {
326
329
  placeholders: ["shop_name", "order_number", "customer_name"],
327
330
  required_blocks: [],
328
331
  },
332
+ "order.picked_up": {
333
+ blocks: ["details", "item_list"],
334
+ conditions: ["invoice_attached"],
335
+ placeholders: ["shop_name", "order_number", "customer_name"],
336
+ required_blocks: [],
337
+ },
329
338
  "order.canceled": {
330
339
  blocks: ["details", "order_summary"],
331
340
  conditions: ["cancellation_attached"],
@@ -16,6 +16,7 @@ export const EmailKindSchema = z.enum([
16
16
  "affiliate.application_submitted.admin",
17
17
  "user.invite",
18
18
  "system.credential_expiry.admin",
19
+ "order.picked_up",
19
20
  ]);
20
21
  export const EmailMessageStatusSchema = z.enum([
21
22
  "pending",
@@ -70,6 +71,7 @@ const NullableWireDateSchema = WireDateSchema.nullable();
70
71
  export const EMAIL_ATTACHABLE_KINDS = [
71
72
  "order.received",
72
73
  "order.shipped",
74
+ "order.picked_up",
73
75
  "order.canceled",
74
76
  "order.return_requested",
75
77
  "order.return_received",
@@ -254,6 +256,7 @@ export const EMAIL_EDITABLE_KINDS = [
254
256
  "order.received",
255
257
  "order.received.admin",
256
258
  "order.shipped",
259
+ "order.picked_up",
257
260
  "order.canceled",
258
261
  "order.return_requested",
259
262
  "order.return_received",
@@ -323,6 +326,12 @@ export const EMAIL_TEMPLATE_CATALOG = {
323
326
  placeholders: ["shop_name", "order_number", "customer_name"],
324
327
  required_blocks: [],
325
328
  },
329
+ "order.picked_up": {
330
+ blocks: ["details", "item_list"],
331
+ conditions: ["invoice_attached"],
332
+ placeholders: ["shop_name", "order_number", "customer_name"],
333
+ required_blocks: [],
334
+ },
326
335
  "order.canceled": {
327
336
  blocks: ["details", "order_summary"],
328
337
  conditions: ["cancellation_attached"],
@@ -1,7 +1,33 @@
1
1
  /**
2
2
  * The shop's MCP endpoint for the order assistant (Streamable HTTP,
3
3
  * stateless). Outside `/admin` and `/store`: it authenticates on its own.
4
+ *
5
+ * `oauth`: the OAuth 2.1 endpoints an MCP client (claude.ai, ChatGPT) uses
6
+ * to sign an Admin user in; the well-known paths are fixed by RFC 9728 and
7
+ * RFC 8414. `admin`: the Admin API behind the consent page and the list of
8
+ * connected chatbots. `adminPages`: Admin pages, relative to the Admin root.
4
9
  */
5
10
  export const orderAssistantPaths = {
6
11
  mcp: "/mcp",
12
+ oauth: {
13
+ protectedResourceMetadata: "/.well-known/oauth-protected-resource",
14
+ /** Same document; clients probe the path of the MCP endpoint first. */
15
+ protectedResourceMetadataForMcp: "/.well-known/oauth-protected-resource/mcp",
16
+ authorizationServerMetadata: "/.well-known/oauth-authorization-server",
17
+ register: "/mcp/oauth/register",
18
+ authorize: "/mcp/oauth/authorize",
19
+ token: "/mcp/oauth/token",
20
+ },
21
+ admin: {
22
+ authorization: (authorizationId) => `/admin/order-assistant/authorizations/${encodeURIComponent(authorizationId)}`,
23
+ connections: "/admin/order-assistant/connections",
24
+ connection: (connectionId) => `/admin/order-assistant/connections/${encodeURIComponent(connectionId)}`,
25
+ },
26
+ adminPages: {
27
+ /**
28
+ * The request id is a path segment on purpose: the Admin login returns
29
+ * to the path it came from and drops the query string.
30
+ */
31
+ authorize: (authorizationId) => `/order-assistant/authorize/${encodeURIComponent(authorizationId)}`,
32
+ },
7
33
  };
@@ -1,5 +1,5 @@
1
1
  import { z } from "@medusajs/framework/zod";
2
- import { NonEmptyStringSchema } from "../shared/primitives.mjs";
2
+ import { NonEmptyStringSchema, WireDateSchema } from "../shared/primitives.mjs";
3
3
  /** Plugin key and container key of the order assistant in the base. */
4
4
  export const ORDER_ASSISTANT_PLUGIN_KEY = "order_assistant";
5
5
  /** Tool names as the MCP client sees them. */
@@ -181,3 +181,205 @@ export const CreateDraftOrderOutputSchema = z.object({
181
181
  /** Path of the draft in the Admin, relative to the backend URL. */
182
182
  admin_path: z.string(),
183
183
  });
184
+ // --- Anmeldung per OAuth (MCP authorization, OAuth 2.1) --------------------
185
+ /** Feature keys of the order assistant's plugin toggles. */
186
+ export const ORDER_ASSISTANT_FEATURES = {
187
+ oauth: "oauth",
188
+ };
189
+ export const ORDER_ASSISTANT_OAUTH = {
190
+ /** The one scope: use the assistant's tools as the signed-in Admin user. */
191
+ scope: "order_assistant",
192
+ accessTokenTtlSeconds: 3600,
193
+ /** A connection ends when its refresh token stays unused this long. */
194
+ connectionIdleDays: 30,
195
+ /** How long the consent page may stay open. */
196
+ authorizationRequestTtlSeconds: 600,
197
+ /** How long the client has to redeem the code after the consent. */
198
+ authorizationCodeTtlSeconds: 120,
199
+ maxRedirectUris: 10,
200
+ maxUriLength: 2000,
201
+ maxClientNameLength: 120,
202
+ maxStateLength: 2000,
203
+ };
204
+ const OAUTH_LOOPBACK_HOSTS = ["localhost", "127.0.0.1", "[::1]"];
205
+ /** `http://localhost`, `http://127.0.0.1` or `http://[::1]`, any port. */
206
+ export const isOAuthLoopbackRedirectUri = (value) => {
207
+ try {
208
+ const url = new URL(value);
209
+ return (url.protocol === "http:" && OAUTH_LOOPBACK_HOSTS.includes(url.hostname));
210
+ }
211
+ catch {
212
+ return false;
213
+ }
214
+ };
215
+ /**
216
+ * A redirect URI a client may register: https, or http on a loopback address
217
+ * (native clients such as Claude Code), without credentials or fragment.
218
+ */
219
+ export const OAuthRedirectUriSchema = z
220
+ .string()
221
+ .max(ORDER_ASSISTANT_OAUTH.maxUriLength)
222
+ .refine((value) => {
223
+ let url;
224
+ try {
225
+ url = new URL(value);
226
+ }
227
+ catch {
228
+ return false;
229
+ }
230
+ if (url.hash || url.username || url.password) {
231
+ return false;
232
+ }
233
+ return url.protocol === "https:" || isOAuthLoopbackRedirectUri(value);
234
+ }, {
235
+ message: "A redirect URI must use https, or http on a loopback address, and carry no fragment.",
236
+ });
237
+ /**
238
+ * Dynamic client registration request (RFC 7591). Unknown metadata is
239
+ * ignored; the requested authentication method, grant and response types are
240
+ * accepted as sent and answered with what the server actually supports.
241
+ */
242
+ export const OAuthClientRegistrationRequestSchema = z.object({
243
+ redirect_uris: z
244
+ .array(OAuthRedirectUriSchema)
245
+ .min(1)
246
+ .max(ORDER_ASSISTANT_OAUTH.maxRedirectUris),
247
+ client_name: z
248
+ .string()
249
+ .trim()
250
+ .min(1)
251
+ .max(ORDER_ASSISTANT_OAUTH.maxClientNameLength)
252
+ .optional(),
253
+ });
254
+ export const OAuthClientRegistrationResponseSchema = z.object({
255
+ client_id: z.string(),
256
+ /** Seconds since the epoch. */
257
+ client_id_issued_at: z.number(),
258
+ client_name: z.string().optional(),
259
+ redirect_uris: z.array(z.string()),
260
+ /** Public clients only: PKCE instead of a client secret. */
261
+ token_endpoint_auth_method: z.literal("none"),
262
+ grant_types: z.array(z.string()),
263
+ response_types: z.array(z.string()),
264
+ scope: z.string(),
265
+ });
266
+ /** Query of the authorization endpoint, before the client is looked up. */
267
+ export const OAuthAuthorizeQuerySchema = z.object({
268
+ client_id: z.string().min(1).max(200),
269
+ redirect_uri: z.string().min(1).max(ORDER_ASSISTANT_OAUTH.maxUriLength),
270
+ response_type: z.string().max(100).optional(),
271
+ code_challenge: z.string().max(200).optional(),
272
+ code_challenge_method: z.string().max(20).optional(),
273
+ state: z.string().max(ORDER_ASSISTANT_OAUTH.maxStateLength).optional(),
274
+ scope: z.string().max(1000).optional(),
275
+ resource: z.string().max(ORDER_ASSISTANT_OAUTH.maxUriLength).optional(),
276
+ });
277
+ /** Body of the token endpoint (`application/x-www-form-urlencoded`). */
278
+ export const OAuthTokenRequestSchema = z.discriminatedUnion("grant_type", [
279
+ z.object({
280
+ grant_type: z.literal("authorization_code"),
281
+ code: z.string().min(1).max(200),
282
+ /** RFC 7636: 43 to 128 unreserved characters. */
283
+ code_verifier: z.string().regex(/^[A-Za-z0-9\-._~]{43,128}$/),
284
+ client_id: z.string().min(1).max(200),
285
+ redirect_uri: z.string().max(ORDER_ASSISTANT_OAUTH.maxUriLength).optional(),
286
+ resource: z.string().max(ORDER_ASSISTANT_OAUTH.maxUriLength).optional(),
287
+ }),
288
+ z.object({
289
+ grant_type: z.literal("refresh_token"),
290
+ refresh_token: z.string().min(1).max(200),
291
+ client_id: z.string().min(1).max(200),
292
+ resource: z.string().max(ORDER_ASSISTANT_OAUTH.maxUriLength).optional(),
293
+ }),
294
+ ]);
295
+ export const OAuthTokenResponseSchema = z.object({
296
+ access_token: z.string(),
297
+ token_type: z.literal("Bearer"),
298
+ /** Seconds until the access token expires. */
299
+ expires_in: z.number(),
300
+ /** Replaces the refresh token that was sent; the old one stops working. */
301
+ refresh_token: z.string(),
302
+ scope: z.string(),
303
+ });
304
+ export const OAuthErrorCodeSchema = z.enum([
305
+ "invalid_request",
306
+ "invalid_client",
307
+ "invalid_grant",
308
+ "invalid_target",
309
+ "invalid_client_metadata",
310
+ "invalid_redirect_uri",
311
+ "unsupported_grant_type",
312
+ "unsupported_response_type",
313
+ "access_denied",
314
+ "temporarily_unavailable",
315
+ ]);
316
+ /** Error body of the registration and token endpoints (RFC 6749, RFC 7591). */
317
+ export const OAuthErrorResponseSchema = z.object({
318
+ error: OAuthErrorCodeSchema,
319
+ error_description: z.string(),
320
+ });
321
+ /** RFC 9728: where the MCP endpoint's authorization server is. */
322
+ export const OAuthProtectedResourceMetadataSchema = z.object({
323
+ resource: z.string(),
324
+ authorization_servers: z.array(z.string()),
325
+ bearer_methods_supported: z.array(z.string()),
326
+ scopes_supported: z.array(z.string()),
327
+ resource_name: z.string(),
328
+ });
329
+ /** RFC 8414: the authorization server's endpoints and capabilities. */
330
+ export const OAuthAuthorizationServerMetadataSchema = z.object({
331
+ issuer: z.string(),
332
+ authorization_endpoint: z.string(),
333
+ token_endpoint: z.string(),
334
+ registration_endpoint: z.string(),
335
+ response_types_supported: z.array(z.string()),
336
+ grant_types_supported: z.array(z.string()),
337
+ code_challenge_methods_supported: z.array(z.string()),
338
+ token_endpoint_auth_methods_supported: z.array(z.string()),
339
+ scopes_supported: z.array(z.string()),
340
+ /** RFC 9207: every authorization response carries `iss`. */
341
+ authorization_response_iss_parameter_supported: z.boolean(),
342
+ });
343
+ /** What the consent page shows about a pending sign-in request. */
344
+ export const AdminOrderAssistantAuthorizationSchema = z.object({
345
+ id: z.string(),
346
+ /** Name the chatbot registered with; `null` when it gave none. */
347
+ client_name: z.string().nullable(),
348
+ /** Host the browser is sent back to after the decision. */
349
+ redirect_host: z.string(),
350
+ /** True when the chatbot runs on this computer (loopback redirect). */
351
+ redirect_is_loopback: z.boolean(),
352
+ /** True when the host belongs to a chatbot service the shop knows. */
353
+ redirect_is_known: z.boolean(),
354
+ expires_at: WireDateSchema,
355
+ });
356
+ export const AdminOrderAssistantAuthorizationResponseSchema = z.object({
357
+ authorization: AdminOrderAssistantAuthorizationSchema,
358
+ });
359
+ export const DecideOrderAssistantAuthorizationSchema = z
360
+ .object({ approve: z.boolean() })
361
+ .strict();
362
+ export const DecideOrderAssistantAuthorizationResponseSchema = z.object({
363
+ /** Where the browser must go next: the chatbot's redirect URI. */
364
+ redirect_to: z.string(),
365
+ });
366
+ /** One chatbot an Admin user connected through OAuth. */
367
+ export const AdminOrderAssistantConnectionSchema = z.object({
368
+ id: z.string(),
369
+ client_name: z.string().nullable(),
370
+ redirect_host: z.string(),
371
+ user_id: z.string(),
372
+ /** `null` when the Admin user no longer exists. */
373
+ user_email: z.string().nullable(),
374
+ created_at: WireDateSchema,
375
+ last_used_at: WireDateSchema.nullable(),
376
+ /** When the connection ends unless the chatbot uses it before. */
377
+ expires_at: WireDateSchema,
378
+ });
379
+ export const AdminOrderAssistantConnectionsResponseSchema = z.object({
380
+ connections: z.array(AdminOrderAssistantConnectionSchema),
381
+ });
382
+ export const DeleteOrderAssistantConnectionResponseSchema = z.object({
383
+ id: z.string(),
384
+ deleted: z.literal(true),
385
+ });
@@ -1,7 +1,33 @@
1
1
  /**
2
2
  * The shop's MCP endpoint for the order assistant (Streamable HTTP,
3
3
  * stateless). Outside `/admin` and `/store`: it authenticates on its own.
4
+ *
5
+ * `oauth`: the OAuth 2.1 endpoints an MCP client (claude.ai, ChatGPT) uses
6
+ * to sign an Admin user in; the well-known paths are fixed by RFC 9728 and
7
+ * RFC 8414. `admin`: the Admin API behind the consent page and the list of
8
+ * connected chatbots. `adminPages`: Admin pages, relative to the Admin root.
4
9
  */
5
10
  export declare const orderAssistantPaths: {
6
11
  readonly mcp: "/mcp";
12
+ readonly oauth: {
13
+ readonly protectedResourceMetadata: "/.well-known/oauth-protected-resource";
14
+ /** Same document; clients probe the path of the MCP endpoint first. */
15
+ readonly protectedResourceMetadataForMcp: "/.well-known/oauth-protected-resource/mcp";
16
+ readonly authorizationServerMetadata: "/.well-known/oauth-authorization-server";
17
+ readonly register: "/mcp/oauth/register";
18
+ readonly authorize: "/mcp/oauth/authorize";
19
+ readonly token: "/mcp/oauth/token";
20
+ };
21
+ readonly admin: {
22
+ readonly authorization: (authorizationId: string) => string;
23
+ readonly connections: "/admin/order-assistant/connections";
24
+ readonly connection: (connectionId: string) => string;
25
+ };
26
+ readonly adminPages: {
27
+ /**
28
+ * The request id is a path segment on purpose: the Admin login returns
29
+ * to the path it came from and drops the query string.
30
+ */
31
+ readonly authorize: (authorizationId: string) => string;
32
+ };
7
33
  };
@@ -4,7 +4,33 @@ exports.orderAssistantPaths = void 0;
4
4
  /**
5
5
  * The shop's MCP endpoint for the order assistant (Streamable HTTP,
6
6
  * stateless). Outside `/admin` and `/store`: it authenticates on its own.
7
+ *
8
+ * `oauth`: the OAuth 2.1 endpoints an MCP client (claude.ai, ChatGPT) uses
9
+ * to sign an Admin user in; the well-known paths are fixed by RFC 9728 and
10
+ * RFC 8414. `admin`: the Admin API behind the consent page and the list of
11
+ * connected chatbots. `adminPages`: Admin pages, relative to the Admin root.
7
12
  */
8
13
  exports.orderAssistantPaths = {
9
14
  mcp: "/mcp",
15
+ oauth: {
16
+ protectedResourceMetadata: "/.well-known/oauth-protected-resource",
17
+ /** Same document; clients probe the path of the MCP endpoint first. */
18
+ protectedResourceMetadataForMcp: "/.well-known/oauth-protected-resource/mcp",
19
+ authorizationServerMetadata: "/.well-known/oauth-authorization-server",
20
+ register: "/mcp/oauth/register",
21
+ authorize: "/mcp/oauth/authorize",
22
+ token: "/mcp/oauth/token",
23
+ },
24
+ admin: {
25
+ authorization: (authorizationId) => `/admin/order-assistant/authorizations/${encodeURIComponent(authorizationId)}`,
26
+ connections: "/admin/order-assistant/connections",
27
+ connection: (connectionId) => `/admin/order-assistant/connections/${encodeURIComponent(connectionId)}`,
28
+ },
29
+ adminPages: {
30
+ /**
31
+ * The request id is a path segment on purpose: the Admin login returns
32
+ * to the path it came from and drops the query string.
33
+ */
34
+ authorize: (authorizationId) => `/order-assistant/authorize/${encodeURIComponent(authorizationId)}`,
35
+ },
10
36
  };