slotlock 0.6.3 → 0.7.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 +467 -0
- package/CONTRIBUTING.md +12 -5
- package/README.md +50 -1551
- package/SECURITY.md +5 -2
- package/SPEC.md +1 -1
- package/agent-server.d.ts +160 -8
- package/agent-server.js +559 -44
- package/agent-store-backend.d.ts +34 -1
- package/agent-store-backend.js +1399 -38
- package/api-keys.d.ts +69 -3
- package/api-keys.js +217 -28
- package/application-api.d.ts +56 -3
- package/application-api.js +826 -15
- package/approvals.d.ts +88 -0
- package/approvals.js +293 -0
- package/assistant.d.ts +40 -0
- package/assistant.js +115 -0
- package/billing.d.ts +114 -0
- package/billing.js +258 -0
- package/config.d.ts +25 -4
- package/config.js +72 -3
- package/dashboard-icon.d.ts +1 -0
- package/dashboard-icon.js +5 -0
- package/dashboard.d.ts +203 -7
- package/dashboard.js +1545 -64
- package/ddl.d.ts +51 -12
- package/ddl.js +2566 -54
- package/event-feed.d.ts +30 -4
- package/event-feed.js +171 -19
- package/index.d.ts +15 -4
- package/index.js +8 -2
- package/maintenance.d.ts +10 -0
- package/maintenance.js +16 -2
- package/metrics.d.ts +41 -0
- package/metrics.js +22 -0
- package/openapi.json +14675 -5957
- package/otel.d.ts +86 -0
- package/otel.js +273 -0
- package/overage.d.ts +33 -0
- package/overage.js +115 -0
- package/package.json +1 -1
- package/partner-billing.d.ts +81 -0
- package/partner-billing.js +333 -0
- package/partner-names.d.ts +8 -0
- package/partner-names.js +10 -0
- package/partners.d.ts +147 -0
- package/partners.js +375 -0
- package/plans.d.ts +92 -0
- package/plans.js +115 -0
- package/quotas.d.ts +108 -0
- package/quotas.js +258 -0
- package/rate-limit.d.ts +21 -1
- package/rate-limit.js +82 -15
- package/resource-profile.d.ts +135 -0
- package/resource-profile.js +263 -0
- package/rest-api.d.ts +2 -0
- package/rest-api.js +68 -3
- package/sandbox.d.ts +70 -0
- package/sandbox.js +295 -0
- package/self-host.d.ts +33 -5
- package/self-host.js +950 -22
- package/slotlock.manifest.json +1 -1
- package/store.d.ts +373 -4
- package/store.js +1212 -118
- package/teams.d.ts +25 -0
- package/teams.js +63 -0
- package/timezone.js +13 -1
- package/types.d.ts +95 -1
- package/usage.d.ts +106 -0
- package/usage.js +238 -0
package/slotlock.manifest.json
CHANGED
package/store.d.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import { type SlotlockResourceKind, type SlotlockResourceProfileInput, type SlotlockLocation, type SlotlockPoolOrder, type SlotlockResourceGroup, type SlotlockResourceScope } from './resource-profile.js';
|
|
2
|
+
import { type SlotlockUsageRow } from './usage.js';
|
|
1
3
|
import { type SlotlockChangeOrigin, type SlotlockEventFeed } from './event-feed.js';
|
|
2
4
|
import { type SlotlockBookingRules } from './booking-rules.js';
|
|
3
5
|
import type { Sql, TransactionSql } from 'postgres';
|
|
4
6
|
import { SLOTLOCK_CALENDAR_HORIZON_DAYS } from './rules.js';
|
|
5
|
-
import type { AcquireHoldResult, CalendarCoverageCommand, CalendarCoverageResult, CalendarEventContent, CalendarEventRetentionResult, BookingRetentionResult, SlotlockTenantErasure, SlotlockBookingRuleDefaults, CalendarFreeBusy, CalendarHorizonRollCursor, CalendarHorizonRollResult, CancelCalendarEventResult, CancelExternalReservationResult, ConfirmHoldResult, CreateReservationResult, DeleteResourceResult, ExternalReservationCommand, ExternalReservationResult, Interval, SlotlockCalendarEvent, SlotlockAgendaEntry, SlotlockHold, SlotlockReservation, SlotlockResource, PutCalendarEventCommand, PutCalendarEventResult, ReleaseHoldResult, WeeklyAvailabilityRule } from './types.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';
|
|
8
|
+
import { type PutApprovalPolicyParams } from './approvals.js';
|
|
6
9
|
export { SLOTLOCK_CALENDAR_HORIZON_DAYS };
|
|
7
10
|
/**
|
|
8
11
|
* Longest one-off event (ten years and some leap days); a recurring series is bounded by its
|
|
@@ -137,6 +140,13 @@ export interface SlotlockStore extends SlotlockEventFeed {
|
|
|
137
140
|
origin?: SlotlockChangeOrigin;
|
|
138
141
|
/** The id (a UUID) of the API key making these changes, recorded with each. */
|
|
139
142
|
keyId?: string;
|
|
143
|
+
/**
|
|
144
|
+
* A key limited to part of its tenant (RFC 0003 G6): the transaction reaches only the
|
|
145
|
+
* resources at these locations (each with every location in it) or in these groups, as they
|
|
146
|
+
* are when it starts, by the database's resource_scope_v1 policies, on every table keyed by
|
|
147
|
+
* resource, for reads and writes. A resource outside it is not found.
|
|
148
|
+
*/
|
|
149
|
+
resourceScope?: SlotlockResourceScope;
|
|
140
150
|
}): Promise<T>;
|
|
141
151
|
/**
|
|
142
152
|
* INVARIANT (erasure completeness): a tenant integration must use a stable, erasable business
|
|
@@ -159,7 +169,103 @@ export interface SlotlockStore extends SlotlockEventFeed {
|
|
|
159
169
|
* refused (`resource_visibility_conflict`).
|
|
160
170
|
*/
|
|
161
171
|
visibility?: SlotlockResource['visibility'];
|
|
172
|
+
/**
|
|
173
|
+
* Its profile (resource-profile.ts): name, description, kind, capacity, labels and attributes,
|
|
174
|
+
* each optional. Creating an existing reference again sets the fields given and keeps the rest.
|
|
175
|
+
* Refused (`invalid_resource_profile`) outside its bounds, or for a resource with no tenant.
|
|
176
|
+
*/
|
|
177
|
+
profile?: SlotlockResourceProfileInput;
|
|
178
|
+
/**
|
|
179
|
+
* The reference of the location it is at (`location_not_found` when the tenant has none such).
|
|
180
|
+
* Without a `timezone`, a new resource takes the nearest time zone its location, or one above
|
|
181
|
+
* it, has, else UTC.
|
|
182
|
+
*/
|
|
183
|
+
location?: string;
|
|
162
184
|
}): Promise<SlotlockResource>;
|
|
185
|
+
/**
|
|
186
|
+
* Change one of the tenant's resources' profile: the fields given, keeping the rest (`null`
|
|
187
|
+
* clears a name, description or capacity). Null for an id that is not the tenant's; refused
|
|
188
|
+
* (`invalid_resource_profile`) outside its bounds. The feed's `resource.updated` names the
|
|
189
|
+
* fields that changed (`profile_changed`), never their values.
|
|
190
|
+
*/
|
|
191
|
+
updateResourceProfile(params: {
|
|
192
|
+
tenantRef: string;
|
|
193
|
+
id: string;
|
|
194
|
+
profile: SlotlockResourceProfileInput;
|
|
195
|
+
/** Move it to this location, or to none (`null`); left out, it stays (`location_not_found`). */
|
|
196
|
+
location?: string | null;
|
|
197
|
+
}): Promise<SlotlockResource | null>;
|
|
198
|
+
/**
|
|
199
|
+
* The tenant's locations, each under its parent, depth first (RFC 0003 G2), with how many
|
|
200
|
+
* resources are at each.
|
|
201
|
+
*/
|
|
202
|
+
listLocations(params: {
|
|
203
|
+
tenantRef: string;
|
|
204
|
+
}): Promise<SlotlockLocation[]>;
|
|
205
|
+
/**
|
|
206
|
+
* Create the location with this reference, or change its name, and the parent and time zone
|
|
207
|
+
* given. Refused: `invalid_location` (naming the field), `location_not_found` (no such parent),
|
|
208
|
+
* `location_too_deep` (past SLOTLOCK_MAX_LOCATION_DEPTH levels), `location_cycle` (under itself),
|
|
209
|
+
* `location_limit_reached` (SLOTLOCK_MAX_LOCATIONS).
|
|
210
|
+
*/
|
|
211
|
+
putLocation(params: {
|
|
212
|
+
tenantRef: string;
|
|
213
|
+
ref: string;
|
|
214
|
+
name: string;
|
|
215
|
+
parentRef?: string | null;
|
|
216
|
+
timezone?: string | null;
|
|
217
|
+
}): Promise<SlotlockLocation>;
|
|
218
|
+
/** Change a location's name, parent or time zone, as putLocation; null when it has none such. */
|
|
219
|
+
updateLocation(params: {
|
|
220
|
+
tenantRef: string;
|
|
221
|
+
ref: string;
|
|
222
|
+
name?: string;
|
|
223
|
+
parentRef?: string | null;
|
|
224
|
+
timezone?: string | null;
|
|
225
|
+
}): Promise<SlotlockLocation | null>;
|
|
226
|
+
/**
|
|
227
|
+
* Delete a location: false when it has none such; refused (`location_in_use`) while a resource is
|
|
228
|
+
* at it or a location is under it.
|
|
229
|
+
*/
|
|
230
|
+
deleteLocation(params: {
|
|
231
|
+
tenantRef: string;
|
|
232
|
+
ref: string;
|
|
233
|
+
}): Promise<boolean>;
|
|
234
|
+
/** The tenant's groups (RFC 0003 G3), by reference, with how many resources are in each. */
|
|
235
|
+
listGroups(params: {
|
|
236
|
+
tenantRef: string;
|
|
237
|
+
}): Promise<SlotlockResourceGroup[]>;
|
|
238
|
+
/**
|
|
239
|
+
* Create the group with this reference, or change its name, and its description when given.
|
|
240
|
+
* Refused: `invalid_group` (naming the field), `group_limit_reached` (SLOTLOCK_MAX_RESOURCE_GROUPS).
|
|
241
|
+
*/
|
|
242
|
+
putGroup(params: {
|
|
243
|
+
tenantRef: string;
|
|
244
|
+
ref: string;
|
|
245
|
+
name: string;
|
|
246
|
+
description?: string | null;
|
|
247
|
+
}): Promise<SlotlockResourceGroup>;
|
|
248
|
+
/** Delete a group, its resources left as they are: false when it has none such. */
|
|
249
|
+
deleteGroup(params: {
|
|
250
|
+
tenantRef: string;
|
|
251
|
+
ref: string;
|
|
252
|
+
}): Promise<boolean>;
|
|
253
|
+
/**
|
|
254
|
+
* Put one of the tenant's resources in a group: true when it was not in it. Refused:
|
|
255
|
+
* `group_not_found`, `resource_not_found`, `resource_group_limit_reached`
|
|
256
|
+
* (SLOTLOCK_MAX_GROUPS_PER_RESOURCE).
|
|
257
|
+
*/
|
|
258
|
+
addGroupMember(params: {
|
|
259
|
+
tenantRef: string;
|
|
260
|
+
group: string;
|
|
261
|
+
resourceId: string;
|
|
262
|
+
}): Promise<boolean>;
|
|
263
|
+
/** Take a resource out of a group: true when it was in it. */
|
|
264
|
+
removeGroupMember(params: {
|
|
265
|
+
tenantRef: string;
|
|
266
|
+
group: string;
|
|
267
|
+
resourceId: string;
|
|
268
|
+
}): Promise<boolean>;
|
|
163
269
|
/**
|
|
164
270
|
* Resolve one tenant-owned resource without revealing another tenant's matching id. An archived
|
|
165
271
|
* one is returned (with `archivedAt`); with `visibility`, only one of that visibility.
|
|
@@ -250,15 +356,55 @@ export interface SlotlockStore extends SlotlockEventFeed {
|
|
|
250
356
|
tenantRef: string;
|
|
251
357
|
pool: string;
|
|
252
358
|
visibility?: 'shared';
|
|
359
|
+
/** In the pool's order (`setPoolOrder`) rather than by id. */
|
|
360
|
+
ordered?: boolean;
|
|
361
|
+
/**
|
|
362
|
+
* For a booking about to take one (with `ordered`): a round-robin pool's place is locked until
|
|
363
|
+
* the transaction ends, so bookings at once go round in turn instead of starting from one place.
|
|
364
|
+
*/
|
|
365
|
+
forBooking?: boolean;
|
|
253
366
|
}): Promise<SlotlockResource[]>;
|
|
254
|
-
/**
|
|
367
|
+
/**
|
|
368
|
+
* The tenant's pools by name, with how many members each has that may be booked (its capacity)
|
|
369
|
+
* and the order a pool booking tries them in.
|
|
370
|
+
*/
|
|
255
371
|
listPools(params: {
|
|
256
372
|
tenantRef: string;
|
|
257
373
|
visibility?: 'shared';
|
|
258
374
|
}): Promise<{
|
|
259
375
|
pool: string;
|
|
260
376
|
capacity: number;
|
|
377
|
+
order: SlotlockPoolOrder;
|
|
261
378
|
}[]>;
|
|
379
|
+
/**
|
|
380
|
+
* Set the order a pool booking tries a pool's members in (RFC 0003 G7): `stable` (by id, the
|
|
381
|
+
* default), `least_booked` or `round_robin`: `invalid_pool` for a name that is not a pool's,
|
|
382
|
+
* `invalid_pool_order` for an order that is not one of these, `pool_order_limit_reached` past
|
|
383
|
+
* SLOTLOCK_MAX_POOL_SETTINGS pools a tenant.
|
|
384
|
+
*/
|
|
385
|
+
setPoolOrder(params: {
|
|
386
|
+
tenantRef: string;
|
|
387
|
+
pool: string;
|
|
388
|
+
order: SlotlockPoolOrder;
|
|
389
|
+
}): Promise<SlotlockPoolOrder>;
|
|
390
|
+
/**
|
|
391
|
+
* Make a resource a part of another (RFC 0003 G8), or no part (`null`): a booking of the whole
|
|
392
|
+
* then conflicts with every part, two parts never with each other. Null for no such resource;
|
|
393
|
+
* `parent_not_found`, `composite_too_deep` (one level only), `composite_parts_limit`
|
|
394
|
+
* (SLOTLOCK_MAX_COMPOSITE_PARTS) and `composite_busy` (either side has a booking or live hold to
|
|
395
|
+
* come) refuse it.
|
|
396
|
+
*/
|
|
397
|
+
setResourceParent(params: {
|
|
398
|
+
tenantRef: string;
|
|
399
|
+
id: string;
|
|
400
|
+
parentId: string | null;
|
|
401
|
+
}): Promise<SlotlockResource | null>;
|
|
402
|
+
/** Note the member a pool booking took, from which `round_robin` goes on. */
|
|
403
|
+
notePoolBooking(params: {
|
|
404
|
+
tenantRef: string;
|
|
405
|
+
pool: string;
|
|
406
|
+
resourceId: string;
|
|
407
|
+
}): Promise<void>;
|
|
262
408
|
/** Set (or clear, with `null`) the bookable hours of every resource the tenant has; returns how many. */
|
|
263
409
|
setTenantAvailability(params: {
|
|
264
410
|
tenantRef: string;
|
|
@@ -273,7 +419,43 @@ export interface SlotlockStore extends SlotlockEventFeed {
|
|
|
273
419
|
visibility?: SlotlockResource['visibility'];
|
|
274
420
|
/** Archived resources too; omitted, only those in use. */
|
|
275
421
|
includeArchived?: boolean;
|
|
422
|
+
/** Only resources of this kind (`other` for those that say none). */
|
|
423
|
+
kind?: SlotlockResourceKind;
|
|
424
|
+
/** Only resources with every one of these labels (at most 20). */
|
|
425
|
+
labels?: readonly string[];
|
|
426
|
+
/** Only resources at this location or a location under it. */
|
|
427
|
+
location?: string;
|
|
428
|
+
/** Only resources in this group. */
|
|
429
|
+
group?: string;
|
|
430
|
+
/** Only this pool's members. */
|
|
431
|
+
pool?: string;
|
|
276
432
|
}): Promise<SlotlockResource[]>;
|
|
433
|
+
/**
|
|
434
|
+
* How many resources the tenant has, archived ones included: the count a resource limit (a hosted
|
|
435
|
+
* plan's, `maxTenantResources`) is checked against.
|
|
436
|
+
*/
|
|
437
|
+
countResources(params: {
|
|
438
|
+
tenantRef: string;
|
|
439
|
+
}): Promise<number>;
|
|
440
|
+
/**
|
|
441
|
+
* Roll the tenant's committed bookings and holds up from its feed into its daily usage
|
|
442
|
+
* (usage.ts, `slotlock.roll_up_usage`), up to `limit` changes (1-100,000, default 5,000): how
|
|
443
|
+
* many it read. Fewer than `limit` means it has caught up.
|
|
444
|
+
*/
|
|
445
|
+
rollUpUsage(params: {
|
|
446
|
+
tenantRef: string;
|
|
447
|
+
limit?: number;
|
|
448
|
+
}): Promise<number>;
|
|
449
|
+
/**
|
|
450
|
+
* The tenant's usage from `from` to `to`, UTC days `YYYY-MM-DD` inclusive, at most
|
|
451
|
+
* SLOTLOCK_USAGE_RETENTION_DAYS apart (usage.ts, `slotlock.tenant_usage`): empty unless the
|
|
452
|
+
* deployment meters it.
|
|
453
|
+
*/
|
|
454
|
+
readUsage(params: {
|
|
455
|
+
tenantRef: string;
|
|
456
|
+
from: string;
|
|
457
|
+
to: string;
|
|
458
|
+
}): Promise<SlotlockUsageRow[]>;
|
|
277
459
|
/**
|
|
278
460
|
* Insert a confirmed reservation with the EXCLUDE constraint as the overlap arbiter; expected
|
|
279
461
|
* outcomes (invalid window, lost race) come back structured. Expired holds overlapping the window
|
|
@@ -331,6 +513,14 @@ export interface SlotlockStore extends SlotlockEventFeed {
|
|
|
331
513
|
* holder and no cap.
|
|
332
514
|
*/
|
|
333
515
|
holderRef?: string;
|
|
516
|
+
/**
|
|
517
|
+
* Lower the holder's caps for this hold (an API key's own limits, RFC 0004 A5): never above
|
|
518
|
+
* `maxHoldsPerHolder` and `maxHeldHoursPerHolder`, which win where they are lower.
|
|
519
|
+
*/
|
|
520
|
+
holderCaps?: {
|
|
521
|
+
maxHolds?: number;
|
|
522
|
+
maxHeldHours?: number;
|
|
523
|
+
};
|
|
334
524
|
/**
|
|
335
525
|
* Holds taken as alternatives for one booking share a group (a UUID): booking one with
|
|
336
526
|
* `fromHold` releases the rest, and releasing one with a holder releases them all.
|
|
@@ -342,6 +532,18 @@ export interface SlotlockStore extends SlotlockEventFeed {
|
|
|
342
532
|
tenantRef: string;
|
|
343
533
|
holdId: string;
|
|
344
534
|
}): Promise<SlotlockHold | null>;
|
|
535
|
+
/**
|
|
536
|
+
* One holder's own hold by id, lapsed or live (`live`), so a confirm can say `hold_expired`
|
|
537
|
+
* rather than not found. Null when it is gone, booked, or another holder's.
|
|
538
|
+
*/
|
|
539
|
+
getHolderHold(params: {
|
|
540
|
+
tenantRef: string;
|
|
541
|
+
holdId: string;
|
|
542
|
+
holderRef: string;
|
|
543
|
+
}): Promise<{
|
|
544
|
+
hold: SlotlockHold;
|
|
545
|
+
live: boolean;
|
|
546
|
+
} | null>;
|
|
345
547
|
/** The tenant's live holds on one resource, by start then id, keyset-paginated like events. */
|
|
346
548
|
listHolds(params: {
|
|
347
549
|
tenantRef: string;
|
|
@@ -371,6 +573,156 @@ export interface SlotlockStore extends SlotlockEventFeed {
|
|
|
371
573
|
tenantRef: string;
|
|
372
574
|
externalRef: string;
|
|
373
575
|
}): Promise<SlotlockReservation | null>;
|
|
576
|
+
/**
|
|
577
|
+
* Any booking, hold or event occurrence of the tenant's by its row id (the id a refused write's
|
|
578
|
+
* `conflictingReservationId` names): the time it occupies, buffers included, and whose it is.
|
|
579
|
+
* Null when the tenant has none, or the transaction's key may not see it.
|
|
580
|
+
*/
|
|
581
|
+
describeBooking(params: {
|
|
582
|
+
tenantRef: string;
|
|
583
|
+
id: string;
|
|
584
|
+
}): Promise<SlotlockBookingDescription | null>;
|
|
585
|
+
/**
|
|
586
|
+
* The time an owner's calendar events occupy now, buffers included, one row per occupation: what
|
|
587
|
+
* an approval (RFC 0004 A4) holds for a write, read in the write's own rolled-back transaction.
|
|
588
|
+
*/
|
|
589
|
+
eventOccupancy(params: {
|
|
590
|
+
tenantRef: string;
|
|
591
|
+
ownerRef: string;
|
|
592
|
+
externalRefs: readonly string[];
|
|
593
|
+
}): Promise<{
|
|
594
|
+
resourceId: string;
|
|
595
|
+
start: Date;
|
|
596
|
+
end: Date;
|
|
597
|
+
recurring: boolean;
|
|
598
|
+
}[]>;
|
|
599
|
+
/** Create or replace an approval policy; null when the tenant has its 50 already. */
|
|
600
|
+
putApprovalPolicy(params: PutApprovalPolicyParams): Promise<SlotlockApprovalPolicy | null>;
|
|
601
|
+
listApprovalPolicies(params: {
|
|
602
|
+
tenantRef: string;
|
|
603
|
+
}): Promise<SlotlockApprovalPolicy[]>;
|
|
604
|
+
deleteApprovalPolicy(params: {
|
|
605
|
+
tenantRef: string;
|
|
606
|
+
ref: string;
|
|
607
|
+
}): Promise<{
|
|
608
|
+
deleted: boolean;
|
|
609
|
+
}>;
|
|
610
|
+
/** The tenant's policies that apply to any of these resources (by id, pool, location, group, or all). */
|
|
611
|
+
approvalPoliciesFor(params: {
|
|
612
|
+
tenantRef: string;
|
|
613
|
+
resourceIds: readonly string[];
|
|
614
|
+
}): Promise<SlotlockApprovalPolicy[]>;
|
|
615
|
+
/**
|
|
616
|
+
* A write waiting for a person: its time held by holds the approval owns, until `expiresAt`, and
|
|
617
|
+
* the request kept to run as its requester when granted. A retry with the same `requestKey`
|
|
618
|
+
* answers the same approval (`replayed`), or `idempotency_conflict` for another request. With
|
|
619
|
+
* `consumeHold`, the requester's own hold of that time gives way to the approval's in the same
|
|
620
|
+
* transaction. `overlap` when the time is taken; `approval_limit_reached` past the pending caps.
|
|
621
|
+
*/
|
|
622
|
+
requestApproval(params: {
|
|
623
|
+
tenantRef: string;
|
|
624
|
+
policyRef: string;
|
|
625
|
+
operation: SlotlockApproval['operation'];
|
|
626
|
+
request: Record<string, unknown>;
|
|
627
|
+
requester: Record<string, unknown>;
|
|
628
|
+
requesterRef: string;
|
|
629
|
+
requestKey: string;
|
|
630
|
+
holds: readonly {
|
|
631
|
+
resourceId: string;
|
|
632
|
+
start: Date;
|
|
633
|
+
end: Date;
|
|
634
|
+
}[];
|
|
635
|
+
start: Date;
|
|
636
|
+
end: Date;
|
|
637
|
+
expiresAt: Date;
|
|
638
|
+
consumeHold?: {
|
|
639
|
+
holdId: string;
|
|
640
|
+
holderRef: string;
|
|
641
|
+
};
|
|
642
|
+
}): Promise<{
|
|
643
|
+
ok: true;
|
|
644
|
+
approval: SlotlockApproval;
|
|
645
|
+
replayed: boolean;
|
|
646
|
+
} | {
|
|
647
|
+
ok: false;
|
|
648
|
+
code: 'overlap' | 'approval_limit_reached' | 'idempotency_conflict';
|
|
649
|
+
limit?: number;
|
|
650
|
+
}>;
|
|
651
|
+
/** The approval a request key made, or null. */
|
|
652
|
+
findApproval(params: {
|
|
653
|
+
tenantRef: string;
|
|
654
|
+
requestKey: string;
|
|
655
|
+
}): Promise<SlotlockApproval | null>;
|
|
656
|
+
getApproval(params: {
|
|
657
|
+
tenantRef: string;
|
|
658
|
+
id: string;
|
|
659
|
+
}): Promise<(SlotlockApproval & {
|
|
660
|
+
requester: Record<string, unknown>;
|
|
661
|
+
}) | null>;
|
|
662
|
+
listApprovals(params: {
|
|
663
|
+
tenantRef: string;
|
|
664
|
+
status?: SlotlockApproval['status'];
|
|
665
|
+
limit?: number;
|
|
666
|
+
}): Promise<SlotlockApproval[]>;
|
|
667
|
+
/**
|
|
668
|
+
* Lock a pending, unexpired approval and let its holds go, so its write can take their time in
|
|
669
|
+
* the same transaction; finishApprovalGrant then marks it granted.
|
|
670
|
+
*/
|
|
671
|
+
beginApprovalGrant(params: {
|
|
672
|
+
tenantRef: string;
|
|
673
|
+
id: string;
|
|
674
|
+
}): Promise<{
|
|
675
|
+
ok: true;
|
|
676
|
+
approval: SlotlockApproval;
|
|
677
|
+
} | {
|
|
678
|
+
ok: false;
|
|
679
|
+
code: 'approval_not_found' | 'approval_not_pending' | 'approval_expired';
|
|
680
|
+
}>;
|
|
681
|
+
finishApprovalGrant(params: {
|
|
682
|
+
tenantRef: string;
|
|
683
|
+
id: string;
|
|
684
|
+
decidedBy: string;
|
|
685
|
+
}): Promise<SlotlockApproval>;
|
|
686
|
+
declineApproval(params: {
|
|
687
|
+
tenantRef: string;
|
|
688
|
+
id: string;
|
|
689
|
+
decidedBy: string;
|
|
690
|
+
reason?: string;
|
|
691
|
+
}): Promise<{
|
|
692
|
+
ok: true;
|
|
693
|
+
approval: SlotlockApproval;
|
|
694
|
+
} | {
|
|
695
|
+
ok: false;
|
|
696
|
+
code: 'approval_not_found' | 'approval_not_pending' | 'approval_expired';
|
|
697
|
+
}>;
|
|
698
|
+
/** Maintenance: up to `limit` pending approvals past their wait expire and free their time. */
|
|
699
|
+
expireApprovals(params: {
|
|
700
|
+
tenantRef: string;
|
|
701
|
+
limit?: number;
|
|
702
|
+
}): Promise<{
|
|
703
|
+
expired: number;
|
|
704
|
+
}>;
|
|
705
|
+
/**
|
|
706
|
+
* Empty a test environment (RFC 0004 A6): its resources, locations, groups, bookings, events,
|
|
707
|
+
* holds, waitlist, approval policies and feed; its keys, webhooks, plan and usage stay. Refused
|
|
708
|
+
* (`sandbox_test_only`) for a tenant that is not a test environment (`~test`). Rows removed, by
|
|
709
|
+
* table.
|
|
710
|
+
*/
|
|
711
|
+
resetTestTenant(params: {
|
|
712
|
+
tenantRef: string;
|
|
713
|
+
}): Promise<Record<string, number>>;
|
|
714
|
+
/**
|
|
715
|
+
* In a test environment, make what would lapse within `minutes` lapse now (RFC 0004 A6): holds
|
|
716
|
+
* (a waitlist offer's and an approval's among them) and pending approvals. Maintenance then
|
|
717
|
+
* reaps them as it would have. Refused (`sandbox_test_only`) elsewhere.
|
|
718
|
+
*/
|
|
719
|
+
fastForwardTestTenant(params: {
|
|
720
|
+
tenantRef: string;
|
|
721
|
+
minutes: number;
|
|
722
|
+
}): Promise<{
|
|
723
|
+
holds: number;
|
|
724
|
+
approvals: number;
|
|
725
|
+
}>;
|
|
374
726
|
/**
|
|
375
727
|
* The tenant's bookings on one resource whose occupied time meets `window` (at most 367 days),
|
|
376
728
|
* by start then id, keyset-paginated: pass the last one's `{ start, id }` as `after`.
|
|
@@ -604,6 +956,11 @@ export interface SlotlockStore extends SlotlockEventFeed {
|
|
|
604
956
|
end: Date;
|
|
605
957
|
holderRef: string;
|
|
606
958
|
offerTtlMs?: number;
|
|
959
|
+
/**
|
|
960
|
+
* A retry identity, kept as long as the entry: the same key and request answer the entry the
|
|
961
|
+
* first made (`replayed`), another request `idempotency_conflict`.
|
|
962
|
+
*/
|
|
963
|
+
idempotencyKey?: string;
|
|
607
964
|
}): Promise<JoinWaitlistResult>;
|
|
608
965
|
/** The tenant's waitlist entries, oldest first, optionally of one resource, pool or holder. */
|
|
609
966
|
listWaitlist(params: {
|
|
@@ -650,6 +1007,17 @@ export interface SlotlockStore extends SlotlockEventFeed {
|
|
|
650
1007
|
deleteAssistantSettings(params: {
|
|
651
1008
|
tenantRef: string;
|
|
652
1009
|
}): Promise<boolean>;
|
|
1010
|
+
/**
|
|
1011
|
+
* Replace the tenant's sealed assistant key `from` with `to`, the same key sealed under a newer
|
|
1012
|
+
* secret (SLOTLOCK_ASSISTANT_PREVIOUS_SECRETS), only while `from` is still the one stored: a key an
|
|
1013
|
+
* owner saved since is never overwritten. Nothing else changes, its hint and who set it included.
|
|
1014
|
+
* True when it was replaced.
|
|
1015
|
+
*/
|
|
1016
|
+
resealAssistantKey(params: {
|
|
1017
|
+
tenantRef: string;
|
|
1018
|
+
from: string;
|
|
1019
|
+
to: string;
|
|
1020
|
+
}): Promise<boolean>;
|
|
653
1021
|
/** A member's live assistant conversation, or null when none is (or it expired). */
|
|
654
1022
|
getAssistantConversation(params: {
|
|
655
1023
|
tenantRef: string;
|
|
@@ -837,9 +1205,10 @@ export interface SlotlockWaitlistEntry {
|
|
|
837
1205
|
export type JoinWaitlistResult = {
|
|
838
1206
|
ok: true;
|
|
839
1207
|
entry: SlotlockWaitlistEntry;
|
|
1208
|
+
replayed: boolean;
|
|
840
1209
|
} | {
|
|
841
1210
|
ok: false;
|
|
842
|
-
code: 'invalid_identity' | 'invalid_window' | 'invalid_ttl' | 'invalid_pool' | 'resource_not_found' | 'resource_archived' | 'pool_not_found' | 'waitlist_limit_reached';
|
|
1211
|
+
code: 'invalid_identity' | 'invalid_window' | 'invalid_ttl' | 'invalid_pool' | 'resource_not_found' | 'resource_archived' | 'pool_not_found' | 'waitlist_limit_reached' | 'idempotency_conflict';
|
|
843
1212
|
};
|
|
844
1213
|
export type CheckInReservationResult = {
|
|
845
1214
|
ok: true;
|
|
@@ -954,4 +1323,4 @@ export declare function createSlotlockStore(sql: StoreSql, options?: SlotlockSto
|
|
|
954
1323
|
* Every store method that writes for a tenant: what a suspended tenant's withTenant store refuses.
|
|
955
1324
|
* Maintenance (rolling series, pruning, purging) and erasure are not among them.
|
|
956
1325
|
*/
|
|
957
|
-
export declare const SLOTLOCK_TENANT_WRITE_METHODS: readonly ["createResource", "archiveResource", "restoreResource", "deleteResource", "setResourceAvailability", "setResourceBookingRules", "setBookingRuleDefaults", "setResourcePool", "setTenantAvailability", "createReservation", "createExternalReservation", "rescheduleExternalReservation", "cancelExternalReservation", "acquireHold", "confirmHold", "releaseHold", "putCalendarEvent", "cancelCalendarEvent", "cancelCalendarEventById", "recordCalendarCoverage", "createWebhookEndpoint", "deleteWebhookEndpoint", "enableWebhookEndpoint", "recordCoverageFailure", "deleteCoverage", "checkInReservation", "joinWaitlist", "leaveWaitlist", "putAssistantSettings", "deleteAssistantSettings", "putAssistantConversation", "settleAssistantAction", "deleteAssistantConversation"];
|
|
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"];
|