Skip to content

Commit 6d9dfbc

Browse files
committed
Add configure function to be able to configure the SDK manually
And move the ApiClient configuration away from AsyncLocalStorage and use our globals system instead
1 parent 6406924 commit 6d9dfbc

File tree

12 files changed

+149
-56
lines changed

12 files changed

+149
-56
lines changed

.changeset/pink-pumas-rhyme.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@trigger.dev/sdk": patch
3+
"@trigger.dev/core": patch
4+
---
5+
6+
Add configure function to be able to configure the SDK manually

apps/webapp/app/v3/services/upsertTaskSchedule.server.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,15 @@ export class UpsertTaskScheduleService extends BaseService {
5151
});
5252

5353
if (!task) {
54-
throw new Error(`Task with identifier ${schedule.taskIdentifier} not found in project.`);
54+
throw new ServiceValidationError(
55+
`Task with identifier ${schedule.taskIdentifier} not found in project.`
56+
);
5557
}
5658

5759
if (task.triggerSource !== "SCHEDULED") {
58-
throw new Error(`Task with identifier ${schedule.taskIdentifier} is not a scheduled task.`);
60+
throw new ServiceValidationError(
61+
`Task with identifier ${schedule.taskIdentifier} is not a scheduled task.`
62+
);
5963
}
6064

6165
const result = await $transaction(this._prisma, async (tx) => {

docs/v3/apikeys.mdx

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,37 @@ When you [trigger a task](/v3/triggering) from your backend code, you need to se
1010
Each environment has its own secret key. You can find the value on the API keys page in the Trigger.dev dashboard:
1111

1212
![How to find your secret key](/images/v3/api-keys.png)
13+
14+
### Automatically Configuring the SDK
15+
16+
To automatically configure the SDK with your secret key, you can set the `TRIGGER_SECRET_KEY` environment variable. The SDK will automatically use this value when calling API methods (like `trigger`).
17+
18+
```bash
19+
export TRIGGER_SECRET_KEY=tr_dev_…
20+
```
21+
22+
You can do the same if you are self-hosting and need to change the default URL by using `TRIGGER_API_URL`.
23+
24+
```bash
25+
export TRIGGER_API_URL=https://trigger.example.com
26+
```
27+
28+
The default URL is `https://api.trigger.dev`.
29+
30+
### Manually Configuring the SDK
31+
32+
If you prefer to manually configure the SDK, you can call the `configure` method:
33+
34+
```ts
35+
import { configure } from "@trigger.dev/sdk/v3";
36+
import { myTask } from "./trigger/myTasks";
37+
38+
configure({
39+
secretKey: "tr_dev_1234", // WARNING: Never actually hardcode your secret key like this
40+
baseURL: "https://mytrigger.example.com", // Optional
41+
});
42+
43+
async function triggerTask() {
44+
await myTask.trigger({ userId: "1234" }); // This will use the secret key and base URL you configured
45+
}
46+
```

packages/core/src/v3/apiClient/index.ts

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -253,44 +253,3 @@ export class ApiClient {
253253
return headers;
254254
}
255255
}
256-
257-
type ApiClientContext = {
258-
baseURL: string;
259-
accessToken: string;
260-
};
261-
262-
export class ApiClientManager {
263-
private _storage: SafeAsyncLocalStorage<ApiClientContext> =
264-
new SafeAsyncLocalStorage<ApiClientContext>();
265-
266-
get baseURL(): string | undefined {
267-
const store = this.#getStore();
268-
return store?.baseURL ?? getEnvVar("TRIGGER_API_URL") ?? "https://api.trigger.dev";
269-
}
270-
271-
get accessToken(): string | undefined {
272-
const store = this.#getStore();
273-
return store?.accessToken ?? getEnvVar("TRIGGER_SECRET_KEY");
274-
}
275-
276-
get client(): ApiClient | undefined {
277-
if (!this.baseURL || !this.accessToken) {
278-
return undefined;
279-
}
280-
281-
return new ApiClient(this.baseURL, this.accessToken);
282-
}
283-
284-
runWith<R extends (...args: any[]) => Promise<any>>(
285-
context: ApiClientContext,
286-
fn: R
287-
): Promise<ReturnType<R>> {
288-
return this._storage.runWith(context, fn);
289-
}
290-
291-
#getStore(): ApiClientContext | undefined {
292-
return this._storage.getStore();
293-
}
294-
}
295-
296-
export const apiClientManager = new ApiClientManager();
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Split module-level variable definition into separate files to allow
2+
// tree-shaking on each api instance.
3+
import { APIClientManagerAPI } from "./apiClientManager";
4+
/** Entrypoint for logger API */
5+
export const apiClientManager = APIClientManagerAPI.getInstance();
6+
7+
export type { ApiClientConfiguration } from "./apiClientManager/types";
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { ApiClient } from "../apiClient";
2+
import { getGlobal, registerGlobal, unregisterGlobal } from "../utils/globals";
3+
import { getEnvVar } from "../utils/getEnv";
4+
import { ApiClientConfiguration } from "./types";
5+
6+
const API_NAME = "api-client";
7+
8+
export class APIClientManagerAPI {
9+
private static _instance?: APIClientManagerAPI;
10+
11+
private constructor() {}
12+
13+
public static getInstance(): APIClientManagerAPI {
14+
if (!this._instance) {
15+
this._instance = new APIClientManagerAPI();
16+
}
17+
18+
return this._instance;
19+
}
20+
21+
public disable() {
22+
unregisterGlobal(API_NAME);
23+
}
24+
25+
public setGlobalAPIClientConfiguration(config: ApiClientConfiguration): boolean {
26+
return registerGlobal(API_NAME, config);
27+
}
28+
29+
get baseURL(): string | undefined {
30+
const store = this.#getConfig();
31+
return store?.baseURL ?? getEnvVar("TRIGGER_API_URL") ?? "https://api.trigger.dev";
32+
}
33+
34+
get accessToken(): string | undefined {
35+
const store = this.#getConfig();
36+
return store?.secretKey ?? getEnvVar("TRIGGER_SECRET_KEY");
37+
}
38+
39+
get client(): ApiClient | undefined {
40+
if (!this.baseURL || !this.accessToken) {
41+
return undefined;
42+
}
43+
44+
return new ApiClient(this.baseURL, this.accessToken);
45+
}
46+
47+
#getConfig(): ApiClientConfiguration | undefined {
48+
return getGlobal(API_NAME);
49+
}
50+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export type ApiClientConfiguration = {
2+
baseURL?: string;
3+
secretKey?: string;
4+
};

packages/core/src/v3/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export * from "./limits";
66
export * from "./logger-api";
77
export * from "./runtime-api";
88
export * from "./task-context-api";
9+
export * from "./apiClientManager-api";
910
export * from "./schemas";
1011
export { SemanticInternalAttributes } from "./semanticInternalAttributes";
1112
export * from "./task-catalog-api";

packages/core/src/v3/utils/globals.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { ApiClientConfiguration } from "../apiClientManager/types";
12
import { Clock } from "../clock/clock";
23
import type { RuntimeManager } from "../runtime/manager";
34
import { TaskCatalog } from "../task-catalog/catalog";
@@ -50,4 +51,5 @@ type TriggerDotDevGlobalAPI = {
5051
clock?: Clock;
5152
["task-catalog"]?: TaskCatalog;
5253
["task-context"]?: TaskContext;
54+
["api-client"]?: ApiClientConfiguration;
5355
};

packages/core/src/v3/utils/ioSerialization.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { Attributes, Span } from "@opentelemetry/api";
2-
import { apiClientManager } from "../apiClient";
32
import { OFFLOAD_IO_PACKET_LENGTH_LIMIT, imposeAttributeLimits } from "../limits";
43
import { SemanticInternalAttributes } from "../semanticInternalAttributes";
54
import { TriggerTracer } from "../tracer";
65
import { flattenAttributes } from "./flattenAttributes";
6+
import { apiClientManager } from "../apiClientManager-api";
77

88
export type IOPacket = {
99
data?: string | undefined;

packages/trigger-sdk/src/v3/index.ts

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,52 @@
1-
export * from "./tasks";
2-
export * from "./config";
3-
export * from "./wait";
41
export * from "./cache";
2+
export * from "./config";
53
export { retry, type RetryOptions } from "./retry";
64
export { queue } from "./shared";
5+
export * from "./tasks";
6+
export * from "./wait";
7+
export type { Context };
78

89
import type { Context } from "./shared";
9-
export type { Context };
10+
11+
import type { ApiClientConfiguration } from "@trigger.dev/core/v3";
12+
import { apiClientManager } from "@trigger.dev/core/v3";
13+
14+
export type { ApiClientConfiguration };
1015

1116
export {
12-
logger,
13-
type LogLevel,
1417
APIError,
15-
BadRequestError,
1618
AuthenticationError,
17-
PermissionDeniedError,
18-
NotFoundError,
19+
BadRequestError,
1920
ConflictError,
20-
UnprocessableEntityError,
21-
RateLimitError,
2221
InternalServerError,
22+
NotFoundError,
23+
PermissionDeniedError,
24+
RateLimitError,
25+
UnprocessableEntityError,
26+
logger,
27+
type LogLevel,
2328
} from "@trigger.dev/core/v3";
2429

2530
export { runs } from "./management";
2631
export * as schedules from "./schedules";
32+
33+
/**
34+
* Register the global API client configuration. Alternatively, you can set the `TRIGGER_SECRET_KEY` and `TRIGGER_API_URL` environment variables.
35+
* @param options The API client configuration.
36+
* @param options.baseURL The base URL of the Trigger API. (default: `https://api.trigger.dev`)
37+
* @param options.secretKey The secret key to authenticate with the Trigger API. (default: `process.env.TRIGGER_SECRET_KEY`) This can be found in your Trigger.dev project "API Keys" settings.
38+
*
39+
* @example
40+
*
41+
* ```typescript
42+
* import { configure } from "@trigger.dev/sdk/v3";
43+
*
44+
* configure({
45+
* baseURL: "https://api.trigger.dev",
46+
* secretKey: "tr_dev_1234567890"
47+
* });
48+
* ```
49+
*/
50+
export function configure(options: ApiClientConfiguration) {
51+
apiClientManager.setGlobalAPIClientConfiguration(options);
52+
}

references/v3-catalog/src/management.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { APIError, runs, schedules } from "@trigger.dev/sdk/v3";
1+
import { APIError, configure, runs, schedules } from "@trigger.dev/sdk/v3";
22
import { simpleChildTask } from "./trigger/subtasks";
33
import dotenv from "dotenv";
44
import { firstScheduledTask } from "./trigger/scheduled";

0 commit comments

Comments
 (0)