@squadbase/vite-server 0.1.2 → 0.1.3-dev.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -44,43 +44,284 @@ var ParameterDefinition = class {
44
44
 
45
45
  // ../connectors/src/connectors/shopify/parameters.ts
46
46
  var parameters = {
47
- accessToken: new ParameterDefinition({
48
- slug: "access-token",
49
- name: "Shopify Admin API Access Token",
50
- description: "The Shopify Admin API access token for authentication (starts with shpat_).",
51
- envVarBaseKey: "SHOPIFY_ACCESS_TOKEN",
52
- type: "text",
53
- secret: true,
54
- required: true
55
- }),
56
47
  storeDomain: new ParameterDefinition({
57
48
  slug: "store-domain",
58
- name: "Shopify Store Domain",
59
- description: "Your Shopify store domain (e.g., mystore.myshopify.com).",
49
+ name: "Shop Name",
50
+ description: 'Your Shopify store name (the subdomain part of your .myshopify.com URL, e.g., "mystore" for mystore.myshopify.com).',
60
51
  envVarBaseKey: "SHOPIFY_STORE_DOMAIN",
61
52
  type: "text",
62
53
  secret: false,
63
54
  required: true
55
+ }),
56
+ clientId: new ParameterDefinition({
57
+ slug: "client-id",
58
+ name: "Client ID",
59
+ description: "The Client ID (API Key) of your Shopify Custom App.",
60
+ envVarBaseKey: "SHOPIFY_CLIENT_ID",
61
+ type: "text",
62
+ secret: false,
63
+ required: true
64
+ }),
65
+ clientSecret: new ParameterDefinition({
66
+ slug: "client-secret",
67
+ name: "Client Secret",
68
+ description: "The Client Secret (API Secret Key) of your Shopify Custom App.",
69
+ envVarBaseKey: "SHOPIFY_CLIENT_SECRET",
70
+ type: "text",
71
+ secret: true,
72
+ required: true
64
73
  })
65
74
  };
66
75
 
67
76
  // ../connectors/src/connectors/shopify/sdk/index.ts
68
- function createClient(params) {
69
- const accessToken = params[parameters.accessToken.slug];
70
- const storeDomain = params[parameters.storeDomain.slug];
71
- if (!accessToken) {
77
+ var API_VERSION = "2024-10";
78
+ async function fetchAccessToken(storeDomain, clientId, clientSecret) {
79
+ const res = await fetch(
80
+ `https://${storeDomain}/admin/oauth/access_token`,
81
+ {
82
+ method: "POST",
83
+ headers: { "Content-Type": "application/json" },
84
+ body: JSON.stringify({
85
+ client_id: clientId,
86
+ client_secret: clientSecret
87
+ })
88
+ }
89
+ );
90
+ if (!res.ok) {
91
+ const body = await res.text().catch(() => "(unreadable body)");
72
92
  throw new Error(
73
- `shopify: missing required parameter: ${parameters.accessToken.slug}`
93
+ `shopify: failed to obtain access token: ${res.status} ${res.statusText} \u2014 ${body}`
74
94
  );
75
95
  }
96
+ const json = await res.json();
97
+ if (!json.access_token) {
98
+ throw new Error("shopify: access_token not found in token response");
99
+ }
100
+ return json.access_token;
101
+ }
102
+ function createClient(params) {
103
+ const storeDomain = params[parameters.storeDomain.slug];
104
+ const clientId = params[parameters.clientId.slug];
105
+ const clientSecret = params[parameters.clientSecret.slug];
76
106
  if (!storeDomain) {
77
107
  throw new Error(
78
108
  `shopify: missing required parameter: ${parameters.storeDomain.slug}`
79
109
  );
80
110
  }
81
- return { accessToken, storeDomain };
111
+ if (!clientId) {
112
+ throw new Error(
113
+ `shopify: missing required parameter: ${parameters.clientId.slug}`
114
+ );
115
+ }
116
+ if (!clientSecret) {
117
+ throw new Error(
118
+ `shopify: missing required parameter: ${parameters.clientSecret.slug}`
119
+ );
120
+ }
121
+ const baseUrl = `https://${storeDomain}`;
122
+ async function getToken() {
123
+ return fetchAccessToken(storeDomain, clientId, clientSecret);
124
+ }
125
+ async function authHeaders(extra) {
126
+ const token = await getToken();
127
+ const headers = new Headers(extra);
128
+ headers.set("X-Shopify-Access-Token", token);
129
+ headers.set("Content-Type", "application/json");
130
+ return headers;
131
+ }
132
+ async function assertOk(res, label) {
133
+ if (!res.ok) {
134
+ const body = await res.text().catch(() => "(unreadable body)");
135
+ throw new Error(
136
+ `shopify ${label}: ${res.status} ${res.statusText} \u2014 ${body}`
137
+ );
138
+ }
139
+ }
140
+ function buildQuery(params2) {
141
+ if (!params2) return "";
142
+ const entries = Object.entries(params2).filter(
143
+ ([, v]) => v !== void 0 && v !== ""
144
+ );
145
+ if (entries.length === 0) return "";
146
+ const sp = new URLSearchParams();
147
+ for (const [k, v] of entries) sp.set(k, String(v));
148
+ return `?${sp.toString()}`;
149
+ }
150
+ return {
151
+ async request(path2, init) {
152
+ const url = `${baseUrl}${path2}`;
153
+ const token = await getToken();
154
+ const headers = new Headers(init?.headers);
155
+ headers.set("X-Shopify-Access-Token", token);
156
+ headers.set("Content-Type", "application/json");
157
+ return fetch(url, { ...init, headers });
158
+ },
159
+ async listProducts(options) {
160
+ const qs = buildQuery({
161
+ limit: options?.limit,
162
+ page_info: options?.pageInfo,
163
+ fields: options?.fields,
164
+ status: options?.status,
165
+ created_at_min: options?.createdAtMin,
166
+ created_at_max: options?.createdAtMax,
167
+ updated_at_min: options?.updatedAtMin,
168
+ updated_at_max: options?.updatedAtMax
169
+ });
170
+ const res = await fetch(
171
+ `${baseUrl}/admin/api/${API_VERSION}/products.json${qs}`,
172
+ { method: "GET", headers: await authHeaders() }
173
+ );
174
+ await assertOk(res, "listProducts");
175
+ const json = await res.json();
176
+ return {
177
+ products: json.products ?? []
178
+ };
179
+ },
180
+ async getProduct(productId) {
181
+ const res = await fetch(
182
+ `${baseUrl}/admin/api/${API_VERSION}/products/${encodeURIComponent(String(productId))}.json`,
183
+ { method: "GET", headers: await authHeaders() }
184
+ );
185
+ await assertOk(res, "getProduct");
186
+ const json = await res.json();
187
+ return { product: json.product };
188
+ },
189
+ async listOrders(options) {
190
+ const qs = buildQuery({
191
+ limit: options?.limit,
192
+ page_info: options?.pageInfo,
193
+ fields: options?.fields,
194
+ status: options?.status,
195
+ financial_status: options?.financialStatus,
196
+ fulfillment_status: options?.fulfillmentStatus,
197
+ created_at_min: options?.createdAtMin,
198
+ created_at_max: options?.createdAtMax,
199
+ updated_at_min: options?.updatedAtMin,
200
+ updated_at_max: options?.updatedAtMax
201
+ });
202
+ const res = await fetch(
203
+ `${baseUrl}/admin/api/${API_VERSION}/orders.json${qs}`,
204
+ { method: "GET", headers: await authHeaders() }
205
+ );
206
+ await assertOk(res, "listOrders");
207
+ const json = await res.json();
208
+ return {
209
+ orders: json.orders ?? []
210
+ };
211
+ },
212
+ async getOrder(orderId) {
213
+ const res = await fetch(
214
+ `${baseUrl}/admin/api/${API_VERSION}/orders/${encodeURIComponent(String(orderId))}.json`,
215
+ { method: "GET", headers: await authHeaders() }
216
+ );
217
+ await assertOk(res, "getOrder");
218
+ const json = await res.json();
219
+ return { order: json.order };
220
+ },
221
+ async listCustomers(options) {
222
+ const qs = buildQuery({
223
+ limit: options?.limit,
224
+ page_info: options?.pageInfo,
225
+ fields: options?.fields,
226
+ created_at_min: options?.createdAtMin,
227
+ created_at_max: options?.createdAtMax,
228
+ updated_at_min: options?.updatedAtMin,
229
+ updated_at_max: options?.updatedAtMax
230
+ });
231
+ const res = await fetch(
232
+ `${baseUrl}/admin/api/${API_VERSION}/customers.json${qs}`,
233
+ { method: "GET", headers: await authHeaders() }
234
+ );
235
+ await assertOk(res, "listCustomers");
236
+ const json = await res.json();
237
+ return {
238
+ customers: json.customers ?? []
239
+ };
240
+ },
241
+ async getCustomer(customerId) {
242
+ const res = await fetch(
243
+ `${baseUrl}/admin/api/${API_VERSION}/customers/${encodeURIComponent(String(customerId))}.json`,
244
+ { method: "GET", headers: await authHeaders() }
245
+ );
246
+ await assertOk(res, "getCustomer");
247
+ const json = await res.json();
248
+ return { customer: json.customer };
249
+ },
250
+ async listCustomCollections(options) {
251
+ const qs = buildQuery({
252
+ limit: options?.limit,
253
+ page_info: options?.pageInfo
254
+ });
255
+ const res = await fetch(
256
+ `${baseUrl}/admin/api/${API_VERSION}/custom_collections.json${qs}`,
257
+ { method: "GET", headers: await authHeaders() }
258
+ );
259
+ await assertOk(res, "listCustomCollections");
260
+ const json = await res.json();
261
+ return {
262
+ custom_collections: json.custom_collections ?? []
263
+ };
264
+ },
265
+ async listSmartCollections(options) {
266
+ const qs = buildQuery({
267
+ limit: options?.limit,
268
+ page_info: options?.pageInfo
269
+ });
270
+ const res = await fetch(
271
+ `${baseUrl}/admin/api/${API_VERSION}/smart_collections.json${qs}`,
272
+ { method: "GET", headers: await authHeaders() }
273
+ );
274
+ await assertOk(res, "listSmartCollections");
275
+ const json = await res.json();
276
+ return {
277
+ smart_collections: json.smart_collections ?? []
278
+ };
279
+ }
280
+ };
82
281
  }
83
282
 
283
+ // ../connectors/src/connector-onboarding.ts
284
+ var ConnectorOnboarding = class {
285
+ /** Phase 1: Connection setup instructions (optional — some connectors don't need this) */
286
+ connectionSetupInstructions;
287
+ /** Phase 2: Data overview instructions */
288
+ dataOverviewInstructions;
289
+ constructor(config) {
290
+ this.connectionSetupInstructions = config.connectionSetupInstructions;
291
+ this.dataOverviewInstructions = config.dataOverviewInstructions;
292
+ }
293
+ getConnectionSetupPrompt(language) {
294
+ return this.connectionSetupInstructions?.[language] ?? null;
295
+ }
296
+ getDataOverviewInstructions(language) {
297
+ return this.dataOverviewInstructions[language];
298
+ }
299
+ };
300
+
301
+ // ../connectors/src/connector-tool.ts
302
+ var ConnectorTool = class {
303
+ name;
304
+ description;
305
+ inputSchema;
306
+ outputSchema;
307
+ _execute;
308
+ constructor(config) {
309
+ this.name = config.name;
310
+ this.description = config.description;
311
+ this.inputSchema = config.inputSchema;
312
+ this.outputSchema = config.outputSchema;
313
+ this._execute = config.execute;
314
+ }
315
+ createTool(connections, config) {
316
+ return {
317
+ description: this.description,
318
+ inputSchema: this.inputSchema,
319
+ outputSchema: this.outputSchema,
320
+ execute: (input) => this._execute(input, connections, config)
321
+ };
322
+ }
323
+ };
324
+
84
325
  // ../connectors/src/connector-plugin.ts
85
326
  var ConnectorPlugin = class _ConnectorPlugin {
86
327
  slug;
@@ -139,8 +380,124 @@ var ConnectorPlugin = class _ConnectorPlugin {
139
380
  }
140
381
  };
141
382
 
383
+ // ../connectors/src/connectors/shopify/setup.ts
384
+ var shopifyOnboarding = new ConnectorOnboarding({
385
+ dataOverviewInstructions: {
386
+ en: `1. Call shopify_request with GET /admin/api/2024-10/products.json?limit=5 to explore products structure
387
+ 2. Call shopify_request with GET /admin/api/2024-10/orders.json?limit=5&status=any to explore orders structure
388
+ 3. Explore other endpoints (customers, inventory, collections) as needed`,
389
+ ja: `1. shopify_request \u3067 GET /admin/api/2024-10/products.json?limit=5 \u3092\u547C\u3073\u51FA\u3057\u3001\u5546\u54C1\u306E\u69CB\u9020\u3092\u78BA\u8A8D
390
+ 2. shopify_request \u3067 GET /admin/api/2024-10/orders.json?limit=5&status=any \u3092\u547C\u3073\u51FA\u3057\u3001\u6CE8\u6587\u306E\u69CB\u9020\u3092\u78BA\u8A8D
391
+ 3. \u5FC5\u8981\u306B\u5FDC\u3058\u3066\u4ED6\u306E\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\uFF08\u9867\u5BA2\u3001\u5728\u5EAB\u3001\u30B3\u30EC\u30AF\u30B7\u30E7\u30F3\uFF09\u3092\u63A2\u7D22`
392
+ }
393
+ });
394
+
395
+ // ../connectors/src/connectors/shopify/tools/request.ts
396
+ import { z } from "zod";
397
+ var REQUEST_TIMEOUT_MS = 6e4;
398
+ var inputSchema = z.object({
399
+ toolUseIntent: z.string().optional().describe(
400
+ "Brief description of what you intend to accomplish with this tool call"
401
+ ),
402
+ connectionId: z.string().describe("ID of the Shopify connection to use"),
403
+ method: z.enum(["GET", "POST", "PUT", "DELETE"]).describe(
404
+ "HTTP method. GET for reading resources (products, orders, customers), POST for creating, PUT for updating, DELETE for removing."
405
+ ),
406
+ path: z.string().describe(
407
+ "API path including version (e.g., '/admin/api/2024-10/products.json', '/admin/api/2024-10/orders.json?limit=50')"
408
+ ),
409
+ body: z.record(z.string(), z.unknown()).optional().describe("Request body (JSON) for POST/PUT requests")
410
+ });
411
+ var outputSchema = z.discriminatedUnion("success", [
412
+ z.object({
413
+ success: z.literal(true),
414
+ status: z.number(),
415
+ data: z.record(z.string(), z.unknown())
416
+ }),
417
+ z.object({
418
+ success: z.literal(false),
419
+ error: z.string()
420
+ })
421
+ ]);
422
+ var requestTool = new ConnectorTool({
423
+ name: "request",
424
+ description: `Send authenticated requests to the Shopify Admin REST API.
425
+ Authentication is handled automatically using Custom App credentials (Client ID + Client Secret). An access token is obtained on each request.
426
+ The store domain is resolved from the connection \u2014 only provide the path starting with /admin/api/.
427
+ Use this tool for all Shopify API interactions: listing products, orders, customers, inventory, collections, and more.`,
428
+ inputSchema,
429
+ outputSchema,
430
+ async execute({ connectionId, method, path: path2, body }, connections) {
431
+ const connection2 = connections.find((c) => c.id === connectionId);
432
+ if (!connection2) {
433
+ return {
434
+ success: false,
435
+ error: `Connection ${connectionId} not found`
436
+ };
437
+ }
438
+ console.log(
439
+ `[connector-request] shopify/${connection2.name}: ${method} ${path2}`
440
+ );
441
+ try {
442
+ const storeDomain = parameters.storeDomain.getValue(connection2);
443
+ const clientId = parameters.clientId.getValue(connection2);
444
+ const clientSecret = parameters.clientSecret.getValue(connection2);
445
+ const tokenRes = await fetch(
446
+ `https://${storeDomain}/admin/oauth/access_token`,
447
+ {
448
+ method: "POST",
449
+ headers: { "Content-Type": "application/json" },
450
+ body: JSON.stringify({
451
+ client_id: clientId,
452
+ client_secret: clientSecret
453
+ })
454
+ }
455
+ );
456
+ if (!tokenRes.ok) {
457
+ const tokenBody = await tokenRes.text().catch(() => "(unreadable body)");
458
+ return {
459
+ success: false,
460
+ error: `Failed to obtain access token: ${tokenRes.status} ${tokenRes.statusText} \u2014 ${tokenBody}`
461
+ };
462
+ }
463
+ const tokenJson = await tokenRes.json();
464
+ if (!tokenJson.access_token) {
465
+ return {
466
+ success: false,
467
+ error: "access_token not found in token response"
468
+ };
469
+ }
470
+ const url = `https://${storeDomain}${path2}`;
471
+ const controller = new AbortController();
472
+ const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
473
+ try {
474
+ const response = await fetch(url, {
475
+ method,
476
+ headers: {
477
+ "X-Shopify-Access-Token": tokenJson.access_token,
478
+ "Content-Type": "application/json"
479
+ },
480
+ body: body ? JSON.stringify(body) : void 0,
481
+ signal: controller.signal
482
+ });
483
+ const data = await response.json();
484
+ if (!response.ok) {
485
+ const errorMessage = typeof data?.errors === "string" ? data.errors : typeof data?.error === "string" ? data.error : `HTTP ${response.status} ${response.statusText}`;
486
+ return { success: false, error: errorMessage };
487
+ }
488
+ return { success: true, status: response.status, data };
489
+ } finally {
490
+ clearTimeout(timeout);
491
+ }
492
+ } catch (err) {
493
+ const msg = err instanceof Error ? err.message : String(err);
494
+ return { success: false, error: msg };
495
+ }
496
+ }
497
+ });
498
+
142
499
  // ../connectors/src/connectors/shopify/index.ts
143
- var tools = {};
500
+ var tools = { request: requestTool };
144
501
  var shopifyConnector = new ConnectorPlugin({
145
502
  slug: "shopify",
146
503
  authType: null,
@@ -149,89 +506,152 @@ var shopifyConnector = new ConnectorPlugin({
149
506
  iconUrl: "https://images.ctfassets.net/9ncizv60xc5y/57KEjZCBskKgSxgKyU4Sm0/117d681a410f48dc36f97cdd9c0593c5/shopify-icon.svg",
150
507
  parameters,
151
508
  releaseFlag: { dev1: true, dev2: false, prod: false },
509
+ onboarding: shopifyOnboarding,
152
510
  systemPrompt: {
153
- en: `### Shopify SDK (TypeScript handler)
154
- Use the Shopify connector via the SDK in TypeScript handlers:
511
+ en: `### Tools
512
+
513
+ - \`shopify_request\`: The only way to call the Shopify Admin REST API. Use it to query products, orders, customers, inventory, collections, and more. Authentication (Custom App Client ID + Client Secret) is configured automatically \u2014 an access token is obtained on each request. Only provide the path starting with \`/admin/api/\`. Shopify uses cursor-based pagination via the \`page_info\` query parameter (obtained from the Link header in the response).
514
+
515
+ ### Business Logic
516
+
517
+ The business logic type for this connector is "typescript". Use the connector SDK in your handler. Do NOT read credentials from environment variables.
518
+
519
+ SDK methods (client created via \`connection(connectionId)\`):
520
+ - \`client.request(path, init?)\` \u2014 low-level authenticated fetch
521
+ - \`client.listProducts(options?)\` \u2014 list products with filters (status, date range) and pagination
522
+ - \`client.getProduct(productId)\` \u2014 fetch a single product
523
+ - \`client.listOrders(options?)\` \u2014 list orders with filters (status, financial_status, fulfillment_status, date range)
524
+ - \`client.getOrder(orderId)\` \u2014 fetch a single order
525
+ - \`client.listCustomers(options?)\` \u2014 list customers with filters and pagination
526
+ - \`client.getCustomer(customerId)\` \u2014 fetch a single customer
527
+ - \`client.listCustomCollections(options?)\` \u2014 list custom collections
528
+ - \`client.listSmartCollections(options?)\` \u2014 list smart collections
155
529
 
156
530
  \`\`\`ts
531
+ import type { Context } from "hono";
157
532
  import { connection } from "@squadbase/vite-server/connectors/shopify";
158
533
 
159
- const { accessToken, storeDomain } = connection("<connectionId>");
534
+ const shopify = connection("<connectionId>");
160
535
 
161
- // Use the Shopify Admin REST API
162
- const res = await fetch(
163
- \`https://\${storeDomain}/admin/api/2024-10/products.json\`,
164
- {
165
- headers: {
166
- "X-Shopify-Access-Token": accessToken,
167
- "Content-Type": "application/json",
168
- },
169
- },
170
- );
171
- const data = await res.json();
536
+ export default async function handler(c: Context) {
537
+ const { status = "active", limit = 50 } = await c.req.json<{
538
+ status?: "active" | "draft" | "archived";
539
+ limit?: number;
540
+ }>();
541
+
542
+ const { products } = await shopify.listProducts({ status, limit });
543
+
544
+ return c.json({
545
+ products: products.map((p: Record<string, unknown>) => ({
546
+ id: p.id,
547
+ title: p.title,
548
+ status: p.status,
549
+ vendor: p.vendor,
550
+ created_at: p.created_at,
551
+ })),
552
+ });
553
+ }
172
554
  \`\`\`
173
555
 
174
- ### Common Endpoints (Base URL: https://{storeDomain}/admin/api/2024-10)
175
- - GET \`/products.json\` \u2014 List products
176
- - GET \`/products/{id}.json\` \u2014 Get a product
177
- - GET \`/orders.json\` \u2014 List orders
178
- - GET \`/orders/{id}.json\` \u2014 Get an order
179
- - GET \`/customers.json\` \u2014 List customers
180
- - GET \`/customers/{id}.json\` \u2014 Get a customer
181
- - GET \`/inventory_items.json?ids={ids}\` \u2014 List inventory items
182
- - GET \`/locations.json\` \u2014 List locations
183
- - GET \`/collects.json\` \u2014 List collects
184
- - GET \`/custom_collections.json\` \u2014 List custom collections
185
- - GET \`/smart_collections.json\` \u2014 List smart collections
186
-
187
- ### Query Parameters
556
+ ### Shopify Admin REST API Reference
557
+
558
+ - Base URL: \`https://{storeDomain}/admin/api/2024-10\`
559
+ - Authentication: Custom App (Client ID + Client Secret \u2192 access token obtained per request)
560
+ - Pagination: cursor-based via \`page_info\` query parameter (from Link header)
561
+ - Max 250 records per page
562
+
563
+ #### Common Endpoints
564
+ - GET \`/admin/api/2024-10/products.json\` \u2014 List products
565
+ - GET \`/admin/api/2024-10/products/{id}.json\` \u2014 Get a product
566
+ - GET \`/admin/api/2024-10/orders.json\` \u2014 List orders
567
+ - GET \`/admin/api/2024-10/orders/{id}.json\` \u2014 Get an order
568
+ - GET \`/admin/api/2024-10/customers.json\` \u2014 List customers
569
+ - GET \`/admin/api/2024-10/customers/{id}.json\` \u2014 Get a customer
570
+ - GET \`/admin/api/2024-10/inventory_items.json?ids={ids}\` \u2014 List inventory items
571
+ - GET \`/admin/api/2024-10/locations.json\` \u2014 List locations
572
+ - GET \`/admin/api/2024-10/collects.json\` \u2014 List collects
573
+ - GET \`/admin/api/2024-10/custom_collections.json\` \u2014 List custom collections
574
+ - GET \`/admin/api/2024-10/smart_collections.json\` \u2014 List smart collections
575
+
576
+ #### Common Query Parameters
188
577
  - \`limit\` \u2014 Max records per page (max 250)
189
578
  - \`page_info\` \u2014 Cursor for pagination (from Link header)
190
579
  - \`fields\` \u2014 Comma-separated list of fields to return
191
- - \`created_at_min\`, \`created_at_max\` \u2014 Date filters
192
- - \`updated_at_min\`, \`updated_at_max\` \u2014 Date filters
193
- - \`status\` \u2014 Filter by status (e.g., active, draft, archived for products)`,
194
- ja: `### Shopify SDK\uFF08TypeScript\u30CF\u30F3\u30C9\u30E9\u30FC\uFF09
195
- TypeScript\u30CF\u30F3\u30C9\u30E9\u30FC\u3067Shopify\u30B3\u30CD\u30AF\u30BF\u30FC\u3092SDK\u7D4C\u7531\u3067\u4F7F\u7528\u3057\u307E\u3059\uFF1A
580
+ - \`created_at_min\`, \`created_at_max\` \u2014 Date filters (ISO 8601)
581
+ - \`updated_at_min\`, \`updated_at_max\` \u2014 Date filters (ISO 8601)
582
+ - \`status\` \u2014 Filter by status (e.g., active, draft, archived for products; open, closed, cancelled, any for orders)`,
583
+ ja: `### \u30C4\u30FC\u30EB
584
+
585
+ - \`shopify_request\`: Shopify Admin REST API\u3092\u547C\u3073\u51FA\u3059\u552F\u4E00\u306E\u624B\u6BB5\u3067\u3059\u3002\u5546\u54C1\u3001\u6CE8\u6587\u3001\u9867\u5BA2\u3001\u5728\u5EAB\u3001\u30B3\u30EC\u30AF\u30B7\u30E7\u30F3\u306A\u3069\u306E\u30AF\u30A8\u30EA\u306B\u4F7F\u7528\u3057\u307E\u3059\u3002\u8A8D\u8A3C\uFF08\u30AB\u30B9\u30BF\u30E0\u30A2\u30D7\u30EA\u306E Client ID + Client Secret\uFF09\u306F\u81EA\u52D5\u7684\u306B\u8A2D\u5B9A\u3055\u308C\u3001\u30EA\u30AF\u30A8\u30B9\u30C8\u3054\u3068\u306B\u30A2\u30AF\u30BB\u30B9\u30C8\u30FC\u30AF\u30F3\u3092\u53D6\u5F97\u3057\u307E\u3059\u3002\`/admin/api/\` \u304B\u3089\u59CB\u307E\u308B\u30D1\u30B9\u306E\u307F\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002Shopify\u306F\u30EC\u30B9\u30DD\u30F3\u30B9\u306E Link \u30D8\u30C3\u30C0\u30FC\u304B\u3089\u53D6\u5F97\u3059\u308B \`page_info\` \u30AF\u30A8\u30EA\u30D1\u30E9\u30E1\u30FC\u30BF\u306B\u3088\u308B\u30AB\u30FC\u30BD\u30EB\u30D9\u30FC\u30B9\u306E\u30DA\u30FC\u30B8\u30CD\u30FC\u30B7\u30E7\u30F3\u3092\u4F7F\u7528\u3057\u307E\u3059\u3002
586
+
587
+ ### Business Logic
588
+
589
+ \u3053\u306E\u30B3\u30CD\u30AF\u30BF\u306E\u30D3\u30B8\u30CD\u30B9\u30ED\u30B8\u30C3\u30AF\u30BF\u30A4\u30D7\u306F "typescript" \u3067\u3059\u3002\u30CF\u30F3\u30C9\u30E9\u5185\u3067\u306F\u30B3\u30CD\u30AF\u30BFSDK\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u74B0\u5883\u5909\u6570\u304B\u3089\u8A8D\u8A3C\u60C5\u5831\u3092\u8AAD\u307F\u53D6\u3089\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002
590
+
591
+ SDK\u30E1\u30BD\u30C3\u30C9 (\`connection(connectionId)\` \u3067\u4F5C\u6210\u3057\u305F\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8):
592
+ - \`client.request(path, init?)\` \u2014 \u4F4E\u30EC\u30D9\u30EB\u306E\u8A8D\u8A3C\u4ED8\u304Dfetch
593
+ - \`client.listProducts(options?)\` \u2014 \u30D5\u30A3\u30EB\u30BF\uFF08\u30B9\u30C6\u30FC\u30BF\u30B9\u3001\u65E5\u4ED8\u7BC4\u56F2\uFF09\u3068\u30DA\u30FC\u30B8\u30CD\u30FC\u30B7\u30E7\u30F3\u4ED8\u304D\u3067\u5546\u54C1\u3092\u4E00\u89A7\u53D6\u5F97
594
+ - \`client.getProduct(productId)\` \u2014 \u5358\u4E00\u5546\u54C1\u3092\u53D6\u5F97
595
+ - \`client.listOrders(options?)\` \u2014 \u30D5\u30A3\u30EB\u30BF\uFF08\u30B9\u30C6\u30FC\u30BF\u30B9\u3001\u652F\u6255\u3044\u72B6\u6CC1\u3001\u914D\u9001\u72B6\u6CC1\u3001\u65E5\u4ED8\u7BC4\u56F2\uFF09\u4ED8\u304D\u3067\u6CE8\u6587\u3092\u4E00\u89A7\u53D6\u5F97
596
+ - \`client.getOrder(orderId)\` \u2014 \u5358\u4E00\u6CE8\u6587\u3092\u53D6\u5F97
597
+ - \`client.listCustomers(options?)\` \u2014 \u30D5\u30A3\u30EB\u30BF\u3068\u30DA\u30FC\u30B8\u30CD\u30FC\u30B7\u30E7\u30F3\u4ED8\u304D\u3067\u9867\u5BA2\u3092\u4E00\u89A7\u53D6\u5F97
598
+ - \`client.getCustomer(customerId)\` \u2014 \u5358\u4E00\u9867\u5BA2\u3092\u53D6\u5F97
599
+ - \`client.listCustomCollections(options?)\` \u2014 \u30AB\u30B9\u30BF\u30E0\u30B3\u30EC\u30AF\u30B7\u30E7\u30F3\u3092\u4E00\u89A7\u53D6\u5F97
600
+ - \`client.listSmartCollections(options?)\` \u2014 \u30B9\u30DE\u30FC\u30C8\u30B3\u30EC\u30AF\u30B7\u30E7\u30F3\u3092\u4E00\u89A7\u53D6\u5F97
196
601
 
197
602
  \`\`\`ts
603
+ import type { Context } from "hono";
198
604
  import { connection } from "@squadbase/vite-server/connectors/shopify";
199
605
 
200
- const { accessToken, storeDomain } = connection("<connectionId>");
606
+ const shopify = connection("<connectionId>");
201
607
 
202
- // Shopify Admin REST API\u3092\u4F7F\u7528
203
- const res = await fetch(
204
- \`https://\${storeDomain}/admin/api/2024-10/products.json\`,
205
- {
206
- headers: {
207
- "X-Shopify-Access-Token": accessToken,
208
- "Content-Type": "application/json",
209
- },
210
- },
211
- );
212
- const data = await res.json();
608
+ export default async function handler(c: Context) {
609
+ const { status = "active", limit = 50 } = await c.req.json<{
610
+ status?: "active" | "draft" | "archived";
611
+ limit?: number;
612
+ }>();
613
+
614
+ const { products } = await shopify.listProducts({ status, limit });
615
+
616
+ return c.json({
617
+ products: products.map((p: Record<string, unknown>) => ({
618
+ id: p.id,
619
+ title: p.title,
620
+ status: p.status,
621
+ vendor: p.vendor,
622
+ created_at: p.created_at,
623
+ })),
624
+ });
625
+ }
213
626
  \`\`\`
214
627
 
215
- ### \u4E3B\u8981\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\uFF08\u30D9\u30FC\u30B9URL: https://{storeDomain}/admin/api/2024-10\uFF09
216
- - GET \`/products.json\` \u2014 \u5546\u54C1\u4E00\u89A7
217
- - GET \`/products/{id}.json\` \u2014 \u5546\u54C1\u306E\u53D6\u5F97
218
- - GET \`/orders.json\` \u2014 \u6CE8\u6587\u4E00\u89A7
219
- - GET \`/orders/{id}.json\` \u2014 \u6CE8\u6587\u306E\u53D6\u5F97
220
- - GET \`/customers.json\` \u2014 \u9867\u5BA2\u4E00\u89A7
221
- - GET \`/customers/{id}.json\` \u2014 \u9867\u5BA2\u306E\u53D6\u5F97
222
- - GET \`/inventory_items.json?ids={ids}\` \u2014 \u5728\u5EAB\u30A2\u30A4\u30C6\u30E0\u4E00\u89A7
223
- - GET \`/locations.json\` \u2014 \u30ED\u30B1\u30FC\u30B7\u30E7\u30F3\u4E00\u89A7
224
- - GET \`/collects.json\` \u2014 \u30B3\u30EC\u30AF\u30C8\u4E00\u89A7
225
- - GET \`/custom_collections.json\` \u2014 \u30AB\u30B9\u30BF\u30E0\u30B3\u30EC\u30AF\u30B7\u30E7\u30F3\u4E00\u89A7
226
- - GET \`/smart_collections.json\` \u2014 \u30B9\u30DE\u30FC\u30C8\u30B3\u30EC\u30AF\u30B7\u30E7\u30F3\u4E00\u89A7
227
-
228
- ### \u30AF\u30A8\u30EA\u30D1\u30E9\u30E1\u30FC\u30BF
628
+ ### Shopify Admin REST API \u30EA\u30D5\u30A1\u30EC\u30F3\u30B9
629
+
630
+ - \u30D9\u30FC\u30B9URL: \`https://{storeDomain}/admin/api/2024-10\`
631
+ - \u8A8D\u8A3C: \u30AB\u30B9\u30BF\u30E0\u30A2\u30D7\u30EA\uFF08Client ID + Client Secret \u2192 \u30EA\u30AF\u30A8\u30B9\u30C8\u3054\u3068\u306B\u30A2\u30AF\u30BB\u30B9\u30C8\u30FC\u30AF\u30F3\u53D6\u5F97\uFF09
632
+ - \u30DA\u30FC\u30B8\u30CD\u30FC\u30B7\u30E7\u30F3: Link \u30D8\u30C3\u30C0\u30FC\u304B\u3089\u306E \`page_info\` \u306B\u3088\u308B\u30AB\u30FC\u30BD\u30EB\u30D9\u30FC\u30B9
633
+ - \u30DA\u30FC\u30B8\u3042\u305F\u308A\u6700\u5927250\u30EC\u30B3\u30FC\u30C9
634
+
635
+ #### \u4E3B\u8981\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8
636
+ - GET \`/admin/api/2024-10/products.json\` \u2014 \u5546\u54C1\u4E00\u89A7
637
+ - GET \`/admin/api/2024-10/products/{id}.json\` \u2014 \u5546\u54C1\u306E\u53D6\u5F97
638
+ - GET \`/admin/api/2024-10/orders.json\` \u2014 \u6CE8\u6587\u4E00\u89A7
639
+ - GET \`/admin/api/2024-10/orders/{id}.json\` \u2014 \u6CE8\u6587\u306E\u53D6\u5F97
640
+ - GET \`/admin/api/2024-10/customers.json\` \u2014 \u9867\u5BA2\u4E00\u89A7
641
+ - GET \`/admin/api/2024-10/customers/{id}.json\` \u2014 \u9867\u5BA2\u306E\u53D6\u5F97
642
+ - GET \`/admin/api/2024-10/inventory_items.json?ids={ids}\` \u2014 \u5728\u5EAB\u30A2\u30A4\u30C6\u30E0\u4E00\u89A7
643
+ - GET \`/admin/api/2024-10/locations.json\` \u2014 \u30ED\u30B1\u30FC\u30B7\u30E7\u30F3\u4E00\u89A7
644
+ - GET \`/admin/api/2024-10/collects.json\` \u2014 \u30B3\u30EC\u30AF\u30C8\u4E00\u89A7
645
+ - GET \`/admin/api/2024-10/custom_collections.json\` \u2014 \u30AB\u30B9\u30BF\u30E0\u30B3\u30EC\u30AF\u30B7\u30E7\u30F3\u4E00\u89A7
646
+ - GET \`/admin/api/2024-10/smart_collections.json\` \u2014 \u30B9\u30DE\u30FC\u30C8\u30B3\u30EC\u30AF\u30B7\u30E7\u30F3\u4E00\u89A7
647
+
648
+ #### \u4E3B\u8981\u30AF\u30A8\u30EA\u30D1\u30E9\u30E1\u30FC\u30BF
229
649
  - \`limit\` \u2014 \u30DA\u30FC\u30B8\u3042\u305F\u308A\u306E\u6700\u5927\u30EC\u30B3\u30FC\u30C9\u6570\uFF08\u6700\u5927250\uFF09
230
650
  - \`page_info\` \u2014 \u30DA\u30FC\u30B8\u30CD\u30FC\u30B7\u30E7\u30F3\u7528\u30AB\u30FC\u30BD\u30EB\uFF08Link\u30D8\u30C3\u30C0\u30FC\u304B\u3089\u53D6\u5F97\uFF09
231
651
  - \`fields\` \u2014 \u8FD4\u5374\u3059\u308B\u30D5\u30A3\u30FC\u30EB\u30C9\u306E\u30AB\u30F3\u30DE\u533A\u5207\u308A\u30EA\u30B9\u30C8
232
- - \`created_at_min\`, \`created_at_max\` \u2014 \u4F5C\u6210\u65E5\u30D5\u30A3\u30EB\u30BF\u30FC
233
- - \`updated_at_min\`, \`updated_at_max\` \u2014 \u66F4\u65B0\u65E5\u30D5\u30A3\u30EB\u30BF\u30FC
234
- - \`status\` \u2014 \u30B9\u30C6\u30FC\u30BF\u30B9\u3067\u30D5\u30A3\u30EB\u30BF\u30FC\uFF08\u4F8B: \u5546\u54C1\u306E\u5834\u5408 active, draft, archived\uFF09`
652
+ - \`created_at_min\`, \`created_at_max\` \u2014 \u4F5C\u6210\u65E5\u30D5\u30A3\u30EB\u30BF\u30FC\uFF08ISO 8601\uFF09
653
+ - \`updated_at_min\`, \`updated_at_max\` \u2014 \u66F4\u65B0\u65E5\u30D5\u30A3\u30EB\u30BF\u30FC\uFF08ISO 8601\uFF09
654
+ - \`status\` \u2014 \u30B9\u30C6\u30FC\u30BF\u30B9\u3067\u30D5\u30A3\u30EB\u30BF\u30FC\uFF08\u4F8B: \u5546\u54C1\u306E\u5834\u5408 active, draft, archived\u3001\u6CE8\u6587\u306E\u5834\u5408 open, closed, cancelled, any\uFF09`
235
655
  },
236
656
  tools
237
657
  });