doordash-cli 0.2.0 → 0.3.1
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/CHANGELOG.md +16 -0
- package/README.md +5 -5
- package/dist/cli.js +6 -5
- package/dist/cli.test.js +22 -4
- package/dist/direct-api.d.ts +7 -0
- package/dist/direct-api.js +56 -17
- package/dist/direct-api.test.js +20 -1
- package/dist/lib.d.ts +1 -1
- package/dist/lib.js +14 -6
- package/docs/examples.md +23 -23
- package/docs/install.md +4 -4
- package/man/dd-cli.1 +25 -25
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -9,6 +9,22 @@ All notable changes to `doordash-cli` will be documented in this file.
|
|
|
9
9
|
|
|
10
10
|
See [docs/releasing.md](docs/releasing.md) for the maintainer release flow.
|
|
11
11
|
|
|
12
|
+
## [0.3.1](https://github.com/LatencyTDH/doordash-cli/compare/v0.3.0...v0.3.1) (2026-03-11)
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
|
|
16
|
+
* keep managed browser session imports quiet ([#28](https://github.com/LatencyTDH/doordash-cli/issues/28)) ([dc25e04](https://github.com/LatencyTDH/doordash-cli/commit/dc25e0444ca63c7af1c2feaa2f32ede54b1c1f98))
|
|
17
|
+
|
|
18
|
+
## [0.3.0](https://github.com/LatencyTDH/doordash-cli/compare/v0.2.0...v0.3.0) (2026-03-11)
|
|
19
|
+
|
|
20
|
+
### Features
|
|
21
|
+
|
|
22
|
+
* rename auth commands to login/logout ([#27](https://github.com/LatencyTDH/doordash-cli/issues/27)) ([f5bf85c](https://github.com/LatencyTDH/doordash-cli/commit/f5bf85c556d23e7cefc95f346777d33fb1021bcc))
|
|
23
|
+
|
|
24
|
+
### Bug Fixes
|
|
25
|
+
|
|
26
|
+
* preserve existing-order docs in release-flow cleanup ([#25](https://github.com/LatencyTDH/doordash-cli/issues/25)) ([4789089](https://github.com/LatencyTDH/doordash-cli/commit/4789089dd831b42cd037707e82a0f102988fd830))
|
|
27
|
+
|
|
12
28
|
## 0.2.0 (2026-03-11)
|
|
13
29
|
|
|
14
30
|
### Features
|
package/README.md
CHANGED
|
@@ -46,7 +46,7 @@ npm run cli -- --help
|
|
|
46
46
|
|
|
47
47
|
### Browser prerequisite
|
|
48
48
|
|
|
49
|
-
If you plan to
|
|
49
|
+
If you plan to sign in with `login`, install Playwright's Chromium build once:
|
|
50
50
|
|
|
51
51
|
```bash
|
|
52
52
|
doordash-cli install-browser
|
|
@@ -57,7 +57,7 @@ npm run install:browser
|
|
|
57
57
|
## First run
|
|
58
58
|
|
|
59
59
|
```bash
|
|
60
|
-
doordash-cli
|
|
60
|
+
doordash-cli login
|
|
61
61
|
doordash-cli auth-check
|
|
62
62
|
doordash-cli set-address --address "350 5th Ave, New York, NY 10118"
|
|
63
63
|
doordash-cli search --query sushi
|
|
@@ -65,7 +65,7 @@ doordash-cli search --query sushi
|
|
|
65
65
|
|
|
66
66
|
If you are running from a checkout without `npm link`, replace `doordash-cli` with `npm run cli --`.
|
|
67
67
|
|
|
68
|
-
If you already have a compatible signed-in DoorDash browser session available, `auth-check` may reuse it instead of asking you to sign in again.
|
|
68
|
+
If you already have a compatible signed-in DoorDash managed-browser session available, `auth-check` may quietly reuse it instead of asking you to sign in again. Routine direct commands stay quiet; use `login` when you want explicit browser interaction.
|
|
69
69
|
|
|
70
70
|
## Command surface
|
|
71
71
|
|
|
@@ -73,8 +73,8 @@ If you already have a compatible signed-in DoorDash browser session available, `
|
|
|
73
73
|
|
|
74
74
|
- `install-browser`
|
|
75
75
|
- `auth-check`
|
|
76
|
-
- `
|
|
77
|
-
- `
|
|
76
|
+
- `login`
|
|
77
|
+
- `logout`
|
|
78
78
|
|
|
79
79
|
### Discovery
|
|
80
80
|
|
package/dist/cli.js
CHANGED
|
@@ -24,8 +24,8 @@ export function usage() {
|
|
|
24
24
|
"Safe commands:",
|
|
25
25
|
" install-browser",
|
|
26
26
|
" auth-check",
|
|
27
|
-
"
|
|
28
|
-
"
|
|
27
|
+
" login",
|
|
28
|
+
" logout",
|
|
29
29
|
' set-address --address "350 5th Ave, New York, NY 10118"',
|
|
30
30
|
" search --query sushi [--cuisine japanese]",
|
|
31
31
|
" menu --restaurant-id 123456",
|
|
@@ -43,7 +43,8 @@ export function usage() {
|
|
|
43
43
|
" - install-browser downloads the matching Playwright Chromium build used by this package.",
|
|
44
44
|
" - Manual pages ship with the project: man dd-cli or man doordash-cli.",
|
|
45
45
|
" - Direct GraphQL/HTTP is the default path for auth-check, set-address, search, menu, item, orders, order, cart, add-to-cart, and update-cart.",
|
|
46
|
-
" -
|
|
46
|
+
" - login launches Chromium for a one-time manual sign-in flow and saves reusable state for later direct API calls.",
|
|
47
|
+
" - auth-check can quietly reuse an already-signed-in compatible managed-browser DoorDash session when one is available; use login for explicit browser interaction.",
|
|
47
48
|
" - set-address now uses DoorDash autocomplete/get-or-create plus addConsumerAddressV2 for brand-new address enrollment when needed.",
|
|
48
49
|
" - configurable items require explicit --options-json selections.",
|
|
49
50
|
' - standalone recommended add-ons that open a nested cursor step are supported via children, e.g. [{"groupId":"recommended_option_546935995","optionId":"546936011","children":[{"groupId":"780057412","optionId":"4702669757"}]}].',
|
|
@@ -58,9 +59,9 @@ export function usage() {
|
|
|
58
59
|
" dd-cli search --query sushi",
|
|
59
60
|
" dd-cli orders --active-only",
|
|
60
61
|
" doordash-cli order --order-id 3f4c6d0e-1234-5678-90ab-cdef12345678",
|
|
61
|
-
" doordash-cli
|
|
62
|
+
" doordash-cli login",
|
|
62
63
|
"",
|
|
63
|
-
"Allowed commands: install-browser, auth-check,
|
|
64
|
+
"Allowed commands: install-browser, auth-check, login, logout, set-address, search, menu, item, orders, order, add-to-cart, update-cart, cart",
|
|
64
65
|
].join("\n");
|
|
65
66
|
}
|
|
66
67
|
export function normalizeOptionToken(token) {
|
package/dist/cli.test.js
CHANGED
|
@@ -33,8 +33,8 @@ test("safe command allowlist stays cart-safe while adding install helpers", () =
|
|
|
33
33
|
assert.deepEqual(SAFE_COMMANDS, [
|
|
34
34
|
"install-browser",
|
|
35
35
|
"auth-check",
|
|
36
|
-
"
|
|
37
|
-
"
|
|
36
|
+
"login",
|
|
37
|
+
"logout",
|
|
38
38
|
"set-address",
|
|
39
39
|
"search",
|
|
40
40
|
"menu",
|
|
@@ -46,11 +46,13 @@ test("safe command allowlist stays cart-safe while adding install helpers", () =
|
|
|
46
46
|
"cart",
|
|
47
47
|
]);
|
|
48
48
|
});
|
|
49
|
-
test("dangerous and
|
|
49
|
+
test("dangerous and renamed legacy commands are rejected with guidance", () => {
|
|
50
50
|
assert.throws(() => assertSafeCommand("checkout"), /Blocked command: checkout/);
|
|
51
51
|
assert.throws(() => assertSafeCommand("place-order"), /Blocked command: place-order/);
|
|
52
52
|
assert.throws(() => assertSafeCommand("track-order"), /Use `orders` or `order --order-id/);
|
|
53
53
|
assert.throws(() => assertSafeCommand("payment"), /Blocked command: payment/);
|
|
54
|
+
assert.throws(() => assertSafeCommand("auth-bootstrap"), /renamed it to login/);
|
|
55
|
+
assert.throws(() => assertSafeCommand("auth-clear"), /renamed it to logout/);
|
|
54
56
|
});
|
|
55
57
|
test("unsupported flags are rejected before network work runs", () => {
|
|
56
58
|
assert.throws(() => assertAllowedFlags("cart", { payment: "visa" }), /Unsupported flag\(s\) for cart/);
|
|
@@ -102,7 +104,8 @@ test("help output shows the direct read-only/cart-safe command surface", () => {
|
|
|
102
104
|
assert.match(result.stdout, /dd-cli <command>/);
|
|
103
105
|
assert.match(result.stdout, /doordash-cli <command>/);
|
|
104
106
|
assert.match(result.stdout, /install-browser/);
|
|
105
|
-
assert.match(result.stdout, /
|
|
107
|
+
assert.match(result.stdout, /login/);
|
|
108
|
+
assert.match(result.stdout, /logout/);
|
|
106
109
|
assert.match(result.stdout, /set-address --address/);
|
|
107
110
|
assert.match(result.stdout, /orders \[--limit 20\] \[--active-only\]/);
|
|
108
111
|
assert.match(result.stdout, /order --order-id/);
|
|
@@ -110,12 +113,17 @@ test("help output shows the direct read-only/cart-safe command surface", () => {
|
|
|
110
113
|
assert.match(result.stdout, /--version, -v/);
|
|
111
114
|
assert.match(result.stdout, /man dd-cli/);
|
|
112
115
|
assert.match(result.stdout, /Out-of-scope commands remain intentionally unsupported/);
|
|
116
|
+
assert.doesNotMatch(result.stdout, /auth-bootstrap/);
|
|
117
|
+
assert.doesNotMatch(result.stdout, /auth-clear/);
|
|
113
118
|
assert.doesNotMatch(result.stdout, /Dd-cli/);
|
|
114
119
|
});
|
|
115
120
|
test("repository ships man pages for the supported lowercase command names", () => {
|
|
116
121
|
const ddManPath = join(distDir, "..", "man", "dd-cli.1");
|
|
117
122
|
const aliasManPath = join(distDir, "..", "man", "doordash-cli.1");
|
|
118
123
|
assert.match(readFileSync(ddManPath, "utf8"), /install-browser/);
|
|
124
|
+
assert.match(readFileSync(ddManPath, "utf8"), /\.B login/);
|
|
125
|
+
assert.doesNotMatch(readFileSync(ddManPath, "utf8"), /auth-bootstrap/);
|
|
126
|
+
assert.doesNotMatch(readFileSync(ddManPath, "utf8"), /auth-clear/);
|
|
119
127
|
assert.doesNotMatch(readFileSync(ddManPath, "utf8"), /Dd-cli/);
|
|
120
128
|
assert.equal(readFileSync(aliasManPath, "utf8").trim(), ".so man1/dd-cli.1");
|
|
121
129
|
});
|
|
@@ -141,6 +149,16 @@ test("version flag prints the package version", () => {
|
|
|
141
149
|
assert.equal(result.status, 0);
|
|
142
150
|
assert.equal(result.stdout.trim(), version());
|
|
143
151
|
});
|
|
152
|
+
test("legacy auth command invocations point users to login/logout", () => {
|
|
153
|
+
const loginRename = runCli(["auth-bootstrap"]);
|
|
154
|
+
assert.equal(loginRename.status, 1);
|
|
155
|
+
assert.match(loginRename.stderr, /Unsupported command: auth-bootstrap/);
|
|
156
|
+
assert.match(loginRename.stderr, /renamed it to login/);
|
|
157
|
+
const logoutRename = runCli(["auth-clear"]);
|
|
158
|
+
assert.equal(logoutRename.status, 1);
|
|
159
|
+
assert.match(logoutRename.stderr, /Unsupported command: auth-clear/);
|
|
160
|
+
assert.match(logoutRename.stderr, /renamed it to logout/);
|
|
161
|
+
});
|
|
144
162
|
test("blocked commands fail immediately", () => {
|
|
145
163
|
const result = runCli(["checkout"]);
|
|
146
164
|
assert.equal(result.status, 1);
|
package/dist/direct-api.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type Cookie } from "playwright";
|
|
1
2
|
export type AuthResult = {
|
|
2
3
|
success: true;
|
|
3
4
|
isLoggedIn: boolean;
|
|
@@ -521,6 +522,12 @@ export declare function resolveAvailableAddressMatch(input: {
|
|
|
521
522
|
printableAddress: string | null;
|
|
522
523
|
source: SetAddressResult["matchedAddressSource"];
|
|
523
524
|
} | null;
|
|
525
|
+
export declare function isDoorDashUrl(value: string): boolean;
|
|
526
|
+
export declare function hasDoorDashCookies(cookies: ReadonlyArray<Pick<Cookie, "domain">>): boolean;
|
|
527
|
+
export declare function selectManagedBrowserImportMode(input: {
|
|
528
|
+
pageUrls: readonly string[];
|
|
529
|
+
cookies: ReadonlyArray<Pick<Cookie, "domain">>;
|
|
530
|
+
}): "page" | "cookies" | "skip";
|
|
524
531
|
export declare function parseSearchRestaurants(body: unknown[]): SearchRestaurantResult[];
|
|
525
532
|
export declare function parseSearchRestaurantRow(entry: unknown): SearchRestaurantResult | null;
|
|
526
533
|
export declare function parseExistingOrderLifecycleStatus(orderRoot: unknown): ExistingOrderLifecycleStatus;
|
package/dist/direct-api.js
CHANGED
|
@@ -808,6 +808,9 @@ class DoorDashDirectSession {
|
|
|
808
808
|
return;
|
|
809
809
|
}
|
|
810
810
|
this.attemptedManagedImport = true;
|
|
811
|
+
if (await hasPersistedSessionArtifacts()) {
|
|
812
|
+
return;
|
|
813
|
+
}
|
|
811
814
|
await importManagedBrowserSessionIfAvailable().catch(() => { });
|
|
812
815
|
}
|
|
813
816
|
}
|
|
@@ -1535,39 +1538,69 @@ function normalizeAddressText(value) {
|
|
|
1535
1538
|
.replace(/[.,]/g, "")
|
|
1536
1539
|
.replace(/\s+/g, " ");
|
|
1537
1540
|
}
|
|
1541
|
+
export function isDoorDashUrl(value) {
|
|
1542
|
+
try {
|
|
1543
|
+
const url = new URL(value);
|
|
1544
|
+
return url.hostname === "doordash.com" || url.hostname.endsWith(".doordash.com");
|
|
1545
|
+
}
|
|
1546
|
+
catch {
|
|
1547
|
+
return false;
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
export function hasDoorDashCookies(cookies) {
|
|
1551
|
+
return cookies.some((cookie) => {
|
|
1552
|
+
const domain = cookie.domain.trim().replace(/^\./, "").toLowerCase();
|
|
1553
|
+
return domain === "doordash.com" || domain.endsWith(".doordash.com");
|
|
1554
|
+
});
|
|
1555
|
+
}
|
|
1556
|
+
export function selectManagedBrowserImportMode(input) {
|
|
1557
|
+
if (input.pageUrls.some((url) => isDoorDashUrl(url))) {
|
|
1558
|
+
return "page";
|
|
1559
|
+
}
|
|
1560
|
+
if (hasDoorDashCookies(input.cookies)) {
|
|
1561
|
+
return "cookies";
|
|
1562
|
+
}
|
|
1563
|
+
return "skip";
|
|
1564
|
+
}
|
|
1538
1565
|
async function importManagedBrowserSessionIfAvailable() {
|
|
1539
1566
|
for (const cdpUrl of await getManagedBrowserCdpCandidates()) {
|
|
1540
1567
|
if (!(await isCdpEndpointReachable(cdpUrl))) {
|
|
1541
1568
|
continue;
|
|
1542
1569
|
}
|
|
1543
1570
|
let browser = null;
|
|
1544
|
-
let tempPage = null;
|
|
1545
1571
|
try {
|
|
1546
1572
|
browser = await chromium.connectOverCDP(cdpUrl);
|
|
1547
1573
|
const context = browser.contexts()[0];
|
|
1548
1574
|
if (!context) {
|
|
1549
1575
|
continue;
|
|
1550
1576
|
}
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
}
|
|
1558
|
-
|
|
1559
|
-
const consumer = consumerData.consumer ?? null;
|
|
1560
|
-
if (!consumer || consumer.isGuest !== false) {
|
|
1577
|
+
const cookies = await context.cookies();
|
|
1578
|
+
const pages = context.pages();
|
|
1579
|
+
const reusablePage = pages.find((candidate) => isDoorDashUrl(candidate.url())) ?? null;
|
|
1580
|
+
const importMode = selectManagedBrowserImportMode({
|
|
1581
|
+
pageUrls: reusablePage ? [reusablePage.url()] : [],
|
|
1582
|
+
cookies,
|
|
1583
|
+
});
|
|
1584
|
+
if (importMode === "skip") {
|
|
1561
1585
|
continue;
|
|
1562
1586
|
}
|
|
1563
|
-
|
|
1564
|
-
|
|
1587
|
+
if (reusablePage) {
|
|
1588
|
+
const consumerData = await fetchConsumerViaPage(reusablePage).catch(() => null);
|
|
1589
|
+
const consumer = consumerData?.consumer ?? null;
|
|
1590
|
+
if (consumer?.isGuest === false) {
|
|
1591
|
+
await saveContextState(context, cookies);
|
|
1592
|
+
return true;
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1595
|
+
if (hasDoorDashCookies(cookies)) {
|
|
1596
|
+
await saveContextState(context, cookies);
|
|
1597
|
+
return true;
|
|
1598
|
+
}
|
|
1565
1599
|
}
|
|
1566
1600
|
catch {
|
|
1567
1601
|
continue;
|
|
1568
1602
|
}
|
|
1569
1603
|
finally {
|
|
1570
|
-
await tempPage?.close().catch(() => { });
|
|
1571
1604
|
await browser?.close().catch(() => { });
|
|
1572
1605
|
}
|
|
1573
1606
|
}
|
|
@@ -1588,12 +1621,12 @@ async function fetchConsumerViaPage(page) {
|
|
|
1588
1621
|
});
|
|
1589
1622
|
return parseGraphQlResponse("managedBrowserConsumerImport", raw.status, raw.text);
|
|
1590
1623
|
}
|
|
1591
|
-
async function saveContextState(context) {
|
|
1624
|
+
async function saveContextState(context, cookies = null) {
|
|
1592
1625
|
const storageStatePath = getStorageStatePath();
|
|
1593
1626
|
await ensureConfigDir();
|
|
1594
1627
|
await context.storageState({ path: storageStatePath });
|
|
1595
|
-
const
|
|
1596
|
-
await writeFile(getCookiesPath(), JSON.stringify(
|
|
1628
|
+
const resolvedCookies = cookies ?? (await context.cookies());
|
|
1629
|
+
await writeFile(getCookiesPath(), JSON.stringify(resolvedCookies, null, 2));
|
|
1597
1630
|
}
|
|
1598
1631
|
async function getManagedBrowserCdpCandidates() {
|
|
1599
1632
|
const candidates = new Set();
|
|
@@ -2282,6 +2315,12 @@ async function hasStorageState() {
|
|
|
2282
2315
|
return false;
|
|
2283
2316
|
}
|
|
2284
2317
|
}
|
|
2318
|
+
async function hasPersistedSessionArtifacts() {
|
|
2319
|
+
if (await hasStorageState()) {
|
|
2320
|
+
return true;
|
|
2321
|
+
}
|
|
2322
|
+
return (await readStoredCookies()).length > 0;
|
|
2323
|
+
}
|
|
2285
2324
|
async function readStoredCookies() {
|
|
2286
2325
|
try {
|
|
2287
2326
|
const raw = await readFile(getCookiesPath(), "utf8");
|
package/dist/direct-api.test.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import test from "node:test";
|
|
2
2
|
import assert from "node:assert/strict";
|
|
3
|
-
import { buildAddConsumerAddressPayload, buildAddToCartPayload, buildUpdateCartPayload, extractExistingOrdersFromApolloCache, normalizeItemName, parseExistingOrderLifecycleStatus, parseExistingOrdersResponse, parseOptionSelectionsJson, parseSearchRestaurantRow, resolveAvailableAddressMatch, } from "./direct-api.js";
|
|
3
|
+
import { buildAddConsumerAddressPayload, buildAddToCartPayload, buildUpdateCartPayload, extractExistingOrdersFromApolloCache, hasDoorDashCookies, normalizeItemName, parseExistingOrderLifecycleStatus, parseExistingOrdersResponse, parseOptionSelectionsJson, parseSearchRestaurantRow, resolveAvailableAddressMatch, selectManagedBrowserImportMode, } from "./direct-api.js";
|
|
4
4
|
function configurableItemDetail() {
|
|
5
5
|
return {
|
|
6
6
|
success: true,
|
|
@@ -144,6 +144,25 @@ test("parseSearchRestaurantRow extracts restaurant metadata from facet rows", ()
|
|
|
144
144
|
url: "https://www.doordash.com/store/24633898/?pickup=false",
|
|
145
145
|
});
|
|
146
146
|
});
|
|
147
|
+
test("managed browser import falls back to cookie reuse without opening a DoorDash page", () => {
|
|
148
|
+
const cookies = [{ domain: ".doordash.com" }];
|
|
149
|
+
assert.equal(hasDoorDashCookies(cookies), true);
|
|
150
|
+
assert.equal(selectManagedBrowserImportMode({ pageUrls: [], cookies }), "cookies");
|
|
151
|
+
});
|
|
152
|
+
test("managed browser import prefers an existing DoorDash page when one is already open", () => {
|
|
153
|
+
const cookies = [{ domain: ".doordash.com" }];
|
|
154
|
+
assert.equal(selectManagedBrowserImportMode({
|
|
155
|
+
pageUrls: ["https://github.com/LatencyTDH/doordash-cli/pulls", "https://www.doordash.com/home"],
|
|
156
|
+
cookies,
|
|
157
|
+
}), "page");
|
|
158
|
+
});
|
|
159
|
+
test("managed browser import skips unrelated browser contexts", () => {
|
|
160
|
+
assert.equal(hasDoorDashCookies([{ domain: ".github.com" }]), false);
|
|
161
|
+
assert.equal(selectManagedBrowserImportMode({
|
|
162
|
+
pageUrls: ["https://github.com/LatencyTDH/doordash-cli"],
|
|
163
|
+
cookies: [{ domain: ".github.com" }],
|
|
164
|
+
}), "skip");
|
|
165
|
+
});
|
|
147
166
|
test("parseOptionSelectionsJson parses structured recursive option selections", () => {
|
|
148
167
|
assert.deepEqual(parseOptionSelectionsJson('[{"groupId":"703393388","optionId":"4716032529"},{"groupId":"recommended_option_546935995","optionId":"546936011","children":[{"groupId":"780057412","optionId":"4702669757","quantity":2}]}]'), [
|
|
149
168
|
{ groupId: "703393388", optionId: "4716032529" },
|
package/dist/lib.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type AddToCartResult, type AuthBootstrapResult, type AuthResult, type CartResult, type ItemResult, type MenuResult, type OrderResult, type OrdersResult, type SearchResult, type SetAddressResult, type UpdateCartResult } from "./direct-api.js";
|
|
2
|
-
export declare const SAFE_COMMANDS: readonly ["install-browser", "auth-check", "
|
|
2
|
+
export declare const SAFE_COMMANDS: readonly ["install-browser", "auth-check", "login", "logout", "set-address", "search", "menu", "item", "orders", "order", "add-to-cart", "update-cart", "cart"];
|
|
3
3
|
export declare const BLOCKED_COMMANDS: readonly ["checkout", "place-order", "track-order", "payment", "pay", "tip", "submit-order"];
|
|
4
4
|
export type SafeCommand = (typeof SAFE_COMMANDS)[number];
|
|
5
5
|
export type CommandFlags = Record<string, string>;
|
package/dist/lib.js
CHANGED
|
@@ -8,8 +8,8 @@ const PLAYWRIGHT_CLI_PATH = join(dirname(require.resolve("playwright/package.jso
|
|
|
8
8
|
export const SAFE_COMMANDS = [
|
|
9
9
|
"install-browser",
|
|
10
10
|
"auth-check",
|
|
11
|
-
"
|
|
12
|
-
"
|
|
11
|
+
"login",
|
|
12
|
+
"logout",
|
|
13
13
|
"set-address",
|
|
14
14
|
"search",
|
|
15
15
|
"menu",
|
|
@@ -29,11 +29,15 @@ export const BLOCKED_COMMANDS = [
|
|
|
29
29
|
"tip",
|
|
30
30
|
"submit-order",
|
|
31
31
|
];
|
|
32
|
+
const LEGACY_COMMAND_RENAMES = {
|
|
33
|
+
"auth-bootstrap": "login",
|
|
34
|
+
"auth-clear": "logout",
|
|
35
|
+
};
|
|
32
36
|
const COMMAND_FLAGS = {
|
|
33
37
|
"install-browser": [],
|
|
34
38
|
"auth-check": [],
|
|
35
|
-
|
|
36
|
-
|
|
39
|
+
login: [],
|
|
40
|
+
logout: [],
|
|
37
41
|
"set-address": ["address"],
|
|
38
42
|
search: ["query", "cuisine"],
|
|
39
43
|
menu: ["restaurant-id"],
|
|
@@ -58,6 +62,10 @@ export function assertSafeCommand(value) {
|
|
|
58
62
|
const guidance = value === "track-order" ? " Use `orders` or `order --order-id ...` for read-only existing-order status instead." : "";
|
|
59
63
|
throw new Error(`Blocked command: ${value}. This CLI is read-only for browse, cart, and existing-order inspection only; checkout, order placement, and payment actions stay out of scope.${guidance}`);
|
|
60
64
|
}
|
|
65
|
+
const renamedTo = LEGACY_COMMAND_RENAMES[value];
|
|
66
|
+
if (renamedTo) {
|
|
67
|
+
throw new Error(`Unsupported command: ${value}. This CLI renamed it to ${renamedTo}.`);
|
|
68
|
+
}
|
|
61
69
|
throw new Error(`Unsupported command: ${value}. Allowed commands: ${SAFE_COMMANDS.join(", ")}`);
|
|
62
70
|
}
|
|
63
71
|
export function assertAllowedFlags(command, args) {
|
|
@@ -76,9 +84,9 @@ export async function runCommand(command, args) {
|
|
|
76
84
|
return installBrowser();
|
|
77
85
|
case "auth-check":
|
|
78
86
|
return checkAuthDirect();
|
|
79
|
-
case "
|
|
87
|
+
case "login":
|
|
80
88
|
return bootstrapAuthSession();
|
|
81
|
-
case "
|
|
89
|
+
case "logout":
|
|
82
90
|
return clearStoredSession();
|
|
83
91
|
case "set-address": {
|
|
84
92
|
const address = requiredArg(args, "address");
|
package/docs/examples.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# doordash-cli examples
|
|
2
2
|
|
|
3
|
-
Use the preferred lowercase command name `
|
|
3
|
+
Use the preferred lowercase command name `doordash-cli`. `dd-cli` is an equivalent shorter alias.
|
|
4
4
|
|
|
5
5
|
If you are running from a local checkout without linking, prefix commands with:
|
|
6
6
|
|
|
@@ -17,25 +17,25 @@ All commands print JSON.
|
|
|
17
17
|
Install the matching Chromium build once if you do not already have it:
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
|
|
20
|
+
doordash-cli install-browser
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
Check whether you already have reusable session state:
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
|
-
|
|
26
|
+
doordash-cli auth-check
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
If needed, launch Chromium for a one-time sign-in and save reusable state:
|
|
30
30
|
|
|
31
31
|
```bash
|
|
32
|
-
|
|
32
|
+
doordash-cli login
|
|
33
33
|
```
|
|
34
34
|
|
|
35
35
|
Reset saved session state when you want a clean start:
|
|
36
36
|
|
|
37
37
|
```bash
|
|
38
|
-
|
|
38
|
+
doordash-cli logout
|
|
39
39
|
```
|
|
40
40
|
|
|
41
41
|
## Search, menus, and items
|
|
@@ -43,21 +43,21 @@ dd-cli auth-clear
|
|
|
43
43
|
Set the active delivery address before discovery commands:
|
|
44
44
|
|
|
45
45
|
```bash
|
|
46
|
-
|
|
46
|
+
doordash-cli set-address --address "350 5th Ave, New York, NY 10118"
|
|
47
47
|
```
|
|
48
48
|
|
|
49
49
|
Search by query, with or without a cuisine filter:
|
|
50
50
|
|
|
51
51
|
```bash
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
doordash-cli search --query tacos
|
|
53
|
+
doordash-cli search --query tacos --cuisine mexican
|
|
54
54
|
```
|
|
55
55
|
|
|
56
56
|
Inspect a restaurant menu and a specific item:
|
|
57
57
|
|
|
58
58
|
```bash
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
doordash-cli menu --restaurant-id 1721744
|
|
60
|
+
doordash-cli item --restaurant-id 1721744 --item-id 546936015
|
|
61
61
|
```
|
|
62
62
|
|
|
63
63
|
## Existing orders
|
|
@@ -65,20 +65,20 @@ dd-cli item --restaurant-id 1721744 --item-id 546936015
|
|
|
65
65
|
List recent existing orders:
|
|
66
66
|
|
|
67
67
|
```bash
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
doordash-cli orders
|
|
69
|
+
doordash-cli orders --limit 5
|
|
70
70
|
```
|
|
71
71
|
|
|
72
72
|
Focus on still-active orders only:
|
|
73
73
|
|
|
74
74
|
```bash
|
|
75
|
-
|
|
75
|
+
doordash-cli orders --active-only
|
|
76
76
|
```
|
|
77
77
|
|
|
78
78
|
Inspect one order in detail. `--order-id` accepts the CLI's returned internal ID, `orderUuid`, or `deliveryUuid`:
|
|
79
79
|
|
|
80
80
|
```bash
|
|
81
|
-
|
|
81
|
+
doordash-cli order --order-id 3f4c6d0e-1234-5678-90ab-cdef12345678
|
|
82
82
|
```
|
|
83
83
|
|
|
84
84
|
## Cart basics
|
|
@@ -86,19 +86,19 @@ dd-cli order --order-id 3f4c6d0e-1234-5678-90ab-cdef12345678
|
|
|
86
86
|
Add by item ID:
|
|
87
87
|
|
|
88
88
|
```bash
|
|
89
|
-
|
|
89
|
+
doordash-cli add-to-cart --restaurant-id 1721744 --item-id 876658890 --quantity 2
|
|
90
90
|
```
|
|
91
91
|
|
|
92
92
|
Add by visible item name:
|
|
93
93
|
|
|
94
94
|
```bash
|
|
95
|
-
|
|
95
|
+
doordash-cli add-to-cart --restaurant-id 1721744 --item-name "Spicy Tuna Roll"
|
|
96
96
|
```
|
|
97
97
|
|
|
98
98
|
Add with special instructions:
|
|
99
99
|
|
|
100
100
|
```bash
|
|
101
|
-
|
|
101
|
+
doordash-cli add-to-cart \
|
|
102
102
|
--restaurant-id 1721744 \
|
|
103
103
|
--item-name "Fries" \
|
|
104
104
|
--special-instructions "extra crispy"
|
|
@@ -107,14 +107,14 @@ dd-cli add-to-cart \
|
|
|
107
107
|
Update quantity or remove an item:
|
|
108
108
|
|
|
109
109
|
```bash
|
|
110
|
-
|
|
111
|
-
|
|
110
|
+
doordash-cli update-cart --cart-item-id 3b231d03-5a72-4636-8d12-c8769d706d45 --quantity 1
|
|
111
|
+
doordash-cli update-cart --cart-item-id 3b231d03-5a72-4636-8d12-c8769d706d45 --quantity 0
|
|
112
112
|
```
|
|
113
113
|
|
|
114
|
-
Inspect the active cart:
|
|
114
|
+
Inspect the active cart before or after a mutation:
|
|
115
115
|
|
|
116
116
|
```bash
|
|
117
|
-
|
|
117
|
+
doordash-cli cart
|
|
118
118
|
```
|
|
119
119
|
|
|
120
120
|
## Configurable items
|
|
@@ -122,7 +122,7 @@ dd-cli cart
|
|
|
122
122
|
For items with required option groups, pass `--options-json` with explicit selections:
|
|
123
123
|
|
|
124
124
|
```bash
|
|
125
|
-
|
|
125
|
+
doordash-cli add-to-cart \
|
|
126
126
|
--restaurant-id 1721744 \
|
|
127
127
|
--item-id 546936015 \
|
|
128
128
|
--options-json '[
|
|
@@ -134,7 +134,7 @@ dd-cli add-to-cart \
|
|
|
134
134
|
Supported standalone recommended add-ons can include recursive `children` selections:
|
|
135
135
|
|
|
136
136
|
```bash
|
|
137
|
-
|
|
137
|
+
doordash-cli add-to-cart \
|
|
138
138
|
--restaurant-id 1721744 \
|
|
139
139
|
--item-id 546936015 \
|
|
140
140
|
--options-json '[
|
package/docs/install.md
CHANGED
|
@@ -33,7 +33,7 @@ If you stay in checkout mode, replace `doordash-cli` with `npm run cli --` in th
|
|
|
33
33
|
|
|
34
34
|
## Install the browser once
|
|
35
35
|
|
|
36
|
-
If you plan to
|
|
36
|
+
If you plan to sign in with `login`, install the matching Playwright Chromium build:
|
|
37
37
|
|
|
38
38
|
### Global or linked install
|
|
39
39
|
|
|
@@ -50,7 +50,7 @@ npm run install:browser
|
|
|
50
50
|
## First run
|
|
51
51
|
|
|
52
52
|
```bash
|
|
53
|
-
doordash-cli
|
|
53
|
+
doordash-cli login
|
|
54
54
|
doordash-cli auth-check
|
|
55
55
|
doordash-cli set-address --address "350 5th Ave, New York, NY 10118"
|
|
56
56
|
doordash-cli search --query sushi
|
|
@@ -58,6 +58,6 @@ doordash-cli search --query sushi
|
|
|
58
58
|
|
|
59
59
|
## Session reuse
|
|
60
60
|
|
|
61
|
-
If you already have a compatible signed-in DoorDash browser session available, direct commands may reuse it instead of opening a
|
|
61
|
+
If you already have a compatible signed-in DoorDash managed-browser session available, direct commands may quietly reuse it instead of opening or navigating a DoorDash tab.
|
|
62
62
|
|
|
63
|
-
If not, run `doordash-cli
|
|
63
|
+
If not, run `doordash-cli login` once to save reusable state for later commands.
|
package/man/dd-cli.1
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
.TH DD-CLI 1 "2026-03-
|
|
1
|
+
.TH DD-CLI 1 "2026-03-11" "doordash-cli 0.3.0" "User Commands"
|
|
2
2
|
.SH NAME
|
|
3
|
-
dd-cli, doordash-cli \- unofficial cart-safe DoorDash CLI for browsing, read-only order inspection, and cart management
|
|
3
|
+
dd-cli, doordash-cli \- unofficial cart-safe DoorDash CLI for browsing, read-only existing-order inspection, and cart management
|
|
4
4
|
.SH SYNOPSIS
|
|
5
5
|
.B dd-cli
|
|
6
6
|
[\fICOMMAND\fR] [\fIOPTIONS\fR]
|
|
@@ -14,18 +14,18 @@ fit well in a terminal: signing in, setting delivery context, searching stores,
|
|
|
14
14
|
inspecting menus and items, inspecting existing orders, and managing the cart.
|
|
15
15
|
.PP
|
|
16
16
|
The command surface is intentionally small. The CLI does not expose checkout,
|
|
17
|
-
order placement, payment actions, or order mutation/cancellation.
|
|
18
|
-
existing-order inspection is allowed. If a payload cannot be
|
|
19
|
-
from known DoorDash consumer-web request shapes, the tool
|
|
20
|
-
of guessing.
|
|
17
|
+
order placement, payment actions, live tracking, or order mutation/cancellation.
|
|
18
|
+
Read-only existing-order inspection is allowed. If a payload cannot be
|
|
19
|
+
validated safely from known DoorDash consumer-web request shapes, the tool
|
|
20
|
+
fails closed instead of guessing.
|
|
21
21
|
.PP
|
|
22
22
|
If invoked with no command, or with
|
|
23
23
|
.BR -h / --help ,
|
|
24
24
|
it prints usage text and exits successfully.
|
|
25
25
|
.PP
|
|
26
26
|
The preferred command name is
|
|
27
|
-
.BR
|
|
28
|
-
.B
|
|
27
|
+
.BR doordash-cli .
|
|
28
|
+
.B dd-cli
|
|
29
29
|
is installed as a lowercase alias.
|
|
30
30
|
.SH COMMANDS
|
|
31
31
|
.TP
|
|
@@ -34,14 +34,14 @@ Install the matching Playwright Chromium build used by this package.
|
|
|
34
34
|
.TP
|
|
35
35
|
.B auth-check
|
|
36
36
|
Verify whether the saved session appears authenticated. This command can also
|
|
37
|
-
|
|
38
|
-
usable CDP endpoint is available.
|
|
37
|
+
quietly reuse an already-signed-in compatible managed-browser DoorDash session
|
|
38
|
+
when a usable CDP endpoint is available.
|
|
39
39
|
.TP
|
|
40
|
-
.B
|
|
40
|
+
.B login
|
|
41
41
|
Launch Chromium for a one-time manual sign-in flow, then save reusable browser
|
|
42
42
|
state for later direct API calls.
|
|
43
43
|
.TP
|
|
44
|
-
.B
|
|
44
|
+
.B logout
|
|
45
45
|
Delete stored session material used by this CLI.
|
|
46
46
|
.TP
|
|
47
47
|
.BI "set-address --address " ADDRESS
|
|
@@ -155,34 +155,34 @@ man dd-cli
|
|
|
155
155
|
Install the matching browser build once:
|
|
156
156
|
.PP
|
|
157
157
|
.EX
|
|
158
|
-
|
|
158
|
+
doordash-cli install-browser
|
|
159
159
|
.EE
|
|
160
160
|
.PP
|
|
161
161
|
Bootstrap a reusable session:
|
|
162
162
|
.PP
|
|
163
163
|
.EX
|
|
164
|
-
|
|
164
|
+
doordash-cli login
|
|
165
165
|
.EE
|
|
166
166
|
.PP
|
|
167
167
|
Set an address and search for sushi:
|
|
168
168
|
.PP
|
|
169
169
|
.EX
|
|
170
|
-
|
|
171
|
-
|
|
170
|
+
doordash-cli set-address --address "350 5th Ave, New York, NY 10118"
|
|
171
|
+
doordash-cli search --query sushi
|
|
172
172
|
.EE
|
|
173
173
|
.PP
|
|
174
174
|
Inspect existing orders:
|
|
175
175
|
.PP
|
|
176
176
|
.EX
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
177
|
+
doordash-cli orders
|
|
178
|
+
doordash-cli orders --active-only
|
|
179
|
+
doordash-cli order --order-id 3f4c6d0e-1234-5678-90ab-cdef12345678
|
|
180
180
|
.EE
|
|
181
181
|
.PP
|
|
182
182
|
Add a configurable item to the cart:
|
|
183
183
|
.PP
|
|
184
184
|
.EX
|
|
185
|
-
|
|
185
|
+
doordash-cli add-to-cart \
|
|
186
186
|
--restaurant-id 1721744 \
|
|
187
187
|
--item-id 546936015 \
|
|
188
188
|
--options-json '[{"groupId":"703393388","optionId":"4716032529"},{"groupId":"703393389","optionId":"4716042466"}]'
|
|
@@ -194,7 +194,7 @@ parsers, or scripts.
|
|
|
194
194
|
The CLI persists reusable session state under the user's configuration
|
|
195
195
|
directory. The exact file layout is an implementation detail and may evolve over
|
|
196
196
|
time, but the saved state is reused across runs unless cleared with
|
|
197
|
-
.BR
|
|
197
|
+
.BR logout .
|
|
198
198
|
.SH ENVIRONMENT
|
|
199
199
|
.TP
|
|
200
200
|
.B DOORDASH_MANAGED_BROWSER_CDP_URL
|
|
@@ -211,10 +211,10 @@ Success, including help and no-argument usage output.
|
|
|
211
211
|
.B 1
|
|
212
212
|
Validation error, blocked command, unsupported flag, or runtime failure.
|
|
213
213
|
.SH SAFETY
|
|
214
|
-
The CLI is intentionally limited to
|
|
215
|
-
inspection, and cart management. Dangerous commands such as
|
|
216
|
-
place-order, payment actions, and order
|
|
217
|
-
immediately. The legacy
|
|
214
|
+
The CLI is intentionally limited to session, discovery, read-only
|
|
215
|
+
existing-order inspection, and cart management. Dangerous commands such as
|
|
216
|
+
checkout, place-order, payment actions, live tracking, and order
|
|
217
|
+
mutation/cancellation are blocked immediately. The legacy
|
|
218
218
|
.B track-order
|
|
219
219
|
verb remains blocked; use
|
|
220
220
|
.B orders
|
package/package.json
CHANGED