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
This commit is contained in:
Eric Allam
2024-05-06 12:12:30 +01:00
parent 6406924b02
commit 6d9dfbc75d
12 changed files with 152 additions and 59 deletions
+6
View File
@@ -0,0 +1,6 @@
---
"@trigger.dev/sdk": patch
"@trigger.dev/core": patch
---
Add configure function to be able to configure the SDK manually
@@ -51,11 +51,15 @@ export class UpsertTaskScheduleService extends BaseService {
}); });
if (!task) { if (!task) {
throw new Error(`Task with identifier ${schedule.taskIdentifier} not found in project.`); throw new ServiceValidationError(
`Task with identifier ${schedule.taskIdentifier} not found in project.`
);
} }
if (task.triggerSource !== "SCHEDULED") { if (task.triggerSource !== "SCHEDULED") {
throw new Error(`Task with identifier ${schedule.taskIdentifier} is not a scheduled task.`); throw new ServiceValidationError(
`Task with identifier ${schedule.taskIdentifier} is not a scheduled task.`
);
} }
const result = await $transaction(this._prisma, async (tx) => { const result = await $transaction(this._prisma, async (tx) => {
+34
View File
@@ -10,3 +10,37 @@ When you [trigger a task](/v3/triggering) from your backend code, you need to se
Each environment has its own secret key. You can find the value on the API keys page in the Trigger.dev dashboard: Each environment has its own secret key. You can find the value on the API keys page in the Trigger.dev dashboard:
![How to find your secret key](/images/v3/api-keys.png) ![How to find your secret key](/images/v3/api-keys.png)
### Automatically Configuring the SDK
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`).
```bash
export TRIGGER_SECRET_KEY=tr_dev_…
```
You can do the same if you are self-hosting and need to change the default URL by using `TRIGGER_API_URL`.
```bash
export TRIGGER_API_URL=https://trigger.example.com
```
The default URL is `https://api.trigger.dev`.
### Manually Configuring the SDK
If you prefer to manually configure the SDK, you can call the `configure` method:
```ts
import { configure } from "@trigger.dev/sdk/v3";
import { myTask } from "./trigger/myTasks";
configure({
secretKey: "tr_dev_1234", // WARNING: Never actually hardcode your secret key like this
baseURL: "https://mytrigger.example.com", // Optional
});
async function triggerTask() {
await myTask.trigger({ userId: "1234" }); // This will use the secret key and base URL you configured
}
```
-41
View File
@@ -253,44 +253,3 @@ export class ApiClient {
return headers; return headers;
} }
} }
type ApiClientContext = {
baseURL: string;
accessToken: string;
};
export class ApiClientManager {
private _storage: SafeAsyncLocalStorage<ApiClientContext> =
new SafeAsyncLocalStorage<ApiClientContext>();
get baseURL(): string | undefined {
const store = this.#getStore();
return store?.baseURL ?? getEnvVar("TRIGGER_API_URL") ?? "https://api.trigger.dev";
}
get accessToken(): string | undefined {
const store = this.#getStore();
return store?.accessToken ?? getEnvVar("TRIGGER_SECRET_KEY");
}
get client(): ApiClient | undefined {
if (!this.baseURL || !this.accessToken) {
return undefined;
}
return new ApiClient(this.baseURL, this.accessToken);
}
runWith<R extends (...args: any[]) => Promise<any>>(
context: ApiClientContext,
fn: R
): Promise<ReturnType<R>> {
return this._storage.runWith(context, fn);
}
#getStore(): ApiClientContext | undefined {
return this._storage.getStore();
}
}
export const apiClientManager = new ApiClientManager();
@@ -0,0 +1,7 @@
// Split module-level variable definition into separate files to allow
// tree-shaking on each api instance.
import { APIClientManagerAPI } from "./apiClientManager";
/** Entrypoint for logger API */
export const apiClientManager = APIClientManagerAPI.getInstance();
export type { ApiClientConfiguration } from "./apiClientManager/types";
@@ -0,0 +1,50 @@
import { ApiClient } from "../apiClient";
import { getGlobal, registerGlobal, unregisterGlobal } from "../utils/globals";
import { getEnvVar } from "../utils/getEnv";
import { ApiClientConfiguration } from "./types";
const API_NAME = "api-client";
export class APIClientManagerAPI {
private static _instance?: APIClientManagerAPI;
private constructor() {}
public static getInstance(): APIClientManagerAPI {
if (!this._instance) {
this._instance = new APIClientManagerAPI();
}
return this._instance;
}
public disable() {
unregisterGlobal(API_NAME);
}
public setGlobalAPIClientConfiguration(config: ApiClientConfiguration): boolean {
return registerGlobal(API_NAME, config);
}
get baseURL(): string | undefined {
const store = this.#getConfig();
return store?.baseURL ?? getEnvVar("TRIGGER_API_URL") ?? "https://api.trigger.dev";
}
get accessToken(): string | undefined {
const store = this.#getConfig();
return store?.secretKey ?? getEnvVar("TRIGGER_SECRET_KEY");
}
get client(): ApiClient | undefined {
if (!this.baseURL || !this.accessToken) {
return undefined;
}
return new ApiClient(this.baseURL, this.accessToken);
}
#getConfig(): ApiClientConfiguration | undefined {
return getGlobal(API_NAME);
}
}
@@ -0,0 +1,4 @@
export type ApiClientConfiguration = {
baseURL?: string;
secretKey?: string;
};
+1
View File
@@ -6,6 +6,7 @@ export * from "./limits";
export * from "./logger-api"; export * from "./logger-api";
export * from "./runtime-api"; export * from "./runtime-api";
export * from "./task-context-api"; export * from "./task-context-api";
export * from "./apiClientManager-api";
export * from "./schemas"; export * from "./schemas";
export { SemanticInternalAttributes } from "./semanticInternalAttributes"; export { SemanticInternalAttributes } from "./semanticInternalAttributes";
export * from "./task-catalog-api"; export * from "./task-catalog-api";
+2
View File
@@ -1,3 +1,4 @@
import { ApiClientConfiguration } from "../apiClientManager/types";
import { Clock } from "../clock/clock"; import { Clock } from "../clock/clock";
import type { RuntimeManager } from "../runtime/manager"; import type { RuntimeManager } from "../runtime/manager";
import { TaskCatalog } from "../task-catalog/catalog"; import { TaskCatalog } from "../task-catalog/catalog";
@@ -50,4 +51,5 @@ type TriggerDotDevGlobalAPI = {
clock?: Clock; clock?: Clock;
["task-catalog"]?: TaskCatalog; ["task-catalog"]?: TaskCatalog;
["task-context"]?: TaskContext; ["task-context"]?: TaskContext;
["api-client"]?: ApiClientConfiguration;
}; };
@@ -1,9 +1,9 @@
import { Attributes, Span } from "@opentelemetry/api"; import { Attributes, Span } from "@opentelemetry/api";
import { apiClientManager } from "../apiClient";
import { OFFLOAD_IO_PACKET_LENGTH_LIMIT, imposeAttributeLimits } from "../limits"; import { OFFLOAD_IO_PACKET_LENGTH_LIMIT, imposeAttributeLimits } from "../limits";
import { SemanticInternalAttributes } from "../semanticInternalAttributes"; import { SemanticInternalAttributes } from "../semanticInternalAttributes";
import { TriggerTracer } from "../tracer"; import { TriggerTracer } from "../tracer";
import { flattenAttributes } from "./flattenAttributes"; import { flattenAttributes } from "./flattenAttributes";
import { apiClientManager } from "../apiClientManager-api";
export type IOPacket = { export type IOPacket = {
data?: string | undefined; data?: string | undefined;
+40 -14
View File
@@ -1,26 +1,52 @@
export * from "./tasks";
export * from "./config";
export * from "./wait";
export * from "./cache"; export * from "./cache";
export * from "./config";
export { retry, type RetryOptions } from "./retry"; export { retry, type RetryOptions } from "./retry";
export { queue } from "./shared"; export { queue } from "./shared";
export * from "./tasks";
import type { Context } from "./shared"; export * from "./wait";
export type { Context }; export type { Context };
import type { Context } from "./shared";
import type { ApiClientConfiguration } from "@trigger.dev/core/v3";
import { apiClientManager } from "@trigger.dev/core/v3";
export type { ApiClientConfiguration };
export { export {
APIError,
AuthenticationError,
BadRequestError,
ConflictError,
InternalServerError,
NotFoundError,
PermissionDeniedError,
RateLimitError,
UnprocessableEntityError,
logger, logger,
type LogLevel, type LogLevel,
APIError,
BadRequestError,
AuthenticationError,
PermissionDeniedError,
NotFoundError,
ConflictError,
UnprocessableEntityError,
RateLimitError,
InternalServerError,
} from "@trigger.dev/core/v3"; } from "@trigger.dev/core/v3";
export { runs } from "./management"; export { runs } from "./management";
export * as schedules from "./schedules"; export * as schedules from "./schedules";
/**
* Register the global API client configuration. Alternatively, you can set the `TRIGGER_SECRET_KEY` and `TRIGGER_API_URL` environment variables.
* @param options The API client configuration.
* @param options.baseURL The base URL of the Trigger API. (default: `https://api.trigger.dev`)
* @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.
*
* @example
*
* ```typescript
* import { configure } from "@trigger.dev/sdk/v3";
*
* configure({
* baseURL: "https://api.trigger.dev",
* secretKey: "tr_dev_1234567890"
* });
* ```
*/
export function configure(options: ApiClientConfiguration) {
apiClientManager.setGlobalAPIClientConfiguration(options);
}
+1 -1
View File
@@ -1,4 +1,4 @@
import { APIError, runs, schedules } from "@trigger.dev/sdk/v3"; import { APIError, configure, runs, schedules } from "@trigger.dev/sdk/v3";
import { simpleChildTask } from "./trigger/subtasks"; import { simpleChildTask } from "./trigger/subtasks";
import dotenv from "dotenv"; import dotenv from "dotenv";
import { firstScheduledTask } from "./trigger/scheduled"; import { firstScheduledTask } from "./trigger/scheduled";