Add Activepieces integration for workflow automation
- Add Activepieces fork with SmoothSchedule custom piece - Create integrations app with Activepieces service layer - Add embed token endpoint for iframe integration - Create Automations page with embedded workflow builder - Add sidebar visibility fix for embed mode - Add list inactive customers endpoint to Public API - Include SmoothSchedule triggers: event created/updated/cancelled - Include SmoothSchedule actions: create/update/cancel events, list resources/services/customers 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "@activepieces/piece-smoothschedule",
|
||||
"version": "0.0.1"
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"name": "pieces-smoothschedule",
|
||||
"$schema": "../../../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "packages/pieces/community/smoothschedule/src",
|
||||
"projectType": "library",
|
||||
"release": {
|
||||
"version": {
|
||||
"currentVersionResolver": "git-tag",
|
||||
"preserveLocalDependencyProtocols": false,
|
||||
"manifestRootsToUpdate": [
|
||||
"dist/{projectRoot}"
|
||||
]
|
||||
}
|
||||
},
|
||||
"tags": [],
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "@nx/js:tsc",
|
||||
"outputs": [
|
||||
"{options.outputPath}"
|
||||
],
|
||||
"options": {
|
||||
"outputPath": "dist/packages/pieces/community/smoothschedule",
|
||||
"tsConfig": "packages/pieces/community/smoothschedule/tsconfig.lib.json",
|
||||
"packageJson": "packages/pieces/community/smoothschedule/package.json",
|
||||
"main": "packages/pieces/community/smoothschedule/src/index.ts",
|
||||
"assets": [
|
||||
"packages/pieces/community/smoothschedule/*.md"
|
||||
],
|
||||
"buildableProjectDepsInPackageJsonType": "dependencies",
|
||||
"updateBuildableProjectDepsInPackageJson": true
|
||||
},
|
||||
"dependsOn": [
|
||||
"^build",
|
||||
"prebuild"
|
||||
]
|
||||
},
|
||||
"nx-release-publish": {
|
||||
"options": {
|
||||
"packageRoot": "dist/{projectRoot}"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nx/eslint:lint",
|
||||
"outputs": [
|
||||
"{options.outputFile}"
|
||||
]
|
||||
},
|
||||
"prebuild": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"cwd": "packages/pieces/community/smoothschedule",
|
||||
"command": "bun install --no-save --silent"
|
||||
},
|
||||
"dependsOn": [
|
||||
"^build"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,54 @@
|
||||
import { Property, createAction } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { smoothScheduleAuth, SmoothScheduleAuth } from '../../index';
|
||||
import { makeRequest } from '../common';
|
||||
|
||||
export const cancelEventAction = createAction({
|
||||
auth: smoothScheduleAuth,
|
||||
name: 'cancel_event',
|
||||
displayName: 'Cancel Event',
|
||||
description: 'Cancels an event in SmoothSchedule.',
|
||||
props: {
|
||||
eventId: Property.ShortText({
|
||||
displayName: 'Event ID',
|
||||
description: 'The ID of the event to cancel',
|
||||
required: true,
|
||||
}),
|
||||
cancellationReason: Property.LongText({
|
||||
displayName: 'Cancellation Reason',
|
||||
description: 'Reason for cancellation',
|
||||
required: false,
|
||||
}),
|
||||
sendNotification: Property.Checkbox({
|
||||
displayName: 'Send Cancellation Notice',
|
||||
description: 'Send cancellation email to customer',
|
||||
required: false,
|
||||
defaultValue: true,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const auth = context.auth as SmoothScheduleAuth;
|
||||
const props = context.propsValue;
|
||||
|
||||
const body: Record<string, unknown> = {
|
||||
status: 'CANCELLED',
|
||||
};
|
||||
|
||||
if (props.cancellationReason) {
|
||||
body['cancellation_reason'] = props.cancellationReason;
|
||||
}
|
||||
|
||||
if (props.sendNotification !== undefined) {
|
||||
body['send_notification'] = props.sendNotification;
|
||||
}
|
||||
|
||||
const response = await makeRequest<Record<string, unknown>>(
|
||||
auth,
|
||||
HttpMethod.PATCH,
|
||||
`/events/${props.eventId}/`,
|
||||
body
|
||||
);
|
||||
|
||||
return response;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,131 @@
|
||||
import { Property, createAction } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { smoothScheduleAuth, SmoothScheduleAuth } from '../../index';
|
||||
import { makeRequest, formatDateTime } from '../common';
|
||||
import { resourceMultiSelectDropdown, serviceDropdown, customerDropdown } from '../common/props';
|
||||
|
||||
export const createEventAction = createAction({
|
||||
auth: smoothScheduleAuth,
|
||||
name: 'create_event',
|
||||
displayName: 'Create Event',
|
||||
description: 'Creates a new appointment or event in SmoothSchedule.',
|
||||
props: {
|
||||
title: Property.ShortText({
|
||||
displayName: 'Title',
|
||||
description: 'Event title (optional - will be auto-generated from service if not provided)',
|
||||
required: false,
|
||||
}),
|
||||
startTime: Property.DateTime({
|
||||
displayName: 'Start Time',
|
||||
description: 'When the event starts',
|
||||
required: true,
|
||||
}),
|
||||
endTime: Property.DateTime({
|
||||
displayName: 'End Time',
|
||||
description: 'When the event ends (optional - will be calculated from service duration if not provided)',
|
||||
required: false,
|
||||
}),
|
||||
serviceId: serviceDropdown({
|
||||
displayName: 'Service',
|
||||
description: 'The service for this appointment',
|
||||
required: false,
|
||||
}),
|
||||
resourceIds: resourceMultiSelectDropdown({
|
||||
displayName: 'Resources',
|
||||
description: 'Staff, rooms, or equipment for this event',
|
||||
required: false,
|
||||
}),
|
||||
customerId: customerDropdown({
|
||||
displayName: 'Customer',
|
||||
description: 'The customer for this appointment',
|
||||
required: false,
|
||||
}),
|
||||
customerEmail: Property.ShortText({
|
||||
displayName: 'Customer Email',
|
||||
description: 'Customer email (used if Customer not selected)',
|
||||
required: false,
|
||||
}),
|
||||
customerFirstName: Property.ShortText({
|
||||
displayName: 'Customer First Name',
|
||||
description: 'Customer first name (used if Customer not selected)',
|
||||
required: false,
|
||||
}),
|
||||
customerLastName: Property.ShortText({
|
||||
displayName: 'Customer Last Name',
|
||||
description: 'Customer last name (used if Customer not selected)',
|
||||
required: false,
|
||||
}),
|
||||
customerPhone: Property.ShortText({
|
||||
displayName: 'Customer Phone',
|
||||
description: 'Customer phone number',
|
||||
required: false,
|
||||
}),
|
||||
notes: Property.LongText({
|
||||
displayName: 'Notes',
|
||||
description: 'Internal notes for this event',
|
||||
required: false,
|
||||
}),
|
||||
status: Property.StaticDropdown({
|
||||
displayName: 'Status',
|
||||
description: 'Event status',
|
||||
required: false,
|
||||
defaultValue: 'CONFIRMED',
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'Confirmed', value: 'CONFIRMED' },
|
||||
{ label: 'Pending', value: 'PENDING' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
sendConfirmation: Property.Checkbox({
|
||||
displayName: 'Send Confirmation',
|
||||
description: 'Send confirmation email to customer',
|
||||
required: false,
|
||||
defaultValue: true,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const auth = context.auth as SmoothScheduleAuth;
|
||||
const props = context.propsValue;
|
||||
|
||||
const body: Record<string, unknown> = {
|
||||
start_time: formatDateTime(props.startTime),
|
||||
status: props.status || 'CONFIRMED',
|
||||
};
|
||||
|
||||
if (props.title) body['title'] = props.title;
|
||||
if (props.endTime) body['end_time'] = formatDateTime(props.endTime);
|
||||
if (props.serviceId) body['service'] = props.serviceId;
|
||||
if (props.notes) body['notes'] = props.notes;
|
||||
|
||||
// Handle resources as participants
|
||||
if (props.resourceIds && props.resourceIds.length > 0) {
|
||||
body['resource_ids'] = props.resourceIds;
|
||||
}
|
||||
|
||||
// Handle customer - either by ID or by creating inline
|
||||
if (props.customerId) {
|
||||
body['customer_id'] = props.customerId;
|
||||
} else if (props.customerEmail) {
|
||||
body['customer'] = {
|
||||
email: props.customerEmail,
|
||||
first_name: props.customerFirstName || '',
|
||||
last_name: props.customerLastName || '',
|
||||
phone: props.customerPhone || '',
|
||||
};
|
||||
}
|
||||
|
||||
if (props.sendConfirmation !== undefined) {
|
||||
body['send_confirmation'] = props.sendConfirmation;
|
||||
}
|
||||
|
||||
const response = await makeRequest<Record<string, unknown>>(
|
||||
auth,
|
||||
HttpMethod.POST,
|
||||
'/events/',
|
||||
body
|
||||
);
|
||||
|
||||
return response;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,84 @@
|
||||
import { Property, createAction } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { smoothScheduleAuth, SmoothScheduleAuth } from '../../index';
|
||||
import { makeRequest } from '../common';
|
||||
import { resourceDropdown, serviceDropdown, eventStatusDropdown } from '../common/props';
|
||||
|
||||
export const findEventsAction = createAction({
|
||||
auth: smoothScheduleAuth,
|
||||
name: 'find_events',
|
||||
displayName: 'Find Events',
|
||||
description: 'Search for events in SmoothSchedule.',
|
||||
props: {
|
||||
startDate: Property.DateTime({
|
||||
displayName: 'Start Date',
|
||||
description: 'Find events starting from this date',
|
||||
required: false,
|
||||
}),
|
||||
endDate: Property.DateTime({
|
||||
displayName: 'End Date',
|
||||
description: 'Find events up to this date',
|
||||
required: false,
|
||||
}),
|
||||
resourceId: resourceDropdown({
|
||||
displayName: 'Resource',
|
||||
description: 'Filter by resource',
|
||||
required: false,
|
||||
}),
|
||||
serviceId: serviceDropdown({
|
||||
displayName: 'Service',
|
||||
description: 'Filter by service',
|
||||
required: false,
|
||||
}),
|
||||
status: eventStatusDropdown,
|
||||
customerEmail: Property.ShortText({
|
||||
displayName: 'Customer Email',
|
||||
description: 'Filter by customer email',
|
||||
required: false,
|
||||
}),
|
||||
limit: Property.Number({
|
||||
displayName: 'Limit',
|
||||
description: 'Maximum number of events to return',
|
||||
required: false,
|
||||
defaultValue: 50,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const auth = context.auth as SmoothScheduleAuth;
|
||||
const props = context.propsValue;
|
||||
|
||||
const queryParams: Record<string, string> = {};
|
||||
|
||||
if (props.startDate) {
|
||||
queryParams['start_date'] = new Date(props.startDate).toISOString().split('T')[0];
|
||||
}
|
||||
if (props.endDate) {
|
||||
queryParams['end_date'] = new Date(props.endDate).toISOString().split('T')[0];
|
||||
}
|
||||
if (props.resourceId) {
|
||||
queryParams['resource'] = props.resourceId.toString();
|
||||
}
|
||||
if (props.serviceId) {
|
||||
queryParams['service'] = props.serviceId.toString();
|
||||
}
|
||||
if (props.status) {
|
||||
queryParams['status'] = props.status;
|
||||
}
|
||||
if (props.customerEmail) {
|
||||
queryParams['customer_email'] = props.customerEmail;
|
||||
}
|
||||
if (props.limit) {
|
||||
queryParams['limit'] = props.limit.toString();
|
||||
}
|
||||
|
||||
const response = await makeRequest<Record<string, unknown>>(
|
||||
auth,
|
||||
HttpMethod.GET,
|
||||
'/events/',
|
||||
undefined,
|
||||
queryParams
|
||||
);
|
||||
|
||||
return response;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
export * from './create-event';
|
||||
export * from './update-event';
|
||||
export * from './cancel-event';
|
||||
export * from './find-events';
|
||||
export * from './list-resources';
|
||||
export * from './list-services';
|
||||
export * from './list-inactive-customers';
|
||||
@@ -0,0 +1,62 @@
|
||||
import { Property, createAction } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { smoothScheduleAuth, SmoothScheduleAuth } from '../../index';
|
||||
import { makeRequest } from '../common';
|
||||
|
||||
interface InactiveCustomer {
|
||||
id: number;
|
||||
email: string;
|
||||
first_name: string;
|
||||
last_name: string;
|
||||
name: string;
|
||||
phone: string | null;
|
||||
last_appointment_at: string | null;
|
||||
days_since_last_appointment: number | null;
|
||||
}
|
||||
|
||||
export const listInactiveCustomersAction = createAction({
|
||||
auth: smoothScheduleAuth,
|
||||
name: 'list_inactive_customers',
|
||||
displayName: 'List Inactive Customers',
|
||||
description: 'Get customers who haven\'t booked an appointment in a specified number of days. Perfect for win-back email campaigns when used with a Schedule trigger.',
|
||||
props: {
|
||||
inactiveDays: Property.Number({
|
||||
displayName: 'Days Inactive',
|
||||
description: 'Number of days without an appointment to consider a customer inactive (1-365)',
|
||||
required: true,
|
||||
defaultValue: 30,
|
||||
}),
|
||||
limit: Property.Number({
|
||||
displayName: 'Maximum Results',
|
||||
description: 'Maximum number of customers to return (1-500)',
|
||||
required: false,
|
||||
defaultValue: 100,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const auth = context.auth as SmoothScheduleAuth;
|
||||
const props = context.propsValue;
|
||||
|
||||
const days = Math.max(1, Math.min(props.inactiveDays || 30, 365));
|
||||
const limit = Math.max(1, Math.min(props.limit || 100, 500));
|
||||
|
||||
const queryParams: Record<string, string> = {
|
||||
days: days.toString(),
|
||||
limit: limit.toString(),
|
||||
};
|
||||
|
||||
const customers = await makeRequest<InactiveCustomer[]>(
|
||||
auth,
|
||||
HttpMethod.GET,
|
||||
'/customers/inactive/',
|
||||
undefined,
|
||||
queryParams
|
||||
);
|
||||
|
||||
return {
|
||||
customers,
|
||||
count: customers.length,
|
||||
days_threshold: days,
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,55 @@
|
||||
import { Property, createAction } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { smoothScheduleAuth, SmoothScheduleAuth } from '../../index';
|
||||
import { makeRequest } from '../common';
|
||||
|
||||
export const listResourcesAction = createAction({
|
||||
auth: smoothScheduleAuth,
|
||||
name: 'list_resources',
|
||||
displayName: 'List Resources',
|
||||
description: 'Get a list of resources (staff, rooms, equipment) from SmoothSchedule.',
|
||||
props: {
|
||||
type: Property.StaticDropdown({
|
||||
displayName: 'Resource Type',
|
||||
description: 'Filter by resource type',
|
||||
required: false,
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'All Types', value: '' },
|
||||
{ label: 'Staff', value: 'STAFF' },
|
||||
{ label: 'Room', value: 'ROOM' },
|
||||
{ label: 'Equipment', value: 'EQUIPMENT' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
activeOnly: Property.Checkbox({
|
||||
displayName: 'Active Only',
|
||||
description: 'Only return active resources',
|
||||
required: false,
|
||||
defaultValue: true,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const auth = context.auth as SmoothScheduleAuth;
|
||||
const props = context.propsValue;
|
||||
|
||||
const queryParams: Record<string, string> = {};
|
||||
|
||||
if (props.type) {
|
||||
queryParams['type'] = props.type;
|
||||
}
|
||||
if (props.activeOnly) {
|
||||
queryParams['is_active'] = 'true';
|
||||
}
|
||||
|
||||
const response = await makeRequest<Record<string, unknown>[]>(
|
||||
auth,
|
||||
HttpMethod.GET,
|
||||
'/resources/',
|
||||
undefined,
|
||||
queryParams
|
||||
);
|
||||
|
||||
return { resources: response };
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,39 @@
|
||||
import { Property, createAction } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { smoothScheduleAuth, SmoothScheduleAuth } from '../../index';
|
||||
import { makeRequest } from '../common';
|
||||
|
||||
export const listServicesAction = createAction({
|
||||
auth: smoothScheduleAuth,
|
||||
name: 'list_services',
|
||||
displayName: 'List Services',
|
||||
description: 'Get a list of services from SmoothSchedule.',
|
||||
props: {
|
||||
activeOnly: Property.Checkbox({
|
||||
displayName: 'Active Only',
|
||||
description: 'Only return active services',
|
||||
required: false,
|
||||
defaultValue: true,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const auth = context.auth as SmoothScheduleAuth;
|
||||
const props = context.propsValue;
|
||||
|
||||
const queryParams: Record<string, string> = {};
|
||||
|
||||
if (props.activeOnly) {
|
||||
queryParams['is_active'] = 'true';
|
||||
}
|
||||
|
||||
const response = await makeRequest<Record<string, unknown>[]>(
|
||||
auth,
|
||||
HttpMethod.GET,
|
||||
'/services/',
|
||||
undefined,
|
||||
queryParams
|
||||
);
|
||||
|
||||
return { services: response };
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,86 @@
|
||||
import { Property, createAction } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { smoothScheduleAuth, SmoothScheduleAuth } from '../../index';
|
||||
import { makeRequest, formatDateTime } from '../common';
|
||||
import { resourceMultiSelectDropdown, serviceDropdown, eventStatusDropdown } from '../common/props';
|
||||
|
||||
export const updateEventAction = createAction({
|
||||
auth: smoothScheduleAuth,
|
||||
name: 'update_event',
|
||||
displayName: 'Update Event',
|
||||
description: 'Updates an existing event in SmoothSchedule.',
|
||||
props: {
|
||||
eventId: Property.ShortText({
|
||||
displayName: 'Event ID',
|
||||
description: 'The ID of the event to update',
|
||||
required: true,
|
||||
}),
|
||||
title: Property.ShortText({
|
||||
displayName: 'Title',
|
||||
description: 'New event title',
|
||||
required: false,
|
||||
}),
|
||||
startTime: Property.DateTime({
|
||||
displayName: 'Start Time',
|
||||
description: 'New start time',
|
||||
required: false,
|
||||
}),
|
||||
endTime: Property.DateTime({
|
||||
displayName: 'End Time',
|
||||
description: 'New end time',
|
||||
required: false,
|
||||
}),
|
||||
serviceId: serviceDropdown({
|
||||
displayName: 'Service',
|
||||
description: 'New service',
|
||||
required: false,
|
||||
}),
|
||||
resourceIds: resourceMultiSelectDropdown({
|
||||
displayName: 'Resources',
|
||||
description: 'New resources (replaces existing)',
|
||||
required: false,
|
||||
}),
|
||||
status: eventStatusDropdown,
|
||||
notes: Property.LongText({
|
||||
displayName: 'Notes',
|
||||
description: 'New notes',
|
||||
required: false,
|
||||
}),
|
||||
sendNotification: Property.Checkbox({
|
||||
displayName: 'Send Notification',
|
||||
description: 'Send update notification to customer',
|
||||
required: false,
|
||||
defaultValue: false,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const auth = context.auth as SmoothScheduleAuth;
|
||||
const props = context.propsValue;
|
||||
|
||||
const body: Record<string, unknown> = {};
|
||||
|
||||
if (props.title !== undefined) body['title'] = props.title;
|
||||
if (props.startTime) body['start_time'] = formatDateTime(props.startTime);
|
||||
if (props.endTime) body['end_time'] = formatDateTime(props.endTime);
|
||||
if (props.serviceId) body['service'] = props.serviceId;
|
||||
if (props.status) body['status'] = props.status;
|
||||
if (props.notes !== undefined) body['notes'] = props.notes;
|
||||
|
||||
if (props.resourceIds && props.resourceIds.length > 0) {
|
||||
body['resource_ids'] = props.resourceIds;
|
||||
}
|
||||
|
||||
if (props.sendNotification !== undefined) {
|
||||
body['send_notification'] = props.sendNotification;
|
||||
}
|
||||
|
||||
const response = await makeRequest<Record<string, unknown>>(
|
||||
auth,
|
||||
HttpMethod.PATCH,
|
||||
`/events/${props.eventId}/`,
|
||||
body
|
||||
);
|
||||
|
||||
return response;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,183 @@
|
||||
import {
|
||||
HttpMethod,
|
||||
httpClient,
|
||||
HttpRequest,
|
||||
} from '@activepieces/pieces-common';
|
||||
import { SmoothScheduleAuth } from '../../index';
|
||||
|
||||
export const API_URL = '/v1';
|
||||
|
||||
/**
|
||||
* Make an authenticated request to the SmoothSchedule API
|
||||
*
|
||||
* Uses Bearer token authentication with ss_live_* or ss_test_* tokens.
|
||||
* Authorization: Bearer ss_live_xxxxx
|
||||
*/
|
||||
export async function makeRequest<T>(
|
||||
auth: SmoothScheduleAuth,
|
||||
method: HttpMethod,
|
||||
endpoint: string,
|
||||
body?: Record<string, unknown>,
|
||||
queryParams?: Record<string, string>
|
||||
): Promise<T> {
|
||||
// When running inside Docker, the baseUrl might be "http://django:8000" (internal Docker network).
|
||||
// Django-tenants requires a valid Host header for tenant resolution.
|
||||
// Map Docker internal hostname to the external hostname that Django recognizes.
|
||||
const url = new URL(auth.props.baseUrl);
|
||||
let hostHeader = `${url.hostname}${url.port ? ':' + url.port : ''}`;
|
||||
|
||||
// Map docker hostname to lvh.me (which Django recognizes)
|
||||
if (url.hostname === 'django') {
|
||||
hostHeader = `lvh.me${url.port ? ':' + url.port : ''}`;
|
||||
}
|
||||
|
||||
const request: HttpRequest = {
|
||||
method,
|
||||
url: `${auth.props.baseUrl}${API_URL}${endpoint}`,
|
||||
body,
|
||||
queryParams,
|
||||
headers: {
|
||||
'X-Tenant': auth.props.subdomain,
|
||||
'Authorization': `Bearer ${auth.props.apiToken}`,
|
||||
'Host': hostHeader,
|
||||
},
|
||||
};
|
||||
|
||||
const response = await httpClient.sendRequest<T>(request);
|
||||
return response.body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch resources (staff, rooms, equipment) for dropdown options
|
||||
*/
|
||||
export async function fetchResources(auth: SmoothScheduleAuth, type?: string) {
|
||||
interface ResourceType {
|
||||
id: string;
|
||||
name: string;
|
||||
category: string;
|
||||
}
|
||||
|
||||
interface Resource {
|
||||
id: string;
|
||||
name: string;
|
||||
resource_type: ResourceType;
|
||||
is_active: boolean;
|
||||
}
|
||||
|
||||
interface PaginatedResponse {
|
||||
results: Resource[];
|
||||
count: number;
|
||||
}
|
||||
|
||||
const queryParams: Record<string, string> = {};
|
||||
if (type) {
|
||||
queryParams['type'] = type;
|
||||
}
|
||||
|
||||
const response = await makeRequest<PaginatedResponse>(
|
||||
auth,
|
||||
HttpMethod.GET,
|
||||
'/resources/',
|
||||
undefined,
|
||||
queryParams
|
||||
);
|
||||
|
||||
const resources = response.results || [];
|
||||
|
||||
return resources
|
||||
.filter((r) => r.is_active)
|
||||
.map((r) => ({
|
||||
label: `${r.name} (${r.resource_type?.name || 'Unknown'})`,
|
||||
value: r.id,
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch services for dropdown options
|
||||
*/
|
||||
export async function fetchServices(auth: SmoothScheduleAuth) {
|
||||
interface Service {
|
||||
id: string;
|
||||
name: string;
|
||||
duration: number;
|
||||
is_active: boolean;
|
||||
}
|
||||
|
||||
interface PaginatedResponse {
|
||||
results: Service[];
|
||||
count: number;
|
||||
}
|
||||
|
||||
const response = await makeRequest<PaginatedResponse>(
|
||||
auth,
|
||||
HttpMethod.GET,
|
||||
'/services/'
|
||||
);
|
||||
|
||||
const services = response.results || [];
|
||||
|
||||
return services
|
||||
.filter((s) => s.is_active)
|
||||
.map((s) => ({
|
||||
label: `${s.name} (${s.duration} min)`,
|
||||
value: s.id,
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch customers for dropdown options
|
||||
*/
|
||||
export async function fetchCustomers(auth: SmoothScheduleAuth, search?: string) {
|
||||
interface Customer {
|
||||
id: string;
|
||||
email: string;
|
||||
first_name: string;
|
||||
last_name: string;
|
||||
}
|
||||
|
||||
interface PaginatedResponse {
|
||||
results: Customer[];
|
||||
count: number;
|
||||
}
|
||||
|
||||
const queryParams: Record<string, string> = {};
|
||||
if (search) {
|
||||
queryParams['search'] = search;
|
||||
}
|
||||
|
||||
const response = await makeRequest<PaginatedResponse>(
|
||||
auth,
|
||||
HttpMethod.GET,
|
||||
'/customers/',
|
||||
undefined,
|
||||
queryParams
|
||||
);
|
||||
|
||||
const customers = response.results || [];
|
||||
|
||||
return customers.map((c) => ({
|
||||
label: `${c.first_name} ${c.last_name} (${c.email})`,
|
||||
value: c.id,
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch appointment/event details by ID
|
||||
*/
|
||||
export async function getEventDetails(auth: SmoothScheduleAuth, eventId: string) {
|
||||
return makeRequest<Record<string, unknown>>(
|
||||
auth,
|
||||
HttpMethod.GET,
|
||||
`/appointments/${eventId}/`
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format ISO datetime string
|
||||
*/
|
||||
export function formatDateTime(date: string | Date): string {
|
||||
if (typeof date === 'string') {
|
||||
return date;
|
||||
}
|
||||
return date.toISOString();
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
import { Property, DropdownOption } from '@activepieces/pieces-framework';
|
||||
import { smoothScheduleAuth, SmoothScheduleAuth } from '../../index';
|
||||
import { fetchResources, fetchServices, fetchCustomers } from './index';
|
||||
|
||||
/**
|
||||
* Resource dropdown property factory
|
||||
*/
|
||||
export function resourceDropdown(options: {
|
||||
displayName: string;
|
||||
description?: string;
|
||||
required: boolean;
|
||||
resourceType?: 'STAFF' | 'ROOM' | 'EQUIPMENT';
|
||||
}) {
|
||||
return Property.Dropdown({
|
||||
auth: smoothScheduleAuth,
|
||||
displayName: options.displayName,
|
||||
description: options.description,
|
||||
required: options.required,
|
||||
refreshers: ['auth'],
|
||||
options: async (propsValue) => {
|
||||
const auth = propsValue.auth as SmoothScheduleAuth;
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Please connect your SmoothSchedule account first',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const resources = await fetchResources(auth, options.resourceType);
|
||||
return {
|
||||
disabled: false,
|
||||
options: resources as DropdownOption<string>[],
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Failed to load resources. Check your connection.',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Multi-select resource dropdown for selecting multiple resources
|
||||
*/
|
||||
export function resourceMultiSelectDropdown(options: {
|
||||
displayName: string;
|
||||
description?: string;
|
||||
required: boolean;
|
||||
resourceType?: 'STAFF' | 'ROOM' | 'EQUIPMENT';
|
||||
}) {
|
||||
return Property.MultiSelectDropdown({
|
||||
auth: smoothScheduleAuth,
|
||||
displayName: options.displayName,
|
||||
description: options.description,
|
||||
required: options.required,
|
||||
refreshers: ['auth'],
|
||||
options: async (propsValue) => {
|
||||
const auth = propsValue.auth as SmoothScheduleAuth;
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Please connect your SmoothSchedule account first',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const resources = await fetchResources(auth, options.resourceType);
|
||||
return {
|
||||
disabled: false,
|
||||
options: resources as DropdownOption<string>[],
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Failed to load resources. Check your connection.',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Service dropdown property factory
|
||||
*/
|
||||
export function serviceDropdown(options: {
|
||||
displayName: string;
|
||||
description?: string;
|
||||
required: boolean;
|
||||
}) {
|
||||
return Property.Dropdown({
|
||||
auth: smoothScheduleAuth,
|
||||
displayName: options.displayName,
|
||||
description: options.description,
|
||||
required: options.required,
|
||||
refreshers: ['auth'],
|
||||
options: async (propsValue) => {
|
||||
const auth = propsValue.auth as SmoothScheduleAuth;
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Please connect your SmoothSchedule account first',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const services = await fetchServices(auth);
|
||||
return {
|
||||
disabled: false,
|
||||
options: services as DropdownOption<string>[],
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Failed to load services. Check your connection.',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Customer dropdown with search capability
|
||||
*/
|
||||
export function customerDropdown(options: {
|
||||
displayName: string;
|
||||
description?: string;
|
||||
required: boolean;
|
||||
}) {
|
||||
return Property.Dropdown({
|
||||
auth: smoothScheduleAuth,
|
||||
displayName: options.displayName,
|
||||
description: options.description,
|
||||
required: options.required,
|
||||
refreshers: ['auth'],
|
||||
options: async (propsValue) => {
|
||||
const auth = propsValue.auth as SmoothScheduleAuth;
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Please connect your SmoothSchedule account first',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const customers = await fetchCustomers(auth);
|
||||
return {
|
||||
disabled: false,
|
||||
options: customers as DropdownOption<string>[],
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Failed to load customers. Check your connection.',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Event status dropdown
|
||||
*/
|
||||
export const eventStatusDropdown = Property.StaticDropdown({
|
||||
displayName: 'Status',
|
||||
description: 'Event status',
|
||||
required: false,
|
||||
options: {
|
||||
options: [
|
||||
{ label: 'Confirmed', value: 'CONFIRMED' },
|
||||
{ label: 'Pending', value: 'PENDING' },
|
||||
{ label: 'Cancelled', value: 'CANCELLED' },
|
||||
{ label: 'Completed', value: 'COMPLETED' },
|
||||
{ label: 'No Show', value: 'NO_SHOW' },
|
||||
],
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,117 @@
|
||||
import { createTrigger, TriggerStrategy } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { smoothScheduleAuth, SmoothScheduleAuth } from '../../index';
|
||||
import { makeRequest } from '../common';
|
||||
import { resourceDropdown, serviceDropdown } from '../common/props';
|
||||
|
||||
const TRIGGER_KEY = 'last_cancelled_check';
|
||||
|
||||
export const eventCancelledTrigger = createTrigger({
|
||||
auth: smoothScheduleAuth,
|
||||
name: 'event_cancelled',
|
||||
displayName: 'Event Cancelled',
|
||||
description: 'Triggers when an event is cancelled in SmoothSchedule.',
|
||||
props: {
|
||||
resourceId: resourceDropdown({
|
||||
displayName: 'Resource',
|
||||
description: 'Only trigger for events with this resource (optional)',
|
||||
required: false,
|
||||
}),
|
||||
serviceId: serviceDropdown({
|
||||
displayName: 'Service',
|
||||
description: 'Only trigger for events with this service (optional)',
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
type: TriggerStrategy.POLLING,
|
||||
async onEnable(context) {
|
||||
// Store the current timestamp as the starting point
|
||||
await context.store.put(TRIGGER_KEY, new Date().toISOString());
|
||||
},
|
||||
async onDisable(context) {
|
||||
await context.store.delete(TRIGGER_KEY);
|
||||
},
|
||||
async test(context) {
|
||||
const auth = context.auth as SmoothScheduleAuth;
|
||||
const { resourceId, serviceId } = context.propsValue;
|
||||
|
||||
const queryParams: Record<string, string> = {
|
||||
limit: '5',
|
||||
status: 'CANCELLED',
|
||||
ordering: '-updated_at',
|
||||
};
|
||||
|
||||
if (resourceId) {
|
||||
queryParams['resource'] = resourceId.toString();
|
||||
}
|
||||
if (serviceId) {
|
||||
queryParams['service'] = serviceId.toString();
|
||||
}
|
||||
|
||||
const events = await makeRequest<Array<Record<string, unknown>>>(
|
||||
auth,
|
||||
HttpMethod.GET,
|
||||
'/events/',
|
||||
undefined,
|
||||
queryParams
|
||||
);
|
||||
|
||||
return events;
|
||||
},
|
||||
async run(context) {
|
||||
const auth = context.auth as SmoothScheduleAuth;
|
||||
const { resourceId, serviceId } = context.propsValue;
|
||||
|
||||
const lastCheck = await context.store.get<string>(TRIGGER_KEY) || new Date(0).toISOString();
|
||||
|
||||
// Look for events that were updated recently and have CANCELLED status
|
||||
const queryParams: Record<string, string> = {
|
||||
status: 'CANCELLED',
|
||||
ordering: 'updated_at',
|
||||
updated_at__gt: lastCheck,
|
||||
};
|
||||
|
||||
if (resourceId) {
|
||||
queryParams['resource'] = resourceId.toString();
|
||||
}
|
||||
if (serviceId) {
|
||||
queryParams['service'] = serviceId.toString();
|
||||
}
|
||||
|
||||
const events = await makeRequest<Array<{ updated_at: string } & Record<string, unknown>>>(
|
||||
auth,
|
||||
HttpMethod.GET,
|
||||
'/events/',
|
||||
undefined,
|
||||
queryParams
|
||||
);
|
||||
|
||||
// Update the last check timestamp
|
||||
await context.store.put(TRIGGER_KEY, new Date().toISOString());
|
||||
|
||||
return events;
|
||||
},
|
||||
sampleData: {
|
||||
id: 12345,
|
||||
title: 'Consultation',
|
||||
start_time: '2024-12-01T10:00:00Z',
|
||||
end_time: '2024-12-01T11:00:00Z',
|
||||
status: 'CANCELLED',
|
||||
cancellation_reason: 'Customer requested cancellation',
|
||||
service: {
|
||||
id: 1,
|
||||
name: 'Consultation',
|
||||
},
|
||||
customer: {
|
||||
id: 100,
|
||||
first_name: 'John',
|
||||
last_name: 'Doe',
|
||||
email: 'john.doe@example.com',
|
||||
},
|
||||
resources: [
|
||||
{ id: 1, name: 'Dr. Smith', type: 'STAFF' },
|
||||
],
|
||||
created_at: '2024-11-28T14:30:00Z',
|
||||
updated_at: '2024-11-30T11:00:00Z',
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,133 @@
|
||||
import { createTrigger, TriggerStrategy } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { smoothScheduleAuth, SmoothScheduleAuth } from '../../index';
|
||||
import { makeRequest } from '../common';
|
||||
import { resourceDropdown, serviceDropdown } from '../common/props';
|
||||
|
||||
const TRIGGER_KEY = 'last_event_created_id';
|
||||
|
||||
export const eventCreatedTrigger = createTrigger({
|
||||
auth: smoothScheduleAuth,
|
||||
name: 'event_created',
|
||||
displayName: 'Event Created',
|
||||
description: 'Triggers when a new event is created in SmoothSchedule.',
|
||||
props: {
|
||||
resourceId: resourceDropdown({
|
||||
displayName: 'Resource',
|
||||
description: 'Only trigger for events with this resource (optional)',
|
||||
required: false,
|
||||
}),
|
||||
serviceId: serviceDropdown({
|
||||
displayName: 'Service',
|
||||
description: 'Only trigger for events with this service (optional)',
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
type: TriggerStrategy.POLLING,
|
||||
async onEnable(context) {
|
||||
// Get the most recent event ID to start from
|
||||
const auth = context.auth as SmoothScheduleAuth;
|
||||
|
||||
try {
|
||||
const events = await makeRequest<Array<{ id: number }>>(
|
||||
auth,
|
||||
HttpMethod.GET,
|
||||
'/events/',
|
||||
undefined,
|
||||
{ limit: '1', ordering: '-created_at' }
|
||||
);
|
||||
|
||||
if (events.length > 0) {
|
||||
await context.store.put(TRIGGER_KEY, events[0].id);
|
||||
} else {
|
||||
await context.store.put(TRIGGER_KEY, 0);
|
||||
}
|
||||
} catch (error) {
|
||||
await context.store.put(TRIGGER_KEY, 0);
|
||||
}
|
||||
},
|
||||
async onDisable(context) {
|
||||
await context.store.delete(TRIGGER_KEY);
|
||||
},
|
||||
async test(context) {
|
||||
const auth = context.auth as SmoothScheduleAuth;
|
||||
const { resourceId, serviceId } = context.propsValue;
|
||||
|
||||
const queryParams: Record<string, string> = {
|
||||
limit: '5',
|
||||
ordering: '-created_at',
|
||||
};
|
||||
|
||||
if (resourceId) {
|
||||
queryParams['resource'] = resourceId.toString();
|
||||
}
|
||||
if (serviceId) {
|
||||
queryParams['service'] = serviceId.toString();
|
||||
}
|
||||
|
||||
const events = await makeRequest<Array<Record<string, unknown>>>(
|
||||
auth,
|
||||
HttpMethod.GET,
|
||||
'/events/',
|
||||
undefined,
|
||||
queryParams
|
||||
);
|
||||
|
||||
return events;
|
||||
},
|
||||
async run(context) {
|
||||
const auth = context.auth as SmoothScheduleAuth;
|
||||
const { resourceId, serviceId } = context.propsValue;
|
||||
|
||||
const lastEventId = await context.store.get<number>(TRIGGER_KEY) || 0;
|
||||
|
||||
const queryParams: Record<string, string> = {
|
||||
ordering: 'created_at',
|
||||
id__gt: lastEventId.toString(),
|
||||
};
|
||||
|
||||
if (resourceId) {
|
||||
queryParams['resource'] = resourceId.toString();
|
||||
}
|
||||
if (serviceId) {
|
||||
queryParams['service'] = serviceId.toString();
|
||||
}
|
||||
|
||||
const events = await makeRequest<Array<{ id: number } & Record<string, unknown>>>(
|
||||
auth,
|
||||
HttpMethod.GET,
|
||||
'/events/',
|
||||
undefined,
|
||||
queryParams
|
||||
);
|
||||
|
||||
if (events.length > 0) {
|
||||
// Update the last event ID
|
||||
const maxId = Math.max(...events.map((e) => e.id));
|
||||
await context.store.put(TRIGGER_KEY, maxId);
|
||||
}
|
||||
|
||||
return events;
|
||||
},
|
||||
sampleData: {
|
||||
id: 12345,
|
||||
title: 'Consultation',
|
||||
start_time: '2024-12-01T10:00:00Z',
|
||||
end_time: '2024-12-01T11:00:00Z',
|
||||
status: 'CONFIRMED',
|
||||
service: {
|
||||
id: 1,
|
||||
name: 'Consultation',
|
||||
},
|
||||
customer: {
|
||||
id: 100,
|
||||
first_name: 'John',
|
||||
last_name: 'Doe',
|
||||
email: 'john.doe@example.com',
|
||||
},
|
||||
resources: [
|
||||
{ id: 1, name: 'Dr. Smith', type: 'STAFF' },
|
||||
],
|
||||
created_at: '2024-11-28T14:30:00Z',
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,119 @@
|
||||
import { createTrigger, TriggerStrategy } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { smoothScheduleAuth, SmoothScheduleAuth } from '../../index';
|
||||
import { makeRequest } from '../common';
|
||||
import { resourceDropdown, serviceDropdown } from '../common/props';
|
||||
|
||||
const TRIGGER_KEY = 'last_event_updated_at';
|
||||
|
||||
export const eventUpdatedTrigger = createTrigger({
|
||||
auth: smoothScheduleAuth,
|
||||
name: 'event_updated',
|
||||
displayName: 'Event Updated',
|
||||
description: 'Triggers when an event is updated in SmoothSchedule.',
|
||||
props: {
|
||||
resourceId: resourceDropdown({
|
||||
displayName: 'Resource',
|
||||
description: 'Only trigger for events with this resource (optional)',
|
||||
required: false,
|
||||
}),
|
||||
serviceId: serviceDropdown({
|
||||
displayName: 'Service',
|
||||
description: 'Only trigger for events with this service (optional)',
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
type: TriggerStrategy.POLLING,
|
||||
async onEnable(context) {
|
||||
// Store the current timestamp as the starting point
|
||||
await context.store.put(TRIGGER_KEY, new Date().toISOString());
|
||||
},
|
||||
async onDisable(context) {
|
||||
await context.store.delete(TRIGGER_KEY);
|
||||
},
|
||||
async test(context) {
|
||||
const auth = context.auth as SmoothScheduleAuth;
|
||||
const { resourceId, serviceId } = context.propsValue;
|
||||
|
||||
const queryParams: Record<string, string> = {
|
||||
limit: '5',
|
||||
ordering: '-updated_at',
|
||||
};
|
||||
|
||||
if (resourceId) {
|
||||
queryParams['resource'] = resourceId.toString();
|
||||
}
|
||||
if (serviceId) {
|
||||
queryParams['service'] = serviceId.toString();
|
||||
}
|
||||
|
||||
const events = await makeRequest<Array<Record<string, unknown>>>(
|
||||
auth,
|
||||
HttpMethod.GET,
|
||||
'/events/',
|
||||
undefined,
|
||||
queryParams
|
||||
);
|
||||
|
||||
return events;
|
||||
},
|
||||
async run(context) {
|
||||
const auth = context.auth as SmoothScheduleAuth;
|
||||
const { resourceId, serviceId } = context.propsValue;
|
||||
|
||||
const lastUpdatedAt = await context.store.get<string>(TRIGGER_KEY) || new Date(0).toISOString();
|
||||
|
||||
const queryParams: Record<string, string> = {
|
||||
ordering: 'updated_at',
|
||||
updated_at__gt: lastUpdatedAt,
|
||||
};
|
||||
|
||||
if (resourceId) {
|
||||
queryParams['resource'] = resourceId.toString();
|
||||
}
|
||||
if (serviceId) {
|
||||
queryParams['service'] = serviceId.toString();
|
||||
}
|
||||
|
||||
const events = await makeRequest<Array<{ updated_at: string } & Record<string, unknown>>>(
|
||||
auth,
|
||||
HttpMethod.GET,
|
||||
'/events/',
|
||||
undefined,
|
||||
queryParams
|
||||
);
|
||||
|
||||
if (events.length > 0) {
|
||||
// Update the last updated timestamp
|
||||
const maxUpdatedAt = events.reduce((max, e) =>
|
||||
e.updated_at > max ? e.updated_at : max,
|
||||
lastUpdatedAt
|
||||
);
|
||||
await context.store.put(TRIGGER_KEY, maxUpdatedAt);
|
||||
}
|
||||
|
||||
return events;
|
||||
},
|
||||
sampleData: {
|
||||
id: 12345,
|
||||
title: 'Consultation',
|
||||
start_time: '2024-12-01T10:00:00Z',
|
||||
end_time: '2024-12-01T11:00:00Z',
|
||||
status: 'CONFIRMED',
|
||||
service: {
|
||||
id: 1,
|
||||
name: 'Consultation',
|
||||
},
|
||||
customer: {
|
||||
id: 100,
|
||||
first_name: 'John',
|
||||
last_name: 'Doe',
|
||||
email: 'john.doe@example.com',
|
||||
},
|
||||
resources: [
|
||||
{ id: 1, name: 'Dr. Smith', type: 'STAFF' },
|
||||
],
|
||||
created_at: '2024-11-28T14:30:00Z',
|
||||
updated_at: '2024-11-29T09:15:00Z',
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from './event-created';
|
||||
export * from './event-updated';
|
||||
export * from './event-cancelled';
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"extends": "../../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"noImplicitOverride": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noPropertyAccessFromIndexSignature": true
|
||||
},
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"outDir": "../../../../dist/out-tsc",
|
||||
"declaration": true,
|
||||
"types": ["node"]
|
||||
},
|
||||
"exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"],
|
||||
"include": ["src/**/*.ts"]
|
||||
}
|
||||
Reference in New Issue
Block a user