@agent-native/scheduling 0.1.57 → 0.1.58-nightly-20260905133321
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/schema/bookings.d.ts +195 -309
- package/dist/schema/bookings.d.ts.map +1 -1
- package/dist/schema/bookings.js +4 -5
- package/dist/schema/bookings.js.map +1 -1
- package/dist/schema/calendar-cache.d.ts +26 -42
- package/dist/schema/calendar-cache.d.ts.map +1 -1
- package/dist/schema/credentials.d.ts +121 -191
- package/dist/schema/credentials.d.ts.map +1 -1
- package/dist/schema/credentials.js +4 -5
- package/dist/schema/credentials.js.map +1 -1
- package/dist/schema/event-types.d.ts +213 -313
- package/dist/schema/event-types.d.ts.map +1 -1
- package/dist/schema/event-types.js +8 -15
- package/dist/schema/event-types.js.map +1 -1
- package/dist/schema/routing-forms.d.ts +93 -149
- package/dist/schema/routing-forms.d.ts.map +1 -1
- package/dist/schema/routing-forms.js +3 -2
- package/dist/schema/routing-forms.js.map +1 -1
- package/dist/schema/schedules.d.ts +135 -213
- package/dist/schema/schedules.d.ts.map +1 -1
- package/dist/schema/schedules.js +2 -3
- package/dist/schema/schedules.js.map +1 -1
- package/dist/schema/teams.d.ts +93 -147
- package/dist/schema/teams.d.ts.map +1 -1
- package/dist/schema/teams.js +4 -5
- package/dist/schema/teams.js.map +1 -1
- package/dist/schema/workflows.d.ts +224 -344
- package/dist/schema/workflows.d.ts.map +1 -1
- package/dist/schema/workflows.js +6 -5
- package/dist/schema/workflows.js.map +1 -1
- package/docs/llms-full.txt +1 -1
- package/docs/schema.md +1 -1
- package/package.json +4 -5
- package/src/actions/booking-authz.spec.ts +34 -21
- package/src/actions/event-type-authz.spec.ts +34 -21
- package/src/schema/bookings.ts +4 -5
- package/src/schema/credentials.ts +4 -5
- package/src/schema/event-types.ts +8 -15
- package/src/schema/routing-forms.ts +2 -2
- package/src/schema/schedules.ts +2 -3
- package/src/schema/teams.ts +3 -5
- package/src/schema/workflows.ts +6 -5
- package/src/server/booking-service.spec.ts +47 -34
package/src/schema/workflows.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
ownableColumns,
|
|
13
13
|
createSharesTable,
|
|
14
14
|
} from "@agent-native/core/db/schema";
|
|
15
|
+
import { boolean } from "drizzle-orm/pg-core";
|
|
15
16
|
|
|
16
17
|
export const workflows = table("workflows", {
|
|
17
18
|
id: text("id").primaryKey(),
|
|
@@ -27,7 +28,7 @@ export const workflows = table("workflows", {
|
|
|
27
28
|
],
|
|
28
29
|
}).notNull(),
|
|
29
30
|
teamId: text("team_id"),
|
|
30
|
-
disabled:
|
|
31
|
+
disabled: boolean("disabled").notNull().default(false),
|
|
31
32
|
/** JSON array of eventTypeIds this workflow runs on. Empty = none. */
|
|
32
33
|
activeOnEventTypeIds: text("active_on_event_type_ids")
|
|
33
34
|
.notNull()
|
|
@@ -78,9 +79,9 @@ export const scheduledReminders = table("scheduled_reminders", {
|
|
|
78
79
|
enum: ["email", "sms", "webhook"],
|
|
79
80
|
}).notNull(),
|
|
80
81
|
scheduledFor: text("scheduled_for").notNull(),
|
|
81
|
-
sent:
|
|
82
|
+
sent: boolean("sent").notNull().default(false),
|
|
82
83
|
sentAt: text("sent_at"),
|
|
83
|
-
failed:
|
|
84
|
+
failed: boolean("failed").notNull().default(false),
|
|
84
85
|
failureReason: text("failure_reason"),
|
|
85
86
|
attempts: integer("attempts").notNull().default(0),
|
|
86
87
|
createdAt: text("created_at").notNull(),
|
|
@@ -92,7 +93,7 @@ export const webhooks = table("webhooks", {
|
|
|
92
93
|
name: text("name"),
|
|
93
94
|
subscriberUrl: text("subscriber_url").notNull(),
|
|
94
95
|
secret: text("secret"),
|
|
95
|
-
active:
|
|
96
|
+
active: boolean("active").notNull().default(true),
|
|
96
97
|
/** JSON array of trigger keys */
|
|
97
98
|
eventTriggers: text("event_triggers").notNull().default("[]"),
|
|
98
99
|
teamId: text("team_id"),
|
|
@@ -109,7 +110,7 @@ export const webhookDeliveries = table("webhook_deliveries", {
|
|
|
109
110
|
payload: text("payload").notNull(),
|
|
110
111
|
responseStatus: integer("response_status"),
|
|
111
112
|
responseBody: text("response_body"),
|
|
112
|
-
success:
|
|
113
|
+
success: boolean("success").notNull().default(false),
|
|
113
114
|
attempts: integer("attempts").notNull().default(0),
|
|
114
115
|
});
|
|
115
116
|
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import { randomUUID } from "node:crypto";
|
|
2
1
|
import { mkdtempSync, rmSync } from "node:fs";
|
|
3
2
|
import { tmpdir } from "node:os";
|
|
4
3
|
import { join } from "node:path";
|
|
5
4
|
|
|
6
|
-
import {
|
|
7
|
-
import { drizzle } from "drizzle-orm/libsql";
|
|
5
|
+
import { closeDbExec, createGetDb, getDbExec } from "@agent-native/core/db";
|
|
8
6
|
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
9
7
|
|
|
10
8
|
import * as schema from "../schema/index.js";
|
|
@@ -18,9 +16,24 @@ import type { CalendarProvider } from "./providers/types.js";
|
|
|
18
16
|
|
|
19
17
|
const HOST_EMAIL = "host@example.com";
|
|
20
18
|
const ATTENDEE_EMAIL = "attendee@example.com";
|
|
19
|
+
|
|
20
|
+
type SqlStatement = string | { sql: string; args?: unknown[] };
|
|
21
|
+
|
|
22
|
+
function postgresSql(sql: string): string {
|
|
23
|
+
let index = 0;
|
|
24
|
+
return sql.replace(/\?/g, () => "$" + ++index);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function execute(statement: SqlStatement) {
|
|
28
|
+
if (typeof statement === "string")
|
|
29
|
+
return getDbExec().execute(postgresSql(statement));
|
|
30
|
+
return getDbExec().execute({
|
|
31
|
+
...statement,
|
|
32
|
+
sql: postgresSql(statement.sql),
|
|
33
|
+
});
|
|
34
|
+
}
|
|
21
35
|
const GUEST_EMAIL = "guest@example.com";
|
|
22
36
|
|
|
23
|
-
let client: Client;
|
|
24
37
|
let dbDir: string;
|
|
25
38
|
|
|
26
39
|
function makeEventType(overrides: Partial<EventType> = {}): EventType {
|
|
@@ -73,8 +86,8 @@ function makeCalendarProvider(
|
|
|
73
86
|
|
|
74
87
|
beforeEach(async () => {
|
|
75
88
|
dbDir = mkdtempSync(join(tmpdir(), "scheduling-booking-test-"));
|
|
76
|
-
|
|
77
|
-
await
|
|
89
|
+
process.env.DATABASE_URL = `pglite:${dbDir}`;
|
|
90
|
+
await execute(`
|
|
78
91
|
CREATE TABLE bookings (
|
|
79
92
|
id TEXT PRIMARY KEY,
|
|
80
93
|
uid TEXT NOT NULL UNIQUE,
|
|
@@ -96,8 +109,8 @@ beforeEach(async () => {
|
|
|
96
109
|
ical_uid TEXT NOT NULL,
|
|
97
110
|
ical_sequence INTEGER NOT NULL DEFAULT 0,
|
|
98
111
|
recurring_event_id TEXT,
|
|
99
|
-
paid
|
|
100
|
-
no_show_host
|
|
112
|
+
paid BOOLEAN NOT NULL DEFAULT false,
|
|
113
|
+
no_show_host BOOLEAN NOT NULL DEFAULT false,
|
|
101
114
|
metadata TEXT,
|
|
102
115
|
created_at TEXT NOT NULL,
|
|
103
116
|
updated_at TEXT NOT NULL,
|
|
@@ -106,7 +119,7 @@ beforeEach(async () => {
|
|
|
106
119
|
visibility TEXT NOT NULL DEFAULT 'private'
|
|
107
120
|
);
|
|
108
121
|
`);
|
|
109
|
-
await
|
|
122
|
+
await execute(`
|
|
110
123
|
CREATE TABLE booking_attendees (
|
|
111
124
|
id TEXT PRIMARY KEY,
|
|
112
125
|
booking_id TEXT NOT NULL,
|
|
@@ -114,11 +127,11 @@ beforeEach(async () => {
|
|
|
114
127
|
name TEXT NOT NULL,
|
|
115
128
|
timezone TEXT,
|
|
116
129
|
locale TEXT,
|
|
117
|
-
no_show
|
|
130
|
+
no_show BOOLEAN NOT NULL DEFAULT false,
|
|
118
131
|
created_at TEXT NOT NULL
|
|
119
132
|
);
|
|
120
133
|
`);
|
|
121
|
-
await
|
|
134
|
+
await execute(`
|
|
122
135
|
CREATE TABLE booking_references (
|
|
123
136
|
id TEXT PRIMARY KEY,
|
|
124
137
|
booking_id TEXT NOT NULL,
|
|
@@ -130,7 +143,7 @@ beforeEach(async () => {
|
|
|
130
143
|
created_at TEXT NOT NULL
|
|
131
144
|
);
|
|
132
145
|
`);
|
|
133
|
-
await
|
|
146
|
+
await execute(`
|
|
134
147
|
CREATE TABLE destination_calendars (
|
|
135
148
|
id TEXT PRIMARY KEY,
|
|
136
149
|
credential_id TEXT NOT NULL,
|
|
@@ -142,7 +155,7 @@ beforeEach(async () => {
|
|
|
142
155
|
created_at TEXT NOT NULL
|
|
143
156
|
);
|
|
144
157
|
`);
|
|
145
|
-
await
|
|
158
|
+
await execute(`
|
|
146
159
|
CREATE TABLE scheduling_credentials (
|
|
147
160
|
id TEXT PRIMARY KEY,
|
|
148
161
|
type TEXT NOT NULL,
|
|
@@ -152,13 +165,13 @@ beforeEach(async () => {
|
|
|
152
165
|
oauth_token_id TEXT,
|
|
153
166
|
display_name TEXT,
|
|
154
167
|
external_email TEXT,
|
|
155
|
-
invalid
|
|
156
|
-
is_default
|
|
168
|
+
invalid BOOLEAN NOT NULL DEFAULT false,
|
|
169
|
+
is_default BOOLEAN NOT NULL DEFAULT false,
|
|
157
170
|
created_at TEXT NOT NULL,
|
|
158
171
|
updated_at TEXT NOT NULL
|
|
159
172
|
);
|
|
160
173
|
`);
|
|
161
|
-
await
|
|
174
|
+
await execute(`
|
|
162
175
|
CREATE TABLE selected_calendars (
|
|
163
176
|
id TEXT PRIMARY KEY,
|
|
164
177
|
credential_id TEXT NOT NULL,
|
|
@@ -169,13 +182,13 @@ beforeEach(async () => {
|
|
|
169
182
|
created_at TEXT NOT NULL
|
|
170
183
|
);
|
|
171
184
|
`);
|
|
172
|
-
await
|
|
185
|
+
await execute(`
|
|
173
186
|
CREATE TABLE workflows (
|
|
174
187
|
id TEXT PRIMARY KEY,
|
|
175
188
|
name TEXT NOT NULL,
|
|
176
189
|
trigger TEXT NOT NULL,
|
|
177
190
|
team_id TEXT,
|
|
178
|
-
disabled
|
|
191
|
+
disabled BOOLEAN NOT NULL DEFAULT false,
|
|
179
192
|
active_on_event_type_ids TEXT NOT NULL DEFAULT '[]',
|
|
180
193
|
created_at TEXT NOT NULL,
|
|
181
194
|
updated_at TEXT NOT NULL,
|
|
@@ -184,13 +197,13 @@ beforeEach(async () => {
|
|
|
184
197
|
visibility TEXT NOT NULL DEFAULT 'private'
|
|
185
198
|
);
|
|
186
199
|
`);
|
|
187
|
-
await
|
|
200
|
+
await execute(`
|
|
188
201
|
CREATE TABLE webhooks (
|
|
189
202
|
id TEXT PRIMARY KEY,
|
|
190
203
|
name TEXT,
|
|
191
204
|
subscriber_url TEXT NOT NULL,
|
|
192
205
|
secret TEXT,
|
|
193
|
-
active
|
|
206
|
+
active BOOLEAN NOT NULL DEFAULT true,
|
|
194
207
|
event_triggers TEXT NOT NULL DEFAULT '[]',
|
|
195
208
|
team_id TEXT,
|
|
196
209
|
event_type_id TEXT,
|
|
@@ -201,7 +214,7 @@ beforeEach(async () => {
|
|
|
201
214
|
visibility TEXT NOT NULL DEFAULT 'private'
|
|
202
215
|
);
|
|
203
216
|
`);
|
|
204
|
-
await
|
|
217
|
+
await execute(`
|
|
205
218
|
CREATE TABLE event_types (
|
|
206
219
|
id TEXT PRIMARY KEY,
|
|
207
220
|
title TEXT NOT NULL,
|
|
@@ -210,7 +223,7 @@ beforeEach(async () => {
|
|
|
210
223
|
length INTEGER NOT NULL DEFAULT 30,
|
|
211
224
|
durations TEXT,
|
|
212
225
|
position INTEGER NOT NULL DEFAULT 0,
|
|
213
|
-
hidden
|
|
226
|
+
hidden BOOLEAN NOT NULL DEFAULT false,
|
|
214
227
|
color TEXT,
|
|
215
228
|
scheduling_type TEXT NOT NULL DEFAULT 'personal',
|
|
216
229
|
team_id TEXT,
|
|
@@ -226,12 +239,12 @@ beforeEach(async () => {
|
|
|
226
239
|
period_start_date TEXT,
|
|
227
240
|
period_end_date TEXT,
|
|
228
241
|
seats_per_time_slot INTEGER,
|
|
229
|
-
requires_confirmation
|
|
230
|
-
disable_guests
|
|
231
|
-
hide_calendar_notes
|
|
242
|
+
requires_confirmation BOOLEAN NOT NULL DEFAULT false,
|
|
243
|
+
disable_guests BOOLEAN NOT NULL DEFAULT false,
|
|
244
|
+
hide_calendar_notes BOOLEAN NOT NULL DEFAULT false,
|
|
232
245
|
success_redirect_url TEXT,
|
|
233
246
|
booking_limits TEXT,
|
|
234
|
-
lock_time_zone_toggle
|
|
247
|
+
lock_time_zone_toggle BOOLEAN NOT NULL DEFAULT false,
|
|
235
248
|
recurring_event TEXT,
|
|
236
249
|
event_name TEXT,
|
|
237
250
|
metadata TEXT,
|
|
@@ -243,7 +256,7 @@ beforeEach(async () => {
|
|
|
243
256
|
);
|
|
244
257
|
`);
|
|
245
258
|
|
|
246
|
-
const db =
|
|
259
|
+
const db = createGetDb(schema)();
|
|
247
260
|
setSchedulingContext({
|
|
248
261
|
getDb: () => db,
|
|
249
262
|
schema,
|
|
@@ -251,14 +264,14 @@ beforeEach(async () => {
|
|
|
251
264
|
});
|
|
252
265
|
});
|
|
253
266
|
|
|
254
|
-
afterEach(() => {
|
|
255
|
-
|
|
267
|
+
afterEach(async () => {
|
|
268
|
+
await closeDbExec();
|
|
256
269
|
rmSync(dbDir, { recursive: true, force: true });
|
|
257
270
|
});
|
|
258
271
|
|
|
259
272
|
/** `rescheduleBooking` re-loads the event type by id, so it must exist. */
|
|
260
273
|
async function seedEventType(eventType: EventType): Promise<void> {
|
|
261
|
-
await
|
|
274
|
+
await execute({
|
|
262
275
|
sql: `INSERT INTO event_types (
|
|
263
276
|
id, title, slug, description, length, durations, position, hidden, color,
|
|
264
277
|
scheduling_type, team_id, locations, custom_fields, schedule_id,
|
|
@@ -365,9 +378,9 @@ describe("insertBooking", () => {
|
|
|
365
378
|
}),
|
|
366
379
|
).rejects.toThrow();
|
|
367
380
|
|
|
368
|
-
const { rows } = await
|
|
381
|
+
const { rows } = await execute("SELECT * FROM bookings");
|
|
369
382
|
expect(rows).toHaveLength(0);
|
|
370
|
-
const { rows: attendeeRows } = await
|
|
383
|
+
const { rows: attendeeRows } = await execute(
|
|
371
384
|
"SELECT * FROM booking_attendees",
|
|
372
385
|
);
|
|
373
386
|
expect(attendeeRows).toHaveLength(0);
|
|
@@ -377,7 +390,7 @@ describe("insertBooking", () => {
|
|
|
377
390
|
describe("createBooking", () => {
|
|
378
391
|
it("creates a booking with attendees and references on a free slot", async () => {
|
|
379
392
|
const now = new Date().toISOString();
|
|
380
|
-
await
|
|
393
|
+
await execute({
|
|
381
394
|
sql: `INSERT INTO destination_calendars
|
|
382
395
|
(id, credential_id, user_email, integration, external_id, created_at)
|
|
383
396
|
VALUES (?, ?, ?, ?, ?, ?)`,
|
|
@@ -433,7 +446,7 @@ describe("createBooking", () => {
|
|
|
433
446
|
}),
|
|
434
447
|
).rejects.toBeInstanceOf(SlotConflictError);
|
|
435
448
|
|
|
436
|
-
const { rows } = await
|
|
449
|
+
const { rows } = await execute(
|
|
437
450
|
"SELECT * FROM bookings WHERE host_email = 'host@example.com'",
|
|
438
451
|
);
|
|
439
452
|
expect(rows).toHaveLength(1);
|