@fayz-ai/plugin-agenda 0.9.0 → 0.9.1

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 (153) hide show
  1. package/README.md +3 -3
  2. package/dist/bridges/create-financial-bridge.d.ts +1 -1
  3. package/dist/bridges/create-financial-bridge.d.ts.map +1 -1
  4. package/dist/bridges/financial-bridge.d.ts.map +1 -0
  5. package/dist/{chunk-Q2PAWBPR.js → chunk-76ZOHRBM.js} +2 -2
  6. package/dist/{chunk-Q2PAWBPR.js.map → chunk-76ZOHRBM.js.map} +1 -1
  7. package/dist/components/PaymentStatusBadge.d.ts +1 -1
  8. package/dist/components/PaymentStatusBadge.d.ts.map +1 -1
  9. package/dist/config.d.ts +2 -2
  10. package/dist/config.d.ts.map +1 -1
  11. package/dist/{AgendaContext.d.ts → context.d.ts} +1 -1
  12. package/dist/context.d.ts.map +1 -0
  13. package/dist/data/registries.d.ts.map +1 -0
  14. package/dist/index.d.ts +2 -1
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +170 -7
  17. package/dist/index.js.map +1 -1
  18. package/dist/lib/message-events.d.ts +12 -0
  19. package/dist/lib/message-events.d.ts.map +1 -0
  20. package/dist/public/{data.d.ts → data/index.d.ts} +4 -4
  21. package/dist/public/data/index.d.ts.map +1 -0
  22. package/dist/public/{data.supabase.d.ts → data/supabase.d.ts} +2 -2
  23. package/dist/public/data/supabase.d.ts.map +1 -0
  24. package/dist/public/{hooks.d.ts → hooks/index.d.ts} +4 -4
  25. package/dist/public/hooks/index.d.ts.map +1 -0
  26. package/dist/public/index.d.ts +4 -4
  27. package/dist/public/index.d.ts.map +1 -1
  28. package/dist/public/index.js +3 -3
  29. package/dist/public/index.js.map +1 -1
  30. package/dist/public/{format.d.ts → lib/format.d.ts} +1 -1
  31. package/dist/public/lib/format.d.ts.map +1 -0
  32. package/dist/public/views/BookingWidget.d.ts.map +1 -0
  33. package/dist/public/{steps → views/steps}/ContactStep.d.ts +1 -1
  34. package/dist/public/views/steps/ContactStep.d.ts.map +1 -0
  35. package/dist/public/{steps → views/steps}/DateTimeStep.d.ts +3 -3
  36. package/dist/public/views/steps/DateTimeStep.d.ts.map +1 -0
  37. package/dist/public/{steps → views/steps}/OverviewStep.d.ts +1 -1
  38. package/dist/public/views/steps/OverviewStep.d.ts.map +1 -0
  39. package/dist/public/{steps → views/steps}/PaymentStep.d.ts +1 -1
  40. package/dist/public/views/steps/PaymentStep.d.ts.map +1 -0
  41. package/dist/store.d.ts +1 -1
  42. package/dist/store.d.ts.map +1 -1
  43. package/dist/styles/calendar-styles.d.ts.map +1 -0
  44. package/dist/types.d.ts +1 -1
  45. package/dist/types.d.ts.map +1 -1
  46. package/dist/{AgendaPage.d.ts → views/AgendaPage.d.ts} +3 -3
  47. package/dist/views/AgendaPage.d.ts.map +1 -0
  48. package/package.json +6 -9
  49. package/dist/AgendaContext.d.ts.map +0 -1
  50. package/dist/AgendaPage.d.ts.map +0 -1
  51. package/dist/calendar-styles.d.ts.map +0 -1
  52. package/dist/financial-bridge.d.ts.map +0 -1
  53. package/dist/public/BookingWidget.d.ts.map +0 -1
  54. package/dist/public/data.d.ts.map +0 -1
  55. package/dist/public/data.supabase.d.ts.map +0 -1
  56. package/dist/public/format.d.ts.map +0 -1
  57. package/dist/public/hooks.d.ts.map +0 -1
  58. package/dist/public/steps/ContactStep.d.ts.map +0 -1
  59. package/dist/public/steps/DateTimeStep.d.ts.map +0 -1
  60. package/dist/public/steps/OverviewStep.d.ts.map +0 -1
  61. package/dist/public/steps/PaymentStep.d.ts.map +0 -1
  62. package/dist/registries.d.ts.map +0 -1
  63. package/src/AgendaContext.tsx +0 -11
  64. package/src/AgendaPage.tsx +0 -33
  65. package/src/bridges/create-financial-bridge.ts +0 -296
  66. package/src/calendar-styles.css +0 -245
  67. package/src/calendar-styles.ts +0 -285
  68. package/src/components/AgendaGeneralSettings.tsx +0 -86
  69. package/src/components/AgendaMobileList.tsx +0 -103
  70. package/src/components/AppointmentModal.tsx +0 -1050
  71. package/src/components/AppointmentPopover.tsx +0 -231
  72. package/src/components/BookingPaymentPanel.tsx +0 -394
  73. package/src/components/CalendarSidebar.tsx +0 -119
  74. package/src/components/CalendarToolbar.tsx +0 -86
  75. package/src/components/EventContextMenu.tsx +0 -125
  76. package/src/components/FloatingPanel.tsx +0 -123
  77. package/src/components/MiniCalendar.tsx +0 -120
  78. package/src/components/PaymentStatusBadge.tsx +0 -62
  79. package/src/components/StatusBadge.tsx +0 -23
  80. package/src/config.ts +0 -368
  81. package/src/data/index.ts +0 -4
  82. package/src/data/mock.ts +0 -344
  83. package/src/data/supabase.ts +0 -636
  84. package/src/data/types.ts +0 -37
  85. package/src/financial-bridge.ts +0 -96
  86. package/src/hooks/useAgendaSettings.ts +0 -17
  87. package/src/index.ts +0 -297
  88. package/src/integrations/google-calendar/GoogleCalendarSettings.tsx +0 -136
  89. package/src/integrations/google-calendar/components/CalendarColorDot.tsx +0 -23
  90. package/src/integrations/google-calendar/components/ChannelMappingList.tsx +0 -329
  91. package/src/integrations/google-calendar/components/ImportEventsWizard.tsx +0 -215
  92. package/src/integrations/google-calendar/components/useAgendaLookups.ts +0 -100
  93. package/src/integrations/google-calendar/connector.ts +0 -20
  94. package/src/integrations/google-calendar/connectorDef.tsx +0 -185
  95. package/src/integrations/google-calendar/data/supabase.ts +0 -170
  96. package/src/integrations/google-calendar/data/tables.ts +0 -12
  97. package/src/integrations/google-calendar/index.ts +0 -45
  98. package/src/integrations/google-calendar/integration.test.ts +0 -199
  99. package/src/integrations/google-calendar/mapping.ts +0 -183
  100. package/src/integrations/google-calendar/migrations/001_google_calendar.sql +0 -97
  101. package/src/integrations/google-calendar/migrations/002_smart_sync.sql +0 -517
  102. package/src/integrations/google-calendar/migrations/003_plg_rename.sql +0 -273
  103. package/src/integrations/google-calendar/types.ts +0 -142
  104. package/src/lib/tenant.ts +0 -3
  105. package/src/locales/en.ts +0 -220
  106. package/src/locales/index.ts +0 -7
  107. package/src/locales/pt-BR.ts +0 -220
  108. package/src/migrations/000b_v_bookings_rename.sql +0 -21
  109. package/src/migrations/000c_dedupe_customer_phones.sql +0 -43
  110. package/src/migrations/001_public_booking.sql +0 -296
  111. package/src/migrations/002_v_bookings_compat.sql +0 -14
  112. package/src/migrations/003_public_client_kind.sql +0 -175
  113. package/src/migrations/004_public_booking_assignee.sql +0 -176
  114. package/src/migrations/005_agent_rpcs.sql +0 -168
  115. package/src/migrations/006_agent_rpc_localtime.sql +0 -181
  116. package/src/migrations/007_schedule_exception_precedence.sql +0 -290
  117. package/src/migrations/008_agent_rpc_exception_precedence.sql +0 -172
  118. package/src/migrations/009_public_booking_location.sql +0 -162
  119. package/src/migrations/010_public_service_curation.sql +0 -31
  120. package/src/migrations/011_default_assignee.sql +0 -167
  121. package/src/migrations/012_drop_legacy_booking_overload.sql +0 -29
  122. package/src/migrations/013_normalize_v_appointments.sql +0 -199
  123. package/src/migrations/014_agent_rpc_update_appointment.sql +0 -199
  124. package/src/migrations/index.ts +0 -2377
  125. package/src/public/BookingWidget.tsx +0 -324
  126. package/src/public/components/BrandHeader.tsx +0 -27
  127. package/src/public/components/ServiceCard.tsx +0 -39
  128. package/src/public/components/SidebarExtras.tsx +0 -30
  129. package/src/public/components/StepRailItem.tsx +0 -27
  130. package/src/public/components/SuccessPanel.tsx +0 -27
  131. package/src/public/components/SummaryRail.tsx +0 -90
  132. package/src/public/components/defaults.ts +0 -14
  133. package/src/public/context.tsx +0 -103
  134. package/src/public/createPublicBookingPlugin.ts +0 -281
  135. package/src/public/data.supabase.ts +0 -97
  136. package/src/public/data.ts +0 -105
  137. package/src/public/format.ts +0 -96
  138. package/src/public/hooks.ts +0 -110
  139. package/src/public/index.ts +0 -69
  140. package/src/public/steps/ContactStep.tsx +0 -184
  141. package/src/public/steps/DateTimeStep.tsx +0 -138
  142. package/src/public/steps/OverviewStep.tsx +0 -81
  143. package/src/public/steps/PaymentStep.tsx +0 -180
  144. package/src/public/types.ts +0 -250
  145. package/src/registries.ts +0 -35
  146. package/src/store.ts +0 -311
  147. package/src/types.ts +0 -273
  148. package/src/views/CalendarView.tsx +0 -1112
  149. package/src/views/ConfirmationsView.tsx +0 -155
  150. /package/dist/{financial-bridge.d.ts → bridges/financial-bridge.d.ts} +0 -0
  151. /package/dist/{registries.d.ts → data/registries.d.ts} +0 -0
  152. /package/dist/public/{BookingWidget.d.ts → views/BookingWidget.d.ts} +0 -0
  153. /package/dist/{calendar-styles.d.ts → styles/calendar-styles.d.ts} +0 -0
@@ -1,183 +0,0 @@
1
- // Booking ↔ Google Calendar event mapping — the SINGLE SOURCE OF TRUTH.
2
- //
3
- // These helpers are pure and Deno-friendly (only `import type`, no runtime
4
- // node/react/https imports), so the Supabase edge function imports this exact
5
- // file via a relative path (`../../src/integrations/google-calendar/mapping.ts`)
6
- // instead of keeping a divergent mirror. `import type` is elided by the Deno /
7
- // esbuild bundler, so the plugin `types.ts`/`CalendarBooking` type imports never
8
- // become runtime dependencies of the function bundle.
9
- //
10
- // Two callers, two input shapes:
11
- // • the SDK/UI works with the rich `CalendarBooking` (camelCase, joined) — see
12
- // bookingToEvent / eventToBookingPatch;
13
- // • the edge function + RPCs work with the raw `AppointmentRow` (snake_case DB
14
- // columns) — see appointmentRowToEvent / eventToAppointmentPatch.
15
- // Field decisions (title, all-day, cancel) are made once, here.
16
- import type { CalendarBooking } from '../../types'
17
- import type { GCalEvent, AppointmentRow, CalendarChannel, CalendarChannelRow } from './types'
18
-
19
- export interface GCalEventInput {
20
- summary: string
21
- description?: string
22
- // Timed events use dateTime; all-day events use date (YYYY-MM-DD).
23
- start: { dateTime?: string; date?: string; timeZone?: string }
24
- end: { dateTime?: string; date?: string; timeZone?: string }
25
- }
26
-
27
- /** Normalized time window read off a Google event, all-day aware. */
28
- export interface EventTimes {
29
- startsAt: string
30
- endsAt: string
31
- allDay: boolean
32
- }
33
-
34
- // --- Booking (rich SDK shape) → event -------------------------------------
35
-
36
- /** Build the event title from the booking's services + client. */
37
- export function bookingSummary(b: Pick<CalendarBooking, 'services' | 'clientName'>): string {
38
- const services = (b.services ?? []).map((s) => s.name).filter(Boolean).join(', ')
39
- const who = b.clientName ?? ''
40
- if (services && who) return `${services} — ${who}`
41
- return services || who || 'Appointment'
42
- }
43
-
44
- /** Map a Fayz booking to a Google Calendar event input. Returns null when the booking has no end. */
45
- export function bookingToEvent(b: CalendarBooking, timeZone?: string): GCalEventInput | null {
46
- if (!b.startsAt || !b.endsAt) return null
47
- const notes = [b.notes, b.professionalName ? `Pro: ${b.professionalName}` : '', b.locationName ?? '']
48
- .filter(Boolean).join('\n')
49
- return {
50
- summary: bookingSummary(b),
51
- description: notes || undefined,
52
- start: { dateTime: b.startsAt, timeZone },
53
- end: { dateTime: b.endsAt, timeZone },
54
- }
55
- }
56
-
57
- /** Map an inbound Google event change to a partial booking update (reschedule/cancel), all-day aware. */
58
- export function eventToBookingPatch(ev: GCalEvent): { startsAt?: string; endsAt?: string; status?: 'cancelled' } {
59
- if (ev.status === 'cancelled') return { status: 'cancelled' }
60
- const t = eventTimes(ev)
61
- return { startsAt: t.startsAt, endsAt: t.endsAt }
62
- }
63
-
64
- // --- Appointment row (raw DB shape) → event -------------------------------
65
-
66
- /**
67
- * Build the event title from an appointments row's denormalized metadata.
68
- * The raw row has no joined services/client, so we read the names the app
69
- * stamps onto metadata (serviceNames, contactName/clientName).
70
- */
71
- export function appointmentRowSummary(row: AppointmentRow): string {
72
- const m = row.metadata ?? {}
73
- const services = (m.serviceNames as string) ?? ''
74
- const who = (m.contactName as string) ?? (m.clientName as string) ?? ''
75
- if (services && who) return `${services} — ${who}`
76
- return services || who || 'Appointment'
77
- }
78
-
79
- /** Map a raw appointments row to a Google event input (outbound push from the edge function). */
80
- export function appointmentRowToEvent(row: AppointmentRow): GCalEventInput {
81
- return {
82
- summary: appointmentRowSummary(row),
83
- description: row.notes ?? undefined,
84
- start: { dateTime: row.starts_at },
85
- end: { dateTime: row.ends_at ?? row.starts_at },
86
- }
87
- }
88
-
89
- /**
90
- * Map an inbound Google event to a DB-friendly appointment patch (snake_case
91
- * times), all-day aware, cancellation included. Consumed by the edge function
92
- * when calling gcal_apply_event_patch.
93
- */
94
- export function eventToAppointmentPatch(ev: GCalEvent): {
95
- starts_at?: string
96
- ends_at?: string
97
- summary?: string
98
- allDay?: boolean
99
- cancelled: boolean
100
- } {
101
- if (ev.status === 'cancelled') return { cancelled: true }
102
- const t = eventTimes(ev)
103
- return { starts_at: t.startsAt, ends_at: t.endsAt, summary: ev.summary, allDay: t.allDay, cancelled: false }
104
- }
105
-
106
- // --- Shared time normalization (all-day aware) ----------------------------
107
-
108
- /**
109
- * Read a normalized {startsAt, endsAt, allDay} window off a Google event.
110
- * All-day events carry `start.date`/`end.date` (YYYY-MM-DD, end exclusive) and
111
- * no dateTime; timed events carry dateTime. Falls back start→end when one side
112
- * is missing so callers always get a usable pair.
113
- */
114
- export function eventTimes(ev: GCalEvent): EventTimes {
115
- const allDay = !ev.start?.dateTime && !!ev.start?.date
116
- const startsAt = ev.start?.dateTime ?? ev.start?.date ?? ''
117
- const endsAt = ev.end?.dateTime ?? ev.end?.date ?? startsAt
118
- return { startsAt, endsAt, allDay }
119
- }
120
-
121
- // --- Channel resolution (outbound destination priority) -------------------
122
-
123
- /** Convert a raw plg_calendar_channels row (snake_case) to the camelCase CalendarChannel. */
124
- export function channelRowToChannel(r: CalendarChannelRow): CalendarChannel {
125
- return {
126
- id: r.id,
127
- integrationId: r.integration_id,
128
- tenantId: r.tenant_id,
129
- googleCalendarId: r.google_calendar_id,
130
- summary: r.summary ?? null,
131
- color: r.color ?? null,
132
- direction: r.direction,
133
- targetKind: r.target_kind ?? null,
134
- targetId: r.target_id ?? null,
135
- importMode: r.import_mode ?? 'appointment',
136
- syncToken: r.sync_token ?? null,
137
- channelId: r.channel_id ?? null,
138
- resourceId: r.resource_id ?? null,
139
- channelExpiresAt: r.channel_expires_at ?? null,
140
- isActive: r.is_active ?? true,
141
- createdAt: r.created_at ?? '',
142
- updatedAt: r.updated_at ?? '',
143
- }
144
- }
145
-
146
- export interface ChannelMatchInput {
147
- assigneeId?: string | null
148
- serviceIds?: string[]
149
- locationId?: string | null
150
- }
151
-
152
- /**
153
- * Pick the outbound destination channel for a booking, by priority:
154
- * 1. a channel targeting the booking's assignee,
155
- * 2. else a channel targeting one of the booking's services,
156
- * 3. else a channel targeting the booking's location,
157
- * 4. else the whole-agenda channel (targetKind === null).
158
- * Only active outbound/bidirectional channels are eligible. Returns null when
159
- * nothing matches (caller falls back to the integration's default calendar).
160
- */
161
- export function resolveTargetChannel(
162
- channels: CalendarChannel[],
163
- booking: ChannelMatchInput,
164
- ): CalendarChannel | null {
165
- const eligible = channels.filter(
166
- (c) => c.isActive && (c.direction === 'outbound' || c.direction === 'bidirectional'),
167
- )
168
- const serviceIds = booking.serviceIds ?? []
169
-
170
- if (booking.assigneeId) {
171
- const byAssignee = eligible.find((c) => c.targetKind === 'assignee' && c.targetId === booking.assigneeId)
172
- if (byAssignee) return byAssignee
173
- }
174
- if (serviceIds.length) {
175
- const byService = eligible.find((c) => c.targetKind === 'service' && !!c.targetId && serviceIds.includes(c.targetId))
176
- if (byService) return byService
177
- }
178
- if (booking.locationId) {
179
- const byLocation = eligible.find((c) => c.targetKind === 'location' && c.targetId === booking.locationId)
180
- if (byLocation) return byLocation
181
- }
182
- return eligible.find((c) => c.targetKind === null) ?? null
183
- }
@@ -1,97 +0,0 @@
1
- -- ---------------------------------------------------------------------------
2
- -- Google Calendar integration (bidirectional) — connection + audit + triggers
3
- -- ---------------------------------------------------------------------------
4
- -- Outbound (Fayz booking → Google event) fires from a trigger on public.appointments
5
- -- via pg_net to the google-calendar-sync edge function (push_event). Inbound
6
- -- (Google → booking) runs on a pg_cron schedule (pull_events) and/or a Google
7
- -- watch-channel webhook. The booking↔event link is stored on
8
- -- public.appointments.metadata.googleCalendarEventId (no schema change there).
9
-
10
- -- Plugin-owned tables carry the platform `plg_<plugin>_` prefix (DATA-MODEL.md
11
- -- Ring 1). Legacy pools provisioned under the old `calendar_*` names are migrated
12
- -- by 003_plg_rename.sql; fresh installs are born with the prefixed names here.
13
- CREATE TABLE IF NOT EXISTS public.plg_calendar_integrations (
14
- id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
15
- tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
16
- provider text NOT NULL DEFAULT 'google',
17
- oauth_refresh_token text,
18
- oauth_access_token text,
19
- token_expires_at timestamptz,
20
- calendar_id text NOT NULL DEFAULT 'primary',
21
- -- Incremental pull cursor + Google watch channel bookkeeping.
22
- sync_token text,
23
- channel_id text,
24
- channel_resource_id text,
25
- channel_expires_at timestamptz,
26
- active boolean NOT NULL DEFAULT true,
27
- last_sync_at timestamptz,
28
- created_at timestamptz NOT NULL DEFAULT now(),
29
- updated_at timestamptz NOT NULL DEFAULT now(),
30
- UNIQUE (tenant_id, provider)
31
- );
32
- ALTER TABLE public.plg_calendar_integrations ENABLE ROW LEVEL SECURITY;
33
- CREATE INDEX IF NOT EXISTS idx_plg_calendar_integrations_tenant ON public.plg_calendar_integrations(tenant_id);
34
-
35
- CREATE TABLE IF NOT EXISTS public.plg_calendar_sync_log (
36
- id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
37
- tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
38
- direction text NOT NULL, -- inbound | outbound
39
- trigger text, -- on-write | scheduled | webhook | manual
40
- status text NOT NULL DEFAULT 'success', -- success | partial | error
41
- fetched integer NOT NULL DEFAULT 0,
42
- written integer NOT NULL DEFAULT 0,
43
- error text,
44
- created_at timestamptz NOT NULL DEFAULT now()
45
- );
46
- ALTER TABLE public.plg_calendar_sync_log ENABLE ROW LEVEL SECURITY;
47
-
48
- -- RLS: tenant isolation.
49
- DO $$
50
- DECLARE t text;
51
- BEGIN
52
- FOR t IN SELECT unnest(ARRAY['plg_calendar_integrations','plg_calendar_sync_log'])
53
- LOOP
54
- EXECUTE format('GRANT SELECT, INSERT, UPDATE, DELETE ON public.%I TO authenticated', t);
55
- IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE schemaname='public' AND tablename=t AND policyname=t||'_rls') THEN
56
- EXECUTE format('CREATE POLICY %I ON public.%I FOR ALL TO authenticated USING (tenant_id IN (SELECT public.user_tenant_ids())) WITH CHECK (tenant_id IN (SELECT public.user_tenant_ids()))', t||'_rls', t);
57
- END IF;
58
- END LOOP;
59
- END $$;
60
-
61
- -- ---------------------------------------------------------------------------
62
- -- Outbound trigger: booking change → edge function (push_event).
63
- -- Requires pg_net + a configured function URL. Set once per project:
64
- -- ALTER DATABASE postgres SET app.gcal_sync_url = 'https://<ref>.functions.supabase.co/google-calendar-sync';
65
- -- ALTER DATABASE postgres SET app.gcal_service_key = '<service-role-key>';
66
- -- Safe to skip in environments without pg_net — outbound also works via the
67
- -- client-side withGoogleCalendarSync() decorator.
68
- -- ---------------------------------------------------------------------------
69
- CREATE OR REPLACE FUNCTION public.fn_gcal_push_booking() RETURNS trigger
70
- LANGUAGE plpgsql SECURITY DEFINER AS $$
71
- DECLARE
72
- url text := current_setting('app.gcal_sync_url', true);
73
- key text := current_setting('app.gcal_service_key', true);
74
- rec record := COALESCE(NEW, OLD);
75
- op text := lower(TG_OP);
76
- BEGIN
77
- IF url IS NULL OR url = '' THEN RETURN COALESCE(NEW, OLD); END IF;
78
- PERFORM net.http_post(
79
- url := url,
80
- headers := jsonb_build_object('Content-Type', 'application/json', 'Authorization', 'Bearer ' || COALESCE(key, '')),
81
- body := jsonb_build_object('action', 'push_event', 'op', op, 'bookingId', rec.id, 'tenantId', rec.tenant_id)
82
- );
83
- RETURN COALESCE(NEW, OLD);
84
- END $$;
85
-
86
- DROP TRIGGER IF EXISTS trg_gcal_push ON public.appointments;
87
- CREATE TRIGGER trg_gcal_push
88
- AFTER INSERT OR UPDATE OR DELETE ON public.appointments
89
- FOR EACH ROW EXECUTE FUNCTION public.fn_gcal_push_booking();
90
-
91
- -- Inbound schedule (optional): pull external changes every 10 minutes.
92
- -- SELECT cron.schedule('gcal-pull', '*/10 * * * *', $$
93
- -- SELECT net.http_post(
94
- -- url := current_setting('app.gcal_sync_url'),
95
- -- headers := jsonb_build_object('Content-Type','application/json','Authorization','Bearer '||current_setting('app.gcal_service_key')),
96
- -- body := jsonb_build_object('action','pull_events'));
97
- -- $$);