@keystrokehq/shopify 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +178 -0
  2. package/dist/_official/index.d.mts +3 -0
  3. package/dist/_official/index.mjs +3 -0
  4. package/dist/_runtime/index.d.mts +56 -0
  5. package/dist/_runtime/index.mjs +3 -0
  6. package/dist/articles.d.mts +174 -0
  7. package/dist/articles.mjs +252 -0
  8. package/dist/blogs.d.mts +113 -0
  9. package/dist/blogs.mjs +174 -0
  10. package/dist/client.d.mts +22 -0
  11. package/dist/client.mjs +90 -0
  12. package/dist/collections.d.mts +140 -0
  13. package/dist/collections.mjs +209 -0
  14. package/dist/connection.d.mts +2 -0
  15. package/dist/connection.mjs +3 -0
  16. package/dist/customers.d.mts +161 -0
  17. package/dist/customers.mjs +225 -0
  18. package/dist/events.d.mts +181 -0
  19. package/dist/events.mjs +67 -0
  20. package/dist/factory-DC-gY8L0.mjs +8 -0
  21. package/dist/fulfillments.d.mts +99 -0
  22. package/dist/fulfillments.mjs +167 -0
  23. package/dist/index.d.mts +1 -0
  24. package/dist/index.mjs +1 -0
  25. package/dist/integration-BN3pjCz4.mjs +204 -0
  26. package/dist/integration-BwDBsGX-.d.mts +71 -0
  27. package/dist/inventory.d.mts +103 -0
  28. package/dist/inventory.mjs +182 -0
  29. package/dist/locations.d.mts +47 -0
  30. package/dist/locations.mjs +81 -0
  31. package/dist/messaging.d.mts +1 -0
  32. package/dist/messaging.mjs +1 -0
  33. package/dist/operation-helpers-CKEDIx0o.mjs +21 -0
  34. package/dist/orders.d.mts +229 -0
  35. package/dist/orders.mjs +271 -0
  36. package/dist/products.d.mts +155 -0
  37. package/dist/products.mjs +171 -0
  38. package/dist/provider-app-DHxVZI6q.d.mts +37 -0
  39. package/dist/schemas.d.mts +233 -0
  40. package/dist/schemas.mjs +164 -0
  41. package/dist/shop.d.mts +20 -0
  42. package/dist/shop.mjs +31 -0
  43. package/dist/triggers.d.mts +23 -0
  44. package/dist/triggers.mjs +138 -0
  45. package/dist/webhook-management-BmIxO0vr.mjs +150 -0
  46. package/package.json +130 -0
package/README.md ADDED
@@ -0,0 +1,178 @@
1
+ # @keystrokehq/shopify
2
+
3
+ Shopify Admin API integration for Keystroke workflows.
4
+
5
+ The package root is intentionally non-canonical. Import from explicit subpaths.
6
+
7
+ ## Public Subpaths
8
+
9
+ - `@keystrokehq/shopify/connection`
10
+ - `@keystrokehq/shopify/client`
11
+ - `@keystrokehq/shopify/schemas`
12
+ - `@keystrokehq/shopify/events`
13
+ - `@keystrokehq/shopify/shop`
14
+ - `@keystrokehq/shopify/products`
15
+ - `@keystrokehq/shopify/collections`
16
+ - `@keystrokehq/shopify/orders`
17
+ - `@keystrokehq/shopify/customers`
18
+ - `@keystrokehq/shopify/blogs`
19
+ - `@keystrokehq/shopify/articles`
20
+ - `@keystrokehq/shopify/locations`
21
+ - `@keystrokehq/shopify/inventory`
22
+ - `@keystrokehq/shopify/fulfillments`
23
+ - `@keystrokehq/shopify/triggers`
24
+
25
+ ## Read Store Data
26
+
27
+ ```ts
28
+ import { Workflow } from '@keystrokehq/core';
29
+ import { z } from 'zod';
30
+ import { shopify } from '@keystrokehq/shopify/connection';
31
+ import { getShop } from '@keystrokehq/shopify/shop';
32
+ import { listProducts } from '@keystrokehq/shopify/products';
33
+
34
+ export const syncCatalog = new Workflow({
35
+ id: 'sync-shopify-catalog',
36
+ name: 'Sync Shopify Catalog',
37
+ input: z.object({}),
38
+ output: z.object({
39
+ credentialSetId: z.string(),
40
+ storeName: z.string(),
41
+ productCount: z.number(),
42
+ }),
43
+ run: async () => {
44
+ const store = await getShop.run({});
45
+ const products = await listProducts.run({
46
+ first: 25,
47
+ query: 'status:active',
48
+ });
49
+
50
+ return {
51
+ credentialSetId: shopify.resolvedCredentialSetId,
52
+ storeName: store.name,
53
+ productCount: products.nodes.length,
54
+ };
55
+ },
56
+ });
57
+ ```
58
+
59
+ ## Create Orders And Adjust Inventory
60
+
61
+ ```ts
62
+ import { Workflow } from '@keystrokehq/core';
63
+ import { z } from 'zod';
64
+ import { createOrder } from '@keystrokehq/shopify/orders';
65
+ import { adjustInventoryQuantities } from '@keystrokehq/shopify/inventory';
66
+
67
+ export const backofficeWriteFlow = new Workflow({
68
+ id: 'shopify-backoffice-write-flow',
69
+ name: 'Shopify Backoffice Write Flow',
70
+ input: z.object({ variantId: z.string(), inventoryItemId: z.string(), locationId: z.string() }),
71
+ output: z.object({ queued: z.boolean() }),
72
+ run: async (input) => {
73
+ await createOrder.run({
74
+ currency: 'USD',
75
+ email: 'buyer@example.com',
76
+ lineItems: [
77
+ {
78
+ variantId: input.variantId,
79
+ quantity: 1,
80
+ },
81
+ ],
82
+ });
83
+
84
+ await adjustInventoryQuantities.run({
85
+ reason: 'correction',
86
+ referenceDocumentUri: 'gid://keystroke/inventory-adjustment/docs-example',
87
+ changes: [
88
+ {
89
+ inventoryItemId: input.inventoryItemId,
90
+ locationId: input.locationId,
91
+ delta: -1,
92
+ },
93
+ ],
94
+ });
95
+
96
+ return { queued: true };
97
+ },
98
+ });
99
+ ```
100
+
101
+ ## Bind Webhook Triggers
102
+
103
+ ```ts
104
+ import { Workflow } from '@keystrokehq/core';
105
+ import { z } from 'zod';
106
+ import { webhooks } from '@keystrokehq/shopify/triggers';
107
+
108
+ const orderCreated = webhooks.orderCreated({
109
+ name: 'Shopify Order Created',
110
+ transform: (event) => ({
111
+ orderId: event.resourceId ?? event.payload.admin_graphql_api_id ?? '',
112
+ topic: event.topic,
113
+ }),
114
+ });
115
+
116
+ export const onNewShopifyOrder = new Workflow({
117
+ id: 'on-new-shopify-order',
118
+ name: 'On New Shopify Order',
119
+ input: z.object({
120
+ orderId: z.string(),
121
+ topic: z.literal('orders/create'),
122
+ }),
123
+ output: z.object({ ok: z.boolean() }),
124
+ triggers: [orderCreated],
125
+ run: async () => ({ ok: true }),
126
+ });
127
+ ```
128
+
129
+ ## Notes
130
+
131
+ - Mutating operations are marked with `needsApproval: true`.
132
+ - Shopify webhook helpers are direct-binding surfaces under `@keystrokehq/shopify/triggers`.
133
+ - Hidden `_official` and `_runtime` exports are for repo internals, not workflow authoring.
134
+
135
+ ## Live Test Runbook
136
+
137
+ The Shopify package now has dedicated `test:int` coverage for every exported operation plus live webhook subscription management:
138
+
139
+ - `shop.int.test.ts`
140
+ - `products.int.test.ts`
141
+ - `collections.int.test.ts`
142
+ - `customers.int.test.ts`
143
+ - `blogs.int.test.ts`
144
+ - `articles.int.test.ts`
145
+ - `orders.int.test.ts`
146
+ - `inventory.int.test.ts`
147
+ - `locations.int.test.ts`
148
+ - `fulfillments.int.test.ts`
149
+ - `webhook-management.int.test.ts`
150
+
151
+ Set up `.env.test` with at least:
152
+
153
+ - `RUN_LIVE_INT=true`
154
+ - `SHOPIFY_LIVE_STORE_DOMAIN`
155
+ - `SHOPIFY_LIVE_ACCESS_TOKEN`
156
+ - `SHOPIFY_LIVE_REFRESH_TOKEN` for control-plane refresh coverage
157
+ - `PUBLIC_SERVER_URL` for webhook subscription coverage
158
+ - `KEYSTROKE_PLATFORM_SHOPIFY_APP_ID`
159
+ - `KEYSTROKE_PLATFORM_SHOPIFY_CLIENT_ID`
160
+ - `KEYSTROKE_PLATFORM_SHOPIFY_CLIENT_SECRET`
161
+ - `KEYSTROKE_PLATFORM_SHOPIFY_WEBHOOK_SECRET`
162
+
163
+ Recommended execution flow:
164
+
165
+ ```bash
166
+ pnpm test:int:wiring
167
+ pnpm --filter @keystrokehq/shopify test:int
168
+ pnpm --filter @keystroke/server test:int
169
+ pnpm --filter @keystroke/control-plane test:int
170
+ ```
171
+
172
+ Operational guidance:
173
+
174
+ - Use a dedicated disposable dev store. `orders`, `inventory`, `fulfillments`, and webhook tests are destructive by design.
175
+ - Keep `PUBLIC_SERVER_URL` pointed at a real public tunnel or staging URL when exercising webhook subscription or OAuth callback flows.
176
+ - The package test helpers try to clean up created products, collections, blogs, articles, and order-free customers automatically.
177
+ - Orders with fulfillment history and customers with placed orders should be treated as disposable-store artifacts rather than shared-environment fixtures.
178
+ - Shopify webhook subscription management requires `read_webhooks` and `write_webhooks` scopes in addition to the Admin API scopes used by the operation surface.
@@ -0,0 +1,3 @@
1
+ import { i as shopifyOfficialIntegration, n as shopify, r as shopifyBundle, t as ShopifyCredentials } from "../integration-BwDBsGX-.mjs";
2
+ import { n as shopifyAppCredentialSet, r as shopifyPlatformProviderSeed, t as ShopifyAppCredentials } from "../provider-app-DHxVZI6q.mjs";
3
+ export { type ShopifyAppCredentials, type ShopifyCredentials, shopify, shopifyAppCredentialSet, shopifyBundle, shopifyOfficialIntegration, shopifyPlatformProviderSeed };
@@ -0,0 +1,3 @@
1
+ import { a as shopifyAppCredentialSet, n as shopifyBundle, o as shopifyPlatformProviderSeed, r as shopifyOfficialIntegration, t as shopify } from "../integration-BN3pjCz4.mjs";
2
+
3
+ export { shopify, shopifyAppCredentialSet, shopifyBundle, shopifyOfficialIntegration, shopifyPlatformProviderSeed };
@@ -0,0 +1,56 @@
1
+ import { t as ShopifyCredentials } from "../integration-BwDBsGX-.mjs";
2
+ import { z } from "zod";
3
+
4
+ //#region src/webhook-management.d.ts
5
+ declare const SHOPIFY_WEBHOOK_RUNTIME_DEFINITIONS: readonly [{
6
+ readonly eventTopic: "products/create";
7
+ readonly subscriptionTopic: "PRODUCTS_CREATE";
8
+ readonly path: "/shopify/products/create";
9
+ }, {
10
+ readonly eventTopic: "products/update";
11
+ readonly subscriptionTopic: "PRODUCTS_UPDATE";
12
+ readonly path: "/shopify/products/update";
13
+ }, {
14
+ readonly eventTopic: "products/delete";
15
+ readonly subscriptionTopic: "PRODUCTS_DELETE";
16
+ readonly path: "/shopify/products/delete";
17
+ }, {
18
+ readonly eventTopic: "orders/create";
19
+ readonly subscriptionTopic: "ORDERS_CREATE";
20
+ readonly path: "/shopify/orders/create";
21
+ }, {
22
+ readonly eventTopic: "orders/updated";
23
+ readonly subscriptionTopic: "ORDERS_UPDATED";
24
+ readonly path: "/shopify/orders/updated";
25
+ }, {
26
+ readonly eventTopic: "orders/cancelled";
27
+ readonly subscriptionTopic: "ORDERS_CANCELLED";
28
+ readonly path: "/shopify/orders/cancelled";
29
+ }, {
30
+ readonly eventTopic: "orders/fulfilled";
31
+ readonly subscriptionTopic: "ORDERS_FULFILLED";
32
+ readonly path: "/shopify/orders/fulfilled";
33
+ }];
34
+ declare const webhookSubscriptionSchema: z.ZodObject<{
35
+ id: z.ZodString;
36
+ topic: z.ZodEnum<{
37
+ PRODUCTS_CREATE: "PRODUCTS_CREATE";
38
+ PRODUCTS_UPDATE: "PRODUCTS_UPDATE";
39
+ PRODUCTS_DELETE: "PRODUCTS_DELETE";
40
+ ORDERS_CREATE: "ORDERS_CREATE";
41
+ ORDERS_UPDATED: "ORDERS_UPDATED";
42
+ ORDERS_CANCELLED: "ORDERS_CANCELLED";
43
+ ORDERS_FULFILLED: "ORDERS_FULFILLED";
44
+ }>;
45
+ uri: z.ZodString;
46
+ }, z.core.$strip>;
47
+ interface EnsureShopifyWebhookSubscriptionsResult {
48
+ readonly kept: readonly string[];
49
+ readonly created: readonly string[];
50
+ readonly deleted: readonly string[];
51
+ }
52
+ declare function buildShopifyWebhookCallbackUri(baseUrl: string, path: string): string;
53
+ declare function listShopifyWebhookSubscriptions(credentials: ShopifyCredentials): Promise<readonly z.infer<typeof webhookSubscriptionSchema>[]>;
54
+ declare function ensureShopifyWebhookSubscriptions(credentials: ShopifyCredentials, callbackBaseUrl: string): Promise<EnsureShopifyWebhookSubscriptionsResult>;
55
+ //#endregion
56
+ export { SHOPIFY_WEBHOOK_RUNTIME_DEFINITIONS, buildShopifyWebhookCallbackUri, ensureShopifyWebhookSubscriptions, listShopifyWebhookSubscriptions };
@@ -0,0 +1,3 @@
1
+ import { i as listShopifyWebhookSubscriptions, n as buildShopifyWebhookCallbackUri, r as ensureShopifyWebhookSubscriptions, t as SHOPIFY_WEBHOOK_RUNTIME_DEFINITIONS } from "../webhook-management-BmIxO0vr.mjs";
2
+
3
+ export { SHOPIFY_WEBHOOK_RUNTIME_DEFINITIONS, buildShopifyWebhookCallbackUri, ensureShopifyWebhookSubscriptions, listShopifyWebhookSubscriptions };
@@ -0,0 +1,174 @@
1
+ import { z } from "zod";
2
+ import * as _keystrokehq_core0 from "@keystrokehq/core";
3
+ import * as _keystrokehq_core_credential_set0 from "@keystrokehq/core/credential-set";
4
+
5
+ //#region src/articles.d.ts
6
+ declare const listArticles: _keystrokehq_core0.Operation<z.ZodObject<{
7
+ first: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
8
+ after: z.ZodOptional<z.ZodString>;
9
+ query: z.ZodOptional<z.ZodString>;
10
+ }, z.core.$strip>, z.ZodObject<{
11
+ nodes: z.ZodArray<z.ZodObject<{
12
+ id: z.ZodString;
13
+ title: z.ZodString;
14
+ handle: z.ZodString;
15
+ blog: z.ZodOptional<z.ZodNullable<z.ZodObject<{
16
+ id: z.ZodString;
17
+ title: z.ZodString;
18
+ handle: z.ZodString;
19
+ createdAt: z.ZodOptional<z.ZodISODateTime>;
20
+ updatedAt: z.ZodOptional<z.ZodISODateTime>;
21
+ commentPolicy: z.ZodOptional<z.ZodNullable<z.ZodString>>;
22
+ templateSuffix: z.ZodOptional<z.ZodNullable<z.ZodString>>;
23
+ }, z.core.$strip>>>;
24
+ author: z.ZodOptional<z.ZodNullable<z.ZodString>>;
25
+ body: z.ZodOptional<z.ZodNullable<z.ZodString>>;
26
+ summary: z.ZodOptional<z.ZodNullable<z.ZodString>>;
27
+ tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
28
+ image: z.ZodOptional<z.ZodNullable<z.ZodObject<{
29
+ url: z.ZodURL;
30
+ altText: z.ZodOptional<z.ZodNullable<z.ZodString>>;
31
+ }, z.core.$strip>>>;
32
+ publishedAt: z.ZodOptional<z.ZodNullable<z.ZodISODateTime>>;
33
+ updatedAt: z.ZodOptional<z.ZodISODateTime>;
34
+ }, z.core.$strip>>;
35
+ pageInfo: z.ZodObject<{
36
+ hasNextPage: z.ZodBoolean;
37
+ hasPreviousPage: z.ZodOptional<z.ZodBoolean>;
38
+ startCursor: z.ZodOptional<z.ZodNullable<z.ZodString>>;
39
+ endCursor: z.ZodNullable<z.ZodString>;
40
+ }, z.core.$strip>;
41
+ }, z.core.$strip>, readonly [_keystrokehq_core0.CredentialSet<"shopify", z.ZodObject<{
42
+ SHOPIFY_STORE_DOMAIN: z.ZodString;
43
+ SHOPIFY_ACCESS_TOKEN: z.ZodString;
44
+ }, z.core.$strip>, readonly _keystrokehq_core_credential_set0.CredentialConnection<z.ZodObject<{
45
+ SHOPIFY_STORE_DOMAIN: z.ZodString;
46
+ SHOPIFY_ACCESS_TOKEN: z.ZodString;
47
+ }, z.core.$strip>>[] | undefined>], undefined>;
48
+ declare const getArticle: _keystrokehq_core0.Operation<z.ZodObject<{
49
+ id: z.ZodString;
50
+ }, z.core.$strip>, z.ZodObject<{
51
+ id: z.ZodString;
52
+ title: z.ZodString;
53
+ handle: z.ZodString;
54
+ blog: z.ZodOptional<z.ZodNullable<z.ZodObject<{
55
+ id: z.ZodString;
56
+ title: z.ZodString;
57
+ handle: z.ZodString;
58
+ createdAt: z.ZodOptional<z.ZodISODateTime>;
59
+ updatedAt: z.ZodOptional<z.ZodISODateTime>;
60
+ commentPolicy: z.ZodOptional<z.ZodNullable<z.ZodString>>;
61
+ templateSuffix: z.ZodOptional<z.ZodNullable<z.ZodString>>;
62
+ }, z.core.$strip>>>;
63
+ author: z.ZodOptional<z.ZodNullable<z.ZodString>>;
64
+ body: z.ZodOptional<z.ZodNullable<z.ZodString>>;
65
+ summary: z.ZodOptional<z.ZodNullable<z.ZodString>>;
66
+ tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
67
+ image: z.ZodOptional<z.ZodNullable<z.ZodObject<{
68
+ url: z.ZodURL;
69
+ altText: z.ZodOptional<z.ZodNullable<z.ZodString>>;
70
+ }, z.core.$strip>>>;
71
+ publishedAt: z.ZodOptional<z.ZodNullable<z.ZodISODateTime>>;
72
+ updatedAt: z.ZodOptional<z.ZodISODateTime>;
73
+ }, z.core.$strip>, readonly [_keystrokehq_core0.CredentialSet<"shopify", z.ZodObject<{
74
+ SHOPIFY_STORE_DOMAIN: z.ZodString;
75
+ SHOPIFY_ACCESS_TOKEN: z.ZodString;
76
+ }, z.core.$strip>, readonly _keystrokehq_core_credential_set0.CredentialConnection<z.ZodObject<{
77
+ SHOPIFY_STORE_DOMAIN: z.ZodString;
78
+ SHOPIFY_ACCESS_TOKEN: z.ZodString;
79
+ }, z.core.$strip>>[] | undefined>], undefined>;
80
+ declare const createArticle: _keystrokehq_core0.Operation<z.ZodObject<{
81
+ handle: z.ZodOptional<z.ZodString>;
82
+ body: z.ZodOptional<z.ZodString>;
83
+ summary: z.ZodOptional<z.ZodString>;
84
+ authorName: z.ZodOptional<z.ZodString>;
85
+ isPublished: z.ZodOptional<z.ZodBoolean>;
86
+ publishDate: z.ZodOptional<z.ZodISODateTime>;
87
+ tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
88
+ blogId: z.ZodString;
89
+ title: z.ZodString;
90
+ }, z.core.$strip>, z.ZodObject<{
91
+ id: z.ZodString;
92
+ title: z.ZodString;
93
+ handle: z.ZodString;
94
+ blog: z.ZodOptional<z.ZodNullable<z.ZodObject<{
95
+ id: z.ZodString;
96
+ title: z.ZodString;
97
+ handle: z.ZodString;
98
+ createdAt: z.ZodOptional<z.ZodISODateTime>;
99
+ updatedAt: z.ZodOptional<z.ZodISODateTime>;
100
+ commentPolicy: z.ZodOptional<z.ZodNullable<z.ZodString>>;
101
+ templateSuffix: z.ZodOptional<z.ZodNullable<z.ZodString>>;
102
+ }, z.core.$strip>>>;
103
+ author: z.ZodOptional<z.ZodNullable<z.ZodString>>;
104
+ body: z.ZodOptional<z.ZodNullable<z.ZodString>>;
105
+ summary: z.ZodOptional<z.ZodNullable<z.ZodString>>;
106
+ tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
107
+ image: z.ZodOptional<z.ZodNullable<z.ZodObject<{
108
+ url: z.ZodURL;
109
+ altText: z.ZodOptional<z.ZodNullable<z.ZodString>>;
110
+ }, z.core.$strip>>>;
111
+ publishedAt: z.ZodOptional<z.ZodNullable<z.ZodISODateTime>>;
112
+ updatedAt: z.ZodOptional<z.ZodISODateTime>;
113
+ }, z.core.$strip>, readonly [_keystrokehq_core0.CredentialSet<"shopify", z.ZodObject<{
114
+ SHOPIFY_STORE_DOMAIN: z.ZodString;
115
+ SHOPIFY_ACCESS_TOKEN: z.ZodString;
116
+ }, z.core.$strip>, readonly _keystrokehq_core_credential_set0.CredentialConnection<z.ZodObject<{
117
+ SHOPIFY_STORE_DOMAIN: z.ZodString;
118
+ SHOPIFY_ACCESS_TOKEN: z.ZodString;
119
+ }, z.core.$strip>>[] | undefined>], undefined>;
120
+ declare const updateArticle: _keystrokehq_core0.Operation<z.ZodObject<{
121
+ blogId: z.ZodOptional<z.ZodString>;
122
+ title: z.ZodOptional<z.ZodString>;
123
+ handle: z.ZodOptional<z.ZodString>;
124
+ body: z.ZodOptional<z.ZodString>;
125
+ summary: z.ZodOptional<z.ZodString>;
126
+ authorName: z.ZodOptional<z.ZodString>;
127
+ isPublished: z.ZodOptional<z.ZodBoolean>;
128
+ publishDate: z.ZodOptional<z.ZodISODateTime>;
129
+ tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
130
+ id: z.ZodString;
131
+ redirectNewHandle: z.ZodOptional<z.ZodBoolean>;
132
+ }, z.core.$strip>, z.ZodObject<{
133
+ id: z.ZodString;
134
+ title: z.ZodString;
135
+ handle: z.ZodString;
136
+ blog: z.ZodOptional<z.ZodNullable<z.ZodObject<{
137
+ id: z.ZodString;
138
+ title: z.ZodString;
139
+ handle: z.ZodString;
140
+ createdAt: z.ZodOptional<z.ZodISODateTime>;
141
+ updatedAt: z.ZodOptional<z.ZodISODateTime>;
142
+ commentPolicy: z.ZodOptional<z.ZodNullable<z.ZodString>>;
143
+ templateSuffix: z.ZodOptional<z.ZodNullable<z.ZodString>>;
144
+ }, z.core.$strip>>>;
145
+ author: z.ZodOptional<z.ZodNullable<z.ZodString>>;
146
+ body: z.ZodOptional<z.ZodNullable<z.ZodString>>;
147
+ summary: z.ZodOptional<z.ZodNullable<z.ZodString>>;
148
+ tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
149
+ image: z.ZodOptional<z.ZodNullable<z.ZodObject<{
150
+ url: z.ZodURL;
151
+ altText: z.ZodOptional<z.ZodNullable<z.ZodString>>;
152
+ }, z.core.$strip>>>;
153
+ publishedAt: z.ZodOptional<z.ZodNullable<z.ZodISODateTime>>;
154
+ updatedAt: z.ZodOptional<z.ZodISODateTime>;
155
+ }, z.core.$strip>, readonly [_keystrokehq_core0.CredentialSet<"shopify", z.ZodObject<{
156
+ SHOPIFY_STORE_DOMAIN: z.ZodString;
157
+ SHOPIFY_ACCESS_TOKEN: z.ZodString;
158
+ }, z.core.$strip>, readonly _keystrokehq_core_credential_set0.CredentialConnection<z.ZodObject<{
159
+ SHOPIFY_STORE_DOMAIN: z.ZodString;
160
+ SHOPIFY_ACCESS_TOKEN: z.ZodString;
161
+ }, z.core.$strip>>[] | undefined>], undefined>;
162
+ declare const deleteArticle: _keystrokehq_core0.Operation<z.ZodObject<{
163
+ id: z.ZodString;
164
+ }, z.core.$strip>, z.ZodObject<{
165
+ deletedArticleId: z.ZodString;
166
+ }, z.core.$strip>, readonly [_keystrokehq_core0.CredentialSet<"shopify", z.ZodObject<{
167
+ SHOPIFY_STORE_DOMAIN: z.ZodString;
168
+ SHOPIFY_ACCESS_TOKEN: z.ZodString;
169
+ }, z.core.$strip>, readonly _keystrokehq_core_credential_set0.CredentialConnection<z.ZodObject<{
170
+ SHOPIFY_STORE_DOMAIN: z.ZodString;
171
+ SHOPIFY_ACCESS_TOKEN: z.ZodString;
172
+ }, z.core.$strip>>[] | undefined>], undefined>;
173
+ //#endregion
174
+ export { createArticle, deleteArticle, getArticle, listArticles, updateArticle };
@@ -0,0 +1,252 @@
1
+ import { shopifyArticleSchema, shopifyConnectionNodesSchema, shopifyGlobalIdSchema, shopifyUserErrorSchema } from "./schemas.mjs";
2
+ import { createShopifyClient } from "./client.mjs";
3
+ import { t as shopifyOperation } from "./factory-DC-gY8L0.mjs";
4
+ import { n as omitUndefined, r as shopifyPageInputSchema, t as assertNoUserErrors } from "./operation-helpers-CKEDIx0o.mjs";
5
+ import { z } from "zod";
6
+
7
+ //#region src/articles.ts
8
+ const articleSelection = `
9
+ id
10
+ title
11
+ handle
12
+ blog {
13
+
14
+ id
15
+ title
16
+ handle
17
+ createdAt
18
+ updatedAt
19
+ commentPolicy
20
+ templateSuffix
21
+
22
+ }
23
+ author {
24
+ name
25
+ }
26
+ body
27
+ summary
28
+ tags
29
+ image {
30
+ url
31
+ altText
32
+ }
33
+ publishedAt
34
+ updatedAt
35
+ `;
36
+ const articleMutationInputSchema = z.object({
37
+ blogId: shopifyGlobalIdSchema.optional(),
38
+ title: z.string().min(1).optional(),
39
+ handle: z.string().min(1).optional(),
40
+ body: z.string().optional(),
41
+ summary: z.string().optional(),
42
+ authorName: z.string().optional(),
43
+ isPublished: z.boolean().optional(),
44
+ publishDate: z.iso.datetime().optional(),
45
+ tags: z.array(z.string()).optional()
46
+ });
47
+ const articleResponseSchema = z.object({
48
+ id: shopifyGlobalIdSchema,
49
+ title: z.string(),
50
+ handle: z.string(),
51
+ blog: z.object({
52
+ id: shopifyGlobalIdSchema,
53
+ title: z.string(),
54
+ handle: z.string(),
55
+ createdAt: z.iso.datetime().optional(),
56
+ updatedAt: z.iso.datetime().optional(),
57
+ commentPolicy: z.string().nullable().optional(),
58
+ templateSuffix: z.string().nullable().optional()
59
+ }).nullable().optional(),
60
+ author: z.object({ name: z.string().nullable().optional() }).nullable().optional(),
61
+ body: z.string().nullable().optional(),
62
+ summary: z.string().nullable().optional(),
63
+ tags: z.array(z.string()).optional(),
64
+ image: z.object({
65
+ url: z.url(),
66
+ altText: z.string().nullable().optional()
67
+ }).nullable().optional(),
68
+ publishedAt: z.iso.datetime().nullable().optional(),
69
+ updatedAt: z.iso.datetime().optional()
70
+ });
71
+ const articleMutationPayloadSchema = z.object({
72
+ article: articleResponseSchema.nullable(),
73
+ userErrors: z.array(shopifyUserErrorSchema.extend({ code: z.string().optional() }))
74
+ });
75
+ const listArticlesResponseSchema = z.object({ articles: shopifyConnectionNodesSchema(articleResponseSchema) });
76
+ const getArticleResponseSchema = z.object({ article: articleResponseSchema.nullable() });
77
+ const deleteArticleResponseSchema = z.object({
78
+ deletedArticleId: shopifyGlobalIdSchema.nullable(),
79
+ userErrors: z.array(shopifyUserErrorSchema.extend({ code: z.string().optional() }))
80
+ });
81
+ function normalizeArticle(article) {
82
+ return {
83
+ id: article.id,
84
+ title: article.title,
85
+ handle: article.handle,
86
+ blog: article.blog ?? null,
87
+ author: article.author?.name ?? null,
88
+ body: article.body ?? null,
89
+ summary: article.summary ?? null,
90
+ tags: article.tags,
91
+ image: article.image ?? null,
92
+ publishedAt: article.publishedAt ?? null,
93
+ updatedAt: article.updatedAt
94
+ };
95
+ }
96
+ function buildArticleInput(input) {
97
+ return omitUndefined({
98
+ blogId: input.blogId,
99
+ title: input.title,
100
+ handle: input.handle,
101
+ body: input.body,
102
+ summary: input.summary,
103
+ author: input.authorName ? { name: input.authorName } : void 0,
104
+ isPublished: input.isPublished,
105
+ publishDate: input.publishDate,
106
+ tags: input.tags
107
+ });
108
+ }
109
+ const listArticles = shopifyOperation({
110
+ id: "list_shopify_articles",
111
+ name: "List Shopify Articles",
112
+ description: "List blog articles from the connected Shopify store.",
113
+ input: shopifyPageInputSchema,
114
+ output: shopifyConnectionNodesSchema(shopifyArticleSchema),
115
+ run: async (input, credentials) => {
116
+ const response = await createShopifyClient(credentials).graphql(`
117
+ query ListArticles($first: Int!, $after: String, $query: String) {
118
+ articles(first: $first, after: $after, query: $query) {
119
+ nodes {
120
+ ${articleSelection}
121
+ }
122
+ pageInfo {
123
+ hasNextPage
124
+ hasPreviousPage
125
+ startCursor
126
+ endCursor
127
+ }
128
+ }
129
+ }
130
+ `, listArticlesResponseSchema, { variables: {
131
+ first: input.first,
132
+ ...input.after ? { after: input.after } : {},
133
+ ...input.query ? { query: input.query } : {}
134
+ } });
135
+ return {
136
+ nodes: response.articles.nodes.map(normalizeArticle),
137
+ pageInfo: response.articles.pageInfo
138
+ };
139
+ }
140
+ });
141
+ const getArticle = shopifyOperation({
142
+ id: "get_shopify_article",
143
+ name: "Get Shopify Article",
144
+ description: "Retrieve a single Shopify article by its global ID.",
145
+ input: z.object({ id: shopifyGlobalIdSchema }),
146
+ output: shopifyArticleSchema,
147
+ run: async (input, credentials) => {
148
+ const response = await createShopifyClient(credentials).graphql(`
149
+ query GetArticle($id: ID!) {
150
+ article(id: $id) {
151
+ ${articleSelection}
152
+ }
153
+ }
154
+ `, getArticleResponseSchema, { variables: { id: input.id } });
155
+ if (!response.article) throw new Error(`Shopify article not found: ${input.id}`);
156
+ return normalizeArticle(response.article);
157
+ }
158
+ });
159
+ const createArticle = shopifyOperation({
160
+ id: "create_shopify_article",
161
+ name: "Create Shopify Article",
162
+ description: "Create an article in the connected Shopify store.",
163
+ needsApproval: true,
164
+ input: articleMutationInputSchema.extend({
165
+ blogId: shopifyGlobalIdSchema,
166
+ title: z.string().min(1)
167
+ }),
168
+ output: shopifyArticleSchema,
169
+ run: async (input, credentials) => {
170
+ const response = await createShopifyClient(credentials).graphql(`
171
+ mutation CreateArticle($article: ArticleCreateInput!) {
172
+ articleCreate(article: $article) {
173
+ article {
174
+ ${articleSelection}
175
+ }
176
+ userErrors {
177
+ code
178
+ field
179
+ message
180
+ }
181
+ }
182
+ }
183
+ `, z.object({ articleCreate: articleMutationPayloadSchema }), { variables: { article: buildArticleInput(input) } });
184
+ assertNoUserErrors(response.articleCreate.userErrors);
185
+ if (!response.articleCreate.article) throw new Error("Shopify did not return the created article.");
186
+ return normalizeArticle(response.articleCreate.article);
187
+ }
188
+ });
189
+ const updateArticle = shopifyOperation({
190
+ id: "update_shopify_article",
191
+ name: "Update Shopify Article",
192
+ description: "Update a Shopify article by its global ID.",
193
+ needsApproval: true,
194
+ input: articleMutationInputSchema.extend({
195
+ id: shopifyGlobalIdSchema,
196
+ redirectNewHandle: z.boolean().optional()
197
+ }),
198
+ output: shopifyArticleSchema,
199
+ run: async (input, credentials) => {
200
+ const response = await createShopifyClient(credentials).graphql(`
201
+ mutation UpdateArticle($id: ID!, $article: ArticleUpdateInput!) {
202
+ articleUpdate(id: $id, article: $article) {
203
+ article {
204
+ ${articleSelection}
205
+ }
206
+ userErrors {
207
+ code
208
+ field
209
+ message
210
+ }
211
+ }
212
+ }
213
+ `, z.object({ articleUpdate: articleMutationPayloadSchema }), { variables: {
214
+ id: input.id,
215
+ article: omitUndefined({
216
+ ...buildArticleInput(input),
217
+ redirectNewHandle: input.redirectNewHandle
218
+ })
219
+ } });
220
+ assertNoUserErrors(response.articleUpdate.userErrors);
221
+ if (!response.articleUpdate.article) throw new Error(`Shopify did not return the updated article: ${input.id}`);
222
+ return normalizeArticle(response.articleUpdate.article);
223
+ }
224
+ });
225
+ const deleteArticle = shopifyOperation({
226
+ id: "delete_shopify_article",
227
+ name: "Delete Shopify Article",
228
+ description: "Delete a Shopify article by its global ID.",
229
+ needsApproval: true,
230
+ input: z.object({ id: shopifyGlobalIdSchema }),
231
+ output: z.object({ deletedArticleId: shopifyGlobalIdSchema }),
232
+ run: async (input, credentials) => {
233
+ const response = await createShopifyClient(credentials).graphql(`
234
+ mutation DeleteArticle($id: ID!) {
235
+ articleDelete(id: $id) {
236
+ deletedArticleId
237
+ userErrors {
238
+ code
239
+ field
240
+ message
241
+ }
242
+ }
243
+ }
244
+ `, z.object({ articleDelete: deleteArticleResponseSchema }), { variables: { id: input.id } });
245
+ assertNoUserErrors(response.articleDelete.userErrors);
246
+ if (!response.articleDelete.deletedArticleId) throw new Error(`Shopify did not confirm article deletion: ${input.id}`);
247
+ return { deletedArticleId: response.articleDelete.deletedArticleId };
248
+ }
249
+ });
250
+
251
+ //#endregion
252
+ export { createArticle, deleteArticle, getArticle, listArticles, updateArticle };