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.
- package/CHANGELOG.md +542 -0
- package/NOTICE +2 -0
- package/README.md +4 -2
- package/agent-server.d.ts +25 -5
- package/agent-server.js +152 -7
- package/agent-store-backend.d.ts +6 -1
- package/agent-store-backend.js +1068 -68
- package/application-api.d.ts +28 -1
- package/application-api.js +789 -21
- package/approvals.d.ts +2 -0
- package/approvals.js +12 -5
- package/assistant.d.ts +34 -8
- package/assistant.js +81 -26
- package/availability-store.d.ts +193 -0
- package/availability-store.js +566 -0
- package/booking-rules.d.ts +103 -5
- package/booking-rules.js +263 -15
- package/config.d.ts +50 -0
- package/config.js +107 -0
- package/dashboard-assistant-ui.d.ts +1 -1
- package/dashboard-assistant-ui.js +109 -8
- package/dashboard-scope.d.ts +7 -0
- package/dashboard-scope.js +21 -0
- package/dashboard.d.ts +152 -8
- package/dashboard.js +3868 -399
- package/ddl-identity.d.ts +25 -0
- package/ddl-identity.js +881 -0
- package/ddl-scim.d.ts +5 -0
- package/ddl-scim.js +740 -0
- package/ddl-sso.d.ts +15 -0
- package/ddl-sso.js +1033 -0
- package/ddl.d.ts +44 -9
- package/ddl.js +2872 -47
- package/domains.d.ts +117 -0
- package/domains.js +340 -0
- package/event-feed.d.ts +2 -2
- package/event-feed.js +24 -34
- package/holiday-import.d.ts +38 -0
- package/holiday-import.js +56 -0
- package/holidays.d.ts +38 -0
- package/holidays.js +209 -0
- package/hours.d.ts +125 -0
- package/hours.js +224 -0
- package/index.d.ts +24 -5
- package/index.js +17 -3
- package/interop.d.ts +25 -7
- package/interop.js +145 -17
- package/invitation-email.d.ts +26 -0
- package/invitation-email.js +73 -0
- package/lifecycle.d.ts +31 -0
- package/lifecycle.js +115 -0
- package/maintenance.d.ts +26 -2
- package/maintenance.js +70 -2
- package/metrics.js +3 -0
- package/oidc.d.ts +135 -0
- package/oidc.js +452 -0
- package/openapi.json +20172 -9850
- package/package.json +2 -1
- package/ranges.d.ts +28 -0
- package/ranges.js +135 -0
- package/resource-search.d.ts +19 -0
- package/resource-search.js +153 -0
- package/rest-api.js +7 -0
- package/rules.d.ts +2 -0
- package/rules.js +2 -0
- package/scim-server.d.ts +19 -0
- package/scim-server.js +243 -0
- package/scim.d.ts +180 -0
- package/scim.js +416 -0
- package/self-host.d.ts +19 -6
- package/self-host.js +483 -28
- package/slotlock.manifest.json +1 -1
- package/store.d.ts +637 -23
- package/store.js +2529 -147
- package/types.d.ts +230 -0
- package/types.js +68 -1
- package/workspace-domains.d.ts +146 -0
- package/workspace-domains.js +249 -0
- package/workspace-roles.d.ts +47 -0
- package/workspace-roles.js +304 -0
- package/workspace-scim.d.ts +89 -0
- package/workspace-scim.js +157 -0
- package/workspace-sso.d.ts +131 -0
- package/workspace-sso.js +180 -0
- package/workspaces.d.ts +240 -0
- 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
|
-
/**
|
|
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
|
-
/**
|
|
1022
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
1031
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
1043
|
-
* `patch`. The action as changed, or null when it is not in that state (or not
|
|
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
|
-
/**
|
|
1054
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
/**
|
|
1199
|
-
|
|
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", "
|
|
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"];
|