@womp/openai-plugin 0.3.0 → 0.4.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
@@ -23,8 +23,8 @@ src/
23
23
  index.ts public API
24
24
  server.ts createServer → registerResources (every card) + registerTools (every tool group)
25
25
  backend.ts WompBackend: the contract the host implements
26
- tools/ one file per tool group (scene.ts); tool.ts: shared helpers
27
- cards/ one folder per card (design/); bridge.ts: shared host connection
26
+ tools/ one file per tool group (scene.ts, commerce.ts); tool.ts: shared helpers
27
+ cards/ one folder per card (design/, quote/, order/); bridge.ts: shared host connection
28
28
  text.ts what tools and cards say to the model
29
29
  prompts/ the workflow the model follows
30
30
  ```
@@ -39,13 +39,17 @@ src/
39
39
 
40
40
  | Export | Purpose |
41
41
  |---|---|
42
- | `createServer({ backend, subject?, onError?, instructions? })` | the MCP server for one request |
42
+ | `createServer({ backend, subject?, onError?, instructions?, liveViewOrigin?, linkOrigins? })` | the MCP server for one request |
43
43
  | `WompBackend` | the contract the host implements |
44
44
  | `BackendRefusal` | an error whose message reaches the model as worded |
45
+ | `CheckoutSession`, `CompleteCheckoutArgs` | ChatGPT's payment sheet: the session it takes, and what it hands `complete_checkout` |
45
46
 
46
47
  `subject` is the caller as the host established it. `onError` receives every
47
48
  error that is not a `BackendRefusal`. `instructions` is appended to the
48
- server instructions, for tools the host registers itself.
49
+ server instructions, for tools the host registers itself. `liveViewOrigin` is
50
+ the one origin the design card may frame, for a live view. `linkOrigins` are
51
+ the origins of the web pages the cards open (checkout, an order's status, an
52
+ account), which ChatGPT then opens without asking the user first.
49
53
 
50
54
  ## Contract
51
55
 
@@ -58,7 +62,12 @@ server instructions, for tools the host registers itself.
58
62
  | `runScript(subject, { designId, code, purpose })` | runs one script on the design; `purpose` becomes the current build's activity, its last screenshot or a fresh render its picture; a failed script returns `ok: false` |
59
63
  | `renderScene(subject, { designId, view?, targetId? })` | renders the design; the image also becomes the current build's picture |
60
64
  | `finishScene(subject, { designId, title })` | marks the current build done, with this version's title |
65
+ | `claimLink?(subject)` | optional: a one-time link to a page that keeps the chat's designs in an account; without it the design card offers no button |
61
66
  | `getBuild(subject, { designId, buildId })` | a build's status, activity, title and picture; a build that isn't the caller's reads as empty |
67
+ | `getPrintOptions(subject, { designId, longestSideCm? })` | the design priced per piece in each material on offer, with its print size, its pieces, and checkout's size limit and order minimum |
68
+ | `checkoutDesign(subject, { designId, material, color?, finish?, quantity?, longestSideCm?, shipTo? })` | freezes the design as quoted and returns the quote with its checkout link; with `shipTo`, also the order to that address as a payment-sheet session |
69
+ | `completeCheckout?(subject, payment)` | optional: charges a payment made in ChatGPT's payment sheet and places the session's order; without it `checkout_design` takes no `shipTo` and there is no `complete_checkout` |
70
+ | `getOrderStatus(subject, { orderId? })` | the caller's paid orders, newest first, and the one to show, with no name, address, email or money |
62
71
 
63
72
  A build is one round of changes and has one card. Opening a new build never
64
73
  changes an earlier one.
@@ -69,7 +78,7 @@ changes an earlier one.
69
78
  - **Errors.** A `BackendRefusal` message reaches the model as is. Any other error is one generic failure, reported to `onError`.
70
79
  - **Tool metadata states facts.** Descriptions, input schemas and server instructions say what a tool does, never how the model should behave. Behaviour lives in `prompts/` and reaches the model in `load_scene_skill`'s result.
71
80
  - **Every tool** declares `ui.visibility`, explicit annotation hints, and `securitySchemes: noauth`. Tools only a card calls are `ui.visibility: ["app"]`.
72
- - **Card data** is the tool result's `structuredContent`, typed by the card's `data.ts`. Tools map backend types to it; a card never receives backend types.
81
+ - **Card data** is the tool result's `structuredContent`, typed by the card's `data.ts`. Tools map backend types to it; a card never receives backend types. What only the card may see is in the result's `_meta`, typed by the same `data.ts`: a link that is a credential, and a quote or an order, which the model would otherwise draw as a card of its own.
73
82
  - **Cards** are MCP Apps resources (`text/html;profile=mcp-app`): one self-contained HTML file each, loading nothing from outside, with a `ui://` URI that changes with its content.
74
83
 
75
84
  ### Tools
@@ -82,6 +91,11 @@ changes an earlier one.
82
91
  | `render_scene` | model | |
83
92
  | `finish_scene` | model | |
84
93
  | `get_scene_progress` | `design` card | |
94
+ | `get_claim_link` | `design` card | |
95
+ | `get_print_options` | model | |
96
+ | `checkout_design` | model | shows `quote` |
97
+ | `complete_checkout` | model and ChatGPT's payment sheet, only with `completeCheckout` | |
98
+ | `get_order_status` | model | shows `order` |
85
99
 
86
100
  ## Extending
87
101
 
package/dist/index.d.ts CHANGED
@@ -57,6 +57,200 @@ interface ClaimLink {
57
57
  url: string;
58
58
  expiresAt: string;
59
59
  }
60
+ interface Size {
61
+ width: number;
62
+ height: number;
63
+ depth: number;
64
+ }
65
+ /** Checkout takes an order whose items cost more than `amount`; below it, it tops the items up to it (`topUp`) or refuses the order. */
66
+ interface MinimumOrder {
67
+ amount: number;
68
+ topUp: boolean;
69
+ }
70
+ /** One material a design can be printed in, priced per piece. */
71
+ interface PrintOption {
72
+ /** The name checkout_design takes, such as "resin-clear-tinted". */
73
+ material: string;
74
+ /** Such as "Tinted clear". */
75
+ label: string;
76
+ /** Per piece, before shipping. */
77
+ unitPrice: number;
78
+ /** Business days to make it, once ordered. */
79
+ productionDays: number;
80
+ /** The material is dyed, so an order names a colour. */
81
+ colorRequired: boolean;
82
+ /** The finishes it is made in; the first is the default. */
83
+ finishes: string[];
84
+ }
85
+ /** A design priced for printing in each material on offer. */
86
+ interface PrintOptions {
87
+ designId: string;
88
+ title: string;
89
+ /** The size it prints at, in cm. */
90
+ sizeCm: Size;
91
+ /** Scaled to the longest side asked for, rather than at its own size. */
92
+ resized: boolean;
93
+ /** How many separate pieces it prints as. */
94
+ pieces: number;
95
+ /** The largest size checkout takes, in cm, in any orientation. */
96
+ maxSizeCm: [number, number, number];
97
+ /** Whether `sizeCm` fits within `maxSizeCm`. */
98
+ fits: boolean;
99
+ currency: string;
100
+ minimumOrder: MinimumOrder;
101
+ options: PrintOption[];
102
+ }
103
+ /** Where an order paid in ChatGPT's payment sheet ships. */
104
+ interface ShipTo {
105
+ name: string;
106
+ line1: string;
107
+ line2?: string;
108
+ city: string;
109
+ state: string;
110
+ postalCode: string;
111
+ /** ISO 3166-1 alpha-2, such as "US". */
112
+ country: string;
113
+ phoneNumber?: string;
114
+ }
115
+ /**
116
+ * The user's own checkout on the web, where they enter an address and pay. Like `ClaimLink` it is a credential: it goes
117
+ * to the card alone, never into text the model reads.
118
+ */
119
+ interface CheckoutLink {
120
+ url: string;
121
+ expiresAt: string;
122
+ }
123
+ /** A design quoted for ordering, as the user chose it. */
124
+ interface Checkout {
125
+ designId: string;
126
+ title: string;
127
+ /** The item as an order lists it, such as "Tinted clear · #e11d48 · glossy · 4.0 × 3.0 × 1.0 cm". */
128
+ summary: string;
129
+ quantity: number;
130
+ /** How many separate pieces each one prints as. */
131
+ pieces: number;
132
+ currency: string;
133
+ /** The whole quantity's price, before shipping. */
134
+ price: number;
135
+ /** The day it leaves the factory, as YYYY-MM-DD. */
136
+ shipsBy: string;
137
+ minimumOrder: MinimumOrder;
138
+ link: CheckoutLink;
139
+ /** Quoted with `shipTo`: the order to that address, ready to pay in ChatGPT's payment sheet. */
140
+ session?: CheckoutSession;
141
+ }
142
+ /** A checkout session in the shape ChatGPT's payment sheet takes (OpenAI's Checkout API). Amounts in cents. */
143
+ interface CheckoutSession {
144
+ id: string;
145
+ status: "ready_for_payment" | "completed";
146
+ currency: string;
147
+ payment_provider: {
148
+ provider: string;
149
+ merchant_id: string;
150
+ supported_payment_methods: {
151
+ type: string;
152
+ allowed_card_brands?: string[];
153
+ }[];
154
+ };
155
+ payment_mode: "test" | "live";
156
+ line_items: {
157
+ id: string;
158
+ item: {
159
+ id: string;
160
+ quantity: number;
161
+ };
162
+ name: string;
163
+ description: string;
164
+ base_amount: number;
165
+ discount: number;
166
+ subtotal: number;
167
+ tax: number;
168
+ total: number;
169
+ }[];
170
+ totals: {
171
+ type: "items_base_amount" | "items_discount" | "subtotal" | "discount" | "fulfillment" | "fee" | "tax" | "total";
172
+ display_text: string;
173
+ amount: number;
174
+ }[];
175
+ fulfillment_options: {
176
+ id: string;
177
+ type: "shipping";
178
+ title: string;
179
+ subtitle: string;
180
+ carrier: string;
181
+ earliest_delivery_time: string;
182
+ latest_delivery_time: string;
183
+ subtotal: number;
184
+ tax: number;
185
+ total: number;
186
+ }[];
187
+ fulfillment_option_id: string;
188
+ fulfillment_address: {
189
+ name: string;
190
+ line_one: string;
191
+ line_two?: string;
192
+ city: string;
193
+ state: string;
194
+ country: string;
195
+ postal_code: string;
196
+ phone_number?: string;
197
+ };
198
+ messages: {
199
+ type: "error";
200
+ code: "missing" | "invalid" | "payment_declined" | "requires_3ds";
201
+ content_type: "plain";
202
+ content: string;
203
+ }[];
204
+ links: {
205
+ type: "terms_of_use" | "privacy_policy";
206
+ url: string;
207
+ }[];
208
+ order?: {
209
+ id: string;
210
+ checkout_session_id: string;
211
+ permalink_url: string;
212
+ };
213
+ }
214
+ /** What ChatGPT's payment sheet hands complete_checkout once the buyer has paid. */
215
+ interface CompleteCheckoutArgs {
216
+ checkout_session_id: string;
217
+ buyer?: {
218
+ name?: string;
219
+ email?: string;
220
+ };
221
+ payment_data: {
222
+ token: string;
223
+ };
224
+ }
225
+ /** One of the user's orders, enough to tell them apart. */
226
+ interface OrderSummary {
227
+ id: number;
228
+ statusLabel: string;
229
+ }
230
+ /**
231
+ * An order as the chat may show it. A checkout link can be forwarded and its buyer's order is found too, so it carries
232
+ * no name, address, email or money.
233
+ */
234
+ interface Order extends OrderSummary {
235
+ step: "paid" | "printing" | "shipped" | "delivered" | "canceled";
236
+ /** Only the items made from this user's checkout links. */
237
+ items: {
238
+ title: string;
239
+ summary: string;
240
+ quantity: number;
241
+ }[];
242
+ tracking: {
243
+ carrier: string;
244
+ trackingNumber: string;
245
+ }[];
246
+ /** When it leaves the factory and when it arrives, as happened or expected (ISO); null when it won't arrive or can't be dated. */
247
+ timeline: {
248
+ factoryShippingStartedAt: string;
249
+ deliveredAt: string;
250
+ } | null;
251
+ /** The order's status page on the web. */
252
+ statusUrl: string | null;
253
+ }
60
254
  interface WompBackend {
61
255
  /** `live` is optional: a host that cannot offer a live view leaves it out and the card shows its picture. */
62
256
  openScene(subject: string, input: {
@@ -92,6 +286,33 @@ interface WompBackend {
92
286
  designId: string;
93
287
  buildId: string;
94
288
  }): Promise<Build>;
289
+ getPrintOptions(subject: string, input: {
290
+ designId: string;
291
+ longestSideCm?: number;
292
+ }): Promise<PrintOptions>;
293
+ /** Freezes the design as quoted, so its order prints it as it is now. `shipTo` comes only to a host with `completeCheckout`. */
294
+ checkoutDesign(subject: string, input: {
295
+ designId: string;
296
+ material: string;
297
+ color?: string;
298
+ finish?: string;
299
+ quantity?: number;
300
+ longestSideCm?: number;
301
+ shipTo?: ShipTo;
302
+ }): Promise<Checkout>;
303
+ /**
304
+ * Optional: paying in ChatGPT's payment sheet. It charges the payment the sheet hands over and places the session's
305
+ * order; a refused payment returns the session with an error message. A host that leaves it out takes no address in
306
+ * checkout_design, and checkout is on the web alone.
307
+ */
308
+ completeCheckout?(subject: string, payment: CompleteCheckoutArgs): Promise<CheckoutSession>;
309
+ /** The user's paid orders, newest first, and the one to show: `orderId` when it is one of theirs, else the newest. */
310
+ getOrderStatus(subject: string, input: {
311
+ orderId?: number;
312
+ }): Promise<{
313
+ order?: Order;
314
+ orders: OrderSummary[];
315
+ }>;
95
316
  }
96
317
  declare class BackendRefusal extends Error {
97
318
  }
@@ -107,7 +328,13 @@ interface ServerOptions {
107
328
  * that is not an origin is the same as none.
108
329
  */
109
330
  liveViewOrigin?: string;
331
+ /**
332
+ * The origins of the web pages the cards open — checkout, an order's status, keeping designs in an account — such as
333
+ * ["https://app.womp.com"]. ChatGPT opens a page on one of them without asking the user first; anything that is not
334
+ * an https origin is left out.
335
+ */
336
+ linkOrigins?: string[];
110
337
  }
111
- declare function createServer({ backend, subject, onError, instructions, liveViewOrigin }: ServerOptions): McpServer;
338
+ declare function createServer({ backend, subject, onError, instructions, liveViewOrigin, linkOrigins }: ServerOptions): McpServer;
112
339
 
113
- export { BackendRefusal, type ClaimLink, type LiveView, type WompBackend, createServer };
340
+ export { BackendRefusal, type CheckoutSession, type ClaimLink, type CompleteCheckoutArgs, type LiveView, type WompBackend, createServer };