Improvement: Added more context to Shopify webhook registering errors (#1090)
* Improvement: Added more context to Shopify webhook registering errors Co-authored-by: Ahmed Ramadan <ahmedramadan1337@gmail.com> * revert: shopify reference jobs * fix: added error handling to some shopify client edge cases * small changes to crud error handling --------- Co-authored-by: Ahmed Ramadan <ahmedramadan1337@gmail.com> Co-authored-by: nicktrn <55853254+nicktrn@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/shopify": patch
|
||||
---
|
||||
|
||||
improved error messages when a shopify webhook fails to register
|
||||
@@ -63,8 +63,30 @@ export class Shopify implements TriggerIntegration {
|
||||
throw `Can't create Shopify integration (${options.id}) as apiKey was undefined`;
|
||||
}
|
||||
|
||||
if (Object.keys(options).includes("apiSecretKey") && !options.apiSecretKey) {
|
||||
throw `Can't create Shopify integration (${options.id}) as apiSecretKey was undefined`;
|
||||
}
|
||||
|
||||
if (Object.keys(options).includes("adminAccessToken") && !options.adminAccessToken) {
|
||||
throw `Can't create Shopify integration (${options.id}) as adminAccessToken was undefined`;
|
||||
}
|
||||
|
||||
if (Object.keys(options).includes("hostName") && !options.hostName) {
|
||||
throw `Can't create Shopify integration (${options.id}) as hostName was undefined`;
|
||||
}
|
||||
|
||||
this._options = options;
|
||||
this._shopDomain = this._options.hostName.replace("http://", "").replace("https://", "");
|
||||
// Extract the shop domain if user has entered the full URL
|
||||
this._shopDomain = this._options.hostName
|
||||
.replace(/^https?:\/\//, "") // Remove http:// or https://
|
||||
.replace(/\/$/, ""); // Remove trailing slash if it exists (e.g. `example.myshopify.com/`)
|
||||
|
||||
// Regular expression to ensure the shopDomain is a valid `.myshopify.com` domain
|
||||
const shopifyDomainPattern = /^[a-zA-Z0-9-]+\.myshopify\.com$/;
|
||||
|
||||
if (!shopifyDomainPattern.test(this._shopDomain)) {
|
||||
throw `Can't create Shopify integration (${options.id}) because hostName should be a valid ".myshopify.com" domain, not a custom primary domain. For example: my-domain.myshopify.com`;
|
||||
}
|
||||
}
|
||||
|
||||
get authSource() {
|
||||
|
||||
@@ -86,21 +86,36 @@ export function createWebhookEventSource(integration: Shopify) {
|
||||
key: (params) => params.topic,
|
||||
crud: {
|
||||
create: async ({ io, ctx }) => {
|
||||
const webhook = await io.integration.rest.Webhook.save("create-webhook", {
|
||||
fromData: {
|
||||
address: ctx.url,
|
||||
topic: ctx.params.topic,
|
||||
// fields: ctx.params.fields,
|
||||
},
|
||||
});
|
||||
try {
|
||||
const webhook = await io.integration.rest.Webhook.save("create-webhook", {
|
||||
fromData: {
|
||||
address: ctx.url,
|
||||
topic: ctx.params.topic,
|
||||
// fields: ctx.params.fields,
|
||||
},
|
||||
});
|
||||
|
||||
const clientSecret = await io.integration.runTask(
|
||||
"get-client-secret",
|
||||
async (client) => client.config.apiSecretKey
|
||||
);
|
||||
if (!webhook.id) {
|
||||
throw new Error(
|
||||
"Failed to create webhook. Ensure your Shopfiy client configuration is correct. Have you set the correct access scopes? Are you using the primary myshopify.com domain?"
|
||||
);
|
||||
}
|
||||
|
||||
await io.store.job.set("set-id", "webhook-id", webhook.id);
|
||||
await io.store.job.set("set-secret", "webhook-secret", clientSecret);
|
||||
const clientSecret = await io.integration.runTask(
|
||||
"get-client-secret",
|
||||
async (client) => client.config.apiSecretKey
|
||||
);
|
||||
|
||||
await io.store.job.set("set-id", "webhook-id", webhook.id);
|
||||
await io.store.job.set("set-secret", "webhook-secret", clientSecret);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
await io.logger.error(`Failed to create webhook: ${error.message}`);
|
||||
} else {
|
||||
await io.logger.error("Failed to create webhook", { rawError: error });
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
delete: async ({ io, ctx }) => {
|
||||
const webhookId = await io.store.job.get<number>("get-webhook-id", "webhook-id");
|
||||
@@ -109,23 +124,41 @@ export function createWebhookEventSource(integration: Shopify) {
|
||||
throw new Error("Missing webhook ID for delete operation.");
|
||||
}
|
||||
|
||||
await io.integration.rest.Webhook.delete("delete-webhook", {
|
||||
id: webhookId,
|
||||
});
|
||||
try {
|
||||
await io.integration.rest.Webhook.delete("delete-webhook", {
|
||||
id: webhookId,
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
await io.logger.error(`Failed to delete webhook: ${error.message}`);
|
||||
} else {
|
||||
await io.logger.error("Failed to delete webhook", { rawError: error });
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
||||
await io.store.job.delete("delete-webhook-id", "webhook-id");
|
||||
},
|
||||
update: async ({ io, ctx }) => {
|
||||
const webhookId = await io.store.job.get<number>("get-webhook-id", "webhook-id");
|
||||
|
||||
await io.integration.rest.Webhook.save("update-webhook", {
|
||||
fromData: {
|
||||
id: webhookId,
|
||||
address: ctx.url,
|
||||
topic: ctx.params.topic,
|
||||
// fields: ctx.params.fields,
|
||||
},
|
||||
});
|
||||
try {
|
||||
await io.integration.rest.Webhook.save("update-webhook", {
|
||||
fromData: {
|
||||
id: webhookId,
|
||||
address: ctx.url,
|
||||
topic: ctx.params.topic,
|
||||
// fields: ctx.params.fields,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
await io.logger.error(`Failed to update webhook: ${error.message}`);
|
||||
} else {
|
||||
await io.logger.error("Failed to update webhook", { rawError: error });
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
},
|
||||
verify: async ({ request, client, ctx }) => {
|
||||
|
||||
Reference in New Issue
Block a user