From 4dcfc21f872cc540f1c94264408bcd7bbca9e328 Mon Sep 17 00:00:00 2001 From: Derrick Chen Date: Wed, 10 Sep 2025 00:09:52 -0400 Subject: [PATCH 1/4] take two ts --- src/server/auth/custom-providers/etsy.ts | 3 +- src/toolkits/toolkits/etsy/base.ts | 3 + src/toolkits/toolkits/etsy/client.tsx | 8 +- src/toolkits/toolkits/etsy/server.ts | 13 +- .../etsy/tools/create-draft-listing/base.ts | 299 ++++++++++++++++++ .../tools/create-draft-listing/client.tsx | 21 ++ .../etsy/tools/create-draft-listing/server.ts | 122 +++++++ .../toolkits/etsy/tools/get-listings/base.ts | 53 +++- .../etsy/tools/get-listings/server.ts | 24 +- src/toolkits/toolkits/etsy/tools/tools.ts | 1 + 10 files changed, 528 insertions(+), 19 deletions(-) create mode 100644 src/toolkits/toolkits/etsy/tools/create-draft-listing/base.ts create mode 100644 src/toolkits/toolkits/etsy/tools/create-draft-listing/client.tsx create mode 100644 src/toolkits/toolkits/etsy/tools/create-draft-listing/server.ts diff --git a/src/server/auth/custom-providers/etsy.ts b/src/server/auth/custom-providers/etsy.ts index 2358607b..20e3e3e2 100644 --- a/src/server/auth/custom-providers/etsy.ts +++ b/src/server/auth/custom-providers/etsy.ts @@ -10,7 +10,8 @@ export interface EtsyProfile { image_url_75x75?: string | null; } -export const etsyScopes = "email_r shops_r listings_r"; +export const etsyScopes = + "address_r address_w billing_r cart_r cart_w email_r favorites_r favorites_w feedback_r listings_d listings_r listings_w profile_r profile_w recommend_r recommend_w shops_r shops_w transactions_r transactions_w"; export default function EtsyProvider

( options: OAuthUserConfig

, diff --git a/src/toolkits/toolkits/etsy/base.ts b/src/toolkits/toolkits/etsy/base.ts index d585bf7d..31ee13ac 100644 --- a/src/toolkits/toolkits/etsy/base.ts +++ b/src/toolkits/toolkits/etsy/base.ts @@ -4,6 +4,8 @@ import { EtsyTools } from "./tools/tools"; import { getListings } from "@/toolkits/toolkits/etsy/tools/get-listings/base"; +import { createDraftListing } from "@/toolkits/toolkits/etsy/tools/create-draft-listing/base"; + import type { ToolkitConfig } from "@/toolkits/types"; export const etsyParameters = z.object({}); @@ -14,6 +16,7 @@ export const baseEtsyToolkitConfig: ToolkitConfig< > = { tools: { [EtsyTools.getListings]: getListings, + [EtsyTools.createDraftListing]: createDraftListing, }, parameters: etsyParameters, }; diff --git a/src/toolkits/toolkits/etsy/client.tsx b/src/toolkits/toolkits/etsy/client.tsx index dc79b09b..3cd041dc 100644 --- a/src/toolkits/toolkits/etsy/client.tsx +++ b/src/toolkits/toolkits/etsy/client.tsx @@ -10,6 +10,8 @@ import { createClientToolkit } from "@/toolkits/create-toolkit"; import { getListingsClientConfig } from "@/toolkits/toolkits/etsy/tools/get-listings/client"; +import { createDraftListingClientConfig } from "@/toolkits/toolkits/etsy/tools/create-draft-listing/client"; + import { ToolkitGroups } from "@/toolkits/types"; import { EtsyTools } from "./tools/tools"; @@ -17,7 +19,8 @@ export const etsyClientToolkit = createClientToolkit( baseEtsyToolkitConfig, { name: "Etsy Toolkit", - description: "Etsy toolkit for fetching listing details.", + description: + "Etsy toolkit for Listing management, Payment management, Receipt management, Shipping management, Shop management and more!", icon: SiEtsy, form: null, type: ToolkitGroups.DataSource, @@ -37,5 +40,6 @@ export const etsyClientToolkit = createClientToolkit( }, { [EtsyTools.getListings]: getListingsClientConfig, + [EtsyTools.createDraftListing]: createDraftListingClientConfig, }, -); +); \ No newline at end of file diff --git a/src/toolkits/toolkits/etsy/server.ts b/src/toolkits/toolkits/etsy/server.ts index a2cc94f5..285632d5 100644 --- a/src/toolkits/toolkits/etsy/server.ts +++ b/src/toolkits/toolkits/etsy/server.ts @@ -10,11 +10,13 @@ import { EtsyTools } from "./tools/tools"; import { EtsySecurityDataStorage } from "./security-data-storage"; import { getListingsServerConfig } from "@/toolkits/toolkits/etsy/tools/get-listings/server"; +import { createDraftListingServerConfig } from "@/toolkits/toolkits/etsy/tools/create-draft-listing/server"; export const etsyToolkitServer = createServerToolkit( baseEtsyToolkitConfig, "You have access to the Etsy toolkit for general account management. Currently, this toolkit provides:\n" + - "- **Get Listings**: Retrieves all listings and their image URLs associated with the shop associated with the signed-in user.\n\n", + "- **Get Listings By Shop**: Retrieves listings associated with the shop owned by authenticated user. Has the ability to fetch associations relating to each listing as well.\n" + + "- **Create Draft Listing**: Creates a new draft listing in the shop owned by authenticated user. Accepts a variety of inputs to assign to listing.\n", async () => { const account = await api.accounts.getAccountByProvider("etsy"); @@ -32,7 +34,14 @@ export const etsyToolkitServer = createServerToolkit( }); return { - [EtsyTools.getListings]: getListingsServerConfig(etsy), + [EtsyTools.getListings]: getListingsServerConfig( + etsy, + account.providerAccountId, + ), + [EtsyTools.createDraftListing]: createDraftListingServerConfig( + etsy, + account.providerAccountId, + ), }; }, ); diff --git a/src/toolkits/toolkits/etsy/tools/create-draft-listing/base.ts b/src/toolkits/toolkits/etsy/tools/create-draft-listing/base.ts new file mode 100644 index 00000000..317a70f3 --- /dev/null +++ b/src/toolkits/toolkits/etsy/tools/create-draft-listing/base.ts @@ -0,0 +1,299 @@ +import { z } from "zod"; +import { createBaseTool } from "@/toolkits/create-tool"; +import type { IShopListing } from "etsy-ts"; + +export const createDraftListing = createBaseTool({ + description: + "Creates a new draft listing in the Etsy shop associated with the authenticated user." + + "Requires input: quantity, title, description, price, who_made, when_made, is_supply, and taxonomy_id." + + "Optional inputs include: (if not specified, the default value is null" + + "shipping_profile_id — ID of the shipping profile to associate with the listing. REQUIRED if listing type is physical." + + "return_policy_id - the numeric ID of the Return Policy." + + "materials - A list of material strings for materials used in the product. Valid materials strings contain only letters, numbers, and whitespace characters. (regex: /[^\\p{L}\\p{Nd}\\p{Zs}]/u)." + + "shop_section_id - The numeric ID of the shop section for this listing." + + "processing_min - The minimum number of days it takes to produce the item." + + "processing_max - The maximum number of days it takes to produce the item." + + "readiness_state_id - The numeric ID of the processing profile associated with the listing. Required when type is physical." + + "tags - A comma-separated list of tag strings for the listing. When creating or updating a listing, valid tag strings contain only letters, numbers, whitespace characters, -, ', ™, ©, and ®. (regex: /[^\\p{L}\\p{Nd}\\p{Zs}-'™©®]/u)." + + 'styles - An array of style strings for this listing, each of which is free-form text string such as "Formal", or "Steampunk". When creating or updating a listing, the listing may have up to two styles. Valid style strings contain only letters, numbers, and whitespace characters. (regex: /[^\\p{L}\\p{Nd}\\p{Zs}]/u).' + + "item_weight - The numeric weight of the product measured in units set in 'item_weight_unit'. If set, the values must be greater than 0." + + "item_length - The numeric length of the product measured in units set in 'item_dimensions_unit'. If set, the values must be greater than 0." + + "item_width - The numeric width of the product measured in units set in 'item_dimensions_unit'. If set, the values must be greater than 0." + + "item_height - The numeric height of the product measured in units set in 'item_dimensions_unit'. If set, the values must be greater than 0." + + "item_weight_unit - The unit of measurement for the weight of the product. Valid values are 'g' (grams), 'kg' (kilograms), 'oz' (ounces), and 'lb' (pounds). Required if 'item_weight' is provided." + + "item_dimensions_unit - The unit of measurement for the dimensions of the product. Valid values are 'mm' (millimeters), 'cm' (centimeters), 'm' (meters), 'in' (inches), and 'ft' (feet). Required if any of 'item_length', 'item_width', or 'item_height' is provided." + + "is_personalizable - When ture, indicates that the listing is personalizable." + + "personalization_is_required - When true, indicates that personalization is required for the listing. Will only change if _is_personalizable is true" + + "personalization_char_count_max - The maximum number of characters allowed for personalization. Will only change if _is_personalizable is true." + + "personalization_instructions - Instructions for personalization. Will only change if _is_personalizable is true." + + "production_partner_ids - An array of unique IDs of production partner ids." + + "image_ids - An array of numeric image IDs of the images in a listing, which can include up to 10 images." + + "is_customizable - When true, a buyer may contact the seller for a customized order. The default value is true when a shop accepts custom orders. Does not apply to shops that do not accept custom orders." + + "should_auto_renew - When true, renews a listing for four months upon expiration." + + "is_taxable - When true, applicable shop tax rates apply to this listing at checkout" + + "type - An enumerated type string that indicates whether the listing is physical or a digital download or both.", + inputSchema: z.object({ + title: z + .string() + .min(1) + .max(140) + .describe( + "The title of the listing. Can only contain letters, numbers, punctuation marks, mathematical symbols, whitespace characters", + ), + description: z + .string() + .min(1) + .max(1000) + .describe("The description of the listing."), + price: z + .number() + .positive() + .describe( + "The price of the item. Must be a positive value with up to two decimal places.", + ), + quantity: z + .number() + .min(1) + .describe( + "The quantity of items available in this listing. Must be at least 1.", + ), + who_made: z + .enum(["i_did", "collective", "someone_else"]) + .describe("Who made the item."), + when_made: z + .enum([ + "made_to_order", + "2020_2023", + "2010_2019", + "2006_2009", + "before_2006", + "2000_2005", + "1990s", + "1980s", + "1970s", + "1960s", + "1950s", + "1940s", + "1930s", + "1920s", + "1910s", + "1900s", + "1800s", + "1700s", + "before_1700", + ]) + .describe( + "An enumerated string for the era in which the maker made the product in this listing. Helps buyers locate the listing under the Vintage heading.", + ), + taxonomy_id: z + .number() + .int() + .positive() + .describe("The taxonomy ID for the category of the listing."), + is_supply: z + .boolean() + .describe( + "When true, tags the listing as a supply product, else indicates that it's a finished product.", + ), + shipping_profile_id: z + .number() + .int() + .positive() + .optional() + .describe( + "ID of the shipping profile to associate with the listing. REQUIRED if listing type is physical.", + ), + return_policy_id: z + .number() + .int() + .positive() + .optional() + .describe("The numeric ID of the Return Policy."), + materials: z + .array( + z + .string() + .regex(/[^\p{L}\p{Nd}\p{Zs}]/u, { + message: + "Valid materials strings contain only letters, numbers, and whitespace characters.", + }) + .min(1) + .max(25) + .describe( + "A material string for materials used in the product. Valid materials strings contain only letters, numbers, and whitespace characters.", + ), + ) + .max(25), + shop_section_id: z + .number() + .int() + .positive() + .optional() + .describe("The numeric ID of the shop section for this listing."), + processing_min: z + .number() + .int() + .min(0) + .optional() + .describe("The minimum number of days it takes to produce the item."), + processing_max: z + .number() + .int() + .min(0) + .optional() + .describe("The maximum number of days it takes to produce the item."), + readiness_state_id: z + .number() + .int() + .positive() + .optional() + .describe( + "The numeric ID of the processing profile associated with the listing. Required when type is physical.", + ), + tags: z + .array( + z + .string() + .regex(/^[\p{L}\p{Nd}\p{Zs}'™©®-]+$/u, { + message: + "Valid tag strings contain only letters, numbers, whitespace characters, -, ', ™, ©, and ®.", + }) + .min(1) + .max(25) + .describe( + "A tag string for the listing. When creating or updating a listing, valid tag strings contain only letters, numbers, whitespace characters, -, ', ™, ©, and ®.", + ), + ) + .max(13) + .describe("A list of tag strings for the listing."), + styles: z + .array( + z + .string() + .regex(/[^\p{L}\p{Nd}\p{Zs}]/u, { + message: + "Valid style strings contain only letters, numbers, and whitespace characters.", + }) + .min(1) + .max(25) + .describe( + 'A style string for this listing, such as "Formal", or "Steampunk". When creating or updating a listing, the listing may have up to two styles. Valid style strings contain only letters, numbers, and whitespace characters.', + ), + ) + .max(2) + .describe("An array of style strings for this listing."), + item_weight: z + .number() + .positive() + .optional() + .describe( + "The numeric weight of the product measured in units set in 'item_weight_unit'. If set, the values must be greater than 0.", + ), + item_length: z + .number() + .positive() + .optional() + .describe( + "The numeric length of the product measured in units set in 'item_dimensions_unit'. If set, the values must be greater than 0.", + ), + item_width: z + .number() + .positive() + .optional() + .describe( + "The numeric width of the product measured in units set in 'item_dimensions_unit'. If set, the values must be greater than 0.", + ), + item_height: z + .number() + .positive() + .optional() + .describe( + "The numeric height of the product measured in units set in 'item_dimensions_unit'. If set, the values must be greater than 0.", + ), + item_weight_unit: z + .enum(["g", "kg", "oz", "lb"]) + .optional() + .describe( + "The unit of measurement for the weight of the product. Valid values are 'g' (grams), 'kg' (kilograms), 'oz' (ounces), and 'lb' (pounds). Required if 'item_weight' is provided.", + ), + item_dimensions_unit: z + .enum(["mm", "cm", "m", "in", "ft"]) + .optional() + .describe( + "The unit of measurement for the dimensions of the product. Valid values are 'mm' (millimeters), 'cm' (centimeters), 'm' (meters), 'in' (inches), and 'ft' (feet). Required if any of 'item_length', 'item_width', or 'item_height' is provided.", + ), + is_personalizable: z + .boolean() + .optional() + .describe("When true, indicates that the listing is personalizable."), + personalization_is_required: z + .boolean() + .optional() + .describe( + "When true, indicates that personalization is required for the listing. Will only change if _is_personalizable is true", + ), + personalization_char_count_max: z + .number() + .int() + .min(1) + .max(250) + .optional() + .describe( + "The maximum number of characters allowed for personalization. Will only change if _is_personalizable is true.", + ), + personalization_instructions: z + .string() + .max(500) + .optional() + .describe( + "Instructions for personalization. Will only change if _is_personalizable is true.", + ), + production_partner_ids: z + .array( + z + .number() + .int() + .positive() + .describe("A unique ID of a production partner."), + ) + .optional() + .describe("An array of unique IDs of production partner ids."), + image_ids: z + .array( + z + .number() + .int() + .positive() + .describe("A numeric image ID of an image in a listing."), + ) + .max(10) + .optional() + .describe( + "An array of numeric image IDs of the images in a listing, which can include up to 10 images.", + ), + is_customizable: z + .boolean() + .optional() + .describe( + "When true, a buyer may contact the seller for a customized order. The default value is true when a shop accepts custom orders. Does not apply to shops that do not accept custom orders.", + ), + should_auto_renew: z + .boolean() + .optional() + .describe("When true, renews a listing for four months upon expiration."), + is_taxable: z + .boolean() + .optional() + .describe( + "When true, applicable shop tax rates apply to this listing at checkout", + ), + type: z + .enum(["physical", "download", "both"]) + .describe( + "An enumerated type string that indicates whether the listing is physical or a digital download or both.", + ), + }), + outputSchema: z.object({ + result: z.custom(), + }), +}); \ No newline at end of file diff --git a/src/toolkits/toolkits/etsy/tools/create-draft-listing/client.tsx b/src/toolkits/toolkits/etsy/tools/create-draft-listing/client.tsx new file mode 100644 index 00000000..99ea9134 --- /dev/null +++ b/src/toolkits/toolkits/etsy/tools/create-draft-listing/client.tsx @@ -0,0 +1,21 @@ +import { Search } from "lucide-react"; +import type { ClientToolConfig } from "@/toolkits/types"; +import type { createDraftListing } from "./base"; + +export const createDraftListingClientConfig: ClientToolConfig< + typeof createDraftListing.inputSchema.shape, + typeof createDraftListing.outputSchema.shape +> = { + CallComponent: ({ isPartial }) => ( +

+ + {isPartial && ...} +
+ ), + ResultComponent: ({ result: { result } }) => ( +
+

Listing

+
{result.title}
) +
+ ), +}; \ No newline at end of file diff --git a/src/toolkits/toolkits/etsy/tools/create-draft-listing/server.ts b/src/toolkits/toolkits/etsy/tools/create-draft-listing/server.ts new file mode 100644 index 00000000..6b82403c --- /dev/null +++ b/src/toolkits/toolkits/etsy/tools/create-draft-listing/server.ts @@ -0,0 +1,122 @@ +import type { Etsy, ICreateDraftListingPayload } from "etsy-ts"; + +import type { ServerToolConfig } from "@/toolkits/types"; +import type { createDraftListing } from "./base"; + +export const createDraftListingServerConfig = ( + etsy: Etsy, + userId: string, +): ServerToolConfig< + typeof createDraftListing.inputSchema.shape, + typeof createDraftListing.outputSchema.shape +> => { + return { + callback: async ({ + title, + description, + price, + quantity, + who_made, + is_supply, + when_made, + taxonomy_id, + shipping_profile_id, + shop_section_id, + materials, + return_policy_id, + processing_min, + processing_max, + readiness_state_id, + tags, + styles, + item_weight, + item_weight_unit, + item_length, + item_width, + item_height, + item_dimensions_unit, + is_personalizable, + personalization_is_required, + personalization_char_count_max, + personalization_instructions, + production_partner_ids, + image_ids, + is_customizable, + should_auto_renew, + is_taxable, + type, + }) => { + try { + const shop = await etsy.Shop.getShopByOwnerUserId(Number(userId)); + + const shopId = shop.data.shop_id; + + if (!shopId) throw new Error("Missing Etsy shop ID"); + + const params: ICreateDraftListingPayload = { + title, + description, + price, + quantity, + who_made, + is_supply, + when_made, + taxonomy_id, + materials, + type, + styles, + ...(shipping_profile_id !== undefined ? { shipping_profile_id } : {}), + ...(shop_section_id !== undefined ? { shop_section_id } : {}), + ...(return_policy_id !== undefined ? { return_policy_id } : {}), + ...(processing_min !== undefined ? { processing_min } : {}), + ...(processing_max !== undefined ? { processing_max } : {}), + ...(readiness_state_id !== undefined ? { readiness_state_id } : {}), + ...(item_weight !== undefined ? { item_weight } : {}), + ...(item_weight_unit !== undefined ? { item_weight_unit } : {}), + ...(item_length !== undefined ? { item_length } : {}), + ...(item_width !== undefined ? { item_width } : {}), + ...(item_height !== undefined ? { item_height } : {}), + ...(item_dimensions_unit !== undefined + ? { item_dimensions_unit } + : {}), + ...(is_personalizable !== undefined ? { is_personalizable } : {}), + ...(personalization_is_required !== undefined + ? { personalization_is_required } + : {}), + ...(personalization_char_count_max !== undefined + ? { personalization_char_count_max } + : {}), + ...(personalization_instructions !== undefined + ? { personalization_instructions } + : {}), + ...(production_partner_ids !== undefined + ? { production_partner_ids } + : {}), + ...(image_ids !== undefined ? { image_ids } : {}), + ...(is_customizable !== undefined ? { is_customizable } : {}), + ...(should_auto_renew !== undefined ? { should_auto_renew } : {}), + ...(is_taxable !== undefined ? { is_taxable } : {}), + ...(type !== undefined ? { type } : {}), + }; + + const listing = await etsy.ShopListing.createDraftListing( + shopId, + params, + undefined, + ); + + if (!listing.data) throw new Error("Missing Etsy listing"); + + return { + result: listing.data, + }; + } catch (error) { + console.error("Etsy API error:", error); + throw new Error("Failed to create draft listing on Etsy"); + } + }, + message: + "Successfully created the Etsy draft listing. The user is shown the responses in the UI. Do not reiterate them. " + + "If you called this tool because the user asked a question, answer the question.", + }; +}; \ No newline at end of file diff --git a/src/toolkits/toolkits/etsy/tools/get-listings/base.ts b/src/toolkits/toolkits/etsy/tools/get-listings/base.ts index 74dc6515..b7ee1ec8 100644 --- a/src/toolkits/toolkits/etsy/tools/get-listings/base.ts +++ b/src/toolkits/toolkits/etsy/tools/get-listings/base.ts @@ -4,9 +4,56 @@ import type { IShopListing } from "etsy-ts"; export const getListings = createBaseTool({ description: - "Fetches all listings from the Etsy shop associated with the authenticated user.", - inputSchema: z.object({}), + "Fetches all listings from the Etsy shop associated with the authenticated user." + + "No additional input is required. But there are optional ones:" + + "limit — page size (default 25; max 100)" + + "offset — number of results to skip (use for pagination)" + + "sort_on — field to sort by (e.g., created, updated, price, score). Note: some sorts only work when combined with a search option; score is always descending regardless of sort_order." + + "sort_order — up (ascending) or down (descending), when supported by the chosen sort_on." + + "includes - An enumerated string that attaches a valid association. Acceptable inputs are 'Shipping', 'Shop', 'Images', 'User', 'Translations' and 'Inventory'.", + inputSchema: z.object({ + limit: z + .number() + .min(1) + .max(100) + .optional() + .describe( + "Maximum number of items to return. Default: 25. Min: 1. Max: 100", + ), + sort_on: z + .enum(["created", "updated", "price", "score"]) + .optional() + .describe( + "Field to sort by (e.g., created, updated, price, score). Note: some sorts only work when combined with a search option; score is always descending regardless of sort_order. Default: created", + ), + sort_order: z + .enum(["asc", "desc", "up", "down"]) + .optional() + .describe( + "Sort order: up (ascending) or down (descending). Default: desc", + ), + offset: z + .number() + .min(0) + .optional() + .describe("Number of results to skip (use for pagination). Default: 0"), + includes: z + .enum([ + "Shipping", + "Images", + "Shop", + "User", + "Translations", + "Inventory", + "Videos", + ]) + .array() + .optional() + .describe( + "An enumerated string that attaches a valid association. Acceptable inputs are 'Shipping', 'Shop', 'Images', 'User', 'Translations' and 'Inventory'.", + ), + }), outputSchema: z.object({ results: z.array(z.custom()), }), -}); +}); \ No newline at end of file diff --git a/src/toolkits/toolkits/etsy/tools/get-listings/server.ts b/src/toolkits/toolkits/etsy/tools/get-listings/server.ts index f6e11259..77c66250 100644 --- a/src/toolkits/toolkits/etsy/tools/get-listings/server.ts +++ b/src/toolkits/toolkits/etsy/tools/get-listings/server.ts @@ -1,32 +1,34 @@ -import type { Etsy } from "etsy-ts"; +import type { Etsy, IGetListingsByShopParams } from "etsy-ts"; import type { ServerToolConfig } from "@/toolkits/types"; import type { getListings } from "./base"; export const getListingsServerConfig = ( etsy: Etsy, + userId: string, ): ServerToolConfig< typeof getListings.inputSchema.shape, typeof getListings.outputSchema.shape > => { return { - callback: async () => { + callback: async ({ limit, offset, sort_on, sort_order, includes }) => { try { - const user = await etsy.User.getMe(); - - const userId = user.data.user_id; - - if (!userId) throw new Error("Missing Etsy user ID"); - - const shop = await etsy.Shop.getShopByOwnerUserId(userId); + const shop = await etsy.Shop.getShopByOwnerUserId(Number(userId)); const shopId = shop.data.shop_id; if (!shopId) throw new Error("Missing Etsy shop ID"); - const listings = await etsy.ShopListing.getFeaturedListingsByShop({ + const params: IGetListingsByShopParams = { shopId, - }); + ...(limit !== undefined ? { limit } : {}), + ...(offset !== undefined ? { offset } : {}), + ...(sort_on !== undefined ? { sort_on } : {}), + ...(sort_order !== undefined ? { sort_order } : {}), + ...(includes !== undefined ? { includes } : {}), + }; + + const listings = await etsy.ShopListing.getListingsByShop(params); if (!listings.data.results) throw new Error("Missing Etsy listings"); diff --git a/src/toolkits/toolkits/etsy/tools/tools.ts b/src/toolkits/toolkits/etsy/tools/tools.ts index 8af37ff8..f8724452 100644 --- a/src/toolkits/toolkits/etsy/tools/tools.ts +++ b/src/toolkits/toolkits/etsy/tools/tools.ts @@ -1,3 +1,4 @@ export enum EtsyTools { getListings = "get-listings", + createDraftListing = "create-draft-listing", } From 7ba87f21b4532e22036f1f3dbf9212b88232f1b3 Mon Sep 17 00:00:00 2001 From: Derrick Chen Date: Wed, 10 Sep 2025 00:12:51 -0400 Subject: [PATCH 2/4] prettier --- src/toolkits/toolkits/etsy/client.tsx | 2 +- src/toolkits/toolkits/etsy/server.ts | 4 +- .../etsy/tools/create-draft-listing/base.ts | 2 +- .../tools/create-draft-listing/client.tsx | 2 +- .../etsy/tools/create-draft-listing/server.ts | 70 +++++++++---------- .../toolkits/etsy/tools/get-listings/base.ts | 2 +- 6 files changed, 41 insertions(+), 41 deletions(-) diff --git a/src/toolkits/toolkits/etsy/client.tsx b/src/toolkits/toolkits/etsy/client.tsx index 3cd041dc..1274e57f 100644 --- a/src/toolkits/toolkits/etsy/client.tsx +++ b/src/toolkits/toolkits/etsy/client.tsx @@ -42,4 +42,4 @@ export const etsyClientToolkit = createClientToolkit( [EtsyTools.getListings]: getListingsClientConfig, [EtsyTools.createDraftListing]: createDraftListingClientConfig, }, -); \ No newline at end of file +); diff --git a/src/toolkits/toolkits/etsy/server.ts b/src/toolkits/toolkits/etsy/server.ts index 285632d5..9985fc3e 100644 --- a/src/toolkits/toolkits/etsy/server.ts +++ b/src/toolkits/toolkits/etsy/server.ts @@ -15,8 +15,8 @@ import { createDraftListingServerConfig } from "@/toolkits/toolkits/etsy/tools/c export const etsyToolkitServer = createServerToolkit( baseEtsyToolkitConfig, "You have access to the Etsy toolkit for general account management. Currently, this toolkit provides:\n" + - "- **Get Listings By Shop**: Retrieves listings associated with the shop owned by authenticated user. Has the ability to fetch associations relating to each listing as well.\n" + - "- **Create Draft Listing**: Creates a new draft listing in the shop owned by authenticated user. Accepts a variety of inputs to assign to listing.\n", + "- **Get Listings By Shop**: Retrieves listings associated with the shop owned by authenticated user. Has the ability to fetch associations relating to each listing as well.\n" + + "- **Create Draft Listing**: Creates a new draft listing in the shop owned by authenticated user. Accepts a variety of inputs to assign to listing.\n", async () => { const account = await api.accounts.getAccountByProvider("etsy"); diff --git a/src/toolkits/toolkits/etsy/tools/create-draft-listing/base.ts b/src/toolkits/toolkits/etsy/tools/create-draft-listing/base.ts index 317a70f3..82f3790a 100644 --- a/src/toolkits/toolkits/etsy/tools/create-draft-listing/base.ts +++ b/src/toolkits/toolkits/etsy/tools/create-draft-listing/base.ts @@ -296,4 +296,4 @@ export const createDraftListing = createBaseTool({ outputSchema: z.object({ result: z.custom(), }), -}); \ No newline at end of file +}); diff --git a/src/toolkits/toolkits/etsy/tools/create-draft-listing/client.tsx b/src/toolkits/toolkits/etsy/tools/create-draft-listing/client.tsx index 99ea9134..92fe60d4 100644 --- a/src/toolkits/toolkits/etsy/tools/create-draft-listing/client.tsx +++ b/src/toolkits/toolkits/etsy/tools/create-draft-listing/client.tsx @@ -18,4 +18,4 @@ export const createDraftListingClientConfig: ClientToolConfig<
{result.title}
) ), -}; \ No newline at end of file +}; diff --git a/src/toolkits/toolkits/etsy/tools/create-draft-listing/server.ts b/src/toolkits/toolkits/etsy/tools/create-draft-listing/server.ts index 6b82403c..f351962d 100644 --- a/src/toolkits/toolkits/etsy/tools/create-draft-listing/server.ts +++ b/src/toolkits/toolkits/etsy/tools/create-draft-listing/server.ts @@ -12,40 +12,40 @@ export const createDraftListingServerConfig = ( > => { return { callback: async ({ - title, - description, - price, - quantity, - who_made, - is_supply, - when_made, - taxonomy_id, - shipping_profile_id, - shop_section_id, - materials, - return_policy_id, - processing_min, - processing_max, - readiness_state_id, - tags, - styles, - item_weight, - item_weight_unit, - item_length, - item_width, - item_height, - item_dimensions_unit, - is_personalizable, - personalization_is_required, - personalization_char_count_max, - personalization_instructions, - production_partner_ids, - image_ids, - is_customizable, - should_auto_renew, - is_taxable, - type, - }) => { + title, + description, + price, + quantity, + who_made, + is_supply, + when_made, + taxonomy_id, + shipping_profile_id, + shop_section_id, + materials, + return_policy_id, + processing_min, + processing_max, + readiness_state_id, + tags, + styles, + item_weight, + item_weight_unit, + item_length, + item_width, + item_height, + item_dimensions_unit, + is_personalizable, + personalization_is_required, + personalization_char_count_max, + personalization_instructions, + production_partner_ids, + image_ids, + is_customizable, + should_auto_renew, + is_taxable, + type, + }) => { try { const shop = await etsy.Shop.getShopByOwnerUserId(Number(userId)); @@ -119,4 +119,4 @@ export const createDraftListingServerConfig = ( "Successfully created the Etsy draft listing. The user is shown the responses in the UI. Do not reiterate them. " + "If you called this tool because the user asked a question, answer the question.", }; -}; \ No newline at end of file +}; diff --git a/src/toolkits/toolkits/etsy/tools/get-listings/base.ts b/src/toolkits/toolkits/etsy/tools/get-listings/base.ts index b7ee1ec8..b67c9734 100644 --- a/src/toolkits/toolkits/etsy/tools/get-listings/base.ts +++ b/src/toolkits/toolkits/etsy/tools/get-listings/base.ts @@ -56,4 +56,4 @@ export const getListings = createBaseTool({ outputSchema: z.object({ results: z.array(z.custom()), }), -}); \ No newline at end of file +}); From 32698e099f98f86ce534e9af644813322a5d0240 Mon Sep 17 00:00:00 2001 From: Derrick Chen Date: Wed, 10 Sep 2025 00:32:29 -0400 Subject: [PATCH 3/4] use latest sdk --- package.json | 2 +- pnpm-lock.yaml | 14 +++++++------- .../etsy/tools/create-draft-listing/base.ts | 4 ++-- .../etsy/tools/create-draft-listing/server.ts | 3 ++- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index 5616cf0b..6498cbf0 100644 --- a/package.json +++ b/package.json @@ -82,8 +82,8 @@ "cmdk": "^1.1.1", "cookies-next": "^6.0.0", "date-fns": "^4.1.0", - "etsy-ts": "^4.2.0", "discord-api-types": "^0.38.17", + "etsy-ts": "^5.0.0", "exa-js": "^1.8.8", "fast-deep-equal": "^3.1.3", "googleapis": "^150.0.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9cafcd36..9c2330ef 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -179,12 +179,12 @@ importers: date-fns: specifier: ^4.1.0 version: 4.1.0 - etsy-ts: - specifier: ^4.2.0 - version: 4.2.0 discord-api-types: specifier: ^0.38.17 version: 0.38.18 + etsy-ts: + specifier: ^5.0.0 + version: 5.0.0 exa-js: specifier: ^1.8.8 version: 1.8.8(encoding@0.1.13)(ws@8.18.3)(zod@3.25.56) @@ -3194,8 +3194,8 @@ packages: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} - etsy-ts@4.2.0: - resolution: {integrity: sha512-YrVSiIP1s1FE7/isCnnkUR86te4+UABHfW7gWUsAHUDtPZj2NOw4VswabcfWxbtis+8pmZm7XQO0cQs8LZL+Fw==} + etsy-ts@5.0.0: + resolution: {integrity: sha512-Bh5Y3QJby9a22VOThJrIPBHEQDT7ixPK67m3EGiQUxRRywK1GWqbGAQi8E63yWGJKF41yO81E83JSBfJ/1ZypA==} event-target-shim@5.0.1: resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} @@ -8670,11 +8670,11 @@ snapshots: etag@1.8.1: {} - etsy-ts@4.2.0: + etsy-ts@5.0.0: dependencies: axios: 1.7.7 axios-auth-refresh: 3.3.6(axios@1.7.7) - form-data: 4.0.3 + form-data: 4.0.4 tslib: 2.8.1 transitivePeerDependencies: - debug diff --git a/src/toolkits/toolkits/etsy/tools/create-draft-listing/base.ts b/src/toolkits/toolkits/etsy/tools/create-draft-listing/base.ts index 82f3790a..b30519e7 100644 --- a/src/toolkits/toolkits/etsy/tools/create-draft-listing/base.ts +++ b/src/toolkits/toolkits/etsy/tools/create-draft-listing/base.ts @@ -63,7 +63,7 @@ export const createDraftListing = createBaseTool({ when_made: z .enum([ "made_to_order", - "2020_2023", + "2020_2025", "2010_2019", "2006_2009", "before_2006", @@ -296,4 +296,4 @@ export const createDraftListing = createBaseTool({ outputSchema: z.object({ result: z.custom(), }), -}); +}); \ No newline at end of file diff --git a/src/toolkits/toolkits/etsy/tools/create-draft-listing/server.ts b/src/toolkits/toolkits/etsy/tools/create-draft-listing/server.ts index f351962d..41bbb323 100644 --- a/src/toolkits/toolkits/etsy/tools/create-draft-listing/server.ts +++ b/src/toolkits/toolkits/etsy/tools/create-draft-listing/server.ts @@ -96,11 +96,12 @@ export const createDraftListingServerConfig = ( ...(is_customizable !== undefined ? { is_customizable } : {}), ...(should_auto_renew !== undefined ? { should_auto_renew } : {}), ...(is_taxable !== undefined ? { is_taxable } : {}), + ...(tags !== undefined ? { tags } : {}), ...(type !== undefined ? { type } : {}), }; const listing = await etsy.ShopListing.createDraftListing( - shopId, + {shopId}, params, undefined, ); From f3be4964af3983a90f724f11cf5ceac94d06a169 Mon Sep 17 00:00:00 2001 From: Derrick Chen Date: Wed, 10 Sep 2025 00:33:57 -0400 Subject: [PATCH 4/4] prettier again --- src/toolkits/toolkits/etsy/tools/create-draft-listing/base.ts | 2 +- src/toolkits/toolkits/etsy/tools/create-draft-listing/server.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/toolkits/toolkits/etsy/tools/create-draft-listing/base.ts b/src/toolkits/toolkits/etsy/tools/create-draft-listing/base.ts index b30519e7..603e2866 100644 --- a/src/toolkits/toolkits/etsy/tools/create-draft-listing/base.ts +++ b/src/toolkits/toolkits/etsy/tools/create-draft-listing/base.ts @@ -296,4 +296,4 @@ export const createDraftListing = createBaseTool({ outputSchema: z.object({ result: z.custom(), }), -}); \ No newline at end of file +}); diff --git a/src/toolkits/toolkits/etsy/tools/create-draft-listing/server.ts b/src/toolkits/toolkits/etsy/tools/create-draft-listing/server.ts index 41bbb323..30097e60 100644 --- a/src/toolkits/toolkits/etsy/tools/create-draft-listing/server.ts +++ b/src/toolkits/toolkits/etsy/tools/create-draft-listing/server.ts @@ -101,7 +101,7 @@ export const createDraftListingServerConfig = ( }; const listing = await etsy.ShopListing.createDraftListing( - {shopId}, + { shopId }, params, undefined, );