SDK: Fixes issue with PING response

CLI: improves how the dev command handles register errors, also doesn’t create a tunnel when hitting local trigger.dev, and improves the dev command output
This commit is contained in:
Eric Allam
2023-07-03 15:33:44 +01:00
parent 612b016a15
commit 6c86946614
11 changed files with 110 additions and 91 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"@trigger.dev/cli": patch
---
[dev] Better handle errors when registering endpoint
+5
View File
@@ -0,0 +1,5 @@
---
"@trigger.dev/sdk": patch
---
Fixed responses from the PING action to match expected schema
+2 -2
View File
@@ -20,8 +20,8 @@
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"tailwindcss": "3.3.2", "tailwindcss": "3.3.2",
"typescript": "5.1.6", "typescript": "5.1.6",
"@trigger.dev/sdk": "^2.0.0-next.4", "@trigger.dev/sdk": "workspace:*",
"@trigger.dev/nextjs": "^1.0.0-next.5" "@trigger.dev/nextjs": "workspace:*"
}, },
"devDependencies": { "devDependencies": {
"@trigger.dev/cli": "workspace:*" "@trigger.dev/cli": "workspace:*"
@@ -23,6 +23,4 @@ new Job(client, {
}, },
}); });
export const { POST, dynamic } = createAppRoute(client, { export const { POST, dynamic } = createAppRoute(client);
path: "/api/trigger",
});
+3 -1
View File
@@ -1,6 +1,8 @@
import { authMiddleware } from "@clerk/nextjs"; import { authMiddleware } from "@clerk/nextjs";
export default authMiddleware(); export default authMiddleware({
publicRoutes: ["/api/trigger"],
});
export const config = { export const config = {
matcher: ["/((?!.*\\..*|_next).*)", "/", "/(api|trpc)(.*)"], matcher: ["/((?!.*\\..*|_next).*)", "/", "/(api|trpc)(.*)"],
+21 -1
View File
@@ -20,7 +20,27 @@
} }
], ],
"paths": { "paths": {
"@/*": ["./src/*"] "@/*": ["./src/*"],
"@trigger.dev/sdk": ["../../packages/trigger-sdk/src/index"],
"@trigger.dev/sdk/*": ["../../packages/trigger-sdk/src/*"],
"@trigger.dev/nextjs": ["../../packages/nextjs/src/index"],
"@trigger.dev/nextjs/*": ["../../packages/nextjs/src/*"],
"@trigger.dev/internal": ["../../packages/internal/src/index"],
"@trigger.dev/internal/*": ["../../packages/internal/src/*"],
"@trigger.dev/integration-kit": [
"../../packages/integration-kit/src/index"
],
"@trigger.dev/integration-kit/*": [
"../../packages/integration-kit/src/*"
],
"@trigger.dev/github": ["../../integrations/github/src/index"],
"@trigger.dev/github/*": ["../../integrations/github/src/*"],
"@trigger.dev/slack": ["../../integrations/slack/src/index"],
"@trigger.dev/slack/*": ["../../integrations/slack/src/*"],
"@trigger.dev/openai": ["../../integrations/openai/src/index"],
"@trigger.dev/openai/*": ["../../integrations/openai/src/*"],
"@trigger.dev/resend": ["../../integrations/resend/src/index"],
"@trigger.dev/resend/*": ["../../integrations/resend/src/*"]
} }
}, },
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
+58 -27
View File
@@ -17,9 +17,6 @@ export const DevCommandOptionsSchema = z.object({
const throttleTimeMs = 1000; const throttleTimeMs = 1000;
const formattedDate = new Intl.DateTimeFormat("en", { const formattedDate = new Intl.DateTimeFormat("en", {
year: "numeric",
month: "short",
day: "numeric",
hour: "numeric", hour: "numeric",
minute: "numeric", minute: "numeric",
second: "numeric", second: "numeric",
@@ -42,7 +39,7 @@ export async function devCommand(path: string, anyOptions: any) {
); );
process.exit(1); process.exit(1);
} }
logger.success(`✔️ Detected valid Next.js project`); logger.success(`✔️ [trigger.dev] Detected valid Next.js project`);
// Read from package.json to get the endpointId // Read from package.json to get the endpointId
const endpointId = await getEndpointIdFromPackageJson(resolvedPath); const endpointId = await getEndpointIdFromPackageJson(resolvedPath);
@@ -52,40 +49,51 @@ export async function devCommand(path: string, anyOptions: any) {
); );
process.exit(1); process.exit(1);
} }
logger.success(`✔️ Detected TriggerClient id: ${endpointId}`); logger.success(`✔️ [trigger.dev] Detected TriggerClient id: ${endpointId}`);
// Read from .env.local to get the TRIGGER_API_KEY and TRIGGER_API_URL
const { apiUrl } = await getTriggerApiDetails(resolvedPath, options.envFile);
logger.success(`✔️ [trigger.dev] Found API Key in ${options.envFile} file`);
// Setup tunnel
const endpointUrl = await resolveEndpointUrl(apiUrl, options.port);
const connectingSpinner = ora(
`[trigger.dev] Connecting to Trigger.dev...`
).start();
//refresh function
let attemptCount = 0;
const refresh = async () => {
const refreshedEndpointId = await getEndpointIdFromPackageJson(
resolvedPath
);
// Read from .env.local to get the TRIGGER_API_KEY and TRIGGER_API_URL // Read from .env.local to get the TRIGGER_API_KEY and TRIGGER_API_URL
const { apiKey, apiUrl } = await getTriggerApiDetails( const { apiKey, apiUrl } = await getTriggerApiDetails(
resolvedPath, resolvedPath,
options.envFile options.envFile
); );
logger.success(`✔️ Found API Key in ${options.envFile} file`);
const apiClient = new TriggerApi(apiKey, apiUrl); const apiClient = new TriggerApi(apiKey, apiUrl);
// Setup tunnel const result = await refreshEndpoint(
const tunnelSpinner = ora(`🚇 Creating tunnel`).start(); apiClient,
const tunnelUrl = await createTunnel(options.port); refreshedEndpointId ?? endpointId,
tunnelSpinner.succeed(`🚇 Created tunnel: ${tunnelUrl}`); endpointUrl
);
const connectingSpinner = ora(`Connecting to Trigger.dev...`).start();
//refresh function
let attemptCount = 0;
const refresh = async () => {
const result = await refreshEndpoint(apiClient, endpointId, tunnelUrl);
if (result.success) { if (result.success) {
attemptCount = 0; attemptCount = 0;
connectingSpinner.stop(); connectingSpinner.succeed(
logger.success( `[trigger.dev] 🔄 Refreshed ${
`🔄 Updated your Jobs ${formattedDate.format( refreshedEndpointId ?? endpointId
new Date(result.data.updatedAt) } ${formattedDate.format(new Date(result.data.updatedAt))}`
)}`
); );
} else { } else {
attemptCount++; attemptCount++;
if (attemptCount === 10) { if (attemptCount === 10 || !result.retryable) {
logger.error(`🚨 Failed to connect: ${result.error}`); connectingSpinner.fail(`🚨 Failed to connect: ${result.error}`);
logger.info(`Will attempt again on the next file change…`); logger.info(`Will attempt again on the next file change…`);
return; return;
} }
@@ -169,6 +177,21 @@ async function getTriggerApiDetails(path: string, envFile: string) {
return { apiKey, apiUrl }; return { apiKey, apiUrl };
} }
async function resolveEndpointUrl(apiUrl: string, port: number) {
const apiURL = new URL(apiUrl);
if (apiURL.hostname === "localhost") {
return `http://localhost:${port}`;
}
// Setup tunnel
const tunnelSpinner = ora(`🚇 Creating tunnel`).start();
const tunnelUrl = await createTunnel(port);
tunnelSpinner.succeed(`🚇 Created tunnel: ${tunnelUrl}`);
return tunnelUrl;
}
async function createTunnel(port: number) { async function createTunnel(port: number) {
try { try {
return await ngrok.connect(port); return await ngrok.connect(port);
@@ -190,15 +213,23 @@ async function refreshEndpoint(
}); });
if (!response.ok) { if (!response.ok) {
return { success: false as const, error: response.error }; return {
success: false as const,
error: response.error,
retryable: response.retryable,
};
} }
return { success: true as const, data: response.data }; return { success: true as const, data: response.data };
} catch (e) { } catch (e) {
if (e instanceof Error) { if (e instanceof Error) {
return { success: false as const, error: e.message }; return { success: false as const, error: e.message, retryable: true };
} else { } else {
return { success: false as const, error: "Unknown error" }; return {
success: false as const,
error: "Unknown error",
retryable: true,
};
} }
} }
} }
+1 -1
View File
@@ -139,7 +139,7 @@ async function printNextSteps(
logger.info("Next steps:"); logger.info("Next steps:");
logger.info(` 1. Run your Next.js project locally with 'npm run dev'`); logger.info(` 1. Run your Next.js project locally with 'npm run dev'`);
logger.info( logger.info(
` 2. Run 'npx @trigger.dev/cli dev' to watch for changes and automatically register Trigger.dev jobs` ` 2. Run 'npx @trigger.dev/cli@latest dev' to watch for changes and automatically register Trigger.dev jobs`
); );
logger.info(` 3. View your jobs at ${projectUrl}`); logger.info(` 3. View your jobs at ${projectUrl}`);
+9 -3
View File
@@ -23,7 +23,9 @@ export type EndpointResponse =
ok: true; ok: true;
data: EndpointData; data: EndpointData;
} }
| { ok: false; error: string }; | { ok: false; error: string; retryable: boolean };
const RETRYABLE_PATTERN = /Could not connect to endpoint/i;
const WhoamiResponseSchema = z.object({ const WhoamiResponseSchema = z.object({
id: z.string(), id: z.string(),
@@ -97,27 +99,31 @@ export class TriggerApi {
ok: false, ok: false,
error: error:
"An unknown issue occurred when registering with Trigger.dev", "An unknown issue occurred when registering with Trigger.dev",
retryable: true,
}; };
} }
const parsedJson = z.object({ message: z.string() }).safeParse(rawJson); const parsedJson = z.object({ error: z.string() }).safeParse(rawJson);
if (!parsedJson.success) { if (!parsedJson.success) {
return { return {
ok: false, ok: false,
error: error:
"An unknown issue occurred when registering with Trigger.dev", "An unknown issue occurred when registering with Trigger.dev",
retryable: true,
}; };
} }
return { return {
ok: false, ok: false,
error: parsedJson.data.message, error: parsedJson.data.error,
retryable: RETRYABLE_PATTERN.test(parsedJson.data.error),
}; };
} else { } else {
return { return {
ok: false, ok: false,
error: "An unknown issue occurred when registering with Trigger.dev", error: "An unknown issue occurred when registering with Trigger.dev",
retryable: true,
}; };
} }
} }
+2 -2
View File
@@ -160,7 +160,7 @@ export class TriggerClient {
status: 200, status: 200,
body: { body: {
ok: false, ok: false,
message: "Missing endpoint ID", error: "Missing endpoint ID",
}, },
}; };
} }
@@ -170,7 +170,7 @@ export class TriggerClient {
status: 200, status: 200,
body: { body: {
ok: false, ok: false,
message: `Endpoint ID mismatch error. Expected ${this.id}, got ${endpointId}`, error: `Endpoint ID mismatch error. Expected ${this.id}, got ${endpointId}`,
}, },
}; };
} }
+4 -52
View File
@@ -462,8 +462,8 @@ importers:
specifiers: specifiers:
'@clerk/nextjs': ^4.21.12 '@clerk/nextjs': ^4.21.12
'@trigger.dev/cli': workspace:* '@trigger.dev/cli': workspace:*
'@trigger.dev/nextjs': ^1.0.0-next.5 '@trigger.dev/nextjs': workspace:*
'@trigger.dev/sdk': ^2.0.0-next.4 '@trigger.dev/sdk': workspace:*
'@types/node': 20.3.2 '@types/node': 20.3.2
'@types/react': ^18.0.21 '@types/react': ^18.0.21
'@types/react-dom': ^18.0.6 '@types/react-dom': ^18.0.6
@@ -476,8 +476,8 @@ importers:
typescript: 5.1.6 typescript: 5.1.6
dependencies: dependencies:
'@clerk/nextjs': 4.21.12_5v7kwk6wz2hvmegftnptprfjvm '@clerk/nextjs': 4.21.12_5v7kwk6wz2hvmegftnptprfjvm
'@trigger.dev/nextjs': 1.0.0-next.5_yuyr3hquo7tgjdmhxnzkuafg3m '@trigger.dev/nextjs': link:../../packages/nextjs
'@trigger.dev/sdk': 2.0.0-next.5 '@trigger.dev/sdk': link:../../packages/trigger-sdk
'@types/node': 20.3.2 '@types/node': 20.3.2
'@types/react': 18.0.26 '@types/react': 18.0.26
'@types/react-dom': 18.0.10 '@types/react-dom': 18.0.10
@@ -10694,46 +10694,6 @@ packages:
react-dom: 18.2.0_react@18.2.0 react-dom: 18.2.0_react@18.2.0
dev: false dev: false
/@trigger.dev/nextjs/1.0.0-next.5_yuyr3hquo7tgjdmhxnzkuafg3m:
resolution: {integrity: sha512-41/RvyfuR3cPDCKAAhWOJMNw3KgA9uho7vcg8Q0ri8NCObsvxbStpnb5lpvNsUVOTyB7qy3tHULVJhKANczQqQ==}
engines: {node: '>=18'}
peerDependencies:
'@trigger.dev/sdk': ^2.0.0-next.2
next: ^13.3.1
dependencies:
'@trigger.dev/sdk': 2.0.0-next.5
debug: 4.3.4
next: 13.4.7_biqbaboplfbrettd7655fr4n2y
transitivePeerDependencies:
- supports-color
dev: false
/@trigger.dev/sdk/2.0.0-next.5:
resolution: {integrity: sha512-ERnhWSiWSO1sOkKVZfFP+bmbDOtgyviahY7tVP/8LD0cJb/uz5zSufcqHRHhVCXU423u24tJcYYJcXKNyoSmHQ==}
engines: {node: '>=18'}
dependencies:
chalk: 5.2.0
debug: 4.3.4
evt: 2.4.13
get-caller-file: 2.0.5
git-remote-origin-url: 4.0.0
git-repo-info: 2.1.1
node-fetch: 2.6.11
slug: 6.1.0
terminal-link: 3.0.0
ulid: 2.3.0
uuid: 9.0.0
ws: 8.12.0
zod: 3.21.4
zod-error: 1.1.0
zod-to-json-schema: 3.20.2_zod@3.21.4
transitivePeerDependencies:
- bufferutil
- encoding
- supports-color
- utf-8-validate
dev: false
/@tsconfig/node10/1.0.9: /@tsconfig/node10/1.0.9:
resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==} resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==}
@@ -25800,14 +25760,6 @@ packages:
zod: 3.20.2 zod: 3.20.2
dev: false dev: false
/zod-to-json-schema/3.20.2_zod@3.21.4:
resolution: {integrity: sha512-qka3UAXmVXD8z5SHkRU89UyHp8JHJW7zc8RQCpt7QloJOn6uijwkjUm8o+M/cF1IysmKc5gxac/QeDikaQMdzQ==}
peerDependencies:
zod: ^3.20.0
dependencies:
zod: 3.21.4
dev: false
/zod/3.20.2: /zod/3.20.2:
resolution: {integrity: sha512-1MzNQdAvO+54H+EaK5YpyEy0T+Ejo/7YLHS93G3RnYWh5gaotGHwGeN/ZO687qEDU2y4CdStQYXVHIgrUl5UVQ==} resolution: {integrity: sha512-1MzNQdAvO+54H+EaK5YpyEy0T+Ejo/7YLHS93G3RnYWh5gaotGHwGeN/ZO687qEDU2y4CdStQYXVHIgrUl5UVQ==}
dev: false dev: false