slotlock 0.8.0 → 0.10.0

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 (86) hide show
  1. package/CHANGELOG.md +542 -0
  2. package/NOTICE +2 -0
  3. package/README.md +4 -2
  4. package/agent-server.d.ts +25 -5
  5. package/agent-server.js +152 -7
  6. package/agent-store-backend.d.ts +6 -1
  7. package/agent-store-backend.js +1068 -68
  8. package/application-api.d.ts +28 -1
  9. package/application-api.js +789 -21
  10. package/approvals.d.ts +2 -0
  11. package/approvals.js +12 -5
  12. package/assistant.d.ts +34 -8
  13. package/assistant.js +81 -26
  14. package/availability-store.d.ts +193 -0
  15. package/availability-store.js +566 -0
  16. package/booking-rules.d.ts +103 -5
  17. package/booking-rules.js +263 -15
  18. package/config.d.ts +50 -0
  19. package/config.js +107 -0
  20. package/dashboard-assistant-ui.d.ts +1 -1
  21. package/dashboard-assistant-ui.js +109 -8
  22. package/dashboard-scope.d.ts +7 -0
  23. package/dashboard-scope.js +21 -0
  24. package/dashboard.d.ts +152 -8
  25. package/dashboard.js +3868 -399
  26. package/ddl-identity.d.ts +25 -0
  27. package/ddl-identity.js +881 -0
  28. package/ddl-scim.d.ts +5 -0
  29. package/ddl-scim.js +740 -0
  30. package/ddl-sso.d.ts +15 -0
  31. package/ddl-sso.js +1033 -0
  32. package/ddl.d.ts +44 -9
  33. package/ddl.js +2872 -47
  34. package/domains.d.ts +117 -0
  35. package/domains.js +340 -0
  36. package/event-feed.d.ts +2 -2
  37. package/event-feed.js +24 -34
  38. package/holiday-import.d.ts +38 -0
  39. package/holiday-import.js +56 -0
  40. package/holidays.d.ts +38 -0
  41. package/holidays.js +209 -0
  42. package/hours.d.ts +125 -0
  43. package/hours.js +224 -0
  44. package/index.d.ts +24 -5
  45. package/index.js +17 -3
  46. package/interop.d.ts +25 -7
  47. package/interop.js +145 -17
  48. package/invitation-email.d.ts +26 -0
  49. package/invitation-email.js +73 -0
  50. package/lifecycle.d.ts +31 -0
  51. package/lifecycle.js +115 -0
  52. package/maintenance.d.ts +26 -2
  53. package/maintenance.js +70 -2
  54. package/metrics.js +3 -0
  55. package/oidc.d.ts +135 -0
  56. package/oidc.js +452 -0
  57. package/openapi.json +20172 -9850
  58. package/package.json +2 -1
  59. package/ranges.d.ts +28 -0
  60. package/ranges.js +135 -0
  61. package/resource-search.d.ts +19 -0
  62. package/resource-search.js +153 -0
  63. package/rest-api.js +7 -0
  64. package/rules.d.ts +2 -0
  65. package/rules.js +2 -0
  66. package/scim-server.d.ts +19 -0
  67. package/scim-server.js +243 -0
  68. package/scim.d.ts +180 -0
  69. package/scim.js +416 -0
  70. package/self-host.d.ts +19 -6
  71. package/self-host.js +483 -28
  72. package/slotlock.manifest.json +1 -1
  73. package/store.d.ts +637 -23
  74. package/store.js +2529 -147
  75. package/types.d.ts +230 -0
  76. package/types.js +68 -1
  77. package/workspace-domains.d.ts +146 -0
  78. package/workspace-domains.js +249 -0
  79. package/workspace-roles.d.ts +47 -0
  80. package/workspace-roles.js +304 -0
  81. package/workspace-scim.d.ts +89 -0
  82. package/workspace-scim.js +157 -0
  83. package/workspace-sso.d.ts +131 -0
  84. package/workspace-sso.js +180 -0
  85. package/workspaces.d.ts +240 -0
  86. package/workspaces.js +433 -0
package/store.d.ts CHANGED
@@ -1,12 +1,17 @@
1
1
  import { type SlotlockResourceKind, type SlotlockResourceProfileInput, type SlotlockLocation, type SlotlockPoolOrder, type SlotlockResourceGroup, type SlotlockResourceScope } from './resource-profile.js';
2
2
  import { type SlotlockUsageRow } from './usage.js';
3
+ import { type SlotlockWorkspaceRole } from './workspace-roles.js';
3
4
  import { type SlotlockChangeOrigin, type SlotlockEventFeed } from './event-feed.js';
4
5
  import { type SlotlockBookingRules } from './booking-rules.js';
5
6
  import type { Sql, TransactionSql } from 'postgres';
6
- import { SLOTLOCK_CALENDAR_HORIZON_DAYS } from './rules.js';
7
- import type { AcquireHoldResult, CalendarCoverageCommand, CalendarCoverageResult, CalendarEventContent, CalendarEventRetentionResult, BookingRetentionResult, SlotlockTenantErasure, SlotlockBookingRuleDefaults, CalendarFreeBusy, CalendarHorizonRollCursor, CalendarHorizonRollResult, CancelCalendarEventResult, CancelExternalReservationResult, ConfirmHoldResult, CreateReservationResult, DeleteResourceResult, ExternalReservationCommand, ExternalReservationResult, Interval, SlotlockCalendarEvent, SlotlockAgendaEntry, SlotlockHold, SlotlockBookingDescription, SlotlockApproval, SlotlockApprovalPolicy, SlotlockReservation, SlotlockResource, PutCalendarEventCommand, PutCalendarEventResult, ReleaseHoldResult, WeeklyAvailabilityRule } from './types.js';
7
+ import { SLOTLOCK_CALENDAR_HORIZON_DAYS, SLOTLOCK_SOURCE_BUSY_MAX } from './rules.js';
8
+ import type { AcquireHoldResult, MarkHoldPaidResult, PutContactResult, SlotlockContact, SlotlockContactConsent, CalendarCoverageCommand, CalendarCoverageResult, SourceBusyCommand, SourceBusyResult, CalendarEventContent, CalendarEventRetentionResult, BookingRetentionResult, SlotlockTenantErasure, SlotlockBookingRuleDefaults, CalendarFreeBusy, CalendarHorizonRollCursor, CalendarHorizonRollResult, CancelCalendarEventResult, CancelExternalReservationResult, ConfirmHoldResult, CreateReservationResult, DeleteResourceResult, ExternalReservationCommand, ExternalReservationResult, Interval, SlotlockCalendarEvent, SlotlockAgendaEntry, SlotlockHold, SlotlockBookingDescription, SlotlockApproval, SlotlockApprovalPolicy, SlotlockReservation, SlotlockResource, PutCalendarEventCommand, PutCalendarEventResult, ReleaseHoldResult, WeeklyAvailabilityRule } from './types.js';
9
+ import { type SlotlockSubjectTable, type SlotlockTenantExportTable } from './types.js';
10
+ import { type SlotlockAvailabilityDefaults, type SlotlockAvailabilityDefaultsResult, type SlotlockAvailabilityExceptionInput, type SlotlockOverrideResources, type SlotlockHolidayCalendar, type SlotlockHolidayImport } from './availability-store.js';
11
+ import type { SlotlockAvailabilityException, SlotlockRankedException } from './hours.js';
12
+ import type { SlotlockHoliday } from './holidays.js';
8
13
  import { type PutApprovalPolicyParams } from './approvals.js';
9
- export { SLOTLOCK_CALENDAR_HORIZON_DAYS };
14
+ export { SLOTLOCK_CALENDAR_HORIZON_DAYS, SLOTLOCK_SOURCE_BUSY_MAX };
10
15
  /**
11
16
  * Longest one-off event (ten years and some leap days); a recurring series is bounded by its
12
17
  * materialization window instead.
@@ -69,6 +74,10 @@ export declare function readSlotlockSchemaVersion(sql: SlotlockSql): Promise<num
69
74
  * migrate`) or `schema_newer`. Both carry `installed` and `expected`.
70
75
  */
71
76
  export declare function assertSlotlockSchemaCurrent(sql: SlotlockSql): Promise<void>;
77
+ /** The most contacts a tenant keeps (RFC 0004 P3). */
78
+ export declare const SLOTLOCK_MAX_CONTACTS_PER_TENANT = 100000;
79
+ /** The longest a hold that waits for payment may live (RFC 0004 C3): 30 minutes. */
80
+ export declare const SLOTLOCK_PAYMENT_HOLD_MAX_TTL_MS: number;
72
81
  /**
73
82
  * A put's identity and the event it asks for, not its storage window: a series' window moves with
74
83
  * the UTC day, so a retry after midnight must still match.
@@ -405,11 +414,135 @@ export interface SlotlockStore extends SlotlockEventFeed {
405
414
  pool: string;
406
415
  resourceId: string;
407
416
  }): Promise<void>;
408
- /** Set (or clear, with `null`) the bookable hours of every resource the tenant has; returns how many. */
417
+ /**
418
+ * Store (or clear, with `null`) the tenant's weekly hours (RFC 0004 B2): every resource without its
419
+ * own and with no location hours above it uses them, new ones too. Nothing is copied: a resource
420
+ * keeps hours of its own unless `overrideResources` clears them (`all`), or clears those that are
421
+ * the same as the tenant's were or as these (`matching`). Refuses `invalid_availability`.
422
+ */
423
+ storeTenantAvailability(params: {
424
+ tenantRef: string;
425
+ rules: readonly WeeklyAvailabilityRule[] | null;
426
+ overrideResources?: SlotlockOverrideResources;
427
+ }): Promise<SlotlockAvailabilityDefaultsResult>;
428
+ /**
429
+ * Every resource the tenant has uses these weekly hours (or the server's, with `null`): as in 0.8.0,
430
+ * whatever hours of their own they had are gone. Now done by storing them as the tenant's, which
431
+ * resources added later inherit too. Returns how many resources in use they now apply to.
432
+ *
433
+ * @deprecated Use storeTenantAvailability, which can keep the hours resources have of their own
434
+ * and says how many do.
435
+ */
409
436
  setTenantAvailability(params: {
410
437
  tenantRef: string;
411
438
  rules: readonly WeeklyAvailabilityRule[] | null;
412
439
  }): Promise<number>;
440
+ /**
441
+ * Store (or clear) a location's weekly hours: resources at it or inside it without their own use
442
+ * them, unless a nearer location has its own. Null for a location the tenant does not have.
443
+ */
444
+ setLocationAvailability(params: {
445
+ tenantRef: string;
446
+ location: string;
447
+ rules: readonly WeeklyAvailabilityRule[] | null;
448
+ }): Promise<SlotlockAvailabilityDefaultsResult | null>;
449
+ /** The tenant's stored hours, and each location's that has them. */
450
+ getAvailabilityDefaults(params: {
451
+ tenantRef: string;
452
+ }): Promise<SlotlockAvailabilityDefaults>;
453
+ /**
454
+ * Add a closure or a day of special hours (RFC 0004 B1) for the tenant, a location or a resource;
455
+ * an import's `sourceUid` already stored at that scope is updated instead. Refuses
456
+ * `invalid_availability_exception`, `location_not_found`, `resource_not_found` and
457
+ * `availability_exceptions_limit_reached`.
458
+ */
459
+ createAvailabilityException(params: SlotlockAvailabilityExceptionInput): Promise<SlotlockAvailabilityException>;
460
+ /**
461
+ * The tenant's exceptions by first day: those that apply to `resourceId`, or a `location`'s own,
462
+ * or all; only those reaching `from` to `to` when given.
463
+ */
464
+ listAvailabilityExceptions(params: {
465
+ tenantRef: string;
466
+ resourceId?: string;
467
+ location?: string;
468
+ from?: string;
469
+ to?: string;
470
+ limit?: number;
471
+ after?: string;
472
+ }): Promise<SlotlockAvailabilityException[]>;
473
+ deleteAvailabilityException(params: {
474
+ tenantRef: string;
475
+ id: string;
476
+ }): Promise<boolean>;
477
+ /**
478
+ * Replace the exceptions an import of one resource's VAVAILABILITY made (source `vavailability`)
479
+ * with `ranges`; returns how many it keeps.
480
+ */
481
+ replaceImportedExceptions(params: {
482
+ tenantRef: string;
483
+ resourceId: string;
484
+ ranges: readonly {
485
+ startsOn: string;
486
+ endsOn: string;
487
+ outcome: 'closed' | 'open';
488
+ hours?: {
489
+ startMinutes: number;
490
+ durationMinutes: number;
491
+ }[];
492
+ }[];
493
+ }): Promise<number>;
494
+ /**
495
+ * Import a holiday calendar's days off as closures at its scope, as the calendar named `name`
496
+ * there (RFC 0004 B1): holidays added or updated, and those it made before and no longer names
497
+ * in `span` deleted. With `url`, a subscription maintenance imports again. See
498
+ * availability-store.ts importHolidayCalendar for its refusals.
499
+ */
500
+ importHolidayCalendar(params: {
501
+ tenantRef: string;
502
+ location?: string;
503
+ resourceId?: string;
504
+ name: string;
505
+ url?: string;
506
+ holidays: readonly SlotlockHoliday[];
507
+ span: {
508
+ from: string;
509
+ to: string;
510
+ };
511
+ }): Promise<SlotlockHolidayImport>;
512
+ /** The tenant's holiday calendars. */
513
+ listHolidayCalendars(params: {
514
+ tenantRef: string;
515
+ }): Promise<SlotlockHolidayCalendar[]>;
516
+ /** Delete a holiday calendar and its closures; null for one the tenant does not have. */
517
+ deleteHolidayCalendar(params: {
518
+ tenantRef: string;
519
+ id: string;
520
+ }): Promise<{
521
+ closures: number;
522
+ } | null>;
523
+ /**
524
+ * Subscriptions due to be imported again, each put off a day before it is read (maintenance):
525
+ * importing it sets its next import, so one a pass never finishes is not tried again at once.
526
+ */
527
+ dueHolidayCalendars(params: {
528
+ tenantRef: string;
529
+ limit: number;
530
+ }): Promise<SlotlockHolidayCalendar[]>;
531
+ /** Note why a subscription's import failed; it is tried again a day later. */
532
+ noteHolidayCalendarFailure(params: {
533
+ tenantRef: string;
534
+ id: string;
535
+ error: string;
536
+ }): Promise<void>;
537
+ /**
538
+ * Each resource's exceptions that reach `window`, in the order the evaluator applies them, by
539
+ * resource id.
540
+ */
541
+ availabilityExceptionsFor(params: {
542
+ tenantRef: string;
543
+ resourceIds: readonly string[];
544
+ window: Interval;
545
+ }): Promise<Map<string, SlotlockRankedException[]>>;
413
546
  /** Bounded tenant resource discovery, ordered and keyset-paginated by immutable UUID. */
414
547
  listResources(params: {
415
548
  tenantRef: string;
@@ -483,6 +616,12 @@ export interface SlotlockStore extends SlotlockEventFeed {
483
616
  tenantRef: string;
484
617
  externalRef: string;
485
618
  revision: number;
619
+ /**
620
+ * An admin's reason for cancelling past the booking's cancel cutoff (RFC 0004 B5), 1-500
621
+ * characters, kept on its tombstone and the feed. Without it, a cancellation past the cutoff is
622
+ * refused.
623
+ */
624
+ overrideReason?: string;
486
625
  }): Promise<CancelExternalReservationResult>;
487
626
  /**
488
627
  * Occupy a window without committing: the hold blocks rivals under the same EXCLUDE arbiter until
@@ -526,7 +665,176 @@ export interface SlotlockStore extends SlotlockEventFeed {
526
665
  * `fromHold` releases the rest, and releasing one with a holder releases them all.
527
666
  */
528
667
  groupId?: string;
668
+ /**
669
+ * The hold waits for payment (RFC 0004 C3): it cannot be confirmed until `markHoldPaid`
670
+ * records the payment's reference, and lives at most SLOTLOCK_PAYMENT_HOLD_MAX_TTL_MS
671
+ * (`invalid_ttl` beyond). Slotlock records payment state; it never moves money.
672
+ */
673
+ paymentRequired?: boolean;
674
+ /**
675
+ * What the payment must be (with `paymentRequired`): markHoldPaid refuses one for less, or in
676
+ * another currency (`payment_amount_mismatch`). Without it, any recorded payment counts.
677
+ */
678
+ payment?: {
679
+ amountMinor: number;
680
+ currency: string;
681
+ };
682
+ /**
683
+ * An agent's hold (RFC 0004 C3): its price is the resource's `holdPrice` booking rule, never its
684
+ * own. On a resource with one, it waits for that payment whatever it asks (and lives at most
685
+ * SLOTLOCK_PAYMENT_HOLD_MAX_TTL_MS); a `payment` other than that price is refused
686
+ * (`payment_price_mismatch`), as is any `payment` where the resource sets none.
687
+ */
688
+ priceFromRules?: boolean;
529
689
  }): Promise<AcquireHoldResult>;
690
+ /**
691
+ * Record that a hold waiting for payment is paid (RFC 0004 C3), by the payment's reference at the
692
+ * integrator's processor: the integrator says so, or an adapter that verified it. Once paid it
693
+ * may be confirmed. The same reference again answers the same hold, whatever became of it since
694
+ * (confirmed or booked from: the payment is kept apart), unless the hold ended without a booking (`hold_ended`: never applied, so refunded); another is `payment_conflict`, naming the one recorded. The feed says so (`hold.paid`). A hold that does not wait for payment is
695
+ * `payment_not_required`; an expired one `hold_expired`; one confirmed, released or unknown
696
+ * `hold_not_found`.
697
+ */
698
+ markHoldPaid(params: {
699
+ tenantRef: string;
700
+ holdId: string;
701
+ paymentRef: string;
702
+ /** What was received, as the processor says: needed when the hold names its payment. */
703
+ received?: {
704
+ amountMinor: number;
705
+ currency: string;
706
+ };
707
+ }): Promise<MarkHoldPaidResult>;
708
+ /**
709
+ * Keep a person a booking may name (`contactRef`) to be told about it (RFC 0004 P3): how to reach
710
+ * them and which channels they agreed to. Replaces what was kept under the reference. A sender
711
+ * reads it to send; Slotlock sends nothing. At most SLOTLOCK_MAX_CONTACTS_PER_TENANT.
712
+ */
713
+ putContact(params: {
714
+ tenantRef: string;
715
+ ref: string;
716
+ name?: string | null;
717
+ email?: string | null;
718
+ phone?: string | null;
719
+ whatsapp?: string | null;
720
+ consent?: SlotlockContactConsent;
721
+ locale?: string | null;
722
+ }): Promise<PutContactResult>;
723
+ /** The tenant's contact with this reference, or null. */
724
+ getContact(params: {
725
+ tenantRef: string;
726
+ ref: string;
727
+ }): Promise<SlotlockContact | null>;
728
+ /** The tenant's contacts by reference, after `after`, up to `limit` (1-100, default 50). */
729
+ listContacts(params: {
730
+ tenantRef: string;
731
+ limit?: number;
732
+ after?: string;
733
+ }): Promise<SlotlockContact[]>;
734
+ /**
735
+ * Forget a person (RFC 0004 P3): their contact, and their reference on every booking that named
736
+ * it, in one transaction. `deleted` is false when there was no contact; `bookings` counts the
737
+ * bookings that no longer name them.
738
+ */
739
+ deleteContact(params: {
740
+ tenantRef: string;
741
+ ref: string;
742
+ }): Promise<{
743
+ deleted: boolean;
744
+ bookings: number;
745
+ }>;
746
+ /**
747
+ * What the tenant keeps about one person (RFC 0004 D3, an access request): the rows that name
748
+ * them, as kept, by table (SLOTLOCK_SUBJECT_TABLES), up to `limit` (1-10,000, default 1,000) a
749
+ * table. It lists what eraseSubject would delete or take them out of; an event lists its time and
750
+ * title, and an approval its decision, never the other people they name.
751
+ */
752
+ exportSubject(params: {
753
+ tenantRef: string;
754
+ subject: SlotlockSubject;
755
+ limit?: number;
756
+ }): Promise<SlotlockSubjectExport>;
757
+ /**
758
+ * Take one person out of the tenant's data (RFC 0004 D3, an erasure request), in one transaction.
759
+ * Their contacts, attendee entries and waitlist entries are deleted; their email leaves events'
760
+ * attendee and organizer lists and approvals' requests; their holder reference and booking
761
+ * reference become one `erased-` name wherever they were (bookings, holds, ended bookings, the
762
+ * change history, approvals), and a contact's reference leaves them. Bookings stay, as time taken.
763
+ * Counts, by table, the rows deleted or changed.
764
+ */
765
+ eraseSubject(params: {
766
+ tenantRef: string;
767
+ subject: SlotlockSubject;
768
+ }): Promise<SlotlockSubjectErasure>;
769
+ /**
770
+ * Ask for a copy of everything the tenant keeps (RFC 0004 D3): a pending export, which
771
+ * buildTenantExport builds. Refused while another is pending (`export_in_progress`) or when the
772
+ * tenant keeps SLOTLOCK_MAX_TENANT_EXPORTS already (`export_limit_reached`).
773
+ */
774
+ createTenantExport(params: {
775
+ tenantRef: string;
776
+ requestedBy?: string;
777
+ }): Promise<SlotlockTenantExport>;
778
+ /**
779
+ * Build a pending export: every table of SLOTLOCK_TENANT_EXPORT_TABLES read through one cursor,
780
+ * so in one snapshot, into parts of one table's rows. Null when it is not pending, or another is
781
+ * building it. Throws `export_too_large` past SLOTLOCK_TENANT_EXPORT_MAX_BYTES, writing nothing.
782
+ */
783
+ buildTenantExport(params: {
784
+ tenantRef: string;
785
+ exportId: string;
786
+ }): Promise<SlotlockTenantExport | null>;
787
+ /** Mark a pending export failed, with why (`export_too_large`, `export_failed`). */
788
+ failTenantExport(params: {
789
+ tenantRef: string;
790
+ exportId: string;
791
+ error: string;
792
+ }): Promise<void>;
793
+ /** One of the tenant's exports, or null. */
794
+ getTenantExport(params: {
795
+ tenantRef: string;
796
+ exportId: string;
797
+ }): Promise<SlotlockTenantExport | null>;
798
+ /** The tenant's exports, newest first. */
799
+ listTenantExports(params: {
800
+ tenantRef: string;
801
+ }): Promise<SlotlockTenantExport[]>;
802
+ /** One part (1 to its `parts`) of a ready export. */
803
+ getTenantExportPart(params: {
804
+ tenantRef: string;
805
+ exportId: string;
806
+ part: number;
807
+ }): Promise<SlotlockTenantExportPartResult>;
808
+ /** Delete one of the tenant's exports at once. False when there was none. */
809
+ deleteTenantExport(params: {
810
+ tenantRef: string;
811
+ exportId: string;
812
+ }): Promise<boolean>;
813
+ /**
814
+ * Delete the tenant's exports past their time; and name those left pending for more than two
815
+ * minutes (their server stopped before building them), for maintenance to build.
816
+ */
817
+ pruneTenantExports(params: {
818
+ tenantRef: string;
819
+ }): Promise<{
820
+ deleted: number;
821
+ pending: string[];
822
+ }>;
823
+ /**
824
+ * Read everything the tenant keeps, as an export holds it, in one snapshot, without storing it
825
+ * (`slotlock tenant export`): each part (one table's rows) to `onPart` as it is read.
826
+ */
827
+ streamTenantExport(params: {
828
+ tenantRef: string;
829
+ onPart: (part: {
830
+ table: SlotlockTenantExportTable;
831
+ lines: string[];
832
+ }) => Promise<void>;
833
+ }): Promise<{
834
+ rows: number;
835
+ bytes: number;
836
+ tables: Record<string, number>;
837
+ }>;
530
838
  /** One of the tenant's live holds, or null (none, expired, confirmed, or another tenant's). */
531
839
  getHold(params: {
532
840
  tenantRef: string;
@@ -639,6 +947,19 @@ export interface SlotlockStore extends SlotlockEventFeed {
639
947
  holdId: string;
640
948
  holderRef: string;
641
949
  };
950
+ /**
951
+ * The agent it holds time for, and its key's caps (RFC 0004 A5): its pending approvals' holds
952
+ * count against its live-hold and held-hour caps with its own holds, so asking for approval
953
+ * never holds more than the agent could hold itself (`hold_limit_reached`,
954
+ * `held_time_limit_reached`). Kept on the approval's requester as `holder_ref`.
955
+ */
956
+ holder?: {
957
+ ref: string;
958
+ caps?: {
959
+ maxHolds?: number;
960
+ maxHeldHours?: number;
961
+ };
962
+ };
642
963
  }): Promise<{
643
964
  ok: true;
644
965
  approval: SlotlockApproval;
@@ -647,6 +968,10 @@ export interface SlotlockStore extends SlotlockEventFeed {
647
968
  ok: false;
648
969
  code: 'overlap' | 'approval_limit_reached' | 'idempotency_conflict';
649
970
  limit?: number;
971
+ } | {
972
+ ok: false;
973
+ code: 'hold_limit_reached' | 'held_time_limit_reached';
974
+ limit: number;
650
975
  }>;
651
976
  /** The approval a request key made, or null. */
652
977
  findApproval(params: {
@@ -814,6 +1139,8 @@ export interface SlotlockStore extends SlotlockEventFeed {
814
1139
  * another, checked under the event's lock.
815
1140
  */
816
1141
  expectedResourceId?: string;
1142
+ /** Hold a one-off event to its resource's cancel cutoff (RFC 0004 B5), as agents' cancels are. */
1143
+ enforceBookingRules?: boolean;
817
1144
  }): Promise<CancelCalendarEventResult>;
818
1145
  /**
819
1146
  * The tenant's cancellation of one of its events by id, whichever owner wrote it: an agent key's
@@ -829,6 +1156,11 @@ export interface SlotlockStore extends SlotlockEventFeed {
829
1156
  expectedRevision: number;
830
1157
  /** As for cancelCalendarEvent: `event_not_found` when the event is on another resource. */
831
1158
  expectedResourceId?: string;
1159
+ /**
1160
+ * An admin's reason for cancelling a one-off event past its cancel cutoff (RFC 0004 B5), kept on
1161
+ * the feed; without it, that cancellation is refused.
1162
+ */
1163
+ overrideReason?: string;
832
1164
  }): Promise<CancelCalendarEventResult>;
833
1165
  /**
834
1166
  * Rematerialize due recurring masters into one rolling window without changing their revision. A
@@ -921,6 +1253,17 @@ export interface SlotlockStore extends SlotlockEventFeed {
921
1253
  maxAgeMs?: number;
922
1254
  limit?: number;
923
1255
  }): Promise<number>;
1256
+ /**
1257
+ * Put each event reminder that has come due on the feed once (RFC 0004 P3), as `reminder.due`:
1258
+ * an occurrence's reminder, its minutes before the start, of an event that may be notified about
1259
+ * (`notify`), due within the last day and not started yet. Each is recorded in
1260
+ * `reminder_dispatches` in the same transaction, so no later pass says it again. The change's id
1261
+ * is the key a sender sends it once by. Up to `limit` (default 500); how many.
1262
+ */
1263
+ dueReminders(params: {
1264
+ tenantRef: string;
1265
+ limit?: number;
1266
+ }): Promise<number>;
924
1267
  /**
925
1268
  * Claim a booking by its reference (check-in), so a resource whose booking rules ask for check-in
926
1269
  * (`checkInMinutes`) does not release it. Check-in opens `SLOTLOCK_CHECK_IN_OPENS_MINUTES` before
@@ -932,6 +1275,15 @@ export interface SlotlockStore extends SlotlockEventFeed {
932
1275
  tenantRef: string;
933
1276
  externalRef: string;
934
1277
  }): Promise<CheckInReservationResult>;
1278
+ /**
1279
+ * Say on the feed that bookings have ended (RFC 0004 B4): each confirmed booking whose end passed
1280
+ * within the last week and was not said yet gets one `reservation.completed`, its row unchanged
1281
+ * but for when it was said. Up to `limit` (default 500); returns how many.
1282
+ */
1283
+ completeEndedBookings(params: {
1284
+ tenantRef: string;
1285
+ limit?: number;
1286
+ }): Promise<number>;
935
1287
  /**
936
1288
  * Release up to `limit` (default 100) bookings left unclaimed: on a resource whose booking rules
937
1289
  * ask for check-in, made since they did, not checked in `checkInMinutes` after the start, and not
@@ -956,12 +1308,44 @@ export interface SlotlockStore extends SlotlockEventFeed {
956
1308
  end: Date;
957
1309
  holderRef: string;
958
1310
  offerTtlMs?: number;
1311
+ /**
1312
+ * Wait for any slot of this many milliseconds within the window (RFC 0004 B6), a whole minute
1313
+ * from one minute to the window's length; left out, the whole window.
1314
+ */
1315
+ durationMs?: number;
959
1316
  /**
960
1317
  * A retry identity, kept as long as the entry: the same key and request answer the entry the
961
1318
  * first made (`replayed`), another request `idempotency_conflict`.
962
1319
  */
963
1320
  idempotencyKey?: string;
964
1321
  }): Promise<JoinWaitlistResult>;
1322
+ /**
1323
+ * One holder's live holds in a group, by resource id (RFC 0004 B7). With `alignExpiry`, every one
1324
+ * expires when the earliest does, so the set has one time to live.
1325
+ */
1326
+ holdGroup(params: {
1327
+ tenantRef: string;
1328
+ holderRef: string;
1329
+ groupId: string;
1330
+ alignExpiry?: boolean;
1331
+ }): Promise<{
1332
+ holdId: string;
1333
+ resourceId: string;
1334
+ start: Date;
1335
+ end: Date;
1336
+ expiresAt: Date;
1337
+ source: string | null;
1338
+ }[]>;
1339
+ /**
1340
+ * Decline an entry's offer (RFC 0004 B6): its hold is let go and the entry is `declined`, so the
1341
+ * time is offered to the next. With `holderRef`, only that holder's. Null when there is no such
1342
+ * offer.
1343
+ */
1344
+ declineWaitlistOffer(params: {
1345
+ tenantRef: string;
1346
+ id: string;
1347
+ holderRef?: string;
1348
+ }): Promise<SlotlockWaitlistEntry | null>;
965
1349
  /** The tenant's waitlist entries, oldest first, optionally of one resource, pool or holder. */
966
1350
  listWaitlist(params: {
967
1351
  tenantRef: string;
@@ -1018,43 +1402,118 @@ export interface SlotlockStore extends SlotlockEventFeed {
1018
1402
  from: string;
1019
1403
  to: string;
1020
1404
  }): Promise<boolean>;
1021
- /** A member's live assistant conversation, or null when none is (or it expired). */
1022
- getAssistantConversation(params: {
1405
+ /**
1406
+ * A member's conversations with the assistant, the most recent first (at most `limit`, default
1407
+ * 100): what the Chats list shows. Expired ones are left out.
1408
+ */
1409
+ listAssistantChats(params: {
1023
1410
  tenantRef: string;
1024
1411
  memberRef: string;
1025
- }): Promise<SlotlockAssistantConversationRecord | null>;
1412
+ limit?: number;
1413
+ }): Promise<SlotlockAssistantChatSummary[]>;
1414
+ /** One of a member's conversations, or null when there is none by that id (or it expired). */
1415
+ getAssistantChat(params: {
1416
+ tenantRef: string;
1417
+ memberRef: string;
1418
+ chatId: string;
1419
+ }): Promise<SlotlockAssistantChatRecord | null>;
1026
1420
  /**
1027
- * Store a member's conversation for `ttlMs` (1 second to a day) from now, replacing its messages.
1421
+ * Store one of a member's conversations, creating it (titled `title`) or replacing its messages.
1028
1422
  * Its actions become those stored already that `keep` names, in their stored state
1029
1423
  * (settleAssistantAction changes it), and the `added` ones not stored already: an action is never
1030
- * put back into a conversation that no longer has it. The tenant's expired conversations are
1031
- * deleted with it, and the tenant is listed for sweepAssistantConversations.
1424
+ * put back into a conversation that no longer has it. It is kept until deleted, or for `ttlMs`
1425
+ * (1 second to 3,650 days) from now when given, and then the tenant is listed for
1426
+ * sweepAssistantConversations. The member keeps at most SLOTLOCK_ASSISTANT_MAX_CHATS: past it,
1427
+ * the least recently used go (the member's writes take turns, so two at once keep the bound).
1428
+ * True when it was written; false when `create` is false and it was not there. Run it in a
1429
+ * transaction (withTenant does) so its lock lasts until the trim commits.
1032
1430
  */
1033
- putAssistantConversation(params: {
1431
+ putAssistantChat(params: {
1034
1432
  tenantRef: string;
1035
1433
  memberRef: string;
1434
+ chatId: string;
1435
+ title: string;
1036
1436
  messages: unknown[];
1037
1437
  added: Record<string, Record<string, unknown>>;
1038
1438
  keep: readonly string[];
1039
- ttlMs: number;
1040
- }): Promise<void>;
1439
+ ttlMs: number | null;
1440
+ /**
1441
+ * False to only change a conversation that is still there: one the member deleted while a turn
1442
+ * on it ran is not written back. True (the default) creates it when it is not.
1443
+ */
1444
+ create?: boolean;
1445
+ }): Promise<boolean>;
1446
+ /** Give one of a member's conversations a new title (1-120 characters). False when there is none. */
1447
+ renameAssistantChat(params: {
1448
+ tenantRef: string;
1449
+ memberRef: string;
1450
+ chatId: string;
1451
+ title: string;
1452
+ }): Promise<boolean>;
1041
1453
  /**
1042
- * Change one proposed action, only while its `status` is `from`: its fields are merged with
1043
- * `patch`. The action as changed, or null when it is not in that state (or not there): of two
1044
- * racing approvals, one wins.
1454
+ * Change one proposed action of a conversation, only while its `status` is `from`: its fields are
1455
+ * merged with `patch`. The action as changed, or null when it is not in that state (or not
1456
+ * there): of two racing approvals, one wins.
1045
1457
  */
1046
1458
  settleAssistantAction(params: {
1047
1459
  tenantRef: string;
1048
1460
  memberRef: string;
1461
+ chatId: string;
1049
1462
  actionId: string;
1050
1463
  from: string;
1051
1464
  patch: Record<string, unknown>;
1052
1465
  }): Promise<Record<string, unknown> | null>;
1053
- /** Forget a member's conversation. False when there was none. */
1054
- deleteAssistantConversation(params: {
1466
+ /** Delete one of a member's conversations. False when there was none. */
1467
+ deleteAssistantChat(params: {
1055
1468
  tenantRef: string;
1056
1469
  memberRef: string;
1470
+ chatId: string;
1057
1471
  }): Promise<boolean>;
1472
+ /**
1473
+ * Add an event to the tenant's audit log (slotlock.audit_events). The log is append-only for the
1474
+ * serving role: nothing here changes or removes an event. Text past its column's bound is cut.
1475
+ */
1476
+ recordAuditEvent(params: {
1477
+ tenantRef: string;
1478
+ event: SlotlockAuditEventInput;
1479
+ }): Promise<void>;
1480
+ /**
1481
+ * The tenant's audit events, newest first: up to `limit` (1-200, default 50), before the event
1482
+ * `before` names, and only those of `action` or `actorRef` when given.
1483
+ */
1484
+ listAuditEvents(params: {
1485
+ tenantRef: string;
1486
+ limit?: number;
1487
+ before?: {
1488
+ occurredAt: Date;
1489
+ id: string;
1490
+ };
1491
+ /** After the event with this id, at its exact time (the API's cursor); none if it was pruned. */
1492
+ beforeId?: string;
1493
+ action?: string;
1494
+ actorRef?: string;
1495
+ }): Promise<SlotlockAuditEvent[]>;
1496
+ /** The tenant's hosted plan and its standing (slotlock.tenant_plan), or null when none applies. */
1497
+ tenantPlan(params: {
1498
+ tenantRef: string;
1499
+ }): Promise<{
1500
+ plan: string;
1501
+ status: string;
1502
+ } | null>;
1503
+ /** Delete the tenant's audit events older than SLOTLOCK_AUDIT_RETENTION_DAYS; how many went. */
1504
+ pruneAuditEvents(params: {
1505
+ tenantRef: string;
1506
+ }): Promise<number>;
1507
+ /**
1508
+ * Check the tenant's audit chain from its oldest event kept (slotlock.verify_audit_chain): how many
1509
+ * events held, and the number of the first that does not (null when every one does).
1510
+ */
1511
+ verifyAuditChain(params: {
1512
+ tenantRef: string;
1513
+ }): Promise<{
1514
+ checked: number;
1515
+ brokenAt: number | null;
1516
+ }>;
1058
1517
  /** Delete up to `limit` (default 1,000) of the tenant's expired assistant conversations: how many. */
1059
1518
  pruneAssistantConversations(params: {
1060
1519
  tenantRef: string;
@@ -1067,6 +1526,14 @@ export interface SlotlockStore extends SlotlockEventFeed {
1067
1526
  sweepAssistantConversations(params?: {
1068
1527
  limit?: number;
1069
1528
  }): Promise<number>;
1529
+ /**
1530
+ * Delete team workspace invitations finished (accepted, revoked or expired) more than 30 days ago,
1531
+ * with the addresses they were sent to (slotlock.prune_workspace_invitations), requests to join
1532
+ * decided a month ago and domain claims ended three months ago (slotlock.prune_workspace_domains), and dashboard
1533
+ * sessions ended or expired a day ago (slotlock.prune_dashboard_sessions), and erase the team
1534
+ * workspaces whose deletion came due (slotlock.erase_deleted_teams): how many.
1535
+ */
1536
+ sweepDashboardRecords(): Promise<number>;
1070
1537
  /**
1071
1538
  * Offer freed time to the waitlist in join order: each waiting entry whose window is free (on its
1072
1539
  * resource, or the first free pool member) gets a hold for its holder (`waitlist.offered`).
@@ -1132,6 +1599,39 @@ export interface SlotlockStore extends SlotlockEventFeed {
1132
1599
  }): Promise<SlotlockTenantErasure>;
1133
1600
  /** Record the bounded, complete source window represented by a provider cursor/revision. */
1134
1601
  recordCalendarCoverage(params: CalendarCoverageCommand): Promise<CalendarCoverageResult>;
1602
+ /**
1603
+ * A calendar that gives busy time but not its events (RFC 0004 C1): records its coverage of the
1604
+ * window at the revision, as recordCalendarCoverage does, and in the same transaction replaces
1605
+ * the busy time it reported for that window (what it said outside the window stays). Busy time
1606
+ * counts in free/busy and is refused to every booking Slotlock makes, as an event's would be;
1607
+ * a confirmed booking the source newly reports busy time over is put on the feed as
1608
+ * coverage.conflict, once, and left as it is. A revision already recorded changes nothing.
1609
+ */
1610
+ replaceSourceBusy(params: SourceBusyCommand): Promise<SourceBusyResult>;
1611
+ /**
1612
+ * A source says a booking it was given (a sync's write-back) was changed or removed in its
1613
+ * calendar (RFC 0004 C4): put on the feed as `coverage.conflict`, named by the source's
1614
+ * `source_id`, with the booking and what the calendar now says. The booking is left as it is:
1615
+ * Slotlock stays the source of truth, and someone decides.
1616
+ */
1617
+ reportCoverageConflict(params: {
1618
+ tenantRef: string;
1619
+ resourceId: string;
1620
+ source: string;
1621
+ booking: {
1622
+ reservationRef: string;
1623
+ } | {
1624
+ eventId: string;
1625
+ };
1626
+ reason: 'changed_in_calendar' | 'removed_from_calendar';
1627
+ /** Where the calendar now has it, when it was moved. */
1628
+ calendar?: Interval;
1629
+ }): Promise<{
1630
+ ok: true;
1631
+ } | {
1632
+ ok: false;
1633
+ code: 'invalid_identity' | 'invalid_window' | 'coverage_not_found' | 'reservation_not_found' | 'event_not_found';
1634
+ }>;
1135
1635
  /** Return merged busy intervals plus explicit completeness for caller-required provider sources. */
1136
1636
  getFreeBusy(params: {
1137
1637
  tenantRef: string;
@@ -1178,12 +1678,111 @@ export interface SlotlockAssistantSettingsRecord {
1178
1678
  updatedAt: Date;
1179
1679
  }
1180
1680
  /** One member's live conversation with the dashboard assistant, as assistant.ts keeps it. */
1181
- export interface SlotlockAssistantConversationRecord {
1681
+ /** One of a member's conversations with the assistant, as the Chats list shows it. */
1682
+ export interface SlotlockAssistantChatSummary {
1683
+ /** 16 URL-safe characters. */
1684
+ id: string;
1685
+ title: string;
1686
+ updatedAt: Date;
1687
+ }
1688
+ /** One of a member's conversations with the assistant, whole. */
1689
+ export interface SlotlockAssistantChatRecord extends SlotlockAssistantChatSummary {
1182
1690
  messages: unknown[];
1183
1691
  /** The writes it proposed, by id. */
1184
1692
  actions: Record<string, Record<string, unknown>>;
1185
- updatedAt: Date;
1693
+ createdAt: Date;
1694
+ /** When it is deleted unless used again; null when it is kept until the member deletes it. */
1695
+ expiresAt: Date | null;
1696
+ }
1697
+ /** What an audit event records (slotlock.audit_events): who did what, to what, from where. */
1698
+ export interface SlotlockAuditEventInput {
1699
+ /** `<area>.<verb>`, such as `api_key.created` or `authz.denied`. */
1700
+ action: string;
1701
+ actorType: 'person' | 'api_key' | 'assistant' | 'system';
1702
+ /** `github:<id>`, `google:<subject>`, `api_key:<id>`: a reference, never a name or an email. */
1703
+ actorRef: string;
1704
+ /** The actor's role in the workspace when it acted. */
1705
+ actorRole?: SlotlockWorkspaceRole | null;
1706
+ targetType?: string;
1707
+ targetRef?: string;
1708
+ outcome?: 'success' | 'denied';
1709
+ reason?: string;
1710
+ ipAddress?: string;
1711
+ userAgent?: string;
1712
+ /** Before-and-after values and the like: never a secret, a token or a key. */
1713
+ metadata?: Record<string, unknown>;
1714
+ }
1715
+ /** An audit event as the API and `slotlock audit export` give it: snake_case, nulls kept. */
1716
+ export declare function slotlockAuditEventRecord(event: SlotlockAuditEvent): Record<string, unknown>;
1717
+ /**
1718
+ * Whom an access or erasure request is about (RFC 0004 D3): one person, by exactly one of the
1719
+ * identifiers Slotlock keeps for them. `email` matches contacts, event attendees and organizers
1720
+ * (ignoring case); `holder` the holder reference on holds, bookings and waitlist entries;
1721
+ * `contact` a contact's reference; `reference` a booking's or an event's reference.
1722
+ */
1723
+ export type SlotlockSubject = {
1724
+ email: string;
1725
+ } | {
1726
+ holder: string;
1727
+ } | {
1728
+ contact: string;
1729
+ } | {
1730
+ reference: string;
1731
+ };
1732
+ /** What the tenant keeps about one person (exportSubject). */
1733
+ export interface SlotlockSubjectExport {
1734
+ /** Each table's rows that name them, as kept (snake_case, without the tenant). */
1735
+ records: Record<SlotlockSubjectTable, Record<string, unknown>[]>;
1736
+ /** True when a table had more rows than the limit: its first ones are listed. */
1737
+ truncated: boolean;
1738
+ }
1739
+ /** What an erasure did (eraseSubject): by table, the rows deleted or taken the person out of. */
1740
+ export interface SlotlockSubjectErasure {
1741
+ erased: Record<SlotlockSubjectTable, number>;
1742
+ }
1743
+ /** Hours a tenant export is kept once ready, or since it was asked for if it never is. */
1744
+ export declare const SLOTLOCK_TENANT_EXPORT_HOURS = 24;
1745
+ /** The most a tenant export holds: past it, the export fails (`export_too_large`). */
1746
+ export declare const SLOTLOCK_TENANT_EXPORT_MAX_BYTES: number;
1747
+ /** The most exports a tenant keeps at once. */
1748
+ export declare const SLOTLOCK_MAX_TENANT_EXPORTS = 5;
1749
+ /** A part of an export: one table's rows, at most this many, or about this many bytes. */
1750
+ export declare const SLOTLOCK_TENANT_EXPORT_PART_ROWS = 5000;
1751
+ /** A copy of everything the tenant keeps (createTenantExport), as built or being built. */
1752
+ export interface SlotlockTenantExport {
1753
+ id: string;
1754
+ /** `pending` until it is built, then `ready`, or `failed` (`error` says why). */
1755
+ status: 'pending' | 'ready' | 'failed';
1756
+ requestedBy: string | null;
1757
+ createdAt: Date;
1758
+ finishedAt: Date | null;
1759
+ /** When maintenance deletes it. */
1186
1760
  expiresAt: Date;
1761
+ parts: number;
1762
+ rows: number;
1763
+ bytes: number;
1764
+ /** Rows by table (SLOTLOCK_TENANT_EXPORT_TABLES), for the tables with any. */
1765
+ tables: Record<string, number>;
1766
+ error: string | null;
1767
+ }
1768
+ /** One part of an export: one table's rows, each a JSON object as kept (NDJSON lines). */
1769
+ export type SlotlockTenantExportPartResult = {
1770
+ ok: true;
1771
+ table: SlotlockTenantExportTable;
1772
+ lines: string[];
1773
+ } | {
1774
+ ok: false;
1775
+ code: 'export_not_found' | 'export_not_ready' | 'export_part_not_found';
1776
+ };
1777
+ /** An audit event as the log keeps it. */
1778
+ export interface SlotlockAuditEvent extends SlotlockAuditEventInput {
1779
+ id: string;
1780
+ occurredAt: Date;
1781
+ outcome: 'success' | 'denied';
1782
+ metadata: Record<string, unknown>;
1783
+ /** Its place in the tenant's chain, and its SHA-256 (hex) over the one before and itself. */
1784
+ chainIndex: number | null;
1785
+ hash: string | null;
1187
1786
  }
1188
1787
  /** One entry of a tenant's waitlist (joinWaitlist). */
1189
1788
  export interface SlotlockWaitlistEntry {
@@ -1195,12 +1794,20 @@ export interface SlotlockWaitlistEntry {
1195
1794
  end: Date;
1196
1795
  holderRef: string;
1197
1796
  offerTtlMs: number;
1198
- /** `waiting`, `offered` (a hold was made: `holdId` on `offeredResourceId`) or `expired`. */
1199
- status: 'waiting' | 'offered' | 'expired';
1797
+ /**
1798
+ * `waiting`; `offered` (a hold was made: `holdId` on `offeredResourceId`); then `accepted` (the
1799
+ * hold was confirmed), `declined` (let go) or `lapsed` (it expired); or `expired` (no slot could
1800
+ * be offered before the window closed).
1801
+ */
1802
+ status: 'waiting' | 'offered' | 'accepted' | 'declined' | 'lapsed' | 'expired';
1200
1803
  holdId: string | null;
1201
1804
  offeredResourceId: string | null;
1202
1805
  offeredAt: Date | null;
1203
1806
  createdAt: Date;
1807
+ /** The length it waits for, any slot of it within the window (RFC 0004 B6); null: the whole window. */
1808
+ durationMs: number | null;
1809
+ /** When its offer was accepted, declined or lapsed. */
1810
+ decidedAt: Date | null;
1204
1811
  }
1205
1812
  export type JoinWaitlistResult = {
1206
1813
  ok: true;
@@ -1318,9 +1925,16 @@ export interface SlotlockHoldTenantOptions {
1318
1925
  * waiter out of the line, rejecting with its reason. Each holder calls the release it gets once.
1319
1926
  */
1320
1927
  export declare function createTenantSlots(max: number): (tenantRef: string, signal?: AbortSignal) => Promise<() => void>;
1928
+ /**
1929
+ * Build a pending tenant export (RFC 0004 D3) in its own tenant transaction, and mark it failed if
1930
+ * that fails (`export_too_large`, else `export_failed`). Null when it was not pending, or another
1931
+ * server is building it. Never throws: a server builds it after answering, and maintenance builds
1932
+ * one left pending.
1933
+ */
1934
+ export declare function buildSlotlockTenantExport(store: SlotlockStore, tenantRef: string, exportId: string): Promise<SlotlockTenantExport | null>;
1321
1935
  export declare function createSlotlockStore(sql: StoreSql, options?: SlotlockStoreOptions): SlotlockStore;
1322
1936
  /**
1323
1937
  * Every store method that writes for a tenant: what a suspended tenant's withTenant store refuses.
1324
1938
  * Maintenance (rolling series, pruning, purging) and erasure are not among them.
1325
1939
  */
1326
- export declare const SLOTLOCK_TENANT_WRITE_METHODS: readonly ["createResource", "updateResourceProfile", "putLocation", "updateLocation", "deleteLocation", "putGroup", "deleteGroup", "addGroupMember", "removeGroupMember", "archiveResource", "restoreResource", "deleteResource", "setResourceAvailability", "setResourceBookingRules", "setBookingRuleDefaults", "setResourcePool", "setResourceParent", "setPoolOrder", "notePoolBooking", "putApprovalPolicy", "deleteApprovalPolicy", "requestApproval", "beginApprovalGrant", "finishApprovalGrant", "declineApproval", "resetTestTenant", "fastForwardTestTenant", "setTenantAvailability", "createReservation", "createExternalReservation", "rescheduleExternalReservation", "cancelExternalReservation", "acquireHold", "confirmHold", "releaseHold", "putCalendarEvent", "cancelCalendarEvent", "cancelCalendarEventById", "recordCalendarCoverage", "createWebhookEndpoint", "deleteWebhookEndpoint", "enableWebhookEndpoint", "recordCoverageFailure", "deleteCoverage", "checkInReservation", "joinWaitlist", "leaveWaitlist", "putAssistantSettings", "deleteAssistantSettings", "resealAssistantKey", "putAssistantConversation", "settleAssistantAction", "deleteAssistantConversation"];
1940
+ export declare const SLOTLOCK_TENANT_WRITE_METHODS: readonly ["createResource", "updateResourceProfile", "putLocation", "updateLocation", "deleteLocation", "putGroup", "deleteGroup", "addGroupMember", "removeGroupMember", "archiveResource", "restoreResource", "deleteResource", "setResourceAvailability", "setResourceBookingRules", "setBookingRuleDefaults", "setResourcePool", "setResourceParent", "setPoolOrder", "notePoolBooking", "putApprovalPolicy", "deleteApprovalPolicy", "requestApproval", "beginApprovalGrant", "finishApprovalGrant", "declineApproval", "resetTestTenant", "fastForwardTestTenant", "storeTenantAvailability", "setTenantAvailability", "setLocationAvailability", "createAvailabilityException", "deleteAvailabilityException", "replaceImportedExceptions", "importHolidayCalendar", "deleteHolidayCalendar", "noteHolidayCalendarFailure", "createReservation", "createExternalReservation", "rescheduleExternalReservation", "cancelExternalReservation", "acquireHold", "markHoldPaid", "putContact", "deleteContact", "confirmHold", "releaseHold", "putCalendarEvent", "cancelCalendarEvent", "cancelCalendarEventById", "recordCalendarCoverage", "replaceSourceBusy", "reportCoverageConflict", "createWebhookEndpoint", "deleteWebhookEndpoint", "enableWebhookEndpoint", "recordCoverageFailure", "deleteCoverage", "checkInReservation", "joinWaitlist", "leaveWaitlist", "declineWaitlistOffer", "putAssistantSettings", "deleteAssistantSettings", "resealAssistantKey", "putAssistantChat", "renameAssistantChat", "settleAssistantAction", "deleteAssistantChat"];