diff --git a/packages/app-sdk-playground/src/plugins/declarations/tasks.ts b/packages/app-sdk-playground/src/plugins/declarations/tasks.ts new file mode 100644 index 00000000000..7af34c915d1 --- /dev/null +++ b/packages/app-sdk-playground/src/plugins/declarations/tasks.ts @@ -0,0 +1,110 @@ +// Tasks SDK type declarations. +export const TASKS_DECLARATIONS = ` +type SdkTaskStatus = + | "pending" + | "running" + | "completed" + | "failed" + | "aborted" + | "stopped"; + +interface SdkTaskDefinition { + /** Unique task definition ID. */ + id: string; + /** Human-readable task title. */ + title: string; + /** Task description. */ + description?: string; +} + +interface SdkTaskRun { + /** Unique task run ID. */ + id: string; + /** ISO timestamp when the task started. */ + startedOn?: string; + /** ISO timestamp when the task finished. */ + finishedOn?: string; + /** Task name. */ + name?: string; + /** The task definition ID this run belongs to. */ + definitionId: string; + /** Number of iterations the task has completed. */ + iterations?: number; + /** Parent task run ID, if this is a child task. */ + parentId?: string; + /** Step Functions execution name. */ + executionName?: string; + /** Raw event response from the task runner. */ + eventResponse?: unknown; + /** Current task status. */ + taskStatus: SdkTaskStatus; + /** Input data passed to the task. */ + input?: unknown; + /** Output data produced by the task. */ + output?: unknown; +} + +interface SdkTaskLogItem { + /** Log message. */ + message: string; + /** ISO timestamp of the log entry. */ + createdOn: string; + /** Log level or type (e.g. "info", "error"). */ + type: string; + /** Additional structured data. */ + data?: unknown; + /** Error details, if this is an error log entry. */ + error?: unknown; +} + +interface SdkTaskLog { + /** Unique log ID. */ + id: string; + /** ISO timestamp when the log was created. */ + createdOn: string; + /** Step Functions execution name. */ + executionName?: string; + /** Iteration number this log belongs to. */ + iteration?: number; + /** Individual log entries within this log. */ + items: SdkTaskLogItem[]; +} + +interface SdkListLogsParams { + where?: { + /** Filter logs by task run ID. */ + task?: string; + }; +} + +interface SdkTriggerTaskParams { + /** The task definition ID to trigger. */ + definition: string; + /** Input data to pass to the task. */ + input?: Record; +} + +interface SdkAbortTaskParams { + /** The task run ID to abort. */ + id: string; + /** Optional reason for aborting the task. */ + message?: string; +} + +interface SdkTasks { + /** List all registered task definitions. */ + listDefinitions(): Promise>; + + /** List all task runs with their status and I/O data. */ + listTasks(): Promise>; + + /** List execution logs, optionally filtered by task run ID. */ + listLogs(params?: SdkListLogsParams): Promise>; + + /** Trigger a task and start an async execution. */ + triggerTask(params: SdkTriggerTaskParams): Promise>; + + /** Abort a running task at its next safe checkpoint. */ + abortTask(params: SdkAbortTaskParams): Promise>; +} +`; diff --git a/packages/app-sdk-playground/src/plugins/sdkGlobalDeclaration.ts b/packages/app-sdk-playground/src/plugins/sdkGlobalDeclaration.ts index 9d6fc59845b..faa31b176d6 100644 --- a/packages/app-sdk-playground/src/plugins/sdkGlobalDeclaration.ts +++ b/packages/app-sdk-playground/src/plugins/sdkGlobalDeclaration.ts @@ -15,6 +15,7 @@ import { CMS_DECLARATIONS } from "./declarations/cms.js"; import { TENANT_MANAGER_DECLARATIONS } from "./declarations/tenantManager.js"; import { FILE_MANAGER_DECLARATIONS } from "./declarations/fileManager.js"; import { LANGUAGES_DECLARATIONS } from "./declarations/languages.js"; +import { TASKS_DECLARATIONS } from "./declarations/tasks.js"; export const SDK_GLOBAL_DECLARATION = ` ${COMMON_DECLARATIONS} @@ -27,6 +28,8 @@ ${FILE_MANAGER_DECLARATIONS} ${LANGUAGES_DECLARATIONS} +${TASKS_DECLARATIONS} + // ============================================================================ // MAIN SDK INTERFACE // ============================================================================ @@ -43,6 +46,9 @@ interface SdkWebiny { /** Languages operations: list enabled languages. */ readonly languages: SdkLanguages; + + /** Tasks operations: trigger, abort, list tasks and logs. */ + readonly tasks: SdkTasks; } declare const sdk: SdkWebiny; diff --git a/packages/pulumi-sdk/src/Pulumi.ts b/packages/pulumi-sdk/src/Pulumi.ts index 496d179ec55..7b4ed0dd939 100644 --- a/packages/pulumi-sdk/src/Pulumi.ts +++ b/packages/pulumi-sdk/src/Pulumi.ts @@ -199,12 +199,11 @@ export class Pulumi { } const pluginsDir = path.join(this.pulumiFolder, "plugins"); + // Pulumi names plugin directories with a "v" prefix (e.g. resource-aws-v7.25.0). const requiredPluginDir = `resource-aws-v${pulumiAwsVersion}`; - const pluginBinary = - process.platform === "win32" ? "pulumi-resource-aws.exe" : "pulumi-resource-aws"; const pluginExists = fs.pathExistsSync( - path.join(pluginsDir, requiredPluginDir, pluginBinary) + path.join(pluginsDir, requiredPluginDir, "pulumi-resource-aws") ); if (!pluginExists) { @@ -231,6 +230,7 @@ export class Pulumi { // lock file are matched by the same prefix check. const baseName = entry.endsWith(".lock") ? entry.slice(0, -5) : entry; if (baseName !== requiredPluginDir) { + console.log("DERI", entry); fs.removeSync(path.join(pluginsDir, entry)); } } diff --git a/packages/sdk/src/TasksSdk.ts b/packages/sdk/src/TasksSdk.ts new file mode 100644 index 00000000000..9061110b4eb --- /dev/null +++ b/packages/sdk/src/TasksSdk.ts @@ -0,0 +1,50 @@ +import type { WebinyConfig } from "./types.js"; +import type { HttpError, GraphQLError, NetworkError } from "./errors.js"; +import type { Result } from "./Result.js"; +import type { TaskDefinition, TaskRun, TaskLog } from "./methods/tasks/taskTypes.js"; +import type { ListLogsParams } from "./methods/tasks/listLogs.js"; +import type { TriggerTaskParams } from "./methods/tasks/triggerTask.js"; +import type { AbortTaskParams } from "./methods/tasks/abortTask.js"; +import { listDefinitions as listDefinitionsFn } from "./methods/tasks/listDefinitions.js"; +import { listTasks as listTasksFn } from "./methods/tasks/listTasks.js"; +import { listLogs as listLogsFn } from "./methods/tasks/listLogs.js"; +import { triggerTask as triggerTaskFn } from "./methods/tasks/triggerTask.js"; +import { abortTask as abortTaskFn } from "./methods/tasks/abortTask.js"; + +export class TasksSdk { + private config: WebinyConfig; + private fetchFn: typeof fetch; + + constructor(config: WebinyConfig) { + this.config = config; + this.fetchFn = config.fetch || fetch; + } + + async listDefinitions(): Promise< + Result + > { + return listDefinitionsFn(this.config, this.fetchFn); + } + + async listTasks(): Promise> { + return listTasksFn(this.config, this.fetchFn); + } + + async listLogs( + params?: ListLogsParams + ): Promise> { + return listLogsFn(this.config, this.fetchFn, params); + } + + async triggerTask( + params: TriggerTaskParams + ): Promise> { + return triggerTaskFn(this.config, this.fetchFn, params); + } + + async abortTask( + params: AbortTaskParams + ): Promise> { + return abortTaskFn(this.config, this.fetchFn, params); + } +} diff --git a/packages/sdk/src/Webiny.ts b/packages/sdk/src/Webiny.ts index 39d75aeff80..a8f872c04c3 100644 --- a/packages/sdk/src/Webiny.ts +++ b/packages/sdk/src/Webiny.ts @@ -3,12 +3,14 @@ import { CmsSdk } from "./CmsSdk.js"; import { TenantManagerSdk } from "./TenantManagerSdk.js"; import { FileManagerSdk } from "./FileManagerSdk.js"; import { LanguagesSdk } from "./LanguagesSdk.js"; +import { TasksSdk } from "./TasksSdk.js"; export class Webiny { public readonly cms: CmsSdk; public readonly tenantManager: TenantManagerSdk; public readonly fileManager: FileManagerSdk; public readonly languages: LanguagesSdk; + public readonly tasks: TasksSdk; constructor(config: WebinyConfig) { this.cms = new CmsSdk({ @@ -27,6 +29,10 @@ export class Webiny { ...config, tenant: config.tenant || "root" }); + this.tasks = new TasksSdk({ + ...config, + tenant: config.tenant || "root" + }); } } diff --git a/packages/sdk/src/index.ts b/packages/sdk/src/index.ts index b46e15ba77c..092b823f5a4 100644 --- a/packages/sdk/src/index.ts +++ b/packages/sdk/src/index.ts @@ -3,6 +3,7 @@ export * from "./CmsSdk.js"; export * from "./TenantManagerSdk.js"; export * from "./FileManagerSdk.js"; export * from "./LanguagesSdk.js"; +export * from "./TasksSdk.js"; export * from "./types.js"; export { Result } from "./Result.js"; export { HttpError, GraphQLError, NetworkError } from "./errors.js"; @@ -92,3 +93,19 @@ export type { CompleteMultiPartUploadParams } from "./methods/fileManager/comple // Export Languages types. export type { Language } from "./methods/languages/listLanguages.js"; + +// Export Tasks types. +export type { + TaskStatus, + TaskDefinition, + TaskRun, + TaskLog, + TaskLogItem +} from "./methods/tasks/taskTypes.js"; + +// Export types from tasks methods. +export type { ListLogsParams } from "./methods/tasks/listLogs.js"; + +export type { TriggerTaskParams } from "./methods/tasks/triggerTask.js"; + +export type { AbortTaskParams } from "./methods/tasks/abortTask.js"; diff --git a/packages/sdk/src/methods/tasks/abortTask.ts b/packages/sdk/src/methods/tasks/abortTask.ts new file mode 100644 index 00000000000..f8b7d97d536 --- /dev/null +++ b/packages/sdk/src/methods/tasks/abortTask.ts @@ -0,0 +1,70 @@ +import type { WebinyConfig } from "../../types.js"; +import { Result } from "../../Result.js"; +import type { HttpError, GraphQLError, NetworkError } from "../../errors.js"; +import type { TaskRun } from "./taskTypes.js"; + +export interface AbortTaskParams { + /** The task run ID to abort. */ + id: string; + /** Optional reason for aborting the task. */ + message?: string; +} + +export async function abortTask( + config: WebinyConfig, + fetchFn: typeof fetch, + params: AbortTaskParams +): Promise> { + const { id, message } = params; + + const { executeGraphQL } = await import("../executeGraphQL.js"); + + const query = ` + mutation AbortTask($id: ID!, $message: String) { + backgroundTasks { + abortTask(id: $id, message: $message) { + data { + id + createdOn + savedOn + startedOn + finishedOn + definitionId + iterations + name + input + output + taskStatus + executionName + eventResponse + parentId + } + error { + message + code + } + } + } + } + `; + + const result = await executeGraphQL(config, fetchFn, query, { id, message }); + + if (result.isFail()) { + return Result.fail(result.error); + } + + const responseData = result.value; + + if (responseData.backgroundTasks.abortTask.error) { + const { GraphQLError } = await import("../../errors.js"); + return Result.fail( + new GraphQLError( + responseData.backgroundTasks.abortTask.error.message, + responseData.backgroundTasks.abortTask.error.code + ) + ); + } + + return Result.ok(responseData.backgroundTasks.abortTask.data); +} diff --git a/packages/sdk/src/methods/tasks/listDefinitions.ts b/packages/sdk/src/methods/tasks/listDefinitions.ts new file mode 100644 index 00000000000..52602ee3233 --- /dev/null +++ b/packages/sdk/src/methods/tasks/listDefinitions.ts @@ -0,0 +1,49 @@ +import type { WebinyConfig } from "../../types.js"; +import { Result } from "../../Result.js"; +import type { HttpError, GraphQLError, NetworkError } from "../../errors.js"; +import type { TaskDefinition } from "./taskTypes.js"; + +export async function listDefinitions( + config: WebinyConfig, + fetchFn: typeof fetch +): Promise> { + const { executeGraphQL } = await import("../executeGraphQL.js"); + + const query = ` + query ListTaskDefinitions { + backgroundTasks { + listDefinitions { + data { + id + title + description + } + error { + message + code + } + } + } + } + `; + + const result = await executeGraphQL(config, fetchFn, query, {}); + + if (result.isFail()) { + return Result.fail(result.error); + } + + const responseData = result.value; + + if (responseData.backgroundTasks.listDefinitions.error) { + const { GraphQLError } = await import("../../errors.js"); + return Result.fail( + new GraphQLError( + responseData.backgroundTasks.listDefinitions.error.message, + responseData.backgroundTasks.listDefinitions.error.code + ) + ); + } + + return Result.ok(responseData.backgroundTasks.listDefinitions.data); +} diff --git a/packages/sdk/src/methods/tasks/listLogs.ts b/packages/sdk/src/methods/tasks/listLogs.ts new file mode 100644 index 00000000000..1964a3af4ac --- /dev/null +++ b/packages/sdk/src/methods/tasks/listLogs.ts @@ -0,0 +1,65 @@ +import type { WebinyConfig } from "../../types.js"; +import { Result } from "../../Result.js"; +import type { HttpError, GraphQLError, NetworkError } from "../../errors.js"; +import type { TaskLog } from "./taskTypes.js"; + +export interface ListLogsParams { + where?: { + /** Filter logs by task ID. */ + task?: string; + }; +} + +export async function listLogs( + config: WebinyConfig, + fetchFn: typeof fetch, + params: ListLogsParams = {} +): Promise> { + const { executeGraphQL } = await import("../executeGraphQL.js"); + + const query = ` + query ListBackgroundTaskLogs($where: BackgroundTaskLogListWhereInput) { + backgroundTasks { + listLogs(where: $where) { + data { + id + createdOn + executionName + iteration + items { + message + createdOn + type + data + error + } + } + error { + message + code + } + } + } + } + `; + + const result = await executeGraphQL(config, fetchFn, query, { where: params.where }); + + if (result.isFail()) { + return Result.fail(result.error); + } + + const responseData = result.value; + + if (responseData.backgroundTasks.listLogs.error) { + const { GraphQLError } = await import("../../errors.js"); + return Result.fail( + new GraphQLError( + responseData.backgroundTasks.listLogs.error.message, + responseData.backgroundTasks.listLogs.error.code + ) + ); + } + + return Result.ok(responseData.backgroundTasks.listLogs.data); +} diff --git a/packages/sdk/src/methods/tasks/listTasks.ts b/packages/sdk/src/methods/tasks/listTasks.ts new file mode 100644 index 00000000000..cfaf3a69c34 --- /dev/null +++ b/packages/sdk/src/methods/tasks/listTasks.ts @@ -0,0 +1,58 @@ +import type { WebinyConfig } from "../../types.js"; +import { Result } from "../../Result.js"; +import type { HttpError, GraphQLError, NetworkError } from "../../errors.js"; +import type { TaskRun } from "./taskTypes.js"; + +export async function listTasks( + config: WebinyConfig, + fetchFn: typeof fetch +): Promise> { + const { executeGraphQL } = await import("../executeGraphQL.js"); + + const query = ` + query ListTasks { + backgroundTasks { + listTasks { + data { + id + startedOn + finishedOn + name + definitionId + iterations + parentId + executionName + eventResponse + taskStatus + input + output + } + error { + message + code + } + } + } + } + `; + + const result = await executeGraphQL(config, fetchFn, query, {}); + + if (result.isFail()) { + return Result.fail(result.error); + } + + const responseData = result.value; + + if (responseData.backgroundTasks.listTasks.error) { + const { GraphQLError } = await import("../../errors.js"); + return Result.fail( + new GraphQLError( + responseData.backgroundTasks.listTasks.error.message, + responseData.backgroundTasks.listTasks.error.code + ) + ); + } + + return Result.ok(responseData.backgroundTasks.listTasks.data); +} diff --git a/packages/sdk/src/methods/tasks/taskTypes.ts b/packages/sdk/src/methods/tasks/taskTypes.ts new file mode 100644 index 00000000000..e4310100861 --- /dev/null +++ b/packages/sdk/src/methods/tasks/taskTypes.ts @@ -0,0 +1,38 @@ +export type TaskStatus = "pending" | "running" | "completed" | "failed" | "aborted" | "stopped"; + +export interface TaskDefinition { + id: string; + title: string; + description?: string; +} + +export interface TaskRun { + id: string; + startedOn?: string; + finishedOn?: string; + name?: string; + definitionId: string; + iterations?: number; + parentId?: string; + executionName?: string; + eventResponse?: unknown; + taskStatus: TaskStatus; + input?: unknown; + output?: unknown; +} + +export interface TaskLogItem { + message: string; + createdOn: string; + type: string; + data?: unknown; + error?: unknown; +} + +export interface TaskLog { + id: string; + createdOn: string; + executionName?: string; + iteration?: number; + items: TaskLogItem[]; +} diff --git a/packages/sdk/src/methods/tasks/triggerTask.ts b/packages/sdk/src/methods/tasks/triggerTask.ts new file mode 100644 index 00000000000..871278f64ca --- /dev/null +++ b/packages/sdk/src/methods/tasks/triggerTask.ts @@ -0,0 +1,68 @@ +import type { WebinyConfig } from "../../types.js"; +import { Result } from "../../Result.js"; +import type { HttpError, GraphQLError, NetworkError } from "../../errors.js"; +import type { TaskRun } from "./taskTypes.js"; + +export interface TriggerTaskParams { + /** The task definition ID to trigger. */ + definition: string; + /** Input data to pass to the task. */ + input?: Record; +} + +export async function triggerTask( + config: WebinyConfig, + fetchFn: typeof fetch, + params: TriggerTaskParams +): Promise> { + const { definition, input } = params; + + const { executeGraphQL } = await import("../executeGraphQL.js"); + + const query = ` + mutation TriggerTask($definition: WebinyBackgroundTaskDefinitionEnum!, $input: JSON) { + backgroundTasks { + triggerTask(definition: $definition, input: $input) { + data { + id + definitionId + executionName + eventResponse + taskStatus + input + output + startedOn + finishedOn + name + iterations + parentId + } + error { + message + code + } + } + } + } + `; + + const result = await executeGraphQL(config, fetchFn, query, { definition, input }); + + if (result.isFail()) { + return Result.fail(result.error); + } + + const responseData = result.value; + + if (responseData.backgroundTasks.triggerTask.error) { + const { GraphQLError } = await import("../../errors.js"); + return Result.fail( + new GraphQLError( + responseData.backgroundTasks.triggerTask.error.message, + responseData.backgroundTasks.triggerTask.error.code + ) + ); + } + + return Result.ok(responseData.backgroundTasks.triggerTask.data); +} diff --git a/skills/user-skills/webiny-sdk/SKILL.md b/skills/user-skills/webiny-sdk/SKILL.md index ce88dd4040c..17c0a208450 100644 --- a/skills/user-skills/webiny-sdk/SKILL.md +++ b/skills/user-skills/webiny-sdk/SKILL.md @@ -6,9 +6,10 @@ description: > Use this skill when the developer is building a Next.js, Vue, Node.js, or any external app that needs to fetch or write content to Webiny, set up the SDK, use the Result pattern, list/get/create/update/publish entries, filter and sort queries, use TypeScript generics - for type safety, work with the File Manager, list languages, or create API keys programmatically. + for type safety, work with the File Manager, list languages, trigger or monitor background tasks, + or create API keys programmatically. Covers read vs preview mode, the `values` wrapper requirement, correct method names, - and the `fields` required parameter. + the `fields` required parameter, and background task management via `sdk.tasks`. --- # Webiny SDK @@ -344,40 +345,158 @@ Register (**YOU MUST include the `.ts` file extension in the `src` prop** — om ``` +## Background Tasks + +`webiny.tasks` wraps the Background Tasks GraphQL API. All methods return a `Result` and never throw. + +### List Task Definitions + +Returns all registered task definitions — use this to discover valid `definition` IDs before triggering. + +```typescript +const result = await webiny.tasks.listDefinitions(); + +if (result.isOk()) { + // result.value: TaskDefinition[] + for (const def of result.value) { + console.log(def.id, def.title, def.description); + } +} +``` + +### List Task Runs + +```typescript +const result = await webiny.tasks.listTasks(); + +if (result.isOk()) { + // result.value: TaskRun[] + for (const task of result.value) { + console.log(task.id, task.taskStatus, task.definitionId); + } +} +``` + +### List Task Logs + +Optionally filter by a specific task run ID: + +```typescript +// All logs +const result = await webiny.tasks.listLogs(); + +// Logs for a specific task run +const result = await webiny.tasks.listLogs({ + where: { task: "yourTaskRunId" } +}); + +if (result.isOk()) { + for (const log of result.value) { + for (const item of log.items) { + console.log(`[${item.type}] ${item.message}`); + } + } +} +``` + +### Trigger a Task + +```typescript +const result = await webiny.tasks.triggerTask({ + definition: "myTaskDefinitionId", + input: { + someVariable: "someValue", + anotherVariable: 42 + } +}); + +if (result.isOk()) { + const task = result.value; // TaskRun + console.log(task.id, task.taskStatus, task.executionName); +} +``` + +### Abort a Task + +The task stops at its next safe checkpoint. + +```typescript +const result = await webiny.tasks.abortTask({ + id: "yourTaskRunId", + message: "Stopped by user request" // optional +}); + +if (result.isOk()) { + console.log(result.value.taskStatus); // "aborted" +} +``` + +### Background Task Types + +```typescript +import type { TaskDefinition, TaskRun, TaskLog, TaskLogItem, TaskStatus } from "@webiny/sdk"; + +type TaskStatus = "pending" | "running" | "completed" | "failed" | "aborted" | "stopped"; + +interface TaskDefinition { + id: string; + title: string; + description?: string; +} + +interface TaskRun { + id: string; + definitionId: string; + taskStatus: TaskStatus; + input?: unknown; + output?: unknown; + startedOn?: string; + finishedOn?: string; + executionName?: string; + iterations?: number; + parentId?: string; +} +``` + ## SDK Modules Reference -| Module | Webiny App | What You Can Do | -| ---------------------- | ------------- | --------------------------------------------------------------------- | -| `webiny.cms` | Headless CMS | List, get, create, update, publish, unpublish, delete entry revisions | -| `webiny.fileManager` | File Manager | List, upload, and manage files and folders | -| `webiny.tenantManager` | Multi-tenancy | Create, install, enable, disable tenants | -| `webiny.languages` | Languages | List enabled languages (id, code, name, direction, isDefault) | +| Module | Webiny App | What You Can Do | +| ---------------------- | ---------------- | --------------------------------------------------------------------- | +| `webiny.cms` | Headless CMS | List, get, create, update, publish, unpublish, delete entry revisions | +| `webiny.fileManager` | File Manager | List, upload, and manage files and folders | +| `webiny.tenantManager` | Multi-tenancy | Create, install, enable, disable tenants | +| `webiny.languages` | Languages | List enabled languages (id, code, name, direction, isDefault) | +| `webiny.tasks` | Background Tasks | Trigger, abort, list task runs, definitions, and logs | ## Common Mistakes -| Mistake | Correct | -| --------------------------- | --------------------------------------- | -| `data: { name: "..." }` | `data: { values: { name: "..." } }` | -| `updateEntry(...)` | `updateEntryRevision(...)` | -| `publishEntry(...)` | `publishEntryRevision(...)` | -| `unpublishEntry(...)` | `unpublishEntryRevision(...)` | -| `sort: ["values.name_ASC"]` | `sort: { "values.name": "asc" }` | -| `getEntry({ id: "..." })` | `getEntry({ where: { id: "..." } })` | -| Omitting `fields` | Always provide `fields: [...]` | -| Trailing slash in endpoint | Remove trailing slash from endpoint URL | +| Mistake | Correct | +| ---------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | +| `data: { name: "..." }` | `data: { values: { name: "..." } }` | +| `updateEntry(...)` | `updateEntryRevision(...)` | +| `publishEntry(...)` | `publishEntryRevision(...)` | +| `unpublishEntry(...)` | `unpublishEntryRevision(...)` | +| `sort: ["values.name_ASC"]` | `sort: { "values.name": "asc" }` | +| `getEntry({ id: "..." })` | `getEntry({ where: { id: "..." } })` | +| Omitting `fields` | Always provide `fields: [...]` | +| Trailing slash in endpoint | Remove trailing slash from endpoint URL | +| `triggerTask` with unknown `definition` string | Use an ID returned by `listDefinitions()` — the GQL schema validates it against `WebinyBackgroundTaskDefinitionEnum!` | ## Quick Reference ``` -Install: npm install @webiny/sdk -Import: import { Webiny } from "@webiny/sdk"; -Type import: import type { CmsEntryData } from "@webiny/sdk"; -Initialize: new Webiny({ token, endpoint, tenant }) -Result check: result.isOk() -> result.value.data / result.error.message -API endpoint: yarn webiny info (in your Webiny project) -- NO trailing slash -Preview mode: pass preview: true to listEntries / getEntry -fields required: every method needs a fields: string[] array -values wrapper: createEntry/updateEntryRevision data must use { values: { ... } } +Install: npm install @webiny/sdk +Import: import { Webiny } from "@webiny/sdk"; +Type import: import type { CmsEntryData, TaskRun } from "@webiny/sdk"; +Initialize: new Webiny({ token, endpoint, tenant }) +Result check: result.isOk() -> result.value / result.error.message +API endpoint: yarn webiny info (in your Webiny project) -- NO trailing slash +Preview mode: pass preview: true to listEntries / getEntry +fields required: every CMS method needs a fields: string[] array +values wrapper: createEntry/updateEntryRevision data must use { values: { ... } } +Background tasks: webiny.tasks.triggerTask({ definition, input }) +Abort task: webiny.tasks.abortTask({ id, message? }) +Filter logs by task: webiny.tasks.listLogs({ where: { task: "id" } }) ``` ## Related Skills