Initial commit

This commit is contained in:
2025-08-22 21:09:48 +02:00
commit 2d84f535f4
68 changed files with 34807 additions and 0 deletions

View File

@@ -0,0 +1,42 @@
import type { TaskHandler } from "payload"
export const createDocumentHandler: TaskHandler<'create-document'> = async ({ input, req }) => {
if (!input) {
throw new Error('No input provided')
}
const { collection, data, draft, locale } = input
if (!collection || typeof collection !== 'string') {
throw new Error('Collection slug is required')
}
if (!data) {
throw new Error('Document data is required')
}
try {
const parsedData = typeof data === 'string' ? JSON.parse(data) : data
const result = await req.payload.create({
collection,
data: parsedData,
draft: draft || false,
locale: locale || undefined,
req
})
return {
output: {
id: result.id,
doc: result
},
state: 'succeeded'
}
} catch (error) {
return {
errorMessage: error instanceof Error ? error.message : 'Failed to create document',
state: 'failed'
}
}
}

View File

@@ -0,0 +1,56 @@
import type { TaskConfig } from "payload"
import { createDocumentHandler } from "./create-document-handler.js"
export const CreateDocumentStepTask = {
slug: 'create-document',
handler: createDocumentHandler,
inputSchema: [
{
name: 'collection',
type: 'text',
admin: {
description: 'The collection slug to create a document in'
},
required: true
},
{
name: 'data',
type: 'json',
admin: {
description: 'The document data to create'
},
required: true
},
{
name: 'draft',
type: 'checkbox',
admin: {
description: 'Create as draft (if collection has drafts enabled)'
}
},
{
name: 'locale',
type: 'text',
admin: {
description: 'Locale for the document (if localization is enabled)'
}
}
],
outputSchema: [
{
name: 'doc',
type: 'json',
admin: {
description: 'The created document'
}
},
{
name: 'id',
type: 'text',
admin: {
description: 'The ID of the created document'
}
}
]
} satisfies TaskConfig<'create-document'>

View File

@@ -0,0 +1,71 @@
import type { TaskHandler } from "payload"
export const deleteDocumentHandler: TaskHandler<'delete-document'> = async ({ input, req }) => {
if (!input) {
throw new Error('No input provided')
}
const { id, collection, where } = input
if (!collection || typeof collection !== 'string') {
throw new Error('Collection slug is required')
}
try {
// If ID is provided, delete by ID
if (id) {
const result = await req.payload.delete({
id: id.toString(),
collection,
req
})
return {
output: {
deletedCount: 1,
doc: result
},
state: 'succeeded'
}
}
// Otherwise, delete multiple documents
if (!where) {
throw new Error('Either ID or where conditions must be provided')
}
const parsedWhere = typeof where === 'string' ? JSON.parse(where) : where
// First find the documents to delete
const toDelete = await req.payload.find({
collection,
limit: 1000, // Set a reasonable limit
req,
where: parsedWhere
})
// Delete each document
const deleted = []
for (const doc of toDelete.docs) {
const result = await req.payload.delete({
id: doc.id,
collection,
req
})
deleted.push(result)
}
return {
output: {
deletedCount: deleted.length,
doc: deleted
},
state: 'succeeded'
}
} catch (error) {
return {
errorMessage: error instanceof Error ? error.message : 'Failed to delete document(s)',
state: 'failed'
}
}
}

View File

@@ -0,0 +1,48 @@
import type { TaskConfig } from "payload"
import { deleteDocumentHandler } from "./delete-document-handler.js"
export const DeleteDocumentStepTask = {
slug: 'delete-document',
handler: deleteDocumentHandler,
inputSchema: [
{
name: 'collection',
type: 'text',
admin: {
description: 'The collection slug to delete from'
},
required: true
},
{
name: 'id',
type: 'text',
admin: {
description: 'The ID of a specific document to delete (leave empty to delete multiple)'
}
},
{
name: 'where',
type: 'json',
admin: {
description: 'Query conditions to find documents to delete (used when ID is not provided)'
}
}
],
outputSchema: [
{
name: 'doc',
type: 'json',
admin: {
description: 'The deleted document(s)'
}
},
{
name: 'deletedCount',
type: 'number',
admin: {
description: 'Number of documents deleted'
}
}
]
} satisfies TaskConfig<'delete-document'>

View File

@@ -0,0 +1,14 @@
import type {TaskHandler} from "payload"
export const httpStepHandler: TaskHandler<'http-request-step'> = async ({input}) => {
if (!input) {
throw new Error('No input provided')
}
const response = await fetch(input.url)
return {
output: {
response: await response.text()
},
state: response.ok ? 'succeeded' : undefined
}
}

20
src/steps/http-request.ts Normal file
View File

@@ -0,0 +1,20 @@
import type {TaskConfig} from "payload"
import {httpStepHandler} from "./http-request-handler.js"
export const HttpRequestStepTask = {
slug: 'http-request-step',
handler: httpStepHandler,
inputSchema: [
{
name: 'url',
type: 'text',
}
],
outputSchema: [
{
name: 'response',
type: 'textarea',
}
]
} satisfies TaskConfig<'http-request-step'>

13
src/steps/index.ts Normal file
View File

@@ -0,0 +1,13 @@
export { CreateDocumentStepTask } from './create-document.js'
export { createDocumentHandler } from './create-document-handler.js'
export { DeleteDocumentStepTask } from './delete-document.js'
export { deleteDocumentHandler } from './delete-document-handler.js'
export { HttpRequestStepTask } from './http-request.js'
export { httpStepHandler } from './http-request-handler.js'
export { ReadDocumentStepTask } from './read-document.js'
export { readDocumentHandler } from './read-document-handler.js'
export { SendEmailStepTask } from './send-email.js'
export { sendEmailHandler } from './send-email-handler.js'
export { UpdateDocumentStepTask } from './update-document.js'
export { updateDocumentHandler } from './update-document-handler.js'

View File

@@ -0,0 +1,60 @@
import type { TaskHandler } from "payload"
export const readDocumentHandler: TaskHandler<'read-document'> = async ({ input, req }) => {
if (!input) {
throw new Error('No input provided')
}
const { id, collection, depth, limit, locale, sort, where } = input
if (!collection || typeof collection !== 'string') {
throw new Error('Collection slug is required')
}
try {
// If ID is provided, find by ID
if (id) {
const result = await req.payload.findByID({
id: id.toString(),
collection,
depth: typeof depth === 'number' ? depth : undefined,
locale: locale || undefined,
req
})
return {
output: {
doc: result,
totalDocs: 1
},
state: 'succeeded'
}
}
// Otherwise, find multiple documents
const parsedWhere = where ? (typeof where === 'string' ? JSON.parse(where) : where) : {}
const result = await req.payload.find({
collection,
depth: typeof depth === 'number' ? depth : undefined,
limit: typeof limit === 'number' ? limit : 10,
locale: locale || undefined,
req,
sort: sort || undefined,
where: parsedWhere
})
return {
output: {
doc: result.docs,
totalDocs: result.totalDocs
},
state: 'succeeded'
}
} catch (error) {
return {
errorName: error instanceof Error ? error.message : 'Failed to read document(s)',
state: 'failed'
}
}
}

View File

@@ -0,0 +1,76 @@
import type { TaskConfig } from "payload"
import { readDocumentHandler } from "./read-document-handler.js"
export const ReadDocumentStepTask = {
slug: 'read-document',
handler: readDocumentHandler,
inputSchema: [
{
name: 'collection',
type: 'text',
admin: {
description: 'The collection slug to read from'
},
required: true
},
{
name: 'id',
type: 'text',
admin: {
description: 'The ID of a specific document to read (leave empty to find multiple)'
}
},
{
name: 'where',
type: 'json',
admin: {
description: 'Query conditions to find documents (used when ID is not provided)'
}
},
{
name: 'limit',
type: 'number',
admin: {
description: 'Maximum number of documents to return (default: 10)'
}
},
{
name: 'sort',
type: 'text',
admin: {
description: 'Field to sort by (prefix with - for descending order)'
}
},
{
name: 'locale',
type: 'text',
admin: {
description: 'Locale for the document (if localization is enabled)'
}
},
{
name: 'depth',
type: 'number',
admin: {
description: 'Depth of relationships to populate (0-10)'
}
}
],
outputSchema: [
{
name: 'doc',
type: 'json',
admin: {
description: 'The document(s) found'
}
},
{
name: 'totalDocs',
type: 'number',
admin: {
description: 'Total number of documents matching the query'
}
}
]
} satisfies TaskConfig<'read-document'>

View File

@@ -0,0 +1,56 @@
import type { TaskHandler } from "payload"
export const sendEmailHandler: TaskHandler<'send-email'> = async ({ input, req }) => {
if (!input) {
throw new Error('No input provided')
}
const { bcc, cc, from, html, subject, text, to } = input
if (!to || typeof to !== 'string') {
throw new Error('Recipient email address (to) is required')
}
if (!subject || typeof subject !== 'string') {
throw new Error('Subject is required')
}
if (!text && !html) {
throw new Error('Either text or html content is required')
}
try {
// Use Payload's email functionality
const emailData = {
bcc: Array.isArray(bcc) ? bcc.filter(email => typeof email === 'string') : undefined,
cc: Array.isArray(cc) ? cc.filter(email => typeof email === 'string') : undefined,
from: typeof from === 'string' ? from : undefined,
html: typeof html === 'string' ? html : undefined,
subject,
text: typeof text === 'string' ? text : undefined,
to
}
// Clean up undefined values
Object.keys(emailData).forEach(key => {
if (emailData[key as keyof typeof emailData] === undefined) {
delete emailData[key as keyof typeof emailData]
}
})
const result = await req.payload.sendEmail(emailData)
return {
output: {
messageId: (result && typeof result === 'object' && 'messageId' in result) ? result.messageId : 'unknown',
response: typeof result === 'object' ? JSON.stringify(result) : String(result)
},
state: 'succeeded'
}
} catch (error) {
return {
errorMessage: error instanceof Error ? error.message : 'Failed to send email',
state: 'failed'
}
}
}

79
src/steps/send-email.ts Normal file
View File

@@ -0,0 +1,79 @@
import type { TaskConfig } from "payload"
import { sendEmailHandler } from "./send-email-handler.js"
export const SendEmailStepTask = {
slug: 'send-email',
handler: sendEmailHandler,
inputSchema: [
{
name: 'to',
type: 'text',
admin: {
description: 'Recipient email address'
},
required: true
},
{
name: 'from',
type: 'text',
admin: {
description: 'Sender email address (optional, uses default if not provided)'
}
},
{
name: 'subject',
type: 'text',
admin: {
description: 'Email subject line'
},
required: true
},
{
name: 'text',
type: 'textarea',
admin: {
description: 'Plain text email content'
}
},
{
name: 'html',
type: 'textarea',
admin: {
description: 'HTML email content (optional)'
}
},
{
name: 'cc',
type: 'text',
admin: {
description: 'CC recipients'
},
hasMany: true
},
{
name: 'bcc',
type: 'text',
admin: {
description: 'BCC recipients'
},
hasMany: true
}
],
outputSchema: [
{
name: 'messageId',
type: 'text',
admin: {
description: 'Email message ID from the mail server'
}
},
{
name: 'response',
type: 'text',
admin: {
description: 'Response from the mail server'
}
}
]
} satisfies TaskConfig<'send-email'>

View File

@@ -0,0 +1,47 @@
import type { TaskHandler } from "payload"
export const updateDocumentHandler: TaskHandler<'update-document'> = async ({ input, req }) => {
if (!input) {
throw new Error('No input provided')
}
const { id, collection, data, draft, locale } = input
if (!collection || typeof collection !== 'string') {
throw new Error('Collection slug is required')
}
if (!id) {
throw new Error('Document ID is required')
}
if (!data) {
throw new Error('Update data is required')
}
try {
const parsedData = typeof data === 'string' ? JSON.parse(data) : data
const result = await req.payload.update({
id: id.toString(),
collection,
data: parsedData,
draft: draft || false,
locale: locale || undefined,
req
})
return {
output: {
id: result.id,
doc: result
},
state: 'succeeded'
}
} catch (error) {
return {
errorName: error instanceof Error ? error.message : 'Failed to update document',
state: 'failed'
}
}
}

View File

@@ -0,0 +1,64 @@
import type { TaskConfig } from "payload"
import { updateDocumentHandler } from "./update-document-handler.js"
export const UpdateDocumentStepTask = {
slug: 'update-document',
handler: updateDocumentHandler,
inputSchema: [
{
name: 'collection',
type: 'text',
admin: {
description: 'The collection slug to update a document in'
},
required: true
},
{
name: 'id',
type: 'text',
admin: {
description: 'The ID of the document to update'
},
required: true
},
{
name: 'data',
type: 'json',
admin: {
description: 'The data to update the document with'
},
required: true
},
{
name: 'draft',
type: 'checkbox',
admin: {
description: 'Update as draft (if collection has drafts enabled)'
}
},
{
name: 'locale',
type: 'text',
admin: {
description: 'Locale for the document (if localization is enabled)'
}
}
],
outputSchema: [
{
name: 'doc',
type: 'json',
admin: {
description: 'The updated document'
}
},
{
name: 'id',
type: 'text',
admin: {
description: 'The ID of the updated document'
}
}
]
} satisfies TaskConfig<'update-document'>