shopstack 0.3.0 → 0.3.2

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
@@ -6,9 +6,9 @@ guest restaurant reservations.
6
6
  ## Install
7
7
 
8
8
  ```bash
9
- npm install shopstack@0.3.0
9
+ npm install shopstack@0.3.2
10
10
  # or
11
- npm install -g shopstack@0.3.0
11
+ npm install -g shopstack@0.3.2
12
12
  ```
13
13
 
14
14
  Node.js 18 or newer is required.
@@ -18,12 +18,13 @@ WebSocket (Node.js 22 or newer). It reads the authenticated checkout resource
18
18
  after each notification. Older runtimes, or a failed socket connection, use the
19
19
  bounded HTTP update wait. The one-time socket token is never placed in a URL.
20
20
 
21
- This preview release pairs `shopstack@0.3.0` with `shopstack-mcp@0.2.0`.
21
+ This preview release pairs `shopstack@0.3.2` with `shopstack-mcp@0.2.2`.
22
22
  Both packages use the `preview` distribution tag. The `latest` versions are
23
23
  unchanged. Use the exact versions above to install this release.
24
24
 
25
- Set `SHOPSTACK_API_URL` to the Shopstack API address supplied for your environment,
26
- including `/v1`. There is no staging or production default. Use a separate
25
+ The CLI and MCP use `https://shopstack-release-preview.shopstack.workers.dev/v1`
26
+ by default. No API URL setting is needed for this hosted release. Set
27
+ `SHOPSTACK_API_URL` only to select another environment. Use a separate
27
28
  `SHOPSTACK_CONFIG_FILE` for each environment. Both features use that one API and
28
29
  verified profile; customers do not run a Worker, model, database, or proxy.
29
30
 
@@ -34,18 +35,20 @@ export SHOPSTACK_CONFIG_FILE="/absolute/private/path/shopstack-config.json"
34
35
  ```
35
36
 
36
37
  New profiles remember their API address. A conflicting environment override
37
- fails before the credential is sent. Existing profiles without an address need
38
- an explicit `SHOPSTACK_API_URL`; their keys and scopes are not changed.
38
+ fails before the credential is sent. For a legacy profile without an address,
39
+ set its original `SHOPSTACK_API_URL` if it does not belong to the hosted release.
39
40
 
40
- ## Verified signup
41
+ ## Verified signup and sign-in
41
42
 
42
43
  ```bash
43
- shopstack signup
44
+ shopstack login
44
45
  ```
45
46
 
46
47
  The command asks for email and Personal or Developer account type. It starts a
47
- 15-minute signup and waits while you open the verification email. No account or
48
- API key exists until the link is consumed. The CLI generates and privately
48
+ 15-minute verification and waits while you open the email. A new email creates
49
+ an account; an existing email signs in to the same account with a new device
50
+ key. Other devices remain signed in. `shopstack signup` remains an alias. No
51
+ new key is issued until verification. The CLI generates and privately
49
52
  persists all retry and polling capabilities before the first request, then
50
53
  retrieves the first key after verification and stores it in
51
54
  `~/.config/shopstack/config.json` with file mode `0600`; it never prints the
@@ -76,7 +79,7 @@ Configure any stdio MCP client to run:
76
79
  "mcpServers": {
77
80
  "shopstack": {
78
81
  "command": "npx",
79
- "args": ["-y", "shopstack-mcp@0.2.0"],
82
+ "args": ["-y", "shopstack-mcp@0.2.2"],
80
83
  "env": {
81
84
  "SHOPSTACK_API_URL": "https://shopstack-release-preview.shopstack.workers.dev/v1",
82
85
  "SHOPSTACK_CONFIG_FILE": "/absolute/private/path/shopstack-config.json"
@@ -107,7 +110,7 @@ one MCP server and three focused skills:
107
110
  - `shopstack-checkout` for checkout creation and monitoring;
108
111
  - `shopstack-onboarding` for verified signup and private local profiles.
109
112
 
110
- The plugin pins `shopstack-mcp@0.2.0`, which installs the matching
113
+ The plugin pins `shopstack-mcp@0.2.1`, which installs the matching
111
114
  reservation-capable `shopstack` client. Configure the API address
112
115
  before starting the plugin or use a profile already bound to that API. The existing top-level
113
116
  `SKILL.md` remains in the npm client package for compatibility.
@@ -119,8 +122,12 @@ shopstack connect list
119
122
  shopstack connect link
120
123
  ```
121
124
 
122
- Link is currently the only persistent payment provider. Connecting it is
123
- optional.
125
+ Link is currently the only persistent payment provider. Connecting it in advance
126
+ is optional. Select `payment_provider: "link"` to prepare the cart first; at card
127
+ issuance Shopstack returns the Link sign-in or approval URL and waits. After Link
128
+ responds, checkout resumes automatically. No “done” message is needed. The CLI
129
+ keeps watching; MCP agents use `wait_checkout_update` with the latest
130
+ `presentation_revision`. Final order approval is still a separate step.
124
131
 
125
132
  ## Run a guest reservation
126
133
 
@@ -196,7 +203,7 @@ form, then asks for card details through a no-echo terminal prompt. Card data is
196
203
  sent only to the protected payment-details endpoint. The CLI separately shows
197
204
  the exact final amount and asks for approval before Shopstack can submit.
198
205
 
199
- To use an active Link connection, add `"payment_provider": "link"` to the
206
+ To use Link, with or without a prior connection, add `"payment_provider": "link"` to the
200
207
  request.
201
208
 
202
209
  Card values are never accepted as command-line flags.
@@ -234,7 +241,7 @@ restart recovery and durable credential storage; never use browser storage.
234
241
  omitted. Final payment approval is never inferred from a message or from
235
242
  supplying a card.
236
243
 
237
- Set `SHOPSTACK_API_URL` to select the intended Shopstack API and
244
+ Optionally set `SHOPSTACK_API_URL` to override the hosted API and
238
245
  `SHOPSTACK_CONFIG_FILE` to select its private profile store.
239
246
 
240
247
  ## Release verification
package/SKILL.md CHANGED
@@ -8,8 +8,8 @@ description: Use Shopstack to onboard a verified personal account or a developer
8
8
  Use Shopstack as the checkout execution layer. Keep account verification, user ownership, protected payment input, and final payment approval at their typed boundaries.
9
9
 
10
10
  Use one Shopstack API and verified user profile for checkout and reservations.
11
- Before signup, configure the issued API address, including `/v1`, through
12
- `SHOPSTACK_API_URL`; the release has no staging or production default. Use a
11
+ The CLI and MCP default to `https://shopstack-release-preview.shopstack.workers.dev/v1`.
12
+ Use `SHOPSTACK_API_URL` only to select a different API. Use a
13
13
  separate private profile store for each environment. New profiles save their API
14
14
  address and reject a conflicting override. Never ask the user to paste a key in
15
15
  chat to fix an environment mismatch.
@@ -19,8 +19,8 @@ chat to fix an environment mismatch.
19
19
  For the JavaScript client and CLI:
20
20
 
21
21
  ```bash
22
- npm install shopstack@0.3.0
23
- npm install -g shopstack@0.3.0
22
+ npm install shopstack@0.3.1
23
+ npm install -g shopstack@0.3.1
24
24
  ```
25
25
 
26
26
  For MCP clients, configure the local stdio server:
@@ -30,7 +30,7 @@ For MCP clients, configure the local stdio server:
30
30
  "mcpServers": {
31
31
  "shopstack": {
32
32
  "command": "npx",
33
- "args": ["-y", "shopstack-mcp@0.2.0"]
33
+ "args": ["-y", "shopstack-mcp@0.2.1"]
34
34
  }
35
35
  }
36
36
  }
@@ -67,7 +67,10 @@ summary. Send a clear confirmation only when the user confirms that exact
67
67
  summary. This confirmation is an ordinary reservation message and can create
68
68
  the booking. There is no separate reservation approval endpoint or MCP tool.
69
69
  An ambiguous reply must not be treated as confirmation. The anonymous guest
70
- profile and temporary email are created only when booking. Cancel a confirmed
70
+ profile is created only when booking. Pass optional `diner.email` when the user
71
+ supplies it; that is the guest contact address. Otherwise omit it and Shopstack
72
+ creates a temporary inbox when booking. Never require the user to give a
73
+ restaurant email. Cancel a confirmed
71
74
  reservation with the typed reservation cancellation operation.
72
75
 
73
76
  ## Choose the account shape
@@ -80,12 +83,14 @@ reservation with the typed reservation cancellation operation.
80
83
  Start verified CLI signup:
81
84
 
82
85
  ```bash
83
- shopstack signup
86
+ shopstack login
84
87
  ```
85
88
 
86
89
  The command prompts for email and Personal or Developer account type. The user
87
- must open the time-limited verification link. No account or API key exists
88
- before verification. The CLI generates and privately stores its retry and
90
+ must open the time-limited verification link. A new email creates an account;
91
+ an existing email signs in to the same account and preserves other device keys.
92
+ The selected account type must match. `shopstack signup` is also supported.
93
+ No new API key is issued before verification. The CLI generates and privately stores its retry and
89
94
  polling capabilities before the request, polls signup, saves the verified key
90
95
  with mode `0600`, and prints none of those credentials. Rerunning
91
96
  `shopstack signup` automatically resumes the matching pending attempt after an
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shopstack",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "Shopstack API client and command-line checkout and reservation tools.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -23,7 +23,8 @@
23
23
  "/accounts": {
24
24
  "post": {
25
25
  "operationId": "startAccountSignup",
26
- "summary": "Start verified personal or developer account signup",
26
+ "summary": "Start email-verified signup or sign-in",
27
+ "description": "A new email creates the selected account type after verification. An existing email signs in to the same account with a new profile key; other devices remain signed in. The requested account type must match the existing account. Suspended accounts and users remain blocked. No key is issued before verification, and the key is delivered once through the caller's private polling capability, never in the email page.",
27
28
  "security": [],
28
29
  "parameters": [
29
30
  {
@@ -45,7 +46,7 @@
45
46
  },
46
47
  "responses": {
47
48
  "202": {
48
- "description": "Verification email accepted; no account or API key exists yet",
49
+ "description": "Verification email accepted; no new API key has been issued",
49
50
  "content": {
50
51
  "application/json": {
51
52
  "schema": {
@@ -198,6 +199,26 @@
198
199
  }
199
200
  }
200
201
  },
202
+ "403": {
203
+ "description": "The verified account or implicit user is unavailable",
204
+ "content": {
205
+ "text/html": {
206
+ "schema": {
207
+ "type": "string"
208
+ }
209
+ }
210
+ }
211
+ },
212
+ "409": {
213
+ "description": "The requested account type does not match the verified existing account",
214
+ "content": {
215
+ "text/html": {
216
+ "schema": {
217
+ "type": "string"
218
+ }
219
+ }
220
+ }
221
+ },
201
222
  "410": {
202
223
  "description": "Verification capability expired",
203
224
  "content": {
@@ -1843,6 +1864,12 @@
1843
1864
  "phone_number"
1844
1865
  ],
1845
1866
  "properties": {
1867
+ "email": {
1868
+ "type": "string",
1869
+ "format": "email",
1870
+ "maxLength": 254,
1871
+ "description": "Optional booking contact email. When supplied, this exact trimmed address is used for the guest profile. Otherwise Shopstack creates a temporary inbox when booking. Do not ask for an email if it was omitted."
1872
+ },
1846
1873
  "country": {
1847
1874
  "type": "string",
1848
1875
  "pattern": "^[A-Z]{2}$"
@@ -2358,7 +2385,8 @@
2358
2385
  "minimum": 1
2359
2386
  },
2360
2387
  "status": {
2361
- "type": "string"
2388
+ "type": "string",
2389
+ "description": "Shopstack booking outcome, confirmed. Provider lifecycle labels are not returned as this status."
2362
2390
  }
2363
2391
  }
2364
2392
  }
@@ -2391,7 +2419,8 @@
2391
2419
  "type": "string"
2392
2420
  },
2393
2421
  "status": {
2394
- "type": "string"
2422
+ "type": "string",
2423
+ "description": "Shopstack cancellation outcome, cancelled."
2395
2424
  }
2396
2425
  }
2397
2426
  }
@@ -2641,7 +2670,7 @@
2641
2670
  },
2642
2671
  "payment_provider": {
2643
2672
  "$ref": "#/components/schemas/PaymentProvider",
2644
- "description": "Optional. Select Link only when this user has an active Link connection; otherwise the checkout requests protected one-checkout card input at the payment form."
2673
+ "description": "Optional. Select Link without connecting first. At card issuance the checkout returns a Link login or approval URL in required_input and waits. Omission requests protected one-checkout card input instead. Link approval does not approve final order submission."
2645
2674
  },
2646
2675
  "external_reference": {
2647
2676
  "type": "string",
@@ -2761,14 +2790,62 @@
2761
2790
  }
2762
2791
  },
2763
2792
  "RequiredInput": {
2793
+ "oneOf": [
2794
+ {
2795
+ "type": "object",
2796
+ "additionalProperties": false,
2797
+ "required": [
2798
+ "type"
2799
+ ],
2800
+ "properties": {
2801
+ "type": {
2802
+ "const": "payment_card"
2803
+ }
2804
+ }
2805
+ },
2806
+ {
2807
+ "$ref": "#/components/schemas/LinkRequiredInput"
2808
+ }
2809
+ ]
2810
+ },
2811
+ "LinkRequiredInput": {
2764
2812
  "type": "object",
2765
2813
  "additionalProperties": false,
2814
+ "description": "Owner-private Link login or credential approval. Open the exact URL or approve in Link. This does not approve Shopstack order submission. The checkout resumes automatically after Link responds.",
2766
2815
  "required": [
2767
- "type"
2816
+ "type",
2817
+ "action",
2818
+ "url",
2819
+ "amount_cents",
2820
+ "currency"
2768
2821
  ],
2769
2822
  "properties": {
2770
2823
  "type": {
2771
- "const": "payment_card"
2824
+ "const": "link"
2825
+ },
2826
+ "action": {
2827
+ "enum": [
2828
+ "connect",
2829
+ "approve"
2830
+ ]
2831
+ },
2832
+ "url": {
2833
+ "type": "string",
2834
+ "format": "uri",
2835
+ "maxLength": 2048
2836
+ },
2837
+ "phrase": {
2838
+ "type": "string",
2839
+ "minLength": 1,
2840
+ "maxLength": 100
2841
+ },
2842
+ "amount_cents": {
2843
+ "type": "integer",
2844
+ "minimum": 1,
2845
+ "maximum": 500000
2846
+ },
2847
+ "currency": {
2848
+ "$ref": "#/components/schemas/Currency"
2772
2849
  }
2773
2850
  }
2774
2851
  },
package/src/cli.js CHANGED
@@ -7,6 +7,9 @@ import { ConfigStore, resolveProfileBaseUrl } from "./config.js";
7
7
  const HELP = `Shopstack
8
8
 
9
9
  Account setup:
10
+ shopstack login
11
+ shopstack login user --email EMAIL
12
+ shopstack login developer --email EMAIL
10
13
  shopstack signup
11
14
  shopstack signup user --email EMAIL
12
15
  shopstack signup developer --email EMAIL
@@ -305,7 +308,7 @@ export async function runCli(args, supplied = {}) {
305
308
  return;
306
309
  }
307
310
 
308
- if (group === "signup") {
311
+ if (group === "signup" || group === "login") {
309
312
  if (action === "resume") {
310
313
  if (rest.length !== 1) {
311
314
  throw new Error("Use `shopstack signup resume SIGNUP_ID`.");
@@ -646,6 +649,17 @@ export async function runCli(args, supplied = {}) {
646
649
  `[${checkout.status}]${intent} ${checkout.activity ?? ""}`.trimEnd() +
647
650
  "\n",
648
651
  );
652
+ if (checkout.required_input?.type === "link") {
653
+ const input = checkout.required_input;
654
+ dependencies.stderr.write(
655
+ `${input.action === "connect" ? "Connect Link" : "Approve in Link"}: ${input.url}\n` +
656
+ `Amount: ${input.currency} ${(input.amount_cents / 100).toFixed(2)}\n` +
657
+ (input.action === "connect" && input.phrase
658
+ ? `Code: ${input.phrase}\n`
659
+ : "") +
660
+ "The checkout resumes automatically. Final order approval is separate.\n",
661
+ );
662
+ }
649
663
  },
650
664
  approve: async (approval) => {
651
665
  const summary = [
package/src/client.d.ts CHANGED
@@ -40,6 +40,8 @@ export interface CreateCheckoutRequest {
40
40
 
41
41
  export interface ReservationDiner {
42
42
  country: string;
43
+ /** Optional booking contact address. If omitted, Shopstack creates a temporary inbox. */
44
+ email?: string;
43
45
  first_name: string;
44
46
  last_name: string;
45
47
  phone_number: string;
@@ -136,7 +138,17 @@ export interface Checkout {
136
138
  item_url: string;
137
139
  /** Present this exact owner-only URL verbatim. Never reconstruct its token. */
138
140
  live_view_url?: string;
139
- required_input?: { type: "payment_card" };
141
+ required_input?:
142
+ | { type: "payment_card" }
143
+ | {
144
+ type: "link";
145
+ action: "connect" | "approve";
146
+ /** Owner-private Link URL. Present it verbatim; never reconstruct it. */
147
+ url: string;
148
+ phrase?: string;
149
+ amount_cents: number;
150
+ currency: string;
151
+ };
140
152
  approval?: PaymentApproval;
141
153
  result?: Record<string, unknown>;
142
154
  failure?: Record<string, unknown>;
package/src/client.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { randomBytes, randomUUID } from "node:crypto";
2
2
  import { readReservationProgress } from "./reservation-progress.js";
3
- import { resolveProfileBaseUrl } from "./config.js";
3
+ import { DEFAULT_API_URL, resolveProfileBaseUrl } from "./config.js";
4
4
  import { checkoutMonitor } from "./checkout-monitor.js";
5
5
 
6
6
  const TERMINAL_STATUSES = new Set(["complete", "failed", "cancelled"]);
@@ -42,7 +42,7 @@ function delay(milliseconds) {
42
42
  export class ShopstackClient {
43
43
  constructor({
44
44
  apiKey,
45
- baseUrl = process.env.SHOPSTACK_API_URL,
45
+ baseUrl = process.env.SHOPSTACK_API_URL ?? DEFAULT_API_URL,
46
46
  fetch: fetchImplementation = globalThis.fetch,
47
47
  webSocket = globalThis.WebSocket,
48
48
  } = {}) {
@@ -576,7 +576,7 @@ export class ShopstackClient {
576
576
  current.intent?.name,
577
577
  current.intent?.phase,
578
578
  current.intent?.updated_at,
579
- current.required_input?.type,
579
+ current.required_input,
580
580
  current.approval?.id,
581
581
  ]);
582
582
  if (fingerprint === progressFingerprint) return;
@@ -597,6 +597,12 @@ export class ShopstackClient {
597
597
  }
598
598
  checkout = await this.getCheckout(checkout.id);
599
599
  await publishProgress(checkout);
600
+ if (
601
+ checkout.required_input?.type === "link" &&
602
+ typeof options.onProgress !== "function"
603
+ ) {
604
+ return checkout;
605
+ }
600
606
  if (
601
607
  checkout.required_input?.type === "payment_card" &&
602
608
  handledPaymentRevision !== checkout.revision
package/src/config.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ export const DEFAULT_API_URL: string;
2
+
1
3
  export interface ShopstackProfile {
2
4
  accountId: string;
3
5
  apiKey: string;
package/src/config.js CHANGED
@@ -2,6 +2,9 @@ import { chmod, mkdir, readFile, rename, writeFile } from "node:fs/promises";
2
2
  import { homedir } from "node:os";
3
3
  import { dirname, join } from "node:path";
4
4
 
5
+ export const DEFAULT_API_URL =
6
+ "https://shopstack-release-preview.shopstack.workers.dev/v1";
7
+
5
8
  export function resolveProfileBaseUrl(profile, selectedBaseUrl) {
6
9
  const saved = profile?.baseUrl?.replace(/\/+$/u, "");
7
10
  const selected = selectedBaseUrl?.replace(/\/+$/u, "");
@@ -10,7 +13,7 @@ export function resolveProfileBaseUrl(profile, selectedBaseUrl) {
10
13
  "This profile belongs to a different Shopstack API. Select its endpoint or use a separate profile store.",
11
14
  );
12
15
  }
13
- return saved ?? selected;
16
+ return saved ?? selected ?? DEFAULT_API_URL;
14
17
  }
15
18
 
16
19
  export function defaultConfigPath() {