@opentabs-dev/opentabs-plugin-panda-express 0.0.74
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 +140 -0
- package/dist/adapter.iife.js +15117 -0
- package/dist/adapter.iife.js.map +7 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +58 -0
- package/dist/index.js.map +1 -0
- package/dist/panda-api.d.ts +9 -0
- package/dist/panda-api.d.ts.map +1 -0
- package/dist/panda-api.js +88 -0
- package/dist/panda-api.js.map +1 -0
- package/dist/tools/add-product-to-basket.d.ts +21 -0
- package/dist/tools/add-product-to-basket.d.ts.map +1 -0
- package/dist/tools/add-product-to-basket.js +39 -0
- package/dist/tools/add-product-to-basket.js.map +1 -0
- package/dist/tools/apply-coupon.d.ts +19 -0
- package/dist/tools/apply-coupon.d.ts.map +1 -0
- package/dist/tools/apply-coupon.js +27 -0
- package/dist/tools/apply-coupon.js.map +1 -0
- package/dist/tools/cancel-order.d.ts +7 -0
- package/dist/tools/cancel-order.d.ts.map +1 -0
- package/dist/tools/cancel-order.js +25 -0
- package/dist/tools/cancel-order.js.map +1 -0
- package/dist/tools/create-basket.d.ts +19 -0
- package/dist/tools/create-basket.d.ts.map +1 -0
- package/dist/tools/create-basket.js +30 -0
- package/dist/tools/create-basket.js.map +1 -0
- package/dist/tools/find-restaurants.d.ts +28 -0
- package/dist/tools/find-restaurants.d.ts.map +1 -0
- package/dist/tools/find-restaurants.js +33 -0
- package/dist/tools/find-restaurants.js.map +1 -0
- package/dist/tools/get-basket.d.ts +25 -0
- package/dist/tools/get-basket.d.ts.map +1 -0
- package/dist/tools/get-basket.js +27 -0
- package/dist/tools/get-basket.js.map +1 -0
- package/dist/tools/get-billing-accounts.d.ts +11 -0
- package/dist/tools/get-billing-accounts.d.ts.map +1 -0
- package/dist/tools/get-billing-accounts.js +35 -0
- package/dist/tools/get-billing-accounts.js.map +1 -0
- package/dist/tools/get-checkout-summary.d.ts +13 -0
- package/dist/tools/get-checkout-summary.d.ts.map +1 -0
- package/dist/tools/get-checkout-summary.js +40 -0
- package/dist/tools/get-checkout-summary.js.map +1 -0
- package/dist/tools/get-favorites.d.ts +9 -0
- package/dist/tools/get-favorites.d.ts.map +1 -0
- package/dist/tools/get-favorites.js +22 -0
- package/dist/tools/get-favorites.js.map +1 -0
- package/dist/tools/get-loyalty-rewards.d.ts +12 -0
- package/dist/tools/get-loyalty-rewards.d.ts.map +1 -0
- package/dist/tools/get-loyalty-rewards.js +33 -0
- package/dist/tools/get-loyalty-rewards.js.map +1 -0
- package/dist/tools/get-product-modifiers.d.ts +17 -0
- package/dist/tools/get-product-modifiers.d.ts.map +1 -0
- package/dist/tools/get-product-modifiers.js +45 -0
- package/dist/tools/get-product-modifiers.js.map +1 -0
- package/dist/tools/get-recent-orders.d.ts +17 -0
- package/dist/tools/get-recent-orders.d.ts.map +1 -0
- package/dist/tools/get-recent-orders.js +22 -0
- package/dist/tools/get-recent-orders.js.map +1 -0
- package/dist/tools/get-restaurant-menu.d.ts +22 -0
- package/dist/tools/get-restaurant-menu.d.ts.map +1 -0
- package/dist/tools/get-restaurant-menu.js +27 -0
- package/dist/tools/get-restaurant-menu.js.map +1 -0
- package/dist/tools/get-restaurant.d.ts +26 -0
- package/dist/tools/get-restaurant.d.ts.map +1 -0
- package/dist/tools/get-restaurant.js +34 -0
- package/dist/tools/get-restaurant.js.map +1 -0
- package/dist/tools/get-user-profile.d.ts +11 -0
- package/dist/tools/get-user-profile.d.ts.map +1 -0
- package/dist/tools/get-user-profile.js +48 -0
- package/dist/tools/get-user-profile.js.map +1 -0
- package/dist/tools/navigate-to-checkout.d.ts +32 -0
- package/dist/tools/navigate-to-checkout.d.ts.map +1 -0
- package/dist/tools/navigate-to-checkout.js +112 -0
- package/dist/tools/navigate-to-checkout.js.map +1 -0
- package/dist/tools/remove-coupon.d.ts +18 -0
- package/dist/tools/remove-coupon.d.ts.map +1 -0
- package/dist/tools/remove-coupon.js +25 -0
- package/dist/tools/remove-coupon.js.map +1 -0
- package/dist/tools/schemas.d.ts +241 -0
- package/dist/tools/schemas.d.ts.map +1 -0
- package/dist/tools/schemas.js +168 -0
- package/dist/tools/schemas.js.map +1 -0
- package/dist/tools/update-product-quantity.d.ts +20 -0
- package/dist/tools/update-product-quantity.d.ts.map +1 -0
- package/dist/tools/update-product-quantity.js +34 -0
- package/dist/tools/update-product-quantity.js.map +1 -0
- package/dist/tools.json +1584 -0
- package/package.json +54 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { OpenTabsPlugin } from '@opentabs-dev/plugin-sdk';
|
|
2
|
+
import type { ToolDefinition } from '@opentabs-dev/plugin-sdk';
|
|
3
|
+
declare class PandaExpressPlugin extends OpenTabsPlugin {
|
|
4
|
+
readonly name = "panda-express";
|
|
5
|
+
readonly description = "OpenTabs plugin for Panda Express \u2014 search restaurants, browse menus, build orders, checkout, manage loyalty rewards, and view order history.";
|
|
6
|
+
readonly displayName = "Panda Express";
|
|
7
|
+
readonly urlPatterns: string[];
|
|
8
|
+
readonly homepage = "https://www.pandaexpress.com";
|
|
9
|
+
readonly tools: ToolDefinition[];
|
|
10
|
+
isReady(): Promise<boolean>;
|
|
11
|
+
}
|
|
12
|
+
declare const _default: PandaExpressPlugin;
|
|
13
|
+
export default _default;
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AA0B/D,cAAM,kBAAmB,SAAQ,cAAc;IAC7C,QAAQ,CAAC,IAAI,mBAAmB;IAChC,QAAQ,CAAC,WAAW,wJAC8H;IAClJ,SAAkB,WAAW,mBAAmB;IAChD,QAAQ,CAAC,WAAW,WAAgC;IACpD,SAAkB,QAAQ,kCAAkC;IAC5D,QAAQ,CAAC,KAAK,EAAE,cAAc,EAAE,CAmB9B;IAEI,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC;CAIlC;;AAED,wBAAwC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { OpenTabsPlugin } from '@opentabs-dev/plugin-sdk';
|
|
2
|
+
import { isAuthenticated, waitForAuth } from './panda-api.js';
|
|
3
|
+
import { addProductToBasket } from './tools/add-product-to-basket.js';
|
|
4
|
+
import { applyCoupon } from './tools/apply-coupon.js';
|
|
5
|
+
import { cancelOrder } from './tools/cancel-order.js';
|
|
6
|
+
import { createBasket } from './tools/create-basket.js';
|
|
7
|
+
import { findRestaurants } from './tools/find-restaurants.js';
|
|
8
|
+
import { getBasket } from './tools/get-basket.js';
|
|
9
|
+
import { getBillingAccounts } from './tools/get-billing-accounts.js';
|
|
10
|
+
import { getCheckoutSummary } from './tools/get-checkout-summary.js';
|
|
11
|
+
import { getFavorites } from './tools/get-favorites.js';
|
|
12
|
+
import { getLoyaltyRewards } from './tools/get-loyalty-rewards.js';
|
|
13
|
+
import { getProductModifiers } from './tools/get-product-modifiers.js';
|
|
14
|
+
import { getRecentOrders } from './tools/get-recent-orders.js';
|
|
15
|
+
import { getRestaurantMenu } from './tools/get-restaurant-menu.js';
|
|
16
|
+
import { getRestaurant } from './tools/get-restaurant.js';
|
|
17
|
+
import { getUserProfile } from './tools/get-user-profile.js';
|
|
18
|
+
import { applyPendingBasket, navigateToCheckout } from './tools/navigate-to-checkout.js';
|
|
19
|
+
import { removeCoupon } from './tools/remove-coupon.js';
|
|
20
|
+
import { updateProductQuantity } from './tools/update-product-quantity.js';
|
|
21
|
+
// Apply any pending basket stashed by navigate_to_checkout before the SPA hydrates.
|
|
22
|
+
// This runs immediately when the adapter IIFE is injected — before isReady() and
|
|
23
|
+
// before Redux reads persist:root — to win the race against the SPA's own hydration.
|
|
24
|
+
applyPendingBasket();
|
|
25
|
+
class PandaExpressPlugin extends OpenTabsPlugin {
|
|
26
|
+
name = 'panda-express';
|
|
27
|
+
description = 'OpenTabs plugin for Panda Express — search restaurants, browse menus, build orders, checkout, manage loyalty rewards, and view order history.';
|
|
28
|
+
displayName = 'Panda Express';
|
|
29
|
+
urlPatterns = ['*://*.pandaexpress.com/*'];
|
|
30
|
+
homepage = 'https://www.pandaexpress.com';
|
|
31
|
+
tools = [
|
|
32
|
+
findRestaurants,
|
|
33
|
+
getRestaurant,
|
|
34
|
+
getRestaurantMenu,
|
|
35
|
+
getProductModifiers,
|
|
36
|
+
createBasket,
|
|
37
|
+
getBasket,
|
|
38
|
+
addProductToBasket,
|
|
39
|
+
updateProductQuantity,
|
|
40
|
+
applyCoupon,
|
|
41
|
+
removeCoupon,
|
|
42
|
+
getCheckoutSummary,
|
|
43
|
+
navigateToCheckout,
|
|
44
|
+
cancelOrder,
|
|
45
|
+
getUserProfile,
|
|
46
|
+
getRecentOrders,
|
|
47
|
+
getFavorites,
|
|
48
|
+
getBillingAccounts,
|
|
49
|
+
getLoyaltyRewards,
|
|
50
|
+
];
|
|
51
|
+
async isReady() {
|
|
52
|
+
if (isAuthenticated())
|
|
53
|
+
return true;
|
|
54
|
+
return waitForAuth();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
export default new PandaExpressPlugin();
|
|
58
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACzF,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAE3E,oFAAoF;AACpF,iFAAiF;AACjF,qFAAqF;AACrF,kBAAkB,EAAE,CAAC;AAErB,MAAM,kBAAmB,SAAQ,cAAc;IACpC,IAAI,GAAG,eAAe,CAAC;IACvB,WAAW,GAClB,+IAA+I,CAAC;IAChI,WAAW,GAAG,eAAe,CAAC;IACvC,WAAW,GAAG,CAAC,0BAA0B,CAAC,CAAC;IAClC,QAAQ,GAAG,8BAA8B,CAAC;IACnD,KAAK,GAAqB;QACjC,eAAe;QACf,aAAa;QACb,iBAAiB;QACjB,mBAAmB;QACnB,YAAY;QACZ,SAAS;QACT,kBAAkB;QAClB,qBAAqB;QACrB,WAAW;QACX,YAAY;QACZ,kBAAkB;QAClB,kBAAkB;QAClB,WAAW;QACX,cAAc;QACd,eAAe;QACf,YAAY;QACZ,kBAAkB;QAClB,iBAAiB;KAClB,CAAC;IAEF,KAAK,CAAC,OAAO;QACX,IAAI,eAAe,EAAE;YAAE,OAAO,IAAI,CAAC;QACnC,OAAO,WAAW,EAAE,CAAC;IACvB,CAAC;CACF;AAED,eAAe,IAAI,kBAAkB,EAAE,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const isAuthenticated: () => boolean;
|
|
2
|
+
export declare const waitForAuth: () => Promise<boolean>;
|
|
3
|
+
export declare const getRequiredAuthToken: () => string;
|
|
4
|
+
export declare const api: <T>(endpoint: string, options?: {
|
|
5
|
+
method?: string;
|
|
6
|
+
body?: Record<string, unknown>;
|
|
7
|
+
query?: Record<string, string | number | boolean | undefined>;
|
|
8
|
+
}) => Promise<T>;
|
|
9
|
+
//# sourceMappingURL=panda-api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"panda-api.d.ts","sourceRoot":"","sources":["../src/panda-api.ts"],"names":[],"mappings":"AAoBA,eAAO,MAAM,eAAe,QAAO,OAAkC,CAAC;AAEtE,eAAO,MAAM,WAAW,QAAO,OAAO,CAAC,OAAO,CAI3C,CAAC;AAEJ,eAAO,MAAM,oBAAoB,QAAO,MAIvC,CAAC;AAEF,eAAO,MAAM,GAAG,GAAU,CAAC,EACzB,UAAU,MAAM,EAChB,UAAS;IACP,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,CAAC;CAC1D,KACL,OAAO,CAAC,CAAC,CA2DX,CAAC"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { ToolError, getLocalStorage, parseRetryAfterMs, waitUntil } from '@opentabs-dev/plugin-sdk';
|
|
2
|
+
/**
|
|
3
|
+
* Panda Express uses Olo (NomNom) APIs proxied through the same origin.
|
|
4
|
+
* Auth is handled via an authtoken stored in Redux persist (localStorage persist:root).
|
|
5
|
+
* The authtoken is used as a path segment for user-specific endpoints (e.g., /users/{authtoken}/recentorders).
|
|
6
|
+
*/
|
|
7
|
+
const getAuthToken = () => {
|
|
8
|
+
try {
|
|
9
|
+
const root = getLocalStorage('persist:root');
|
|
10
|
+
if (!root)
|
|
11
|
+
return null;
|
|
12
|
+
const parsed = JSON.parse(root);
|
|
13
|
+
const appState = JSON.parse(parsed.appState ?? '{}');
|
|
14
|
+
return appState?.authentication?.authtoken ?? null;
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
export const isAuthenticated = () => getAuthToken() !== null;
|
|
21
|
+
export const waitForAuth = () => waitUntil(() => isAuthenticated(), { interval: 500, timeout: 5000 }).then(() => true, () => false);
|
|
22
|
+
export const getRequiredAuthToken = () => {
|
|
23
|
+
const token = getAuthToken();
|
|
24
|
+
if (!token)
|
|
25
|
+
throw ToolError.auth('Not authenticated — please log in to Panda Express.');
|
|
26
|
+
return token;
|
|
27
|
+
};
|
|
28
|
+
export const api = async (endpoint, options = {}) => {
|
|
29
|
+
let url = endpoint;
|
|
30
|
+
if (options.query) {
|
|
31
|
+
const params = new URLSearchParams();
|
|
32
|
+
for (const [k, v] of Object.entries(options.query)) {
|
|
33
|
+
if (v !== undefined)
|
|
34
|
+
params.append(k, String(v));
|
|
35
|
+
}
|
|
36
|
+
const qs = params.toString();
|
|
37
|
+
if (qs)
|
|
38
|
+
url += `?${qs}`;
|
|
39
|
+
}
|
|
40
|
+
const headers = {
|
|
41
|
+
Accept: 'application/json',
|
|
42
|
+
};
|
|
43
|
+
let fetchBody;
|
|
44
|
+
if (options.body) {
|
|
45
|
+
headers['Content-Type'] = 'application/json';
|
|
46
|
+
fetchBody = JSON.stringify(options.body);
|
|
47
|
+
}
|
|
48
|
+
let response;
|
|
49
|
+
try {
|
|
50
|
+
response = await fetch(url, {
|
|
51
|
+
method: options.method ?? 'GET',
|
|
52
|
+
headers,
|
|
53
|
+
body: fetchBody,
|
|
54
|
+
credentials: 'include',
|
|
55
|
+
signal: AbortSignal.timeout(30_000),
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
if (err instanceof DOMException && err.name === 'TimeoutError') {
|
|
60
|
+
throw ToolError.timeout(`Timed out: ${endpoint}`);
|
|
61
|
+
}
|
|
62
|
+
throw new ToolError(`Network error: ${err instanceof Error ? err.message : String(err)}`, 'network_error', {
|
|
63
|
+
category: 'internal',
|
|
64
|
+
retryable: true,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
if (!response.ok) {
|
|
68
|
+
const body = (await response.text().catch(() => '')).substring(0, 512);
|
|
69
|
+
if (response.status === 429) {
|
|
70
|
+
const retryAfter = response.headers.get('Retry-After');
|
|
71
|
+
throw ToolError.rateLimited(`Rate limited: ${endpoint}`, retryAfter ? parseRetryAfterMs(retryAfter) : undefined);
|
|
72
|
+
}
|
|
73
|
+
if (response.status === 401 || response.status === 403) {
|
|
74
|
+
throw ToolError.auth(`Auth error (${response.status}): ${body}`);
|
|
75
|
+
}
|
|
76
|
+
if (response.status === 404) {
|
|
77
|
+
throw ToolError.notFound(`Not found: ${endpoint}`);
|
|
78
|
+
}
|
|
79
|
+
if (response.status === 422) {
|
|
80
|
+
throw ToolError.validation(`Validation error: ${body}`);
|
|
81
|
+
}
|
|
82
|
+
throw ToolError.internal(`API error (${response.status}): ${endpoint} — ${body}`);
|
|
83
|
+
}
|
|
84
|
+
if (response.status === 204)
|
|
85
|
+
return {};
|
|
86
|
+
return (await response.json());
|
|
87
|
+
};
|
|
88
|
+
//# sourceMappingURL=panda-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"panda-api.js","sourceRoot":"","sources":["../src/panda-api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const addProductToBasket: import("@opentabs-dev/plugin-sdk").ToolDefinition<z.ZodObject<{
|
|
3
|
+
basket_id: z.ZodString;
|
|
4
|
+
product_id: z.ZodNumber;
|
|
5
|
+
quantity: z.ZodOptional<z.ZodNumber>;
|
|
6
|
+
options: z.ZodOptional<z.ZodArray<z.ZodNumber>>;
|
|
7
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
8
|
+
basket: z.ZodObject<{
|
|
9
|
+
id: z.ZodString;
|
|
10
|
+
vendor_id: z.ZodNumber;
|
|
11
|
+
subtotal: z.ZodNumber;
|
|
12
|
+
sales_tax: z.ZodNumber;
|
|
13
|
+
total: z.ZodNumber;
|
|
14
|
+
product_count: z.ZodNumber;
|
|
15
|
+
delivery_mode: z.ZodString;
|
|
16
|
+
earliest_ready_time: z.ZodString;
|
|
17
|
+
lead_time_minutes: z.ZodNumber;
|
|
18
|
+
coupon_discount: z.ZodNumber;
|
|
19
|
+
}, z.core.$strip>;
|
|
20
|
+
}, z.core.$strip>>;
|
|
21
|
+
//# sourceMappingURL=add-product-to-basket.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add-product-to-basket.d.ts","sourceRoot":"","sources":["../../src/tools/add-product-to-basket.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;kBAoC7B,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { defineTool } from '@opentabs-dev/plugin-sdk';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { api } from '../panda-api.js';
|
|
4
|
+
import { basketSchema, mapBasket } from './schemas.js';
|
|
5
|
+
export const addProductToBasket = defineTool({
|
|
6
|
+
name: 'add_product_to_basket',
|
|
7
|
+
displayName: 'Add Product to Basket',
|
|
8
|
+
description: 'Add a menu product to an existing basket. Most products require modifier selections — call get_product_modifiers first to get available options, then pass the selected option IDs. For simple products (bottled drinks), only the size option is needed.',
|
|
9
|
+
summary: 'Add a menu item to your order',
|
|
10
|
+
icon: 'plus-circle',
|
|
11
|
+
group: 'Orders',
|
|
12
|
+
input: z.object({
|
|
13
|
+
basket_id: z.string().describe('Basket ID (UUID)'),
|
|
14
|
+
product_id: z.number().int().describe('Product ID from get_restaurant_menu'),
|
|
15
|
+
quantity: z.number().int().optional().describe('Quantity to add (default 1)'),
|
|
16
|
+
options: z
|
|
17
|
+
.array(z.number())
|
|
18
|
+
.optional()
|
|
19
|
+
.describe('Array of modifier option IDs from get_product_modifiers. For combos, include one option from each mandatory group (e.g., side choice, entree choice, drink choice).'),
|
|
20
|
+
}),
|
|
21
|
+
output: z.object({
|
|
22
|
+
basket: basketSchema.describe('Updated basket after adding the product'),
|
|
23
|
+
}),
|
|
24
|
+
handle: async (params) => {
|
|
25
|
+
const body = {
|
|
26
|
+
productid: params.product_id,
|
|
27
|
+
quantity: params.quantity ?? 1,
|
|
28
|
+
};
|
|
29
|
+
if (params.options && params.options.length > 0) {
|
|
30
|
+
body.options = params.options.join(',');
|
|
31
|
+
}
|
|
32
|
+
const data = await api(`/baskets/${params.basket_id}/products`, {
|
|
33
|
+
method: 'POST',
|
|
34
|
+
body,
|
|
35
|
+
});
|
|
36
|
+
return { basket: mapBasket(data) };
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
//# sourceMappingURL=add-product-to-basket.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"add-product-to-basket.js","sourceRoot":"","sources":["../../src/tools/add-product-to-basket.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AACtC,OAAO,EAAkB,YAAY,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEvE,MAAM,CAAC,MAAM,kBAAkB,GAAG,UAAU,CAAC;IAC3C,IAAI,EAAE,uBAAuB;IAC7B,WAAW,EAAE,uBAAuB;IACpC,WAAW,EACT,2PAA2P;IAC7P,OAAO,EAAE,+BAA+B;IACxC,IAAI,EAAE,aAAa;IACnB,KAAK,EAAE,QAAQ;IACf,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,kBAAkB,CAAC;QAClD,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,qCAAqC,CAAC;QAC5E,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6BAA6B,CAAC;QAC7E,OAAO,EAAE,CAAC;aACP,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;aACjB,QAAQ,EAAE;aACV,QAAQ,CACP,qKAAqK,CACtK;KACJ,CAAC;IACF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,MAAM,EAAE,YAAY,CAAC,QAAQ,CAAC,yCAAyC,CAAC;KACzE,CAAC;IACF,MAAM,EAAE,KAAK,EAAC,MAAM,EAAC,EAAE;QACrB,MAAM,IAAI,GAA4B;YACpC,SAAS,EAAE,MAAM,CAAC,UAAU;YAC5B,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,CAAC;SAC/B,CAAC;QACF,IAAI,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChD,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC1C,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,GAAG,CAAY,YAAY,MAAM,CAAC,SAAS,WAAW,EAAE;YACzE,MAAM,EAAE,MAAM;YACd,IAAI;SACL,CAAC,CAAC;QACH,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;IACrC,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const applyCoupon: import("@opentabs-dev/plugin-sdk").ToolDefinition<z.ZodObject<{
|
|
3
|
+
basket_id: z.ZodString;
|
|
4
|
+
coupon_code: z.ZodString;
|
|
5
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
6
|
+
basket: z.ZodObject<{
|
|
7
|
+
id: z.ZodString;
|
|
8
|
+
vendor_id: z.ZodNumber;
|
|
9
|
+
subtotal: z.ZodNumber;
|
|
10
|
+
sales_tax: z.ZodNumber;
|
|
11
|
+
total: z.ZodNumber;
|
|
12
|
+
product_count: z.ZodNumber;
|
|
13
|
+
delivery_mode: z.ZodString;
|
|
14
|
+
earliest_ready_time: z.ZodString;
|
|
15
|
+
lead_time_minutes: z.ZodNumber;
|
|
16
|
+
coupon_discount: z.ZodNumber;
|
|
17
|
+
}, z.core.$strip>;
|
|
18
|
+
}, z.core.$strip>>;
|
|
19
|
+
//# sourceMappingURL=apply-coupon.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply-coupon.d.ts","sourceRoot":"","sources":["../../src/tools/apply-coupon.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;kBAqBtB,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { defineTool } from '@opentabs-dev/plugin-sdk';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { api } from '../panda-api.js';
|
|
4
|
+
import { basketSchema, mapBasket } from './schemas.js';
|
|
5
|
+
export const applyCoupon = defineTool({
|
|
6
|
+
name: 'apply_coupon',
|
|
7
|
+
displayName: 'Apply Coupon',
|
|
8
|
+
description: 'Apply a coupon or promo code to an existing basket. Returns the updated basket with discount applied.',
|
|
9
|
+
summary: 'Apply a coupon code to your order',
|
|
10
|
+
icon: 'ticket',
|
|
11
|
+
group: 'Orders',
|
|
12
|
+
input: z.object({
|
|
13
|
+
basket_id: z.string().describe('Basket ID (UUID)'),
|
|
14
|
+
coupon_code: z.string().describe('Coupon or promo code to apply'),
|
|
15
|
+
}),
|
|
16
|
+
output: z.object({
|
|
17
|
+
basket: basketSchema.describe('Updated basket with coupon applied'),
|
|
18
|
+
}),
|
|
19
|
+
handle: async (params) => {
|
|
20
|
+
const data = await api(`/baskets/${params.basket_id}/coupon`, {
|
|
21
|
+
method: 'PUT',
|
|
22
|
+
body: { couponcode: params.coupon_code },
|
|
23
|
+
});
|
|
24
|
+
return { basket: mapBasket(data) };
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
//# sourceMappingURL=apply-coupon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply-coupon.js","sourceRoot":"","sources":["../../src/tools/apply-coupon.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AACtC,OAAO,EAAkB,YAAY,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEvE,MAAM,CAAC,MAAM,WAAW,GAAG,UAAU,CAAC;IACpC,IAAI,EAAE,cAAc;IACpB,WAAW,EAAE,cAAc;IAC3B,WAAW,EAAE,uGAAuG;IACpH,OAAO,EAAE,mCAAmC;IAC5C,IAAI,EAAE,QAAQ;IACd,KAAK,EAAE,QAAQ;IACf,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,kBAAkB,CAAC;QAClD,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;KAClE,CAAC;IACF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,MAAM,EAAE,YAAY,CAAC,QAAQ,CAAC,oCAAoC,CAAC;KACpE,CAAC;IACF,MAAM,EAAE,KAAK,EAAC,MAAM,EAAC,EAAE;QACrB,MAAM,IAAI,GAAG,MAAM,GAAG,CAAY,YAAY,MAAM,CAAC,SAAS,SAAS,EAAE;YACvE,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,WAAW,EAAE;SACzC,CAAC,CAAC;QACH,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;IACrC,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const cancelOrder: import("@opentabs-dev/plugin-sdk").ToolDefinition<z.ZodObject<{
|
|
3
|
+
order_id: z.ZodString;
|
|
4
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
5
|
+
cancelled: z.ZodBoolean;
|
|
6
|
+
}, z.core.$strip>>;
|
|
7
|
+
//# sourceMappingURL=cancel-order.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cancel-order.d.ts","sourceRoot":"","sources":["../../src/tools/cancel-order.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,WAAW;;;;kBAqBtB,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { defineTool } from '@opentabs-dev/plugin-sdk';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { api } from '../panda-api.js';
|
|
4
|
+
export const cancelOrder = defineTool({
|
|
5
|
+
name: 'cancel_order',
|
|
6
|
+
displayName: 'Cancel Order',
|
|
7
|
+
description: 'Cancel a previously submitted order. Only works for orders that have not yet been prepared. The order ID can be obtained from get_recent_orders.',
|
|
8
|
+
summary: 'Cancel a pending order',
|
|
9
|
+
icon: 'x-circle',
|
|
10
|
+
group: 'Orders',
|
|
11
|
+
input: z.object({
|
|
12
|
+
order_id: z.string().describe('Order ID to cancel (from get_recent_orders)'),
|
|
13
|
+
}),
|
|
14
|
+
output: z.object({
|
|
15
|
+
cancelled: z.boolean().describe('Whether the order was successfully cancelled'),
|
|
16
|
+
}),
|
|
17
|
+
handle: async (params) => {
|
|
18
|
+
await api(`/orders/${params.order_id}/cancel`, {
|
|
19
|
+
method: 'POST',
|
|
20
|
+
body: {},
|
|
21
|
+
});
|
|
22
|
+
return { cancelled: true };
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
//# sourceMappingURL=cancel-order.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cancel-order.js","sourceRoot":"","sources":["../../src/tools/cancel-order.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAEtC,MAAM,CAAC,MAAM,WAAW,GAAG,UAAU,CAAC;IACpC,IAAI,EAAE,cAAc;IACpB,WAAW,EAAE,cAAc;IAC3B,WAAW,EACT,kJAAkJ;IACpJ,OAAO,EAAE,wBAAwB;IACjC,IAAI,EAAE,UAAU;IAChB,KAAK,EAAE,QAAQ;IACf,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,6CAA6C,CAAC;KAC7E,CAAC;IACF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,8CAA8C,CAAC;KAChF,CAAC;IACF,MAAM,EAAE,KAAK,EAAC,MAAM,EAAC,EAAE;QACrB,MAAM,GAAG,CAA0B,WAAW,MAAM,CAAC,QAAQ,SAAS,EAAE;YACtE,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,EAAE;SACT,CAAC,CAAC;QACH,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IAC7B,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const createBasket: import("@opentabs-dev/plugin-sdk").ToolDefinition<z.ZodObject<{
|
|
3
|
+
restaurant_id: z.ZodNumber;
|
|
4
|
+
time_wanted: z.ZodOptional<z.ZodString>;
|
|
5
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
6
|
+
basket: z.ZodObject<{
|
|
7
|
+
id: z.ZodString;
|
|
8
|
+
vendor_id: z.ZodNumber;
|
|
9
|
+
subtotal: z.ZodNumber;
|
|
10
|
+
sales_tax: z.ZodNumber;
|
|
11
|
+
total: z.ZodNumber;
|
|
12
|
+
product_count: z.ZodNumber;
|
|
13
|
+
delivery_mode: z.ZodString;
|
|
14
|
+
earliest_ready_time: z.ZodString;
|
|
15
|
+
lead_time_minutes: z.ZodNumber;
|
|
16
|
+
coupon_discount: z.ZodNumber;
|
|
17
|
+
}, z.core.$strip>;
|
|
18
|
+
}, z.core.$strip>>;
|
|
19
|
+
//# sourceMappingURL=create-basket.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-basket.d.ts","sourceRoot":"","sources":["../../src/tools/create-basket.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;kBAyBvB,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { defineTool } from '@opentabs-dev/plugin-sdk';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { api } from '../panda-api.js';
|
|
4
|
+
import { basketSchema, mapBasket } from './schemas.js';
|
|
5
|
+
export const createBasket = defineTool({
|
|
6
|
+
name: 'create_basket',
|
|
7
|
+
displayName: 'Create Basket',
|
|
8
|
+
description: 'Create a new order basket (cart) at a specific Panda Express restaurant. The basket must be created before adding products. Use "asap" for timewanted to order immediately.',
|
|
9
|
+
summary: 'Start a new order at a restaurant',
|
|
10
|
+
icon: 'shopping-cart',
|
|
11
|
+
group: 'Orders',
|
|
12
|
+
input: z.object({
|
|
13
|
+
restaurant_id: z.number().int().describe('Restaurant ID to order from'),
|
|
14
|
+
time_wanted: z.string().optional().describe('Desired pickup/delivery time, or "asap" (default "asap")'),
|
|
15
|
+
}),
|
|
16
|
+
output: z.object({
|
|
17
|
+
basket: basketSchema.describe('The created basket'),
|
|
18
|
+
}),
|
|
19
|
+
handle: async (params) => {
|
|
20
|
+
const data = await api('/baskets/create', {
|
|
21
|
+
method: 'POST',
|
|
22
|
+
body: {
|
|
23
|
+
vendorid: params.restaurant_id,
|
|
24
|
+
timewanted: params.time_wanted ?? 'asap',
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
return { basket: mapBasket(data) };
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
//# sourceMappingURL=create-basket.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-basket.js","sourceRoot":"","sources":["../../src/tools/create-basket.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AACtC,OAAO,EAAkB,YAAY,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEvE,MAAM,CAAC,MAAM,YAAY,GAAG,UAAU,CAAC;IACrC,IAAI,EAAE,eAAe;IACrB,WAAW,EAAE,eAAe;IAC5B,WAAW,EACT,6KAA6K;IAC/K,OAAO,EAAE,mCAAmC;IAC5C,IAAI,EAAE,eAAe;IACrB,KAAK,EAAE,QAAQ;IACf,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,6BAA6B,CAAC;QACvE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,0DAA0D,CAAC;KACxG,CAAC;IACF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,MAAM,EAAE,YAAY,CAAC,QAAQ,CAAC,oBAAoB,CAAC;KACpD,CAAC;IACF,MAAM,EAAE,KAAK,EAAC,MAAM,EAAC,EAAE;QACrB,MAAM,IAAI,GAAG,MAAM,GAAG,CAAY,iBAAiB,EAAE;YACnD,MAAM,EAAE,MAAM;YACd,IAAI,EAAE;gBACJ,QAAQ,EAAE,MAAM,CAAC,aAAa;gBAC9B,UAAU,EAAE,MAAM,CAAC,WAAW,IAAI,MAAM;aACzC;SACF,CAAC,CAAC;QACH,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;IACrC,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const findRestaurants: import("@opentabs-dev/plugin-sdk").ToolDefinition<z.ZodObject<{
|
|
3
|
+
latitude: z.ZodNumber;
|
|
4
|
+
longitude: z.ZodNumber;
|
|
5
|
+
radius: z.ZodOptional<z.ZodNumber>;
|
|
6
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
7
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
8
|
+
restaurants: z.ZodArray<z.ZodObject<{
|
|
9
|
+
id: z.ZodNumber;
|
|
10
|
+
name: z.ZodString;
|
|
11
|
+
slug: z.ZodString;
|
|
12
|
+
street_address: z.ZodString;
|
|
13
|
+
city: z.ZodString;
|
|
14
|
+
state: z.ZodString;
|
|
15
|
+
zip: z.ZodString;
|
|
16
|
+
phone: z.ZodString;
|
|
17
|
+
latitude: z.ZodNumber;
|
|
18
|
+
longitude: z.ZodNumber;
|
|
19
|
+
distance: z.ZodNumber;
|
|
20
|
+
is_available: z.ZodBoolean;
|
|
21
|
+
is_open: z.ZodBoolean;
|
|
22
|
+
can_deliver: z.ZodBoolean;
|
|
23
|
+
can_pickup: z.ZodBoolean;
|
|
24
|
+
delivery_fee: z.ZodString;
|
|
25
|
+
ext_ref: z.ZodString;
|
|
26
|
+
}, z.core.$strip>>;
|
|
27
|
+
}, z.core.$strip>>;
|
|
28
|
+
//# sourceMappingURL=find-restaurants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"find-restaurants.d.ts","sourceRoot":"","sources":["../../src/tools/find-restaurants.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;kBA4B1B,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { defineTool } from '@opentabs-dev/plugin-sdk';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { api } from '../panda-api.js';
|
|
4
|
+
import { mapRestaurant, restaurantSchema } from './schemas.js';
|
|
5
|
+
export const findRestaurants = defineTool({
|
|
6
|
+
name: 'find_restaurants',
|
|
7
|
+
displayName: 'Find Restaurants',
|
|
8
|
+
description: 'Search for nearby Panda Express restaurants by geographic coordinates. Returns restaurants sorted by distance with availability, delivery, and pickup status.',
|
|
9
|
+
summary: 'Find nearby Panda Express locations',
|
|
10
|
+
icon: 'map-pin',
|
|
11
|
+
group: 'Restaurants',
|
|
12
|
+
input: z.object({
|
|
13
|
+
latitude: z.number().describe('Latitude coordinate of the search center'),
|
|
14
|
+
longitude: z.number().describe('Longitude coordinate of the search center'),
|
|
15
|
+
radius: z.number().optional().describe('Search radius in miles (default 10)'),
|
|
16
|
+
limit: z.number().int().optional().describe('Maximum number of results (default 10)'),
|
|
17
|
+
}),
|
|
18
|
+
output: z.object({
|
|
19
|
+
restaurants: z.array(restaurantSchema).describe('List of nearby restaurants'),
|
|
20
|
+
}),
|
|
21
|
+
handle: async (params) => {
|
|
22
|
+
const data = await api('/restaurants/near', {
|
|
23
|
+
query: {
|
|
24
|
+
lat: params.latitude,
|
|
25
|
+
long: params.longitude,
|
|
26
|
+
radius: params.radius ?? 10,
|
|
27
|
+
limit: params.limit ?? 10,
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
return { restaurants: (data.restaurants ?? []).map(mapRestaurant) };
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
//# sourceMappingURL=find-restaurants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"find-restaurants.js","sourceRoot":"","sources":["../../src/tools/find-restaurants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AACtC,OAAO,EAAsB,aAAa,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEnF,MAAM,CAAC,MAAM,eAAe,GAAG,UAAU,CAAC;IACxC,IAAI,EAAE,kBAAkB;IACxB,WAAW,EAAE,kBAAkB;IAC/B,WAAW,EACT,+JAA+J;IACjK,OAAO,EAAE,qCAAqC;IAC9C,IAAI,EAAE,SAAS;IACf,KAAK,EAAE,aAAa;IACpB,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,0CAA0C,CAAC;QACzE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2CAA2C,CAAC;QAC3E,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,qCAAqC,CAAC;QAC7E,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,wCAAwC,CAAC;KACtF,CAAC;IACF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,QAAQ,CAAC,4BAA4B,CAAC;KAC9E,CAAC;IACF,MAAM,EAAE,KAAK,EAAC,MAAM,EAAC,EAAE;QACrB,MAAM,IAAI,GAAG,MAAM,GAAG,CAAoC,mBAAmB,EAAE;YAC7E,KAAK,EAAE;gBACL,GAAG,EAAE,MAAM,CAAC,QAAQ;gBACpB,IAAI,EAAE,MAAM,CAAC,SAAS;gBACtB,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE;gBAC3B,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,EAAE;aAC1B;SACF,CAAC,CAAC;QACH,OAAO,EAAE,WAAW,EAAE,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC;IACtE,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const getBasket: import("@opentabs-dev/plugin-sdk").ToolDefinition<z.ZodObject<{
|
|
3
|
+
basket_id: z.ZodString;
|
|
4
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
5
|
+
basket: z.ZodObject<{
|
|
6
|
+
id: z.ZodString;
|
|
7
|
+
vendor_id: z.ZodNumber;
|
|
8
|
+
subtotal: z.ZodNumber;
|
|
9
|
+
sales_tax: z.ZodNumber;
|
|
10
|
+
total: z.ZodNumber;
|
|
11
|
+
product_count: z.ZodNumber;
|
|
12
|
+
delivery_mode: z.ZodString;
|
|
13
|
+
earliest_ready_time: z.ZodString;
|
|
14
|
+
lead_time_minutes: z.ZodNumber;
|
|
15
|
+
coupon_discount: z.ZodNumber;
|
|
16
|
+
}, z.core.$strip>;
|
|
17
|
+
products: z.ZodArray<z.ZodObject<{
|
|
18
|
+
id: z.ZodNumber;
|
|
19
|
+
product_id: z.ZodNumber;
|
|
20
|
+
name: z.ZodString;
|
|
21
|
+
quantity: z.ZodNumber;
|
|
22
|
+
total_cost: z.ZodNumber;
|
|
23
|
+
}, z.core.$strip>>;
|
|
24
|
+
}, z.core.$strip>>;
|
|
25
|
+
//# sourceMappingURL=get-basket.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-basket.d.ts","sourceRoot":"","sources":["../../src/tools/get-basket.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAWxB,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;kBAqBpB,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { defineTool } from '@opentabs-dev/plugin-sdk';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { api } from '../panda-api.js';
|
|
4
|
+
import { basketProductSchema, basketSchema, mapBasket, mapBasketProduct, } from './schemas.js';
|
|
5
|
+
export const getBasket = defineTool({
|
|
6
|
+
name: 'get_basket',
|
|
7
|
+
displayName: 'Get Basket',
|
|
8
|
+
description: 'Get the current contents and totals of an order basket including all products, quantities, and prices.',
|
|
9
|
+
summary: 'View basket contents and totals',
|
|
10
|
+
icon: 'shopping-bag',
|
|
11
|
+
group: 'Orders',
|
|
12
|
+
input: z.object({
|
|
13
|
+
basket_id: z.string().describe('Basket ID (UUID from create_basket)'),
|
|
14
|
+
}),
|
|
15
|
+
output: z.object({
|
|
16
|
+
basket: basketSchema.describe('Basket summary'),
|
|
17
|
+
products: z.array(basketProductSchema).describe('Products in the basket'),
|
|
18
|
+
}),
|
|
19
|
+
handle: async (params) => {
|
|
20
|
+
const data = await api(`/baskets/${params.basket_id}`);
|
|
21
|
+
return {
|
|
22
|
+
basket: mapBasket(data),
|
|
23
|
+
products: (data.products ?? []).map(mapBasketProduct),
|
|
24
|
+
};
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
//# sourceMappingURL=get-basket.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-basket.js","sourceRoot":"","sources":["../../src/tools/get-basket.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AACtC,OAAO,EAGL,mBAAmB,EACnB,YAAY,EACZ,SAAS,EACT,gBAAgB,GACjB,MAAM,cAAc,CAAC;AAEtB,MAAM,CAAC,MAAM,SAAS,GAAG,UAAU,CAAC;IAClC,IAAI,EAAE,YAAY;IAClB,WAAW,EAAE,YAAY;IACzB,WAAW,EAAE,wGAAwG;IACrH,OAAO,EAAE,iCAAiC;IAC1C,IAAI,EAAE,cAAc;IACpB,KAAK,EAAE,QAAQ;IACf,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,qCAAqC,CAAC;KACtE,CAAC;IACF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,MAAM,EAAE,YAAY,CAAC,QAAQ,CAAC,gBAAgB,CAAC;QAC/C,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC,QAAQ,CAAC,wBAAwB,CAAC;KAC1E,CAAC;IACF,MAAM,EAAE,KAAK,EAAC,MAAM,EAAC,EAAE;QACrB,MAAM,IAAI,GAAG,MAAM,GAAG,CAAgD,YAAY,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;QACtG,OAAO;YACL,MAAM,EAAE,SAAS,CAAC,IAAI,CAAC;YACvB,QAAQ,EAAE,CAAC,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,gBAAgB,CAAC;SACtD,CAAC;IACJ,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const getBillingAccounts: import("@opentabs-dev/plugin-sdk").ToolDefinition<z.ZodObject<{}, z.core.$strip>, z.ZodObject<{
|
|
3
|
+
accounts: z.ZodArray<z.ZodObject<{
|
|
4
|
+
id: z.ZodNumber;
|
|
5
|
+
card_type: z.ZodString;
|
|
6
|
+
card_suffix: z.ZodString;
|
|
7
|
+
expiration: z.ZodString;
|
|
8
|
+
is_default: z.ZodBoolean;
|
|
9
|
+
}, z.core.$strip>>;
|
|
10
|
+
}, z.core.$strip>>;
|
|
11
|
+
//# sourceMappingURL=get-billing-accounts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-billing-accounts.d.ts","sourceRoot":"","sources":["../../src/tools/get-billing-accounts.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA2BxB,eAAO,MAAM,kBAAkB;;;;;;;;kBAiB7B,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { defineTool } from '@opentabs-dev/plugin-sdk';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { api, getRequiredAuthToken } from '../panda-api.js';
|
|
4
|
+
const billingAccountSchema = z.object({
|
|
5
|
+
id: z.number().describe('Billing account ID'),
|
|
6
|
+
card_type: z.string().describe('Card type (e.g., "Visa", "Mastercard")'),
|
|
7
|
+
card_suffix: z.string().describe('Last 4 digits of the card number'),
|
|
8
|
+
expiration: z.string().describe('Card expiration date (MM/YY)'),
|
|
9
|
+
is_default: z.boolean().describe('Whether this is the default payment method'),
|
|
10
|
+
});
|
|
11
|
+
const mapBillingAccount = (a) => ({
|
|
12
|
+
id: a.accountid ?? 0,
|
|
13
|
+
card_type: a.cardtype ?? '',
|
|
14
|
+
card_suffix: a.cardsuffix ?? '',
|
|
15
|
+
expiration: a.expiration ?? '',
|
|
16
|
+
is_default: a.isdefault ?? false,
|
|
17
|
+
});
|
|
18
|
+
export const getBillingAccounts = defineTool({
|
|
19
|
+
name: 'get_billing_accounts',
|
|
20
|
+
displayName: 'Get Billing Accounts',
|
|
21
|
+
description: "Get the authenticated user's saved payment methods. Returns card type, last 4 digits, and default status.",
|
|
22
|
+
summary: 'View your saved payment methods',
|
|
23
|
+
icon: 'credit-card',
|
|
24
|
+
group: 'Account',
|
|
25
|
+
input: z.object({}),
|
|
26
|
+
output: z.object({
|
|
27
|
+
accounts: z.array(billingAccountSchema).describe('Saved billing accounts'),
|
|
28
|
+
}),
|
|
29
|
+
handle: async () => {
|
|
30
|
+
const authtoken = getRequiredAuthToken();
|
|
31
|
+
const data = await api(`/users/${authtoken}/billingaccounts`);
|
|
32
|
+
return { accounts: (data.billingaccounts ?? []).map(mapBillingAccount) };
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
//# sourceMappingURL=get-billing-accounts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-billing-accounts.js","sourceRoot":"","sources":["../../src/tools/get-billing-accounts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,GAAG,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAE5D,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,oBAAoB,CAAC;IAC7C,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,wCAAwC,CAAC;IACxE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,kCAAkC,CAAC;IACpE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,8BAA8B,CAAC;IAC/D,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,4CAA4C,CAAC;CAC/E,CAAC,CAAC;AAUH,MAAM,iBAAiB,GAAG,CAAC,CAAoB,EAAE,EAAE,CAAC,CAAC;IACnD,EAAE,EAAE,CAAC,CAAC,SAAS,IAAI,CAAC;IACpB,SAAS,EAAE,CAAC,CAAC,QAAQ,IAAI,EAAE;IAC3B,WAAW,EAAE,CAAC,CAAC,UAAU,IAAI,EAAE;IAC/B,UAAU,EAAE,CAAC,CAAC,UAAU,IAAI,EAAE;IAC9B,UAAU,EAAE,CAAC,CAAC,SAAS,IAAI,KAAK;CACjC,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,kBAAkB,GAAG,UAAU,CAAC;IAC3C,IAAI,EAAE,sBAAsB;IAC5B,WAAW,EAAE,sBAAsB;IACnC,WAAW,EACT,2GAA2G;IAC7G,OAAO,EAAE,iCAAiC;IAC1C,IAAI,EAAE,aAAa;IACnB,KAAK,EAAE,SAAS;IAChB,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;IACnB,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC,QAAQ,CAAC,wBAAwB,CAAC;KAC3E,CAAC;IACF,MAAM,EAAE,KAAK,IAAI,EAAE;QACjB,MAAM,SAAS,GAAG,oBAAoB,EAAE,CAAC;QACzC,MAAM,IAAI,GAAG,MAAM,GAAG,CAA4C,UAAU,SAAS,kBAAkB,CAAC,CAAC;QACzG,OAAO,EAAE,QAAQ,EAAE,CAAC,IAAI,CAAC,eAAe,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,iBAAiB,CAAC,EAAE,CAAC;IAC3E,CAAC;CACF,CAAC,CAAC"}
|