@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.
Files changed (43) hide show
  1. package/dist/schema/bookings.d.ts +195 -309
  2. package/dist/schema/bookings.d.ts.map +1 -1
  3. package/dist/schema/bookings.js +4 -5
  4. package/dist/schema/bookings.js.map +1 -1
  5. package/dist/schema/calendar-cache.d.ts +26 -42
  6. package/dist/schema/calendar-cache.d.ts.map +1 -1
  7. package/dist/schema/credentials.d.ts +121 -191
  8. package/dist/schema/credentials.d.ts.map +1 -1
  9. package/dist/schema/credentials.js +4 -5
  10. package/dist/schema/credentials.js.map +1 -1
  11. package/dist/schema/event-types.d.ts +213 -313
  12. package/dist/schema/event-types.d.ts.map +1 -1
  13. package/dist/schema/event-types.js +8 -15
  14. package/dist/schema/event-types.js.map +1 -1
  15. package/dist/schema/routing-forms.d.ts +93 -149
  16. package/dist/schema/routing-forms.d.ts.map +1 -1
  17. package/dist/schema/routing-forms.js +3 -2
  18. package/dist/schema/routing-forms.js.map +1 -1
  19. package/dist/schema/schedules.d.ts +135 -213
  20. package/dist/schema/schedules.d.ts.map +1 -1
  21. package/dist/schema/schedules.js +2 -3
  22. package/dist/schema/schedules.js.map +1 -1
  23. package/dist/schema/teams.d.ts +93 -147
  24. package/dist/schema/teams.d.ts.map +1 -1
  25. package/dist/schema/teams.js +4 -5
  26. package/dist/schema/teams.js.map +1 -1
  27. package/dist/schema/workflows.d.ts +224 -344
  28. package/dist/schema/workflows.d.ts.map +1 -1
  29. package/dist/schema/workflows.js +6 -5
  30. package/dist/schema/workflows.js.map +1 -1
  31. package/docs/llms-full.txt +1 -1
  32. package/docs/schema.md +1 -1
  33. package/package.json +4 -5
  34. package/src/actions/booking-authz.spec.ts +34 -21
  35. package/src/actions/event-type-authz.spec.ts +34 -21
  36. package/src/schema/bookings.ts +4 -5
  37. package/src/schema/credentials.ts +4 -5
  38. package/src/schema/event-types.ts +8 -15
  39. package/src/schema/routing-forms.ts +2 -2
  40. package/src/schema/schedules.ts +2 -3
  41. package/src/schema/teams.ts +3 -5
  42. package/src/schema/workflows.ts +6 -5
  43. package/src/server/booking-service.spec.ts +47 -34
@@ -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: integer("disabled", { mode: "boolean" }).notNull().default(false),
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: integer("sent", { mode: "boolean" }).notNull().default(false),
82
+ sent: boolean("sent").notNull().default(false),
82
83
  sentAt: text("sent_at"),
83
- failed: integer("failed", { mode: "boolean" }).notNull().default(false),
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: integer("active", { mode: "boolean" }).notNull().default(true),
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: integer("success", { mode: "boolean" }).notNull().default(false),
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 { createClient, type Client } from "@libsql/client";
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
- client = createClient({ url: `file:${join(dbDir, `${randomUUID()}.db`)}` });
77
- await client.execute(`
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 INTEGER NOT NULL DEFAULT 0,
100
- no_show_host INTEGER NOT NULL DEFAULT 0,
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 client.execute(`
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 INTEGER NOT NULL DEFAULT 0,
130
+ no_show BOOLEAN NOT NULL DEFAULT false,
118
131
  created_at TEXT NOT NULL
119
132
  );
120
133
  `);
121
- await client.execute(`
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 client.execute(`
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 client.execute(`
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 INTEGER NOT NULL DEFAULT 0,
156
- is_default INTEGER NOT NULL DEFAULT 0,
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 client.execute(`
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 client.execute(`
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 INTEGER NOT NULL DEFAULT 0,
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 client.execute(`
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 INTEGER NOT NULL DEFAULT 1,
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 client.execute(`
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 INTEGER NOT NULL DEFAULT 0,
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 INTEGER NOT NULL DEFAULT 0,
230
- disable_guests INTEGER NOT NULL DEFAULT 0,
231
- hide_calendar_notes INTEGER NOT NULL DEFAULT 0,
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 INTEGER NOT NULL DEFAULT 0,
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 = drizzle(client, { schema });
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
- client.close();
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 client.execute({
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 client.execute("SELECT * FROM bookings");
381
+ const { rows } = await execute("SELECT * FROM bookings");
369
382
  expect(rows).toHaveLength(0);
370
- const { rows: attendeeRows } = await client.execute(
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 client.execute({
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 client.execute(
449
+ const { rows } = await execute(
437
450
  "SELECT * FROM bookings WHERE host_email = 'host@example.com'",
438
451
  );
439
452
  expect(rows).toHaveLength(1);