Compare commits

..

9 Commits

Author SHA1 Message Date
Bas
7f04275d39 Merge pull request #33 from xtr-dev/dev
Dev
2025-09-13 23:53:56 +02:00
20afe30e88 Fix scheduledAt type in SendEmailTaskInput and add Date normalization
- Update SendEmailTaskInput.scheduledAt to support string | Date types
- Add Date object normalization to ISO strings in sendEmail processing
- Ensure consistent database storage format for all timestamp fields
- Convert Date objects to ISO strings before database operations

Resolves remaining "Type Date is not assignable to type string" error
for scheduledAt field in job task input.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-13 23:53:25 +02:00
02b3fecadf Bump package version to 0.1.17 in package.json. 2025-09-13 23:52:53 +02:00
Bas
ea87f14308 Merge pull request #32 from xtr-dev/dev
Dev
2025-09-13 23:48:28 +02:00
6886027727 Bump package version to 0.1.16 in package.json. 2025-09-13 23:45:39 +02:00
965569be06 Add Date type support for timestamp fields
- Update scheduledAt, sentAt, lastAttemptAt, createdAt, updatedAt fields to support Date | string | null
- Support both Date objects and ISO string formats for all timestamp fields
- Update BaseEmailDocument, BaseEmailTemplateDocument, and QueuedEmail interfaces consistently
- Update documentation to reflect Date object compatibility

Fixes type constraint error where customer timestamp fields use Date objects
but plugin interfaces only supported string formats.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-13 23:44:57 +02:00
Bas
ff788c1ecf Merge pull request #31 from xtr-dev/dev
Fix variables field type to support all JSON-compatible values
2025-09-13 23:41:43 +02:00
c12438aaa2 Bump package version to 0.1.15 in package.json. 2025-09-13 23:40:31 +02:00
4dcbc1446a Fix variables field type to support all JSON-compatible values
- Replace restrictive Record<string, any> with flexible JSONValue type for variables field
- Add JSONValue type alias that matches Payload's JSON field type specification
- Support string, number, boolean, objects, arrays, null, and undefined for variables
- Update both BaseEmailDocument and QueuedEmail interfaces consistently
- Update documentation to reflect JSONValue support

Fixes type constraint error where customer Email.variables field type
(string | number | boolean | {...} | unknown[] | null | undefined)
was not assignable to Record<string, any>.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-13 23:38:46 +02:00
5 changed files with 47 additions and 22 deletions

View File

@@ -44,6 +44,8 @@ The plugin works with:
- **String IDs**: `id: string`
- **Number IDs**: `id: number`
- **Nullable fields**: Fields can be `null`, `undefined`, or have values
- **Date fields**: Timestamp fields support both `Date` objects and `string` (ISO) formats
- **JSON variables**: Variables field supports any JSON-compatible value type
- **Generated types**: Works with `payload generate:types` output
Your Payload configuration determines which types are used. The plugin automatically adapts to your setup.
@@ -53,6 +55,9 @@ Your Payload configuration determines which types are used. The plugin automatic
The base interfaces provided by the plugin:
```typescript
// JSON value type that matches Payload's JSON field type
type JSONValue = string | number | boolean | { [k: string]: unknown } | unknown[] | null | undefined
interface BaseEmailDocument {
id: string | number
template?: any
@@ -64,16 +69,16 @@ interface BaseEmailDocument {
subject: string
html: string
text?: string | null
variables?: Record<string, any> | null
scheduledAt?: string | null
sentAt?: string | null
variables?: JSONValue // Supports any JSON-compatible value
scheduledAt?: string | Date | null
sentAt?: string | Date | null
status?: 'pending' | 'processing' | 'sent' | 'failed' | null
attempts?: number | null
lastAttemptAt?: string | null
lastAttemptAt?: string | Date | null
error?: string | null
priority?: number | null
createdAt?: string | null
updatedAt?: string | null
createdAt?: string | Date | null
updatedAt?: string | Date | null
}
interface BaseEmailTemplateDocument {
@@ -82,8 +87,8 @@ interface BaseEmailTemplateDocument {
slug: string
subject?: string | null
content?: any
createdAt?: string | null
updatedAt?: string | null
createdAt?: string | Date | null
updatedAt?: string | Date | null
}
```

View File

@@ -1,6 +1,6 @@
{
"name": "@xtr-dev/payload-mailing",
"version": "0.1.14",
"version": "0.1.17",
"description": "Template-based email system with scheduling and job processing for PayloadCMS",
"type": "module",
"main": "dist/index.js",

View File

@@ -15,7 +15,7 @@ export interface SendEmailTaskInput {
to: string | string[]
cc?: string | string[]
bcc?: string | string[]
scheduledAt?: string // ISO date string
scheduledAt?: string | Date // ISO date string or Date object
priority?: number
// Allow any additional fields that users might have in their email collection

View File

@@ -100,6 +100,23 @@ export const sendEmail = async <TEmail extends BaseEmailDocument = BaseEmailDocu
emailData.from = validated && validated.length > 0 ? validated[0] : undefined
}
// Normalize Date objects to ISO strings for consistent database storage
if (emailData.scheduledAt instanceof Date) {
emailData.scheduledAt = emailData.scheduledAt.toISOString()
}
if (emailData.sentAt instanceof Date) {
emailData.sentAt = emailData.sentAt.toISOString()
}
if (emailData.lastAttemptAt instanceof Date) {
emailData.lastAttemptAt = emailData.lastAttemptAt.toISOString()
}
if (emailData.createdAt instanceof Date) {
emailData.createdAt = emailData.createdAt.toISOString()
}
if (emailData.updatedAt instanceof Date) {
emailData.updatedAt = emailData.updatedAt.toISOString()
}
// Create the email in the collection with proper typing
const email = await payload.create({
collection: collectionSlug,

View File

@@ -2,6 +2,9 @@ import { Payload } from 'payload'
import type { CollectionConfig, RichTextField } from 'payload'
import { Transporter } from 'nodemailer'
// JSON value type that matches Payload's JSON field type
export type JSONValue = string | number | boolean | { [k: string]: unknown } | unknown[] | null | undefined
// Generic base interfaces that work with any ID type and null values
export interface BaseEmailDocument {
id: string | number
@@ -14,16 +17,16 @@ export interface BaseEmailDocument {
subject: string
html: string
text?: string | null
variables?: Record<string, any> | null
scheduledAt?: string | null
sentAt?: string | null
variables?: JSONValue
scheduledAt?: string | Date | null
sentAt?: string | Date | null
status?: 'pending' | 'processing' | 'sent' | 'failed' | null
attempts?: number | null
lastAttemptAt?: string | null
lastAttemptAt?: string | Date | null
error?: string | null
priority?: number | null
createdAt?: string | null
updatedAt?: string | null
createdAt?: string | Date | null
updatedAt?: string | Date | null
}
export interface BaseEmailTemplateDocument {
@@ -32,8 +35,8 @@ export interface BaseEmailTemplateDocument {
slug: string
subject?: string | null
content?: any
createdAt?: string | null
updatedAt?: string | null
createdAt?: string | Date | null
updatedAt?: string | Date | null
}
export type BaseEmail<TEmail extends BaseEmailDocument = BaseEmailDocument, TEmailTemplate extends BaseEmailTemplateDocument = BaseEmailTemplateDocument> = Omit<TEmail, 'id' | 'template'> & {template: Omit<TEmailTemplate, 'id'> | TEmailTemplate['id'] | undefined | null}
@@ -84,12 +87,12 @@ export interface QueuedEmail {
subject: string
html: string
text?: string | null
variables?: Record<string, any> | null
scheduledAt?: string | null
sentAt?: string | null
variables?: JSONValue
scheduledAt?: string | Date | null
sentAt?: string | Date | null
status: 'pending' | 'processing' | 'sent' | 'failed'
attempts: number
lastAttemptAt?: string | null
lastAttemptAt?: string | Date | null
error?: string | null
priority?: number | null
createdAt: string